mime type handling and setuid/setgid support
This commit is contained in:
parent
4a9c6c11ac
commit
872197c558
6 changed files with 98 additions and 5 deletions
20
Cargo.lock
generated
20
Cargo.lock
generated
|
@ -68,6 +68,19 @@ version = "0.1.8"
|
|||
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"
|
||||
|
@ -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"
|
||||
|
|
|
@ -7,4 +7,5 @@ edition = "2018"
|
|||
[dependencies]
|
||||
openssl = { version = "0.10" }
|
||||
url = { version = "2.1" }
|
||||
nix = { version = "0.17" }
|
||||
|
||||
|
|
17
src/main.rs
17
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;
|
||||
}
|
||||
|
||||
|
|
20
src/mime/mod.rs
Normal file
20
src/mime/mod.rs
Normal file
|
@ -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(),
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue