diff --git a/Cargo.lock b/Cargo.lock index 56c2a42..8a739b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,15 @@ version = 3 name = "agena-cgi" version = "0.1.0" +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + [[package]] name = "atty" version = "0.2.14" @@ -186,12 +195,14 @@ dependencies = [ [[package]] name = "gemserv" -version = "0.6.5" +version = "0.6.6" dependencies = [ "futures-util", + "lazy_static", "log", "mime", "new_mime_guess", + "regex", "rustls-pemfile", "serde", "serde_derive", @@ -503,6 +514,23 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "ring" version = "0.16.20" diff --git a/Cargo.toml b/Cargo.toml index df4579c..273fe7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gemserv" -version = "0.6.5" +version = "0.6.6" authors = ["int 80h "] edition = "2018" description = "A gemini server" @@ -27,6 +27,8 @@ log = "0.4.14" simple_logger = "1.16" sha2 = "0.9.8" x509-parser = "0.12" +regex = "1.5.4" +lazy_static = "1.4.0" [dependencies.tokio-rustls] version = "0.23.2" diff --git a/README b/README index b6aa1d0..903280c 100644 --- a/README +++ b/README @@ -78,6 +78,10 @@ TLS variables ## Changelog +### [0.6.6] - 20220217 + +Bug fix: File path is checked to make sure it's in the root directory or in ~/public_gemini + ### [0.6.5] - 20220209 Bug fix: Another traversal bug. diff --git a/src/con_handler.rs b/src/con_handler.rs index 33cb604..6d6c83f 100644 --- a/src/con_handler.rs +++ b/src/con_handler.rs @@ -3,6 +3,7 @@ use std::path::{Path, PathBuf}; use tokio::fs::{self, File}; use tokio::io::{self, AsyncBufReadExt, AsyncWrite, BufReader}; use url::Url; +use regex::Regex; #[cfg(any(feature = "cgi", feature = "scgi"))] use crate::cgi; @@ -15,6 +16,7 @@ use crate::util; type Result = std::result::Result>; + fn get_mime(path: &Path) -> String { let mut mime = "text/gemini".to_string(); if path.is_dir() { @@ -248,6 +250,37 @@ pub async fn handle_connection(mut con: conn::Connection, url: url::Url) -> Resu } } + match path.canonicalize() { + Ok(p) => { + if !p.starts_with(&con.srv.server.dir) { + if con.srv.server.usrdir.unwrap_or(false) { + #[cfg(target_os = "macos")] + lazy_static! { + static ref RE: Regex = Regex::new(r"^/Users/([^/]*)/public_gemini(.*)").unwrap(); + } + #[cfg(not(target_os = "macos"))] + lazy_static! { + static ref RE: Regex = Regex::new(r"^/home/([^/]*)/public_gemini(.*)").unwrap(); + } + if !RE.is_match(p.to_str().unwrap()) { + logger::logger(con.peer_addr, Status::NotFound, url.as_str()); + con.send_status(Status::NotFound, None).await?; + return Ok(()); + } + } else { + logger::logger(con.peer_addr, Status::NotFound, url.as_str()); + con.send_status(Status::NotFound, None).await?; + return Ok(()); + } + } + }, + Err(_) => { + logger::logger(con.peer_addr, Status::NotFound, url.as_str()); + con.send_status(Status::NotFound, None).await?; + return Ok(()); + }, + } + if !path.exists() { // See if it's a subpath of a CGI script before returning NotFound #[cfg(feature = "cgi")] diff --git a/src/main.rs b/src/main.rs index b07a0dc..34ae1e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ #[macro_use] extern crate serde_derive; +#[macro_use] +extern crate lazy_static; #[cfg(any(feature = "cgi", feature = "scgi"))] mod cgi;