diff --git a/Cargo.lock b/Cargo.lock index 5176221..7758c04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,12 +28,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "clap" version = "2.34.0" @@ -49,15 +43,6 @@ dependencies = [ "vec_map", ] -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "version_check", -] - [[package]] name = "heck" version = "0.3.3" @@ -76,64 +61,17 @@ dependencies = [ "libc", ] -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi", -] - -[[package]] -name = "itoa" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" - [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" - -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - -[[package]] -name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "proc-macro-error" @@ -161,37 +99,29 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "saslauthd" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "once_cell", "structopt", - "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" @@ -224,28 +154,15 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "syslog" -version = "6.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978044cc68150ad5e40083c9f6a725e6fd02d7ba1bcf691ec2ff0d66c0b41acc" -dependencies = [ - "error-chain", - "hostname", - "libc", - "log", - "time", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -255,52 +172,23 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "time" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" -dependencies = [ - "itoa", - "libc", - "num_threads", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -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" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-segmentation" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "vec_map" @@ -310,9 +198,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "winapi" diff --git a/Cargo.toml b/Cargo.toml index 8719967..d643d79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,9 @@ [package] name = "saslauthd" -version = "0.1.0" +version = "0.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -once_cell = "^1.9.0" -structopt = "^0.3.26" -syslog = "^6.0" \ No newline at end of file +structopt = "^0.3.26" \ No newline at end of file diff --git a/passwords/bp b/passwords/bp index 8446d27..dff6ee9 100644 --- a/passwords/bp +++ b/passwords/bp @@ -1,3 +1,5 @@ # Demo password file -some-rad-password \ No newline at end of file +some-rad-password + +#commented-out \ No newline at end of file diff --git a/src/handler.rs b/src/handler.rs index 7d7e0a0..537e08f 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -2,25 +2,26 @@ use std::fs::File; use std::io::{BufRead, BufReader}; use crate::options::OPTIONS; -use crate::server::{Handler, Request}; +use crate::request::Request; +#[derive(Clone)] pub struct FileHandler; - impl FileHandler { - pub fn new() -> FileHandler {} -} + pub fn new() -> FileHandler { + FileHandler {} + } -impl Handler for FileHandler { - pub fn check_auth(&request: Request) -> bool { + pub fn check_auth(&self, request: &Request) -> bool { // Don't allow empty userids or passwords // - if request.userid.is_empty() || request.userid.contains('/') || request.password.is_empty() { + 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); + file_name.push(&request.userid); if let Ok(file) = File::open(file_name) { for line in BufReader::new(file).lines().flatten() { @@ -33,3 +34,61 @@ impl Handler for FileHandler { false } } + +#[cfg(test)] +mod tests { + use crate::handler::FileHandler; + use crate::request::Request; + + #[test] + fn it_checks_good_password() { + let handler = FileHandler::new(); + let request = Request { + userid: "bp".to_string(), + password: "some-rad-password".to_string(), + service: "ignore-this".to_string(), + realm: "also-ignore-this".to_string(), + }; + + assert_eq!(handler.check_auth(&request), true); + } + + #[test] + fn it_fails_bad_password() { + let handler = FileHandler::new(); + let request = Request { + userid: "bp".to_string(), + password: "not-correct".to_string(), + service: "ignore-this".to_string(), + realm: "also-ignore-this".to_string(), + }; + + assert_eq!(handler.check_auth(&request), false); + } + + #[test] + fn it_fails_bad_userid() { + let handler = FileHandler::new(); + let request = Request { + userid: "bp-xxx".to_string(), + password: "some-rad-password".to_string(), + service: "ignore-this".to_string(), + realm: "also-ignore-this".to_string(), + }; + + assert_eq!(handler.check_auth(&request), false); + } + + #[test] + fn it_ignores_comments() { + let handler = FileHandler::new(); + let request = Request { + userid: "bp".to_string(), + password: "commented-out".to_string(), + service: "ignore-this".to_string(), + realm: "also-ignore-this".to_string(), + }; + + assert_eq!(handler.check_auth(&request), false); + } +} diff --git a/src/listener.rs b/src/listener.rs index f2f00f2..52d69d1 100644 --- a/src/listener.rs +++ b/src/listener.rs @@ -1,19 +1,19 @@ +use crate::handler::FileHandler; +use crate::options::OPTIONS; +use crate::server::Server; use std::fs::{metadata, set_permissions}; use std::io::Error; use std::os::unix::fs::PermissionsExt; use std::os::unix::net::UnixListener; use std::thread; -use crate::options::OPTIONS; -use crate::server::{CheckFn, Handler, Server}; - pub struct Listener { listener: UnixListener, - handler: Box, + handler: FileHandler, } impl Listener { - pub fn new(handler: Box) -> Result { + pub fn new(handler: FileHandler) -> Result { if OPTIONS.socket_name.exists() { std::fs::remove_file(&OPTIONS.socket_name)?; } @@ -33,7 +33,8 @@ impl Listener { match stream { Ok(stream) => { /* connection succeeded */ - thread::spawn(|| Server::new(stream, &self.handler).unwrap().handle_client()); + let handler = self.handler.clone(); + thread::spawn(|| Server::new(stream, handler).unwrap().handle_client()); } Err(_err) => { /* connection failed */ diff --git a/src/main.rs b/src/main.rs index c2c9c87..7e28b3c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,13 @@ mod handler; mod listener; mod options; +mod request; mod server; -use crate::listener::Listener; use crate::handler::FileHandler; +use crate::listener::Listener; fn main() -> std::io::Result<()> { - let mut listener = Listener::new(Box::new(FileHandler::new()))?; + let mut listener = Listener::new(FileHandler::new())?; listener.run() } diff --git a/src/options.rs b/src/options.rs index 64e7d7b..94cae2d 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use once_cell::sync::Lazy; +use std::sync::LazyLock; use structopt::StructOpt; #[derive(StructOpt, Clone, Debug)] @@ -24,4 +24,4 @@ pub struct Opt { pub password_dir: PathBuf, } -pub static OPTIONS: Lazy = Lazy::new(Opt::from_args); +pub static OPTIONS: LazyLock = LazyLock::new(Opt::from_args); diff --git a/src/request.rs b/src/request.rs new file mode 100644 index 0000000..16eb67a --- /dev/null +++ b/src/request.rs @@ -0,0 +1,6 @@ +pub struct Request { + pub userid: String, + pub password: String, + pub service: String, + pub realm: String, +} diff --git a/src/server.rs b/src/server.rs index b706a86..c480cf5 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,3 +1,5 @@ +use crate::handler::FileHandler; +use crate::request::Request; use std::io::{Error, ErrorKind, Read, Write}; use std::os::unix::net::UnixStream; @@ -6,30 +8,12 @@ const RESPONSE_OK: [u8; 4] = [0x0, 0x2, b'O', b'K']; pub struct Server { stream: UnixStream, - handler: &Box, + handler: FileHandler, } -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, handler: &Box) -> Result { - Ok( - Server { - stream, - handler, - } - ) + pub fn new(stream: UnixStream, handler: FileHandler) -> Result { + Ok(Server { stream, handler }) } /// The saslauthd protocol transmits strings as @@ -52,6 +36,7 @@ impl Server { } } + /* fn write_string(&mut self, s: &str) -> Result<(), Error> { let length = s.len(); @@ -66,19 +51,14 @@ impl Server { Ok(()) } - + */ 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()?; - - if userid.is_empty() || password.is_empty() { - self.stream.write_all(&RESPONSE_NO)?; - return Ok(()); - } - + let request = Request { userid, password, @@ -86,9 +66,9 @@ impl Server { realm, }; - if self.check_auth(&request) { + if self.handler.check_auth(&request) { self.stream.write_all(&RESPONSE_OK)? - }else { + } else { self.stream.write_all(&RESPONSE_NO)? } diff --git a/test.yml b/test.yml deleted file mode 100644 index 1af594a..0000000 --- a/test.yml +++ /dev/null @@ -1,3 +0,0 @@ -users: - bp: - - some-rad-password \ No newline at end of file