Mercurial > crates > nonstick
view testharness/src/lib.rs @ 167:0cabe7b94a4f
Check for old_authtok in change_authtok to emulate real behavior.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Tue, 15 Jul 2025 00:39:08 -0400 |
parents | 2f5913131295 |
children | 6642e89d29a2 |
line wrap: on
line source
//! The nonstick library use crate::nonstick::items::ItemsMut; use std::cell::Cell; extern crate nonstick; use nonstick::conv::{ErrorMsg, InfoMsg, MaskedQAndA, QAndA}; use nonstick::{ error, info, pam_hooks, AuthnFlags, AuthtokAction, AuthtokFlags, ErrorCode, ModuleClient, PamModule, }; use std::ffi::{CStr, OsString}; use std::os::unix::ffi::OsStrExt; struct TestHarness; impl<M: ModuleClient> PamModule<M> for TestHarness { fn authenticate(handle: &mut M, args: Vec<&CStr>, _: AuthnFlags) -> nonstick::Result<()> { let strings: Vec<_> = args.iter().map(|&a| Vec::from(a.to_bytes())).collect(); if strings != vec![Vec::from(b"param"), Vec::from(b"param2")] { return Err(ErrorCode::SystemError); } let username = handle.username(None)?; if username != "initial" { return Err(ErrorCode::UserUnknown); } handle .items_mut() .set_user(Some("updated-in-process".as_ref()))?; handle.set_module_data("florgus", Cell::new(99))?; let authtok = handle.authtok(Some("custom".as_ref()))?; if authtok.as_bytes() != b"valid" { return Err(ErrorCode::AuthenticationError); } let info = InfoMsg::new("Watch out!".as_ref()); let err = ErrorMsg::new("It's broken!".as_ref()); let public = QAndA::new("How many?".as_ref()); let private = MaskedQAndA::new("Where?".as_ref()); let msgs = &[ info.exchange(), err.exchange(), public.exchange(), private.exchange(), ]; handle.communicate(msgs); let public = public.answer()?; info!(handle, "public question: {:?}", public); let private = private.answer()?; info!(handle, "private question: {:?}", private); if public.as_bytes() == b"123" && private.as_bytes() == b"abc" { Ok(()) } else { Err(ErrorCode::Abort) } } fn account_management(handle: &mut M, _: Vec<&CStr>, _: AuthnFlags) -> nonstick::Result<()> { let value: &Cell<i32> = match handle.username(None)?.as_bytes() { b"initial" => return Err(ErrorCode::AccountExpired), b"updated-in-process" => handle.get_module_data("florgus"), _ => return Err(ErrorCode::UserUnknown), } .ok_or(ErrorCode::SessionError)?; let florgus_str: Option<&i32> = handle.get_module_data("florgus"); if let Some(s) = florgus_str { error!( handle, "module_data type mismatch: florgus = <{s}> but should not be set" ) } if value.get() != 99 { error!(handle, "wrong value! {}", value.get()); return Err(ErrorCode::AuthTokError); } let password = handle.authtok(None)?; if password.as_bytes() == b"valid" { Err(ErrorCode::NewAuthTokRequired) } else { Ok(()) } } fn change_authtok( handle: &mut M, _: Vec<&CStr>, action: AuthtokAction, _flags: AuthtokFlags, ) -> nonstick::Result<()> { match action { AuthtokAction::PreliminaryCheck => { if handle.old_authtok(None)?.as_bytes() != b"old token!" { return Err(ErrorCode::AuthenticationError); } let password = handle.authtok(None)?; if password.as_bytes() != b"acceptable" { return Err(ErrorCode::PermissionDenied); } handle.set_module_data("checked_pass", password) } AuthtokAction::Update => { let password = handle.authtok(None)?; let checked: &OsString = handle .get_module_data("checked_pass") .ok_or(ErrorCode::SystemError)?; if password != *checked { error!(handle, "password mismatch? {password:?} {checked:?}"); return Err(ErrorCode::AuthenticationError); } Ok(()) } } } } pam_hooks!(TestHarness);