Mercurial > crates > nonstick
view testharness/src/lib.rs @ 171:e27c5c667a5a
Create full new types for return code and flags, separate end to end.
This plumbs the ReturnCode and RawFlags types through the places where
we call into or are called from PAM.
Also adds Sun documentation to the project.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Fri, 25 Jul 2025 20:52:14 -0400 |
parents | 77470e45e397 |
children | 6727cbe56f4a |
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; 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::Validate => { if handle.old_authtok(None)?.as_bytes() != b"old token!" { return Err(ErrorCode::AuthenticationError); } Ok(()) } AuthtokAction::Update => { let password = handle.authtok(None)?; if password.as_bytes() != b"acceptable" { return Err(ErrorCode::PermissionDenied); } Ok(()) } } } } pam_hooks!(TestHarness);