Mercurial > crates > nonstick
changeset 17:53efbcff805d
Add pam-sober
author | Anthony Nowell <anthony@algorithmia.com> |
---|---|
date | Sun, 24 Sep 2017 00:57:13 -0600 |
parents | f64ee7b6cdf1 |
children | 0f5e9e8963ae |
files | README.md pam-sober/Cargo.toml pam-sober/Justfile pam-sober/conf/sober-auth pam-sober/src/.lib.rs.swp pam-sober/src/ffi.rs pam-sober/src/lib.rs pam-sober/test.c |
diffstat | 8 files changed, 257 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/README.md Sun Sep 24 00:32:36 2017 -0600 +++ b/README.md Sun Sep 24 00:57:13 2017 -0600 @@ -8,8 +8,13 @@ of functions for use in a pam authentication module. A pam module is a shared library that is invoked to authenticate a user, or to perform other functions. -Additionally, [pam-http](pam-http) is an example of using pam-rs by performing -HTTP basic access auth to authenticate users. +## 🌐 [pam-http](pam-http) + +An example of using pam-rs by performing HTTP basic access auth to authenticate users. + +## 🍻 [pam-sober](pam-sober) + +If you aren't sober enough for basic math, you can't login! ### Credits
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pam-sober/Cargo.toml Sun Sep 24 00:57:13 2017 -0600 @@ -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 = { path = "../pam/" } +rand = "0.3.16"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pam-sober/Justfile Sun Sep 24 00:57:13 2017 -0600 @@ -0,0 +1,12 @@ + +all: + cargo build + +install: + @cargo build + sudo cp conf/sober-auth /etc/pam.d/ + sudo cp target/debug/libpam_sober.so /lib/security/pam_sober.so + +test: + @just install + gcc -o target/pam_test test.c -lpam -lpam_misc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pam-sober/conf/sober-auth Sun Sep 24 00:57:13 2017 -0600 @@ -0,0 +1,2 @@ +auth sufficient pam_sober.so +account sufficient pam_sober.so
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pam-sober/src/ffi.rs Sun Sep 24 00:57:13 2017 -0600 @@ -0,0 +1,82 @@ +use pam::module::{PamHandleT}; +use pam::constants::{PamFlag, PamResultCode, PAM_SILENT}; +use std::ffi::CStr; +use std::os::raw::{c_char, c_int}; + + + +fn extract_argv(argc: c_int, argv: *const *const c_char) -> Vec<String> { + (0..argc) + .map(|o| unsafe { + CStr::from_ptr(*argv.offset(o as isize) as *const c_char) + .to_string_lossy() + .into_owned() + }) + .collect() +} + +#[no_mangle] +pub extern "C" fn pam_sm_acct_mgmt( + pamh: &PamHandleT, + flags: PamFlag, + argc: c_int, + argv: *const *const c_char, +) -> PamResultCode { + let args = extract_argv(argc, argv); + let silent = (flags & PAM_SILENT) != 0; + super::acct_mgmt(pamh, args, silent) +} + +#[no_mangle] +pub extern "C" fn pam_sm_authenticate( + pamh: &PamHandleT, + flags: PamFlag, + argc: c_int, + argv: *const *const c_char, +) -> PamResultCode { + let args = extract_argv(argc, argv); + let silent = (flags & PAM_SILENT) != 0; + super::sm_authenticate(pamh, args, silent) +} + +#[no_mangle] +pub extern "C" fn pam_sm_chauthtok( + _: &PamHandleT, + _: PamFlag, + _: c_int, + _: *const *const c_char, +) -> PamResultCode { + PamResultCode::PAM_IGNORE +} + +#[no_mangle] +pub extern "C" fn pam_sm_close_session( + _: &PamHandleT, + _: PamFlag, + _: c_int, + _: *const *const c_char, +) -> PamResultCode { + PamResultCode::PAM_IGNORE +} + +#[no_mangle] +pub extern "C" fn pam_sm_open_session( + _: &PamHandleT, + _: PamFlag, + _: c_int, + _: *const *const c_char, +) -> PamResultCode { + PamResultCode::PAM_IGNORE +} + +#[no_mangle] +pub extern "C" fn pam_sm_setcred( + pamh: &PamHandleT, + flags: PamFlag, + argc: c_int, + argv: *const *const c_char, +) -> PamResultCode { + let args = extract_argv(argc, argv); + let silent = (flags & PAM_SILENT) != 0; + super::sm_setcred(pamh, args, silent) +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pam-sober/src/lib.rs Sun Sep 24 00:57:13 2017 -0600 @@ -0,0 +1,90 @@ +extern crate pam; +extern crate rand; + +pub mod ffi; + +use pam::module::{PamHandleT, get_item, get_user}; +use pam::constants::{PamResultCode, PAM_PROMPT_ECHO_OFF}; +use pam::conv::PamConv; +use std::collections::HashMap; +use std::time::Duration; +use rand::Rng; +use std::str::FromStr; + +macro_rules! pam_try { + ($e:expr) => ( + match $e { + Ok(v) => v, + Err(e) => return e, + } + ); + ($e:expr, $err:expr) => ( + match $e { + Ok(v) => v, + Err(e) => { + println!("Error: {}", e); + return $err; + } + } + ); +} + +// This function performs the task of authenticating the user. +pub fn sm_authenticate(pamh: &PamHandleT, args: Vec<String>, silent: bool) -> PamResultCode { + println!("Let's auth over HTTP"); + + /* 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!(get_user(&pamh, None)); + + let conv = match get_item::<PamConv>(&pamh) { + Ok(conv) => conv, + 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 + println!("{}", math); + + let password = pam_try!(conv.send(PAM_PROMPT_ECHO_OFF, &math)); + + if password.and_then(|p| u32::from_str(&p).ok()) == Some(a+b) { + return PamResultCode::PAM_SUCCESS; + } + + println!("You failed the PAM sobriety test."); + return PamResultCode::PAM_AUTH_ERR; +} + +// This function performs the task of altering the credentials of the user with respect to the +// corresponding authorization scheme. Generally, an authentication module may have access to more +// information about a user than their authentication token. This function is used to make such +// information available to the application. It should only be called after the user has been +// authenticated but before a session has been established. +pub fn sm_setcred(_pamh: &PamHandleT, _args: Vec<String>, _silent: bool) -> PamResultCode { + println!("set credentials"); + PamResultCode::PAM_SUCCESS +} + +// This function performs the task of establishing whether the user is permitted to gain access at +// this time. It should be understood that the user has previously been validated by an +// authentication module. This function checks for other things. Such things might be: the time of +// day or the date, the terminal line, remote hostname, etc. This function may also determine +// things like the expiration on passwords, and respond that the user change it before continuing. +pub fn acct_mgmt(_pamh: &PamHandleT, _args: Vec<String>, _silent: bool) -> PamResultCode { + println!("account management"); + PamResultCode::PAM_SUCCESS +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pam-sober/test.c Sun Sep 24 00:57:13 2017 -0600 @@ -0,0 +1,52 @@ +#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("Credentials accepted.\n"); + retval = pam_authenticate(pamh, 0); + } + + // Can the accound be used at this time? + if (retval == PAM_SUCCESS) { + printf("Account is valid.\n"); + retval = pam_acct_mgmt(pamh, 0); + } + + // Did everything work? + if (retval == PAM_SUCCESS) { + 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; +} +