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);