diff src/module.rs @ 66:a674799a5cd3

Make `PamHandle` and `PamModuleHandle` traits. This creates traits for PAM functionality and pulls the definitions of that functionality out of the original `PamHandle` (renamed to `LibPamHandle`) and into those traits. This supports testing PAM module implementations using mock PAM library implementations. Also uses a better representation of opaque pointers.
author Paul Fisher <paul@pfish.zone>
date Tue, 27 May 2025 14:37:28 -0400
parents bbe84835d6db
children
line wrap: on
line diff
--- a/src/module.rs	Thu May 22 02:08:10 2025 -0400
+++ b/src/module.rs	Tue May 27 14:37:28 2025 -0400
@@ -1,7 +1,7 @@
 //! Functions and types useful for implementing a PAM module.
 
 use crate::constants::{ErrorCode, Flags, Result};
-use crate::handle::PamHandle;
+use crate::handle::PamModuleHandle;
 use std::ffi::CStr;
 
 /// A trait for a PAM module to implement.
@@ -18,14 +18,14 @@
 /// [manpage]: https://www.man7.org/linux/man-pages/man3/pam.3.html
 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/Linux-PAM_MWG.html
 #[allow(unused_variables)]
-pub trait PamModule {
+pub trait PamModule<T: PamModuleHandle> {
     // Functions for auth modules.
 
     /// Authenticate the user.
     ///
     /// This is probably the first thing you want to implement.
     /// In most cases, you will want to get the user and password,
-    /// using [`PamHandle::get_user`] and [`PamHandle::get_authtok`],
+    /// using [`LibPamHandle::get_user`] and [`LibPamHandle::get_authtok`],
     /// and verify them against something.
     ///
     /// See [the Module Writer's Guide entry for `pam_sm_authenticate`][mwg]
@@ -55,7 +55,7 @@
     ///   They should not try again.
     ///
     /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-auth.html#mwg-pam_sm_authenticate
-    fn authenticate(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
+    fn authenticate(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> {
         Err(ErrorCode::Ignore)
     }
 
@@ -98,7 +98,7 @@
     /// - [`ErrorCode::UserUnknown`]: The supplied username is not known by this service.
     ///
     /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-acct.html#mwg-pam_sm_acct_mgmt
-    fn account_management(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
+    fn account_management(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> {
         Err(ErrorCode::Ignore)
     }
 
@@ -134,7 +134,7 @@
     /// - [`ErrorCode::UserUnknown`]: The supplied username is not known by this service.
     ///
     /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-auth.html#mwg-pam_sm_setcred
-    fn set_credentials(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
+    fn set_credentials(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> {
         Err(ErrorCode::Ignore)
     }
 
@@ -182,7 +182,7 @@
     /// - [`ErrorCode::UserUnknown`]: The supplied username is not known by this service.
     ///
     /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-chauthtok.html#mwg-pam_sm_chauthtok
-    fn change_authtok(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
+    fn change_authtok(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> {
         Err(ErrorCode::Ignore)
     }
 
@@ -206,7 +206,7 @@
     /// - [`ErrorCode::SessionError`]: Cannot make an entry for this session.
     ///
     /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-session.html#mwg-pam_sm_open_session
-    fn open_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
+    fn open_session(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> {
         Err(ErrorCode::Ignore)
     }
 
@@ -228,7 +228,7 @@
     /// - [`ErrorCode::SessionError`]: Cannot remove an entry for this session.
     ///
     /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-session.html#mwg-pam_sm_close_session
-    fn close_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
+    fn close_session(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> {
         Err(ErrorCode::Ignore)
     }
 }
@@ -244,21 +244,21 @@
 /// Here is full example of a PAM module that would authenticate and authorize everybody:
 ///
 /// ```no_run
-/// use nonstick::{Flags, PamHandle, PamModule, Result as PamResult, pam_hooks};
+/// use nonstick::{Flags, LibPamHandle, PamModule, PamModuleHandle, Result as PamResult, pam_hooks};
 /// use std::ffi::CStr;
 /// # fn main() {}
 ///
 /// struct MyPamModule;
 /// pam_hooks!(MyPamModule);
 ///
-/// impl PamModule for MyPamModule {
-///     fn authenticate(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> {
+/// impl<T: PamModuleHandle> PamModule<T> for MyPamModule {
+///     fn authenticate(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> PamResult<()> {
 ///         let password = handle.get_authtok(Some("what's your password?"))?;
 ///         eprintln!("If you say your password is {:?}, who am I to disagree!", password.unsecure());
 ///         Ok(())
 ///     }
 ///
-///     fn account_management(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> {
+///     fn account_management(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> PamResult<()> {
 ///         let username = handle.get_user(None)?;
 ///         // You should use a Conversation to communicate with the user
 ///         // instead of writing to the console, but this is just an example.
@@ -272,7 +272,7 @@
     ($ident:ident) => {
         mod _pam_hooks_scope {
             use std::ffi::{c_char, c_int, CStr};
-            use $crate::{ErrorCode, Flags, PamModule};
+            use $crate::{ErrorCode, Flags, LibPamHandle, PamModule};
 
             #[no_mangle]
             extern "C" fn pam_sm_acct_mgmt(
@@ -283,7 +283,7 @@
             ) -> c_int {
                 let args = extract_argv(argc, argv);
                 ErrorCode::result_to_c(super::$ident::account_management(
-                    &mut pamh.into(),
+                    unsafe { LibPamHandle::from_ptr(pamh) },
                     args,
                     flags,
                 ))
@@ -297,7 +297,11 @@
                 argv: *const *const c_char,
             ) -> c_int {
                 let args = extract_argv(argc, argv);
-                ErrorCode::result_to_c(super::$ident::authenticate(&mut pamh.into(), args, flags))
+                ErrorCode::result_to_c(super::$ident::authenticate(
+                    unsafe { LibPamHandle::from_ptr(pamh) },
+                    args,
+                    flags,
+                ))
             }
 
             #[no_mangle]
@@ -308,7 +312,11 @@
                 argv: *const *const c_char,
             ) -> c_int {
                 let args = extract_argv(argc, argv);
-                ErrorCode::result_to_c(super::$ident::change_authtok(&mut pamh.into(), args, flags))
+                ErrorCode::result_to_c(super::$ident::change_authtok(
+                    unsafe { LibPamHandle::from_ptr(pamh) },
+                    args,
+                    flags,
+                ))
             }
 
             #[no_mangle]
@@ -319,7 +327,11 @@
                 argv: *const *const c_char,
             ) -> c_int {
                 let args = extract_argv(argc, argv);
-                ErrorCode::result_to_c(super::$ident::close_session(&mut pamh.into(), args, flags))
+                ErrorCode::result_to_c(super::$ident::close_session(
+                    unsafe { LibPamHandle::from_ptr(pamh) },
+                    args,
+                    flags,
+                ))
             }
 
             #[no_mangle]
@@ -330,7 +342,11 @@
                 argv: *const *const c_char,
             ) -> c_int {
                 let args = extract_argv(argc, argv);
-                ErrorCode::result_to_c(super::$ident::open_session(&mut pamh.into(), args, flags))
+                ErrorCode::result_to_c(super::$ident::open_session(
+                    unsafe { LibPamHandle::from_ptr(pamh) },
+                    args,
+                    flags,
+                ))
             }
 
             #[no_mangle]
@@ -342,7 +358,7 @@
             ) -> c_int {
                 let args = extract_argv(argc, argv);
                 ErrorCode::result_to_c(super::$ident::set_credentials(
-                    &mut pamh.into(),
+                    unsafe { LibPamHandle::from_ptr(pamh) },
                     args,
                     flags,
                 ))
@@ -364,10 +380,10 @@
 
 #[cfg(test)]
 pub mod test {
-    use crate::module::PamModule;
+    use crate::module::{PamModule, PamModuleHandle};
 
     struct Foo;
-    impl PamModule for Foo {}
+    impl<T: PamModuleHandle> PamModule<T> for Foo {}
 
     pam_hooks!(Foo);
 }