Updated README, added ~usrdirs and now checks permissions

This commit is contained in:
int 80h
2020-05-04 20:59:39 -04:00
parent c077d94835
commit f50a748bde
6 changed files with 77 additions and 7 deletions

30
README
View File

@@ -1,3 +1,29 @@
Gemserv is a gemini server written in rust. It supports vhosts and cgi. To run
use "cargo run /path/to/config"
# Gemserv
A gemini server written in rust.
## Features
- Vhosts
- CGI
- User directories
## Installation and running
- Clone the repo
- Run 'cargo build --release'
- Modify the config.toml to your needs
- Run './target/release/gemserv config.toml'
## Create server key/cert pairs
## CGI
- GEMINI_URL
- SERVER_NAME
- SERVER_PROTOCOL
- SCRIPT_NAME
- REMOTE_ADDR
- REMOTE_HOST
- REMOTE_PORT
- QUERY_STRING

View File

@@ -9,6 +9,8 @@ key = "/path/to/key"
cert = "/path/to/cert"
# cgi dir is optional
cgi = "/path/to/cgi-bin/"
# usrdir is optional. it'll look in /home/~usr/public_gemini
usrdir = true
[[server]]
hostname = "example.net"

View File

@@ -2,6 +2,7 @@ use std::collections::HashMap;
use std::io::{self, BufReader};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::os::unix::fs::PermissionsExt;
use tokio::net::TcpStream;
use tokio_rustls::server::TlsStream;
use url::Url;

View File

@@ -19,6 +19,7 @@ pub struct Server {
pub key: String,
pub cert: String,
pub cgi: Option<String>,
pub usrdir: Option<bool>,
}
impl Config {
@@ -35,7 +36,8 @@ impl Config {
dir: srv.dir.clone(),
key: srv.key.clone(),
cert: srv.cert.clone(),
cgi: srv.cgi.clone()
cgi: srv.cgi.clone(),
usrdir: srv.usrdir.clone(),
});
}
map

View File

@@ -12,6 +12,7 @@ pub struct Connection {
pub hostname: String,
pub dir: String,
pub cgi: String,
pub usrdir: bool,
}
impl Connection {

View File

@@ -82,6 +82,10 @@ fn get_content(path: PathBuf, u: url::Url) -> Result<String, io::Error> {
for file in fs::read_dir(&path)? {
if let Ok(file) = file {
let m = file.metadata()?;
let perm = m.permissions();
if perm.mode() & 0o0444 != 0o0444 {
continue
}
let file = file.path();
let p = file.strip_prefix(&path).unwrap();
if m.is_dir() {
@@ -118,9 +122,23 @@ async fn handle_connection(mut con: conn::Connection) -> Result<(), io::Error> {
return Ok(());
}
let mut path = PathBuf::from(&con.dir);
if url.path() != "" || url.path() != "/" {
path.push(url.path().trim_start_matches("/"));
let mut path = PathBuf::new();
if url.path().starts_with("/~") && con.usrdir == true{
let usr = url.path().trim_start_matches("/~");
let usr: Vec<&str> = usr.splitn(2, "/").collect();
path.push("/home/");
if usr.len() == 2 {
path.push(format!("{}/{}/{}", usr[0], "public_gemini", usr[1]));
} else {
path.push(format!("{}/{}/",usr[0], "public_gemini"));
}
} else {
path.push(&con.dir);
if url.path() != "" || url.path() != "/" {
path.push(url.path().trim_start_matches("/"));
}
}
if !path.exists() {
@@ -128,7 +146,8 @@ async fn handle_connection(mut con: conn::Connection) -> Result<(), io::Error> {
return Ok(());
}
let meta = fs::metadata(&path).expect("Unable to read metadata");
let mut meta = fs::metadata(&path).expect("Unable to read metadata");
let mut perm = meta.permissions();
if meta.is_dir() {
if !url.path().ends_with("/") {
@@ -141,13 +160,27 @@ async fn handle_connection(mut con: conn::Connection) -> Result<(), io::Error> {
}
if path.join("index.gemini").exists() {
path.push("index.gemini");
meta = fs::metadata(&path).expect("Unable to read metadata");
perm = meta.permissions();
}
}
// add timeout
if con.cgi.trim_end_matches("/") == path.parent().unwrap().to_str().unwrap() {
if perm.mode() & 0o0111 == 0o0111 {
cgi::cgi(con, path, url).await?;
return Ok(());
} else {
con.send_status(
status::Status::CGIError, "CGI Error!\r\n").await?;
return Ok(());
}
}
if perm.mode() & 0o0444 != 0o0444 {
con.send_status(
status::Status::NotFound, "Not Found!\r\n").await?;
return Ok(());
}
let mime = get_mime(&path);
@@ -209,6 +242,7 @@ fn main() -> io::Result<()> {
let mut dir = String::new();
let mut cgi = String::new();
let mut hostname = String::new();
let mut usrdir: bool = false;
for server in &cfg.server {
if Some(server.hostname.as_str()) == sni {
@@ -217,6 +251,9 @@ fn main() -> io::Result<()> {
if server.cgi.is_some() {
cgi = server.cgi.as_ref().unwrap().to_string();
}
if server.usrdir.is_some() {
usrdir = server.usrdir.unwrap();
}
break;
}
}
@@ -227,6 +264,7 @@ fn main() -> io::Result<()> {
hostname,
dir,
cgi,
usrdir,
};
handle_connection(con).await?;