Bug fix: File path is checked to make sure it's in the root directory or in ~/public_gemini

This commit is contained in:
int 80h 2022-02-17 22:24:21 -05:00
parent eb129467f1
commit 827a9c1481
5 changed files with 71 additions and 2 deletions

30
Cargo.lock generated
View File

@ -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"

View File

@ -1,6 +1,6 @@
[package]
name = "gemserv"
version = "0.6.5"
version = "0.6.6"
authors = ["int 80h <int@80h.dev>"]
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"

4
README
View File

@ -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.

View File

@ -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<T = ()> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
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")]

View File

@ -1,5 +1,7 @@
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate lazy_static;
#[cfg(any(feature = "cgi", feature = "scgi"))]
mod cgi;