🐛 Use file permissions to forbid access to ptth_server.toml
parent
563465c85b
commit
5378e66e39
|
@ -29,6 +29,7 @@ reqwest = { version = "0.10.8", features = ["stream"] }
|
||||||
rmp-serde = "0.14.4"
|
rmp-serde = "0.14.4"
|
||||||
serde = {version = "1.0.117", features = ["derive"]}
|
serde = {version = "1.0.117", features = ["derive"]}
|
||||||
structopt = "0.3.20"
|
structopt = "0.3.20"
|
||||||
|
# thiserror = "1.0.22"
|
||||||
tokio = { version = "0.2.22", features = ["full"] }
|
tokio = { version = "0.2.22", features = ["full"] }
|
||||||
tracing = "0.1.21"
|
tracing = "0.1.21"
|
||||||
tracing-futures = "0.2.4"
|
tracing-futures = "0.2.4"
|
||||||
|
|
|
@ -21,7 +21,7 @@ async fn main () -> Result <(), Box <dyn Error>> {
|
||||||
.init ()
|
.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);
|
info! ("ptth_relay Git version: {:?}", ptth::git_version::GIT_VERSION);
|
||||||
|
|
||||||
|
|
|
@ -7,19 +7,48 @@ use std::{
|
||||||
|
|
||||||
use serde::de::DeserializeOwned;
|
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,
|
T: DeserializeOwned,
|
||||||
P: AsRef <Path> + Debug
|
P: AsRef <Path> + Debug
|
||||||
> (
|
> (
|
||||||
config_file_path: P
|
config_file_path: P
|
||||||
) -> T {
|
) -> T {
|
||||||
let mut f = File::open (&config_file_path).unwrap_or_else (|_| panic! ("Can't open {:?}", config_file_path));
|
let mut f = File::open (&config_file_path).unwrap_or_else (|_| panic! ("Can't open {:?}", config_file_path));
|
||||||
let mut buffer = vec! [0u8; 4096];
|
load_inner (f)
|
||||||
let bytes_read = f.read (&mut buffer).unwrap_or_else (|_| panic! ("Can't read {:?}", config_file_path));
|
}
|
||||||
buffer.truncate (bytes_read);
|
|
||||||
|
|
||||||
{
|
/// For files that may contain secrets and should have permissions or other
|
||||||
let config_s = String::from_utf8 (buffer).unwrap_or_else (|_| panic! ("Can't parse {:?} as UTF-8", config_file_path));
|
/// safeties checked
|
||||||
toml::from_str (&config_s).unwrap_or_else (|e| panic! ("Can't parse {:?} as TOML: {}", config_file_path, e))
|
|
||||||
}
|
pub fn load <
|
||||||
|
T: DeserializeOwned,
|
||||||
|
P: AsRef <Path> + 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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -500,7 +500,8 @@ async fn handle_all (req: Request <Body>, state: Arc <RelayState>)
|
||||||
servers: Vec <ServerEntry <'a>>,
|
servers: Vec <ServerEntry <'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let names = state.list_servers ().await;
|
let mut names = state.list_servers ().await;
|
||||||
|
names.sort ();
|
||||||
|
|
||||||
//println! ("Found {} servers", names.len ());
|
//println! ("Found {} servers", names.len ());
|
||||||
|
|
||||||
|
|
|
@ -501,8 +501,7 @@ async fn internal_serve_all (
|
||||||
let path_s = percent_decode (encoded_path.as_bytes ()).decode_utf8 ().unwrap ();
|
let path_s = percent_decode (encoded_path.as_bytes ()).decode_utf8 ().unwrap ();
|
||||||
let path = Path::new (&*path_s);
|
let path = Path::new (&*path_s);
|
||||||
|
|
||||||
let mut full_path = PathBuf::from (root);
|
let full_path = root.join (path);
|
||||||
full_path.push (path);
|
|
||||||
|
|
||||||
debug! ("full_path = {:?}", full_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 {
|
else if let Ok (mut file) = File::open (&full_path).await {
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
|
||||||
let file_md = file.metadata ().await.unwrap ();
|
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 file_len = file_md.len ();
|
||||||
|
|
||||||
let range_header = headers.get ("range").map (|v| std::str::from_utf8 (v).ok ()).flatten ();
|
let range_header = headers.get ("range").map (|v| std::str::from_utf8 (v).ok ()).flatten ();
|
||||||
|
|
5
todo.md
5
todo.md
|
@ -76,3 +76,8 @@ what happens.
|
||||||
|
|
||||||
I might have to build a client that imitates this behavior, since it's hard
|
I might have to build a client that imitates this behavior, since it's hard
|
||||||
to control.
|
to control.
|
||||||
|
|
||||||
|
## Server won't work on Windows
|
||||||
|
|
||||||
|
This is because I use Unix-specific file permissions to protect the server
|
||||||
|
config.
|
||||||
|
|
Loading…
Reference in New Issue