WIP: trying to refactor to separate password-checking from network-communication

This commit is contained in:
Barry Pederson
2024-11-02 11:05:16 -07:00
parent 15daa7d7a1
commit ac9743dc8a
5 changed files with 140 additions and 75 deletions
+41 -38
View File
@@ -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<dyn Handler>,
}
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<Server, Error> {
Ok(Server { stream })
pub fn new(stream: UnixStream, handler: &Box<dyn Handler>) -> Result<Server, Error> {
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<bool, Error> {
// 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}");
}
}
}