Mercurial > crates > nonstick
comparison testharness/src/lib.rs @ 166:2f5913131295
Separate flag/action flags into flags and action.
This also individualizes the type of flag for each PAM function,
so that you can only call a function with the right flags and values.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Tue, 15 Jul 2025 00:32:24 -0400 |
| parents | a75a66cb4181 |
| children | 0cabe7b94a4f |
comparison
equal
deleted
inserted
replaced
| 165:c4b1e280463c | 166:2f5913131295 |
|---|---|
| 3 use crate::nonstick::items::ItemsMut; | 3 use crate::nonstick::items::ItemsMut; |
| 4 use std::cell::Cell; | 4 use std::cell::Cell; |
| 5 extern crate nonstick; | 5 extern crate nonstick; |
| 6 | 6 |
| 7 use nonstick::conv::{ErrorMsg, InfoMsg, MaskedQAndA, QAndA}; | 7 use nonstick::conv::{ErrorMsg, InfoMsg, MaskedQAndA, QAndA}; |
| 8 use nonstick::{error, info, pam_hooks, ErrorCode, Flags, ModuleClient, PamModule}; | 8 use nonstick::{ |
| 9 error, info, pam_hooks, AuthnFlags, AuthtokAction, AuthtokFlags, ErrorCode, ModuleClient, | |
| 10 PamModule, | |
| 11 }; | |
| 9 use std::ffi::{CStr, OsString}; | 12 use std::ffi::{CStr, OsString}; |
| 10 use std::os::unix::ffi::OsStrExt; | 13 use std::os::unix::ffi::OsStrExt; |
| 11 | 14 |
| 12 struct TestHarness; | 15 struct TestHarness; |
| 13 | 16 |
| 14 impl<M: ModuleClient> PamModule<M> for TestHarness { | 17 impl<M: ModuleClient> PamModule<M> for TestHarness { |
| 15 fn authenticate(handle: &mut M, args: Vec<&CStr>, _: Flags) -> nonstick::Result<()> { | 18 fn authenticate(handle: &mut M, args: Vec<&CStr>, _: AuthnFlags) -> nonstick::Result<()> { |
| 16 let strings: Vec<_> = args.iter().map(|&a| Vec::from(a.to_bytes())).collect(); | 19 let strings: Vec<_> = args.iter().map(|&a| Vec::from(a.to_bytes())).collect(); |
| 17 if strings != vec![Vec::from(b"param"), Vec::from(b"param2")] { | 20 if strings != vec![Vec::from(b"param"), Vec::from(b"param2")] { |
| 18 return Err(ErrorCode::SystemError); | 21 return Err(ErrorCode::SystemError); |
| 19 } | 22 } |
| 20 let username = handle.username(None)?; | 23 let username = handle.username(None)?; |
| 49 } else { | 52 } else { |
| 50 Err(ErrorCode::Abort) | 53 Err(ErrorCode::Abort) |
| 51 } | 54 } |
| 52 } | 55 } |
| 53 | 56 |
| 54 fn account_management(handle: &mut M, _: Vec<&CStr>, _: Flags) -> nonstick::Result<()> { | 57 fn account_management(handle: &mut M, _: Vec<&CStr>, _: AuthnFlags) -> nonstick::Result<()> { |
| 55 let value: &Cell<i32> = match handle.username(None)?.as_bytes() { | 58 let value: &Cell<i32> = match handle.username(None)?.as_bytes() { |
| 56 b"initial" => return Err(ErrorCode::AccountExpired), | 59 b"initial" => return Err(ErrorCode::AccountExpired), |
| 57 b"updated-in-process" => handle.get_module_data("florgus"), | 60 b"updated-in-process" => handle.get_module_data("florgus"), |
| 58 _ => return Err(ErrorCode::UserUnknown), | 61 _ => return Err(ErrorCode::UserUnknown), |
| 59 } | 62 } |
| 75 } else { | 78 } else { |
| 76 Ok(()) | 79 Ok(()) |
| 77 } | 80 } |
| 78 } | 81 } |
| 79 | 82 |
| 80 fn change_authtok(handle: &mut M, _: Vec<&CStr>, flags: Flags) -> nonstick::Result<()> { | 83 fn change_authtok( |
| 81 if flags.contains(Flags::PRELIMINARY_CHECK) { | 84 handle: &mut M, |
| 82 let password = handle.authtok(None)?; | 85 _: Vec<&CStr>, |
| 83 if password.as_bytes() != b"acceptable" { | 86 action: AuthtokAction, |
| 84 return Err(ErrorCode::PermissionDenied); | 87 _flags: AuthtokFlags, |
| 88 ) -> nonstick::Result<()> { | |
| 89 match action { | |
| 90 AuthtokAction::PreliminaryCheck => { | |
| 91 let password = handle.authtok(None)?; | |
| 92 if password.as_bytes() != b"acceptable" { | |
| 93 return Err(ErrorCode::PermissionDenied); | |
| 94 } | |
| 95 handle.set_module_data("checked_pass", password) | |
| 85 } | 96 } |
| 86 handle.set_module_data("checked_pass", password) | 97 AuthtokAction::Update => { |
| 87 } else if flags.contains(Flags::UPDATE_AUTHTOK) { | 98 let password = handle.authtok(None)?; |
| 88 let password = handle.authtok(None)?; | 99 let checked: &OsString = handle |
| 89 let checked: &OsString = handle | 100 .get_module_data("checked_pass") |
| 90 .get_module_data("checked_pass") | 101 .ok_or(ErrorCode::SystemError)?; |
| 91 .ok_or(ErrorCode::SystemError)?; | 102 if password != *checked { |
| 92 if password != *checked { | 103 error!(handle, "password mismatch? {password:?} {checked:?}"); |
| 93 error!(handle, "password mismatch? {password:?} {checked:?}"); | 104 return Err(ErrorCode::AuthenticationError); |
| 94 return Err(ErrorCode::AuthenticationError); | 105 } |
| 106 Ok(()) | |
| 95 } | 107 } |
| 96 Ok(()) | |
| 97 } else { | |
| 98 error!(handle, "invalid flag state: {flags:?}"); | |
| 99 Err(ErrorCode::SystemError) | |
| 100 } | 108 } |
| 101 } | 109 } |
| 102 } | 110 } |
| 103 | 111 |
| 104 pam_hooks!(TestHarness); | 112 pam_hooks!(TestHarness); |
