Mercurial > crates > nonstick
diff src/libpam/module.rs @ 171:e27c5c667a5a
Create full new types for return code and flags, separate end to end.
This plumbs the ReturnCode and RawFlags types through the places where
we call into or are called from PAM.
Also adds Sun documentation to the project.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Fri, 25 Jul 2025 20:52:14 -0400 |
parents | 2f5913131295 |
children | 6727cbe56f4a |
line wrap: on
line diff
--- a/src/libpam/module.rs Wed Jul 16 18:45:20 2025 -0400 +++ b/src/libpam/module.rs Fri Jul 25 20:52:14 2025 -0400 @@ -1,7 +1,13 @@ +use crate::constants::{ErrorCode, RawFlags, Result}; +use crate::libpam::handle::LibPamHandle; +use crate::module::PamModule; +use crate::{AuthnFlags, AuthtokAction, BaseFlags, CredAction}; +use std::ffi::{c_char, c_int, c_void, CStr}; + /// Generates the dynamic library entry points for a PAM module /// /// Calling `pam_hooks!(SomeType)` on a type that implements -/// [`PamModule`](crate::PamModule) will generate the exported +/// [`PamModule`] will generate the exported /// `extern "C"` functions that PAM uses to call into your module. /// /// ## Examples: @@ -41,115 +47,132 @@ macro_rules! pam_hooks { ($ident:ident) => { mod _pam_hooks_scope { - use std::ffi::{c_char, c_int, c_void, CStr}; - use $crate::{ - AuthnFlags, AuthtokAction, BaseFlags, CredAction, ErrorCode, LibPamHandle, - PamModule, - }; + use std::ffi::{c_char, c_int, c_void}; + use $crate::ModuleExporter; + use $crate::constants::{RawFlags, ReturnCode}; - macro_rules! handle { - ($pamh:ident) => { - match unsafe { $pamh.cast::<LibPamHandle>().as_mut() } { - Some(handle) => handle, - None => return ErrorCode::Ignore.into(), + macro_rules! export { + ($func:ident) => { + #[no_mangle] + unsafe extern "C" fn $func( + pamh: *mut c_void, + flags: RawFlags, + argc: c_int, + argv: *const *const c_char, + ) -> c_int { + let ret: ReturnCode = ModuleExporter::$func::<super::$ident>( + pamh, flags, argc, argv + ).into(); + ret.into() } }; } - #[no_mangle] - extern "C" fn pam_sm_acct_mgmt( - pamh: *mut c_void, - flags: AuthnFlags, - argc: c_int, - argv: *const *const c_char, - ) -> c_int { - let handle = handle!(pamh); - let args = extract_argv(argc, argv); - ErrorCode::result_to_c(super::$ident::account_management(handle, args, flags)) - } - - #[no_mangle] - extern "C" fn pam_sm_authenticate( - pamh: *mut c_void, - flags: AuthnFlags, - argc: c_int, - argv: *const *const c_char, - ) -> c_int { - let handle = handle!(pamh); - let args = extract_argv(argc, argv); - ErrorCode::result_to_c(super::$ident::authenticate(handle, args, flags)) - } - - #[no_mangle] - extern "C" fn pam_sm_chauthtok( - pamh: *mut c_void, - flags: c_int, - argc: c_int, - argv: *const *const c_char, - ) -> c_int { - let handle = handle!(pamh); - let (action, flags) = match AuthtokAction::extract(flags) { - Ok(val) => val, - Err(e) => return e.into(), - }; - let args = extract_argv(argc, argv); - ErrorCode::result_to_c(super::$ident::change_authtok(handle, args, action, flags)) - } - - #[no_mangle] - extern "C" fn pam_sm_close_session( - pamh: *mut c_void, - flags: BaseFlags, - argc: c_int, - argv: *const *const c_char, - ) -> c_int { - let handle = handle!(pamh); - let args = extract_argv(argc, argv); - ErrorCode::result_to_c(super::$ident::close_session(handle, args, flags)) - } - - #[no_mangle] - extern "C" fn pam_sm_open_session( - pamh: *mut c_void, - flags: BaseFlags, - argc: c_int, - argv: *const *const c_char, - ) -> c_int { - let handle = handle!(pamh); - let args = extract_argv(argc, argv); - ErrorCode::result_to_c(super::$ident::open_session(handle, args, flags)) - } - - #[no_mangle] - extern "C" fn pam_sm_setcred( - pamh: *mut c_void, - flags: c_int, - argc: c_int, - argv: *const *const c_char, - ) -> c_int { - let handle = handle!(pamh); - let (action, flags) = match CredAction::extract(flags) { - Ok(val) => val, - Err(e) => return e.into(), - }; - let args = extract_argv(argc, argv); - ErrorCode::result_to_c(super::$ident::set_credentials(handle, args, action, flags)) - } - - /// Turns `argc`/`argv` into a [Vec] of [CStr]s. - /// - /// # Safety - /// - /// We use this only with arguments we get from `libpam`, which we kind of have to trust. - fn extract_argv<'a>(argc: c_int, argv: *const *const c_char) -> Vec<&'a CStr> { - (0..argc) - .map(|o| unsafe { CStr::from_ptr(*argv.offset(o as isize) as *const c_char) }) - .collect() - } + export!(pam_sm_acct_mgmt); + export!(pam_sm_authenticate); + export!(pam_sm_chauthtok); + export!(pam_sm_close_session); + export!(pam_sm_open_session); + export!(pam_sm_setcred); } }; } +#[doc(hidden)] +pub struct ModuleExporter; + +// All of the below are only intended to be called directly from C. +#[allow(clippy::missing_safety_doc)] +impl ModuleExporter { + pub unsafe fn pam_sm_acct_mgmt<M: PamModule<LibPamHandle>>( + pamh: *mut c_void, + flags: RawFlags, + argc: c_int, + argv: *const *const c_char, + ) -> Result<()> { + let handle = wrap(pamh)?; + let args = extract_argv(argc, argv); + M::account_management(handle, args, AuthnFlags::from(flags)) + } + + pub unsafe fn pam_sm_authenticate<M: PamModule<LibPamHandle>>( + pamh: *mut c_void, + flags: RawFlags, + argc: c_int, + argv: *const *const c_char, + ) -> Result<()> { + let handle = wrap(pamh)?; + let args = extract_argv(argc, argv); + M::authenticate(handle, args, AuthnFlags::from(flags)) + } + + pub unsafe fn pam_sm_chauthtok<M: PamModule<LibPamHandle>>( + pamh: *mut c_void, + flags: RawFlags, + argc: c_int, + argv: *const *const c_char, + ) -> Result<()> { + let handle = wrap(pamh)?; + let (action, flags) = AuthtokAction::extract(flags)?; + let args = extract_argv(argc, argv); + M::change_authtok(handle, args, action, flags) + } + + pub unsafe fn pam_sm_close_session<M: PamModule<LibPamHandle>>( + pamh: *mut c_void, + flags: RawFlags, + argc: c_int, + argv: *const *const c_char, + ) -> Result<()> { + let handle = wrap(pamh)?; + let args = extract_argv(argc, argv); + M::close_session(handle, args, BaseFlags::from(flags)) + } + + pub unsafe fn pam_sm_open_session<M: PamModule<LibPamHandle>>( + pamh: *mut c_void, + flags: RawFlags, + argc: c_int, + argv: *const *const c_char, + ) -> Result<()> { + let handle = wrap(pamh)?; + let args = extract_argv(argc, argv); + M::open_session(handle, args, BaseFlags::from(flags)) + } + + pub unsafe fn pam_sm_setcred<M: PamModule<LibPamHandle>>( + pamh: *mut c_void, + flags: RawFlags, + argc: c_int, + argv: *const *const c_char, + ) -> Result<()> { + let handle = wrap(pamh)?; + let (action, flags) = CredAction::extract(flags)?; + let args = extract_argv(argc, argv); + M::set_credentials(handle, args, action, flags) + } +} + +/// Turns `argc`/`argv` into a [Vec] of [CStr]s. +/// +/// # Safety +/// +/// We use this only with arguments we get from `libpam`, which we kind of have to trust. +unsafe fn extract_argv<'a>(argc: c_int, argv: *const *const c_char) -> Vec<&'a CStr> { + (0..argc) + .map(|o| unsafe { CStr::from_ptr(*argv.offset(o as isize) as *const c_char) }) + .collect() +} + +/// Wraps the pointer in a PAM handle, or returns an error if it's null. +/// +/// # Safety +/// +/// It's up to you to pass a valid handle. +unsafe fn wrap<'a>(handle: *mut c_void) -> Result<&'a mut LibPamHandle> { + handle.cast::<LibPamHandle>().as_mut().ok_or(ErrorCode::SystemError) +} + #[cfg(test)] mod tests { // Compile-time test that the `pam_hooks` macro compiles.