config file support

This commit is contained in:
Jan Wolff 2020-05-17 15:18:50 +00:00
parent 39885844a2
commit 72c1e3c813
3 changed files with 95 additions and 51 deletions

17
doc/sheldond.conf Normal file
View file

@ -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

View file

@ -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;

View file

@ -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() {