Mercurial > crates > nonstick
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); }