Files
saslauthd_yaml/src/server.rs
T

104 lines
2.5 KiB
Rust

use std::io::{Error, ErrorKind, Read, Write};
use std::os::unix::net::UnixStream;
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, handler: &Box<dyn Handler>) -> Result<Server, Error> {
Ok(
Server {
stream,
handler,
}
)
}
/// The saslauthd protocol transmits strings as
/// 16-bit unsigned network-byte-order lengths followed
/// by the string itself.
///
fn read_string(&mut self) -> Result<String, Error> {
let mut length_buffer = [0u8, 0u8];
self.stream.read_exact(&mut length_buffer)?;
let length = u16::from_be_bytes(length_buffer);
let mut string_buffer = vec![0u8; length as usize];
self.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(&mut self, s: &str) -> 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];
self.stream.write_all(&length_buffer)?;
self.stream.write_all(s.as_bytes())?;
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,
service,
realm,
};
if self.check_auth(&request) {
self.stream.write_all(&RESPONSE_OK)?
}else {
self.stream.write_all(&RESPONSE_NO)?
}
Ok(())
}
pub fn handle_client(&mut self) {
if let Err(error) = self.communicate() {
eprint!("{error}");
}
}
}