WIP: trying to refactor to separate password-checking from network-communication
This commit is contained in:
+41
-38
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user