This commit is contained in:
2025-07-26 10:10:52 +08:00
parent 9f83969584
commit 81c11d3f30
21 changed files with 1095 additions and 1 deletions

12
pam-sober/Cargo.toml Normal file
View File

@@ -0,0 +1,12 @@
[package]
name = "pam-sober"
version = "0.1.0"
authors = ["Anthony Nowell <anowell@gmail.com>"]
[lib]
name = "pam_sober"
crate-type = ["cdylib"]
[dependencies]
pam-bindings = { path = "../pam/" }
rand = "0.8.4"

12
pam-sober/Justfile Normal file
View File

@@ -0,0 +1,12 @@
all:
cargo build
install:
@cargo build --release
sudo cp conf/sober-auth /etc/pam.d/
sudo cp ../target/release/libpam_sober.so /lib/security/pam_sober.so
test:
@just install
gcc -o ../target/pam_test test.c -lpam -lpam_misc

View File

@@ -0,0 +1,2 @@
auth sufficient pam_sober.so
account sufficient pam_sober.so

73
pam-sober/src/lib.rs Normal file
View File

@@ -0,0 +1,73 @@
extern crate pam;
extern crate rand;
use pam::constants::{PamFlag, PamResultCode, PAM_PROMPT_ECHO_ON};
use pam::conv::Conv;
use pam::module::{PamHandle, PamHooks};
use rand::Rng;
use std::ffi::CStr;
use std::str::FromStr;
use pam::pam_try;
struct PamSober;
pam::pam_hooks!(PamSober);
impl PamHooks for PamSober {
// This function performs the task of authenticating the user.
fn sm_authenticate(pamh: &mut PamHandle, _args: Vec<&CStr>, _flags: PamFlag) -> PamResultCode {
println!("Let's make sure you're sober enough to perform basic addition");
/* TODO: use args to change difficulty ;-)
let args: HashMap<&str, &str> = args.iter().map(|s| {
let mut parts = s.splitn(2, "=");
(parts.next().unwrap(), parts.next().unwrap_or(""))
}).collect();
*/
// TODO: maybe we can change difficulty base on user?
// let user = pam_try!(pam.get_user(None));
let conv = match pamh.get_item::<Conv>() {
Ok(Some(conv)) => conv,
Ok(None) => todo!(),
Err(err) => {
println!("Couldn't get pam_conv");
return err;
}
};
let mut rng = rand::thread_rng();
let a = rng.gen::<u32>() % 100;
let b = rng.gen::<u32>() % 100;
let math = format!("{} + {} = ", a, b);
// This println kinda helps debugging since the test script doesn't echo
eprintln!("[DEBUG]: {}{}", math, a + b);
let password = pam_try!(conv.send(PAM_PROMPT_ECHO_ON, &math));
if let Some(password) = password {
let password = pam_try!(password.to_str(), PamResultCode::PAM_AUTH_ERR);
let answer = pam_try!(u32::from_str(password), PamResultCode::PAM_AUTH_ERR);
if answer == a + b {
PamResultCode::PAM_SUCCESS
} else {
println!("Wrong answer provided {} + {} != {}", a, b, answer);
PamResultCode::PAM_AUTH_ERR
}
} else {
println!("You failed the PAM sobriety test.");
PamResultCode::PAM_AUTH_ERR
}
}
fn sm_setcred(_pamh: &mut PamHandle, _args: Vec<&CStr>, _flags: PamFlag) -> PamResultCode {
println!("set credentials");
PamResultCode::PAM_SUCCESS
}
fn acct_mgmt(_pamh: &mut PamHandle, _args: Vec<&CStr>, _flags: PamFlag) -> PamResultCode {
println!("account management");
PamResultCode::PAM_SUCCESS
}
}

53
pam-sober/test.c Normal file
View File

@@ -0,0 +1,53 @@
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>
const struct pam_conv conv = {
misc_conv,
NULL
};
int main(int argc, char *argv[]) {
pam_handle_t* pamh = NULL;
int retval;
const char* user = "nobody";
if(argc != 2) {
printf("Usage: app [username]\n");
exit(1);
}
user = argv[1];
retval = pam_start("sober-auth", user, &conv, &pamh);
// Are the credentials correct?
if (retval == PAM_SUCCESS) {
printf("PAM module initialized\n");
retval = pam_authenticate(pamh, 0);
}
// Can the accound be used at this time?
if (retval == PAM_SUCCESS) {
printf("Credentials accepted.\n");
retval = pam_acct_mgmt(pamh, 0);
}
// Did everything work?
if (retval == PAM_SUCCESS) {
printf("Account is valid.\n");
printf("Authenticated\n");
} else {
printf("Not Authenticated\n");
}
// close PAM (end session)
if (pam_end(pamh, retval) != PAM_SUCCESS) {
pamh = NULL;
printf("check_user: failed to release authenticator\n");
exit(1);
}
return retval == PAM_SUCCESS ? 0 : 1;
}