summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Wolff <janw@mailbox.org>2020-05-17 15:18:50 +0000
committerJan Wolff <janw@mailbox.org>2020-05-17 15:18:50 +0000
commit72c1e3c8132a8269833396ab955586185e7b0e58 (patch)
tree395892d019d8300398bed25b89c00b5e13b07e52
parent39885844a2b7c0fdf03e501379cdc9acd6cd6f30 (diff)
config file support
-rw-r--r--doc/sheldond.conf17
-rw-r--r--src/main.rs97
-rw-r--r--src/server/mod.rs32
3 files changed, 95 insertions, 51 deletions
diff --git a/doc/sheldond.conf b/doc/sheldond.conf
new file mode 100644
index 0000000..87610d1
--- /dev/null
+++ b/doc/sheldond.conf
@@ -0,0 +1,17 @@
+# no virtual host support yet, so this is actually the only host
+default_host = localhost
+
+# should be self explanatory
+gem_root = /var/gemini/
+
+# you can define as many of these as you like
+listen = [::1]:1965
+listen = 127.0.0.1:1965
+
+# privilige level for the server to drop to after initializing
+user = gem-data
+group = gem-data
+
+# certificate data MUST be in PEM format right now
+cert_key = /etc/ssl/private/gemini-key.pem
+cert_chain = /etc/ssl/certs/gemini-chain.pem
diff --git a/src/main.rs b/src/main.rs
index 7f64e33..5639158 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,9 @@
mod mime;
mod server;
use std::env;
+use std::fs::File;
+use std::io::{BufRead, BufReader};
+use std::path::Path;
fn help() {
let version = match option_env!("CARGO_PKG_VERSION") {
@@ -9,69 +12,73 @@ fn help() {
};
println!("usage: sheldond {}", version);
- println!(" -h, --help\t\tdisplay this message");
- println!(" -l, --listen\t\tadd a listening address (you can define multiple)");
- println!(" -d, --default-host\tdefault hostname to listen for");
- println!(" -g, --gem-root\tpath to the gemini root, aka the folder to serve files from");
- println!(" --user\tuser to drop to after opening TLS socket");
- println!(" --group\tgroup to drop to after opening TLS socket");
+ println!(" -c, --config\t\tpath to the configuration file");
}
-fn parse_args() -> Option<server::ServerConfig> {
- let mut has_addr = false;
- let mut has_host = false;
- let mut has_root = false;
- let mut has_user = false;
- let mut has_group = false;
-
- let mut config = server::ServerConfig::new();
+fn parse_args() -> Option<String> {
let mut args = env::args();
loop {
match args.next() {
Some(arg) => {
- if arg == "-h" || arg == "--help" {
- return None;
- }
- if arg == "-l" || arg == "--listen" {
- let addr = args.next().unwrap();
- config.add_addr(addr);
- has_addr = true;
- }
- if arg == "-d" || arg == "--default-host" {
- let host = args.next().unwrap();
- config.set_default_host(host);
- has_host = true;
- }
- if arg == "-g" || arg == "--gem-root" {
- let gem_root = args.next().unwrap();
- config.set_gem_root(gem_root);
- has_root = true;
- }
- if arg == "--user" {
- let user = args.next().unwrap();
- config.set_user(user);
- has_user = true;
- }
- if arg == "--group" {
- let group = args.next().unwrap();
- config.set_group(group);
- has_group = true;
+ if arg == "-c" || arg == "--config" {
+ let config_fname = args.next().unwrap();
+ return Some(config_fname);
}
}
None => break,
}
}
- if !has_addr || !has_host || !has_root || !has_user || !has_group {
- return None;
+ None
+}
+
+fn parse_config(fname: String) -> server::ServerConfig {
+ let path = Path::new(&fname);
+ let mut config = server::ServerConfig::new();
+
+ let file = match File::open(path) {
+ Ok(file) => BufReader::new(file),
+ Err(e) => {
+ panic!(e);
+ }
+ };
+
+ for rline in file.lines() {
+ let line = rline.unwrap();
+ if line == "" || line.starts_with("#") {
+ continue;
+ }
+
+ let mut parts = line.split_whitespace();
+
+ let key = parts.next().unwrap();
+
+ if parts.next().unwrap() != "=" {
+ panic!("malformatted line in config: {}", line);
+ }
+
+ let val = parts.next().unwrap().to_string();
+
+ match key {
+ "default_host" => config.set_default_host(val),
+ "gem_root" => config.set_gem_root(val),
+ "listen" => config.add_addr(val),
+ "user" => config.set_user(val),
+ "group" => config.set_group(val),
+ "cert_key" => config.set_cert_key(val),
+ "cert_chain" => config.set_cert_chain(val),
+ _ => {
+ panic!("unknown key in config: {}", key);
+ }
+ }
}
- Some(config)
+ return config;
}
fn main() {
let config = match parse_args() {
- Some(config) => config,
+ Some(config_fname) => parse_config(config_fname),
None => {
help();
return;
diff --git a/src/server/mod.rs b/src/server/mod.rs
index 643c15b..8359c32 100644
--- a/src/server/mod.rs
+++ b/src/server/mod.rs
@@ -17,6 +17,8 @@ pub struct ServerConfig {
addrs: Vec<SocketAddr>,
user: unistd::Uid,
group: unistd::Gid,
+ cert_key: String,
+ cert_chain: String,
}
impl ServerConfig {
@@ -27,6 +29,8 @@ impl ServerConfig {
addrs: Vec::new(),
user: unistd::getuid(),
group: unistd::getgid(),
+ cert_key: "".to_string(),
+ cert_chain: "".to_string(),
}
}
@@ -53,17 +57,31 @@ impl ServerConfig {
pub fn set_user(&mut self, uname: String) {
self.user = match unistd::User::from_name(&uname) {
- Ok(user) => user.unwrap().uid,
+ Ok(user) => match user {
+ Some(user) => user.uid,
+ None => panic!("unknown user {}", uname),
+ },
Err(e) => panic!(e),
};
}
pub fn set_group(&mut self, gname: String) {
self.group = match unistd::Group::from_name(&gname) {
- Ok(group) => group.unwrap().gid,
+ Ok(group) => match group {
+ Some(group) => group.gid,
+ None => panic!("unknown group {}", gname),
+ },
Err(e) => panic!(e),
};
}
+
+ pub fn set_cert_key(&mut self, fname: String) {
+ self.cert_key = fname;
+ }
+
+ pub fn set_cert_chain(&mut self, fname: String) {
+ self.cert_chain = fname;
+ }
}
pub struct Server {
@@ -77,18 +95,20 @@ impl Server {
}
}
- fn build_acceptor() -> std::sync::Arc<SslAcceptor> {
+ fn build_acceptor(config: &ServerConfig) -> std::sync::Arc<SslAcceptor> {
let mut acceptor = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls()).unwrap();
acceptor
- .set_private_key_file("doc/key.pem", SslFiletype::PEM)
+ .set_private_key_file(config.cert_key.as_str(), SslFiletype::PEM)
+ .unwrap();
+ acceptor
+ .set_certificate_chain_file(config.cert_chain.as_str())
.unwrap();
- acceptor.set_certificate_chain_file("doc/cert.pem").unwrap();
acceptor.check_private_key().unwrap();
return Arc::new(acceptor.build());
}
pub fn serve(&self) {
- let acceptor = Server::build_acceptor();
+ let acceptor = Server::build_acceptor(&self.config);
let listener = TcpListener::bind(&self.config.addrs[..]).unwrap();
if self.config.user.is_root() {