From 5378e66e395e7df9ec00d69b129d9da5c6318655 Mon Sep 17 00:00:00 2001 From: _ <> Date: Thu, 19 Nov 2020 01:45:42 +0000 Subject: [PATCH] :bug: Use file permissions to forbid access to ptth_server.toml --- Cargo.toml | 1 + src/bin/ptth_relay.rs | 2 +- src/load_toml.rs | 47 +++++++++++++++++++++++++++++++-------- src/relay/mod.rs | 3 ++- src/server/file_server.rs | 10 +++++++-- todo.md | 5 +++++ 6 files changed, 55 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5bc3f40..2ced302 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ reqwest = { version = "0.10.8", features = ["stream"] } rmp-serde = "0.14.4" serde = {version = "1.0.117", features = ["derive"]} structopt = "0.3.20" +# thiserror = "1.0.22" tokio = { version = "0.2.22", features = ["full"] } tracing = "0.1.21" tracing-futures = "0.2.4" diff --git a/src/bin/ptth_relay.rs b/src/bin/ptth_relay.rs index 77bbb56..a525580 100644 --- a/src/bin/ptth_relay.rs +++ b/src/bin/ptth_relay.rs @@ -21,7 +21,7 @@ async fn main () -> Result <(), Box > { .init () ; - let config_file = ptth::load_toml::load ("config/ptth_relay.toml"); + let config_file = ptth::load_toml::load_public ("config/ptth_relay.toml"); info! ("ptth_relay Git version: {:?}", ptth::git_version::GIT_VERSION); diff --git a/src/load_toml.rs b/src/load_toml.rs index 99acc89..58f7159 100644 --- a/src/load_toml.rs +++ b/src/load_toml.rs @@ -7,19 +7,48 @@ use std::{ use serde::de::DeserializeOwned; -pub fn load < +pub const CONFIG_PERMISSIONS_MODE: u32 = 33152; + +fn load_inner < + T: DeserializeOwned +> ( + mut f: File +) -> T { + let mut buffer = vec! [0u8; 4096]; + let bytes_read = f.read (&mut buffer).unwrap_or_else (|_| panic! ("Can't read config")); + buffer.truncate (bytes_read); + + let config_s = String::from_utf8 (buffer).unwrap_or_else (|_| panic! ("Can't parse config as UTF-8")); + toml::from_str (&config_s).unwrap_or_else (|e| panic! ("Can't parse config as TOML: {}", e)) +} + +/// For files that contain public-viewable information + +pub fn load_public < T: DeserializeOwned, P: AsRef + Debug > ( config_file_path: P ) -> T { let mut f = File::open (&config_file_path).unwrap_or_else (|_| panic! ("Can't open {:?}", config_file_path)); - let mut buffer = vec! [0u8; 4096]; - let bytes_read = f.read (&mut buffer).unwrap_or_else (|_| panic! ("Can't read {:?}", config_file_path)); - buffer.truncate (bytes_read); - - { - let config_s = String::from_utf8 (buffer).unwrap_or_else (|_| panic! ("Can't parse {:?} as UTF-8", config_file_path)); - toml::from_str (&config_s).unwrap_or_else (|e| panic! ("Can't parse {:?} as TOML: {}", config_file_path, e)) - } + load_inner (f) +} + +/// For files that may contain secrets and should have permissions or other +/// safeties checked + +pub fn load < + T: DeserializeOwned, + P: AsRef + Debug +> ( + config_file_path: P +) -> T { + use std::os::unix::fs::PermissionsExt; + + let mut f = File::open (&config_file_path).unwrap_or_else (|_| panic! ("Can't open {:?}", config_file_path)); + + let mode = f.metadata ().unwrap ().permissions ().mode (); + assert_eq! (mode, CONFIG_PERMISSIONS_MODE, "Config file has bad permissions mode, it should be octal 0600"); + + load_inner (f) } diff --git a/src/relay/mod.rs b/src/relay/mod.rs index ce04aaf..0b44369 100644 --- a/src/relay/mod.rs +++ b/src/relay/mod.rs @@ -500,7 +500,8 @@ async fn handle_all (req: Request , state: Arc ) servers: Vec >, } - let names = state.list_servers ().await; + let mut names = state.list_servers ().await; + names.sort (); //println! ("Found {} servers", names.len ()); diff --git a/src/server/file_server.rs b/src/server/file_server.rs index d89fc43..2e3a688 100644 --- a/src/server/file_server.rs +++ b/src/server/file_server.rs @@ -501,8 +501,7 @@ async fn internal_serve_all ( let path_s = percent_decode (encoded_path.as_bytes ()).decode_utf8 ().unwrap (); let path = Path::new (&*path_s); - let mut full_path = PathBuf::from (root); - full_path.push (path); + let full_path = root.join (path); debug! ("full_path = {:?}", full_path); @@ -531,7 +530,14 @@ async fn internal_serve_all ( }) } else if let Ok (mut file) = File::open (&full_path).await { + use std::os::unix::fs::PermissionsExt; + let file_md = file.metadata ().await.unwrap (); + if file_md.permissions ().mode () == crate::load_toml::CONFIG_PERMISSIONS_MODE + { + return Forbidden; + } + let file_len = file_md.len (); let range_header = headers.get ("range").map (|v| std::str::from_utf8 (v).ok ()).flatten (); diff --git a/todo.md b/todo.md index f0531fc..53daba4 100644 --- a/todo.md +++ b/todo.md @@ -76,3 +76,8 @@ what happens. I might have to build a client that imitates this behavior, since it's hard to control. + +## Server won't work on Windows + +This is because I use Unix-specific file permissions to protect the server +config.