diff 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
line wrap: on
line diff
--- a/testharness/src/lib.rs	Mon Jul 14 18:56:55 2025 -0400
+++ b/testharness/src/lib.rs	Tue Jul 15 00:32:24 2025 -0400
@@ -5,14 +5,17 @@
 extern crate nonstick;
 
 use nonstick::conv::{ErrorMsg, InfoMsg, MaskedQAndA, QAndA};
-use nonstick::{error, info, pam_hooks, ErrorCode, Flags, ModuleClient, PamModule};
+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>, _: Flags) -> nonstick::Result<()> {
+    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);
@@ -51,7 +54,7 @@
         }
     }
 
-    fn account_management(handle: &mut M, _: Vec<&CStr>, _: Flags) -> nonstick::Result<()> {
+    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"),
@@ -77,26 +80,31 @@
         }
     }
 
-    fn change_authtok(handle: &mut M, _: Vec<&CStr>, flags: Flags) -> nonstick::Result<()> {
-        if flags.contains(Flags::PRELIMINARY_CHECK) {
-            let password = handle.authtok(None)?;
-            if password.as_bytes() != b"acceptable" {
-                return Err(ErrorCode::PermissionDenied);
+    fn change_authtok(
+        handle: &mut M,
+        _: Vec<&CStr>,
+        action: AuthtokAction,
+        _flags: AuthtokFlags,
+    ) -> nonstick::Result<()> {
+        match action {
+            AuthtokAction::PreliminaryCheck => {
+                let password = handle.authtok(None)?;
+                if password.as_bytes() != b"acceptable" {
+                    return Err(ErrorCode::PermissionDenied);
+                }
+                handle.set_module_data("checked_pass", password)
             }
-            handle.set_module_data("checked_pass", password)
-        } else if flags.contains(Flags::UPDATE_AUTHTOK) {
-            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);
+            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(())
             }
-            Ok(())
-        } else {
-            error!(handle, "invalid flag state: {flags:?}");
-            Err(ErrorCode::SystemError)
         }
     }
 }