pam-honeypot/src/lib.rs
2024-12-28 21:21:06 +01:00

70 lines
2 KiB
Rust

use std::{collections::HashMap, env::temp_dir, ffi::CStr, fs::File};
use pam::{
constants::{PamResultCode, PAM_PROMPT_ECHO_ON},
conv::Conv,
module::PamHooks,
pam_try,
};
struct PamHoneypot;
impl PamHooks for PamHoneypot {
fn sm_authenticate(
pamh: &mut pam::module::PamHandle,
args: Vec<&CStr>,
_flags: pam::constants::PamFlag,
) -> pam::constants::PamResultCode {
let args: Vec<_> = args.iter().map(|s| s.to_string_lossy()).collect();
let args: HashMap<&str, &str> = args
.iter()
.map(|s| {
let mut parts = s.splitn(2, '=');
(parts.next().unwrap(), parts.next().unwrap_or(""))
})
.collect();
let honey_user = match args.get("user") {
Some(user) => user,
_ => return PamResultCode::PAM_IGNORE,
};
let honey_password = match args.get("password") {
Some(password) => password,
_ => return PamResultCode::PAM_IGNORE,
};
let user = pam_try!(pamh.get_user(None));
if user != *honey_user {
return PamResultCode::PAM_IGNORE;
}
let conv = match pamh.get_item::<Conv>() {
Ok(Some(conv)) => conv,
Ok(_) => {
unreachable!("No conv available");
}
Err(err) => {
return err;
}
};
let password = pam_try!(conv.send(PAM_PROMPT_ECHO_ON, "Password"));
let password = match password {
Some(password) => Some(pam_try!(password.to_str(), PamResultCode::PAM_AUTH_ERR)),
_ => None,
};
if let Some(password) = password {
if *honey_password == password {
let mut tmp = temp_dir();
tmp.push("honeypot");
let _ = File::create(tmp);
return PamResultCode::PAM_AUTH_ERR;
}
}
PamResultCode::PAM_IGNORE
}
}
pam::pam_hooks!(PamHoneypot);