config file support
This commit is contained in:
parent
39885844a2
commit
72c1e3c813
3 changed files with 95 additions and 51 deletions
17
doc/sheldond.conf
Normal file
17
doc/sheldond.conf
Normal 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
|
97
src/main.rs
97
src/main.rs
|
@ -1,6 +1,9 @@
|
||||||
mod mime;
|
mod mime;
|
||||||
mod server;
|
mod server;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
fn help() {
|
fn help() {
|
||||||
let version = match option_env!("CARGO_PKG_VERSION") {
|
let version = match option_env!("CARGO_PKG_VERSION") {
|
||||||
|
@ -9,69 +12,73 @@ fn help() {
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("usage: sheldond {}", version);
|
println!("usage: sheldond {}", version);
|
||||||
println!(" -h, --help\t\tdisplay this message");
|
println!(" -c, --config\t\tpath to the configuration file");
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_args() -> Option<server::ServerConfig> {
|
fn parse_args() -> Option<String> {
|
||||||
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();
|
|
||||||
let mut args = env::args();
|
let mut args = env::args();
|
||||||
loop {
|
loop {
|
||||||
match args.next() {
|
match args.next() {
|
||||||
Some(arg) => {
|
Some(arg) => {
|
||||||
if arg == "-h" || arg == "--help" {
|
if arg == "-c" || arg == "--config" {
|
||||||
return None;
|
let config_fname = args.next().unwrap();
|
||||||
}
|
return Some(config_fname);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !has_addr || !has_host || !has_root || !has_user || !has_group {
|
None
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(config)
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let config = match parse_args() {
|
let config = match parse_args() {
|
||||||
Some(config) => config,
|
Some(config_fname) => parse_config(config_fname),
|
||||||
None => {
|
None => {
|
||||||
help();
|
help();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -17,6 +17,8 @@ pub struct ServerConfig {
|
||||||
addrs: Vec<SocketAddr>,
|
addrs: Vec<SocketAddr>,
|
||||||
user: unistd::Uid,
|
user: unistd::Uid,
|
||||||
group: unistd::Gid,
|
group: unistd::Gid,
|
||||||
|
cert_key: String,
|
||||||
|
cert_chain: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerConfig {
|
impl ServerConfig {
|
||||||
|
@ -27,6 +29,8 @@ impl ServerConfig {
|
||||||
addrs: Vec::new(),
|
addrs: Vec::new(),
|
||||||
user: unistd::getuid(),
|
user: unistd::getuid(),
|
||||||
group: unistd::getgid(),
|
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) {
|
pub fn set_user(&mut self, uname: String) {
|
||||||
self.user = match unistd::User::from_name(&uname) {
|
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),
|
Err(e) => panic!(e),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_group(&mut self, gname: String) {
|
pub fn set_group(&mut self, gname: String) {
|
||||||
self.group = match unistd::Group::from_name(&gname) {
|
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),
|
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 {
|
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();
|
let mut acceptor = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls()).unwrap();
|
||||||
acceptor
|
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();
|
.unwrap();
|
||||||
acceptor.set_certificate_chain_file("doc/cert.pem").unwrap();
|
|
||||||
acceptor.check_private_key().unwrap();
|
acceptor.check_private_key().unwrap();
|
||||||
return Arc::new(acceptor.build());
|
return Arc::new(acceptor.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve(&self) {
|
pub fn serve(&self) {
|
||||||
let acceptor = Server::build_acceptor();
|
let acceptor = Server::build_acceptor(&self.config);
|
||||||
let listener = TcpListener::bind(&self.config.addrs[..]).unwrap();
|
let listener = TcpListener::bind(&self.config.addrs[..]).unwrap();
|
||||||
|
|
||||||
if self.config.user.is_root() {
|
if self.config.user.is_root() {
|
||||||
|
|
Loading…
Reference in a new issue