summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock20
-rw-r--r--Cargo.toml1
-rw-r--r--src/main.rs17
-rw-r--r--src/mime/mod.rs20
-rw-r--r--src/server/handler.rs7
-rw-r--r--src/server/mod.rs38
6 files changed, 98 insertions, 5 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 19bbbb0..65bd816 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -69,6 +69,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
+name = "nix"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
+dependencies = [
+ "bitflags",
+ "cc",
+ "cfg-if",
+ "libc",
+ "void",
+]
+
+[[package]]
name = "openssl"
version = "0.10.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -111,6 +124,7 @@ checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
name = "sheldond"
version = "0.1.0"
dependencies = [
+ "nix",
"openssl",
"url",
]
@@ -155,3 +169,9 @@ name = "vcpkg"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
+
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
diff --git a/Cargo.toml b/Cargo.toml
index ab1b0c2..d61783c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,4 +7,5 @@ edition = "2018"
[dependencies]
openssl = { version = "0.10" }
url = { version = "2.1" }
+nix = { version = "0.17" }
diff --git a/src/main.rs b/src/main.rs
index a381e28..aa572bb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
mod server;
+mod mime;
use std::env;
fn help() {
@@ -12,12 +13,16 @@ fn help() {
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> {
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();
@@ -42,12 +47,22 @@ fn parse_args() -> Option<server::ServerConfig> {
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,
}
}
- if !has_addr || !has_host || !has_root {
+ if !has_addr || !has_host || !has_root || !has_user || !has_group {
return None;
}
diff --git a/src/mime/mod.rs b/src/mime/mod.rs
new file mode 100644
index 0000000..4727f7e
--- /dev/null
+++ b/src/mime/mod.rs
@@ -0,0 +1,20 @@
+use std::ffi::OsStr;
+
+pub fn default_mime_type() -> &'static str {
+ "application/octet-stream"
+}
+
+pub fn get_mime_type(extension: &OsStr) -> &'static str {
+ let ext_str = match extension.to_str() {
+ Some(ext_str) => ext_str,
+ None => {
+ return default_mime_type();
+ },
+ };
+
+ match ext_str {
+ "gmi" => "text/gemini",
+ "txt" => "text/plain",
+ _ => default_mime_type(),
+ }
+}
diff --git a/src/server/handler.rs b/src/server/handler.rs
index d27d292..ec9b523 100644
--- a/src/server/handler.rs
+++ b/src/server/handler.rs
@@ -1,5 +1,6 @@
use crate::server::response;
use crate::server::ServerConfig;
+use crate::mime;
use openssl::ssl::SslStream;
use std::fs::File;
use std::io::{copy, BufReader, BufWriter};
@@ -77,7 +78,11 @@ fn handle_response(config: &ServerConfig, url: Url, mut stream: &mut SslStream<T
}
};
- let header = response::Header::new(response::Status::Success, "text/gemini");
+ let mime_type = match path.extension() {
+ Some(ext) => mime::get_mime_type(ext),
+ None => mime::default_mime_type(),
+ };
+ let header = response::Header::new(response::Status::Success, mime_type);
send_header(&mut stream, &header);
let mut buf_file = BufReader::new(file);
diff --git a/src/server/mod.rs b/src/server/mod.rs
index 696a3a5..f00ab35 100644
--- a/src/server/mod.rs
+++ b/src/server/mod.rs
@@ -5,6 +5,7 @@ use std::sync::Arc;
use std::thread;
use std::vec::Vec;
use url::Url;
+use nix::unistd;
pub mod handler;
pub mod response;
@@ -14,6 +15,8 @@ pub struct ServerConfig {
default_host: Url,
gem_root: PathBuf,
addrs: Vec<SocketAddr>,
+ user: unistd::Uid,
+ group: unistd::Gid,
}
impl ServerConfig {
@@ -22,6 +25,8 @@ impl ServerConfig {
default_host: Url::parse("gemini://localhost").unwrap(),
gem_root: PathBuf::from(""),
addrs: Vec::new(),
+ user: unistd::getuid(),
+ group: unistd::getgid(),
}
}
@@ -45,17 +50,29 @@ impl ServerConfig {
Err(e) => panic!(e),
});
}
+
+ pub fn set_user(&mut self, uname: String) {
+ self.user = match unistd::User::from_name(&uname) {
+ Ok(user) => user.unwrap().uid,
+ 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,
+ Err(e) => panic!(e),
+ };
+ }
}
pub struct Server {
- acceptor: std::sync::Arc<SslAcceptor>,
config: ServerConfig,
}
impl Server {
pub fn new(config: &ServerConfig) -> Server {
Server {
- acceptor: Server::build_acceptor(),
config: config.clone(),
}
}
@@ -71,12 +88,27 @@ impl Server {
}
pub fn serve(&self) {
+ let acceptor = Server::build_acceptor();
let listener = TcpListener::bind(&self.config.addrs[..]).unwrap();
+ if self.config.user.is_root() {
+ panic!("refusing to run as root");
+ }
+
+ match unistd::setgid(self.config.group) {
+ Ok(_) => {},
+ Err(e) => {panic!(e);},
+ };
+
+ match unistd::setuid(self.config.user) {
+ Ok(_) => {},
+ Err(e) => {panic!(e);},
+ };
+
for stream in listener.incoming() {
match stream {
Ok(stream) => {
- let acceptor = self.acceptor.clone();
+ let acceptor = acceptor.clone();
let config = self.config.clone();
thread::spawn(move || {
let stream = acceptor.accept(stream).unwrap();