Mercurial > crates > nonstick
comparison testharness/src/lib.rs @ 163:a75a66cb4181
Add end-to-end tests; fix issues found by tests.
- Create tests and installer/remover shell script
- Fix Pointer/pointee problems
- Add Debug formatting
- Misc cleanup
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Mon, 14 Jul 2025 17:40:11 -0400 |
| parents | 634cd5f2ac8b |
| children | 2f5913131295 |
comparison
equal
deleted
inserted
replaced
| 162:180237d0b498 | 163:a75a66cb4181 |
|---|---|
| 1 //! The nonstick library | 1 //! The nonstick library |
| 2 | |
| 3 use crate::nonstick::items::ItemsMut; | |
| 4 use std::cell::Cell; | |
| 2 extern crate nonstick; | 5 extern crate nonstick; |
| 3 | 6 |
| 4 use nonstick::{pam_hooks, Flags, ModuleClient, PamModule}; | 7 use nonstick::conv::{ErrorMsg, InfoMsg, MaskedQAndA, QAndA}; |
| 5 use std::ffi::CStr; | 8 use nonstick::{error, info, pam_hooks, ErrorCode, Flags, ModuleClient, PamModule}; |
| 9 use std::ffi::{CStr, OsString}; | |
| 10 use std::os::unix::ffi::OsStrExt; | |
| 6 | 11 |
| 7 struct TestHarness; | 12 struct TestHarness; |
| 8 | 13 |
| 9 impl<M: ModuleClient> PamModule<M> for TestHarness { | 14 impl<M: ModuleClient> PamModule<M> for TestHarness { |
| 10 fn authenticate(_handle: &mut M, _args: Vec<&CStr>, _flags: Flags) -> nonstick::Result<()> { | 15 fn authenticate(handle: &mut M, args: Vec<&CStr>, _: Flags) -> nonstick::Result<()> { |
| 11 Ok(()) | 16 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")] { | |
| 18 return Err(ErrorCode::SystemError); | |
| 19 } | |
| 20 let username = handle.username(None)?; | |
| 21 if username != "initial" { | |
| 22 return Err(ErrorCode::UserUnknown); | |
| 23 } | |
| 24 handle | |
| 25 .items_mut() | |
| 26 .set_user(Some("updated-in-process".as_ref()))?; | |
| 27 handle.set_module_data("florgus", Cell::new(99))?; | |
| 28 let authtok = handle.authtok(Some("custom".as_ref()))?; | |
| 29 if authtok.as_bytes() != b"valid" { | |
| 30 return Err(ErrorCode::AuthenticationError); | |
| 31 } | |
| 32 let info = InfoMsg::new("Watch out!".as_ref()); | |
| 33 let err = ErrorMsg::new("It's broken!".as_ref()); | |
| 34 let public = QAndA::new("How many?".as_ref()); | |
| 35 let private = MaskedQAndA::new("Where?".as_ref()); | |
| 36 let msgs = &[ | |
| 37 info.exchange(), | |
| 38 err.exchange(), | |
| 39 public.exchange(), | |
| 40 private.exchange(), | |
| 41 ]; | |
| 42 handle.communicate(msgs); | |
| 43 let public = public.answer()?; | |
| 44 info!(handle, "public question: {:?}", public); | |
| 45 let private = private.answer()?; | |
| 46 info!(handle, "private question: {:?}", private); | |
| 47 if public.as_bytes() == b"123" && private.as_bytes() == b"abc" { | |
| 48 Ok(()) | |
| 49 } else { | |
| 50 Err(ErrorCode::Abort) | |
| 51 } | |
| 12 } | 52 } |
| 13 | 53 |
| 14 fn account_management( | 54 fn account_management(handle: &mut M, _: Vec<&CStr>, _: Flags) -> nonstick::Result<()> { |
| 15 _handle: &mut M, | 55 let value: &Cell<i32> = match handle.username(None)?.as_bytes() { |
| 16 _args: Vec<&CStr>, | 56 b"initial" => return Err(ErrorCode::AccountExpired), |
| 17 _flags: Flags, | 57 b"updated-in-process" => handle.get_module_data("florgus"), |
| 18 ) -> nonstick::Result<()> { | 58 _ => return Err(ErrorCode::UserUnknown), |
| 19 Ok(()) | 59 } |
| 60 .ok_or(ErrorCode::SessionError)?; | |
| 61 let florgus_str: Option<&i32> = handle.get_module_data("florgus"); | |
| 62 if let Some(s) = florgus_str { | |
| 63 error!( | |
| 64 handle, | |
| 65 "module_data type mismatch: florgus = <{s}> but should not be set" | |
| 66 ) | |
| 67 } | |
| 68 if value.get() != 99 { | |
| 69 error!(handle, "wrong value! {}", value.get()); | |
| 70 return Err(ErrorCode::AuthTokError); | |
| 71 } | |
| 72 let password = handle.authtok(None)?; | |
| 73 if password.as_bytes() == b"valid" { | |
| 74 Err(ErrorCode::NewAuthTokRequired) | |
| 75 } else { | |
| 76 Ok(()) | |
| 77 } | |
| 20 } | 78 } |
| 21 | 79 |
| 22 fn change_authtok(_handle: &mut M, _args: Vec<&CStr>, _flags: Flags) -> nonstick::Result<()> { | 80 fn change_authtok(handle: &mut M, _: Vec<&CStr>, flags: Flags) -> nonstick::Result<()> { |
| 23 todo!() | 81 if flags.contains(Flags::PRELIMINARY_CHECK) { |
| 82 let password = handle.authtok(None)?; | |
| 83 if password.as_bytes() != b"acceptable" { | |
| 84 return Err(ErrorCode::PermissionDenied); | |
| 85 } | |
| 86 handle.set_module_data("checked_pass", password) | |
| 87 } else if flags.contains(Flags::UPDATE_AUTHTOK) { | |
| 88 let password = handle.authtok(None)?; | |
| 89 let checked: &OsString = handle | |
| 90 .get_module_data("checked_pass") | |
| 91 .ok_or(ErrorCode::SystemError)?; | |
| 92 if password != *checked { | |
| 93 error!(handle, "password mismatch? {password:?} {checked:?}"); | |
| 94 return Err(ErrorCode::AuthenticationError); | |
| 95 } | |
| 96 Ok(()) | |
| 97 } else { | |
| 98 error!(handle, "invalid flag state: {flags:?}"); | |
| 99 Err(ErrorCode::SystemError) | |
| 100 } | |
| 24 } | 101 } |
| 25 } | 102 } |
| 26 | 103 |
| 27 pam_hooks!(TestHarness); | 104 pam_hooks!(TestHarness); |
