70 lines
2 KiB
Rust
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);
|