From 36f26d4a8511e20a0703a35266075e02074a69b6 Mon Sep 17 00:00:00 2001 From: Barry Pederson Date: Mon, 28 Feb 2022 11:58:57 -0800 Subject: [PATCH] First pass, creates socket, should listen and respond --- .gitignore | 1 + Cargo.lock | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 10 ++++ src/main.rs | 118 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..986d131 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,140 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[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 = "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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "libc" +version = "0.2.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" + +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15" +dependencies = [ + "libc", +] + +[[package]] +name = "saslauthd" +version = "0.1.0" +dependencies = [ + "syslog", + "yaml-rust", +] + +[[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 = "time" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" +dependencies = [ + "itoa", + "libc", + "num_threads", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..912a845 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "saslauthd" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +syslog = "^6.0" +yaml-rust = "0.4" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..3a3bb28 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,118 @@ +use std::fs::{metadata, set_permissions}; +use std::io::{Error, ErrorKind, Read, Write}; +use std::net::Shutdown; +use std::os::unix::fs::PermissionsExt; +use std::os::unix::net::{UnixListener, UnixStream}; +use std::path::PathBuf; +use std::thread; + +extern crate yaml_rust; + +use yaml_rust::{YamlEmitter, YamlLoader}; + +const RESPONSE_NO: [u8; 4] = [0x0, 0x2, b'N', b'O']; +const RESPONSE_OK: [u8; 4] = [0x0, 0x2, b'O', b'K']; + +struct SaslSock { + name: PathBuf, + listener: UnixListener, +} + +impl SaslSock { + pub fn new(name: &str) -> Result { + let path = PathBuf::from(&name); + if path.exists() { + std::fs::remove_file(&path)?; + } + + let listener = UnixListener::bind(&name)?; + + let mut perms = metadata(&path)?.permissions(); + perms.set_mode(0o0777); + set_permissions(&path, perms)?; + + Ok(SaslSock { + name: PathBuf::from(&name), + listener, + }) + } +} + +impl Drop for SaslSock { + fn drop(&mut self) { + let _result = std::fs::remove_file(&self.name); + println!("Shutting down"); + } +} + +/// The saslauthd protocol transmits strings as +/// 16-bit unsigned network-byte-order lengths followed +/// by the string itself. +/// +fn read_string(stream: &mut UnixStream) -> Result { + let mut length_buffer = [0u8, 0u8]; + + stream.read_exact(&mut length_buffer)?; + let length = u16::from_be_bytes(length_buffer); + + let mut string_buffer = vec![0u8; length as usize]; + + stream.read_exact(&mut string_buffer)?; + + match String::from_utf8(string_buffer) { + Ok(str) => Ok(str), + Err(_err) => Err(Error::new(ErrorKind::Other, "Invalid UTF-8 sent")), + } +} + +fn write_string(s: &str, stream: &mut UnixStream) -> Result<(), Error> { + let length = s.len(); + + if length > 0xffff { + return Err(Error::new(ErrorKind::Other, "String too long to write")); + } + + let length_buffer = [(length >> 8) as u8, (length & 0xff) as u8]; + + stream.write_all(&length_buffer)?; + stream.write_all(s.as_bytes())?; + + Ok(()) +} + +fn check_auth(mut stream: UnixStream) -> Result<(), Error> { + let userid = read_string(&mut stream)?; + let password = read_string(&mut stream)?; + let service = read_string(&mut stream)?; + let _realm = read_string(&mut stream)?; + + stream.write_all(&RESPONSE_NO)?; + stream.shutdown(Shutdown::Both)?; + + Ok(()) +} + +fn handle_client(stream: UnixStream) { + if let Err(error) = check_auth(stream) { + eprint!("{}", error); + } +} + +fn main() -> std::io::Result<()> { + let sock = SaslSock::new("/tmp/saslauthd.sock")?; + + // accept connections and process them, spawning a new thread for each one + for stream in sock.listener.incoming() { + match stream { + Ok(stream) => { + /* connection succeeded */ + thread::spawn(|| handle_client(stream)); + } + Err(_err) => { + /* connection failed */ + break; + } + } + } + Ok(()) +}