From ac9743dc8a8fa183127b952599b7c4b550b16f24 Mon Sep 17 00:00:00 2001 From: Barry Pederson Date: Sat, 2 Nov 2024 11:05:16 -0700 Subject: [PATCH] WIP: trying to refactor to separate password-checking from network-communication --- Cargo.lock | 86 +++++++++++++++++++++++++++++++------------------ src/handler.rs | 35 ++++++++++++++++++++ src/listener.rs | 9 +++--- src/main.rs | 6 ++-- src/server.rs | 79 +++++++++++++++++++++++---------------------- 5 files changed, 140 insertions(+), 75 deletions(-) create mode 100644 src/handler.rs diff --git a/Cargo.lock b/Cargo.lock index b766437..5176221 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,9 +89,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "lazy_static" @@ -101,15 +101,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.119" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] @@ -122,18 +122,18 @@ checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "num_threads" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" dependencies = [ "libc", ] [[package]] name = "once_cell" -version = "1.9.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "proc-macro-error" @@ -161,18 +161,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.15" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -186,6 +186,12 @@ dependencies = [ "syslog", ] +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" + [[package]] name = "strsim" version = "0.8.0" @@ -218,13 +224,13 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.86" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -251,32 +257,50 @@ dependencies = [ [[package]] name = "time" -version = "0.3.7" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ "itoa", "libc", "num_threads", + "serde", + "time-core", + "time-macros", ] [[package]] -name = "unicode-segmentation" -version = "1.9.0" +name = "time-core" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +dependencies = [ + "time-core", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-segmentation" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "vec_map" diff --git a/src/handler.rs b/src/handler.rs new file mode 100644 index 0000000..7d7e0a0 --- /dev/null +++ b/src/handler.rs @@ -0,0 +1,35 @@ +use std::fs::File; +use std::io::{BufRead, BufReader}; + +use crate::options::OPTIONS; +use crate::server::{Handler, Request}; + +pub struct FileHandler; + + +impl FileHandler { + pub fn new() -> FileHandler {} +} + +impl Handler for FileHandler { + pub fn check_auth(&request: Request) -> bool { + // Don't allow empty userids or passwords + // + if request.userid.is_empty() || request.userid.contains('/') || request.password.is_empty() { + return false; + } + + let mut file_name = OPTIONS.password_dir.clone(); + file_name.push(request.userid); + + if let Ok(file) = File::open(file_name) { + for line in BufReader::new(file).lines().flatten() { + if !line.starts_with('#') && line.trim() == request.password { + return true; + } + } + } + + false + } +} diff --git a/src/listener.rs b/src/listener.rs index 931d96b..f2f00f2 100644 --- a/src/listener.rs +++ b/src/listener.rs @@ -5,14 +5,15 @@ use std::os::unix::net::UnixListener; use std::thread; use crate::options::OPTIONS; -use crate::server::Server; +use crate::server::{CheckFn, Handler, Server}; pub struct Listener { listener: UnixListener, + handler: Box, } impl Listener { - pub fn new() -> Result { + pub fn new(handler: Box) -> Result { if OPTIONS.socket_name.exists() { std::fs::remove_file(&OPTIONS.socket_name)?; } @@ -23,7 +24,7 @@ impl Listener { perms.set_mode(0o0777); set_permissions(&OPTIONS.socket_name, perms)?; - Ok(Listener { listener }) + Ok(Listener { handler, listener }) } pub fn run(&mut self) -> Result<(), Error> { @@ -32,7 +33,7 @@ impl Listener { match stream { Ok(stream) => { /* connection succeeded */ - thread::spawn(|| Server::new(stream).unwrap().handle_client()); + thread::spawn(|| Server::new(stream, &self.handler).unwrap().handle_client()); } Err(_err) => { /* connection failed */ diff --git a/src/main.rs b/src/main.rs index 62c9a7f..c2c9c87 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,12 @@ +mod handler; mod listener; mod options; mod server; use crate::listener::Listener; +use crate::handler::FileHandler; fn main() -> std::io::Result<()> { - let mut server = Listener::new()?; - server.run() + let mut listener = Listener::new(Box::new(FileHandler::new()))?; + listener.run() } diff --git a/src/server.rs b/src/server.rs index 9943bda..b706a86 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,20 +1,35 @@ -use std::fs::File; -use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write}; -use std::net::Shutdown; +use std::io::{Error, ErrorKind, Read, Write}; use std::os::unix::net::UnixStream; -use crate::options::OPTIONS; - const RESPONSE_NO: [u8; 4] = [0x0, 0x2, b'N', b'O']; const RESPONSE_OK: [u8; 4] = [0x0, 0x2, b'O', b'K']; pub struct Server { stream: UnixStream, + handler: &Box, } +pub struct Request { + userid: String, + password: String, + service: String, + realm: String, +} + +pub trait Handler { + fn check_auth(&self, request: &Request) -> bool; +} + +pub type CheckFn = fn(&Request) -> bool; + impl Server { - pub fn new(stream: UnixStream) -> Result { - Ok(Server { stream }) + pub fn new(stream: UnixStream, handler: &Box) -> Result { + Ok( + Server { + stream, + handler, + } + ) } /// The saslauthd protocol transmits strings as @@ -52,41 +67,29 @@ impl Server { Ok(()) } - fn check_auth(&mut self, userid: &str, password: &str) -> Result { - // Don't allow empty userids or passwords - // - if userid.is_empty() || password.is_empty() { - return Ok(false); - } - - let mut password_file = OPTIONS.password_dir.clone(); - password_file.push(&userid); - - let file = File::open(password_file)?; - - for line in BufReader::new(file).lines().flatten() { - if !line.starts_with('#') && line.trim() == password { - return Ok(true); - } - } - - Ok(false) - } fn communicate(&mut self) -> Result<(), Error> { let userid = self.read_string()?; let password = self.read_string()?; - let _service = self.read_string()?; - let _realm = self.read_string()?; + let service = self.read_string()?; + let realm = self.read_string()?; - match self.check_auth(&userid, &password) { - Ok(true) => self.stream.write_all(&RESPONSE_OK)?, - Ok(false) => self.stream.write_all(&RESPONSE_NO)?, - Err(e) => { - self.stream.write_all(&RESPONSE_NO)?; - self.stream.shutdown(Shutdown::Both)?; - return Err(e); - } + if userid.is_empty() || password.is_empty() { + self.stream.write_all(&RESPONSE_NO)?; + return Ok(()); + } + + let request = Request { + userid, + password, + service, + realm, + }; + + if self.check_auth(&request) { + self.stream.write_all(&RESPONSE_OK)? + }else { + self.stream.write_all(&RESPONSE_NO)? } Ok(()) @@ -94,7 +97,7 @@ impl Server { pub fn handle_client(&mut self) { if let Err(error) = self.communicate() { - eprint!("{}", error); + eprint!("{error}"); } } }