Mercurial > crates > nonstick
view src/libpam/module.rs @ 75:c30811b4afae
rename pam_ffi submodule to libpam.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Fri, 06 Jun 2025 22:35:08 -0400 |
parents | src/pam_ffi/module.rs@c7c596e6388f |
children | 351bdc13005e |
line wrap: on
line source
use std::ffi::CStr; /// Generates the dynamic library entry points for a [PamModule] implementation. /// /// Calling `pam_hooks!(SomeType)` on a type that implements [PamModule] will /// generate the exported `extern "C"` functions that PAM uses to call into /// your module. /// /// ## Examples: /// /// Here is full example of a PAM module that would authenticate and authorize everybody: /// /// ``` /// use nonstick::{Flags, OwnedLibPamHandle, PamModule, PamHandleModule, Result as PamResult, pam_hooks}; /// use std::ffi::CStr; /// # fn main() {} /// /// struct MyPamModule; /// pam_hooks!(MyPamModule); /// /// impl<T: PamHandleModule> 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?"))?; /// handle.info_msg(fmt!("If you say your password is {password:?}, who am I to disagree?")); /// } /// /// fn account_management(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { /// let username = handle.get_user(None)?; /// handle.info_msg(fmt!("Hello {username}! I trust you unconditionally.")) /// Ok(()) /// } /// } /// ``` #[macro_export] macro_rules! pam_hooks { ($ident:ident) => { mod _pam_hooks_scope { use std::ffi::{c_char, c_int, CStr}; use $crate::{ErrorCode, Flags, LibPamHandle, PamModule}; #[no_mangle] extern "C" fn pam_sm_acct_mgmt( pamh: *mut libc::c_void, flags: Flags, argc: c_int, argv: *const *const c_char, ) -> c_int { if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { let args = extract_argv(argc, argv); ErrorCode::result_to_c(super::$ident::account_management(handle, args, flags)) } else { ErrorCode::Ignore as c_int } } #[no_mangle] extern "C" fn pam_sm_authenticate( pamh: *mut libc::c_void, flags: Flags, argc: c_int, argv: *const *const c_char, ) -> c_int { if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { let args = extract_argv(argc, argv); ErrorCode::result_to_c(super::$ident::authenticate(handle, args, flags)) } else { ErrorCode::Ignore as c_int } } #[no_mangle] extern "C" fn pam_sm_chauthtok( pamh: *mut libc::c_void, flags: Flags, argc: c_int, argv: *const *const c_char, ) -> c_int { if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { let args = extract_argv(argc, argv); ErrorCode::result_to_c(super::$ident::change_authtok(handle, args, flags)) } else { ErrorCode::Ignore as c_int } } #[no_mangle] extern "C" fn pam_sm_close_session( pamh: *mut libc::c_void, flags: Flags, argc: c_int, argv: *const *const c_char, ) -> c_int { if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { let args = extract_argv(argc, argv); ErrorCode::result_to_c(super::$ident::close_session(handle, args, flags)) } else { ErrorCode::Ignore as c_int } } #[no_mangle] extern "C" fn pam_sm_open_session( pamh: *mut libc::c_void, flags: Flags, argc: c_int, argv: *const *const c_char, ) -> c_int { let args = extract_argv(argc, argv); if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { ErrorCode::result_to_c(super::$ident::open_session(handle, args, flags)) } else { ErrorCode::Ignore as c_int } } #[no_mangle] extern "C" fn pam_sm_setcred( pamh: *mut libc::c_void, flags: Flags, argc: c_int, argv: *const *const c_char, ) -> c_int { let args = extract_argv(argc, argv); if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { ErrorCode::result_to_c(super::$ident::set_credentials(handle, args, flags)) } else { ErrorCode::Ignore as c_int } } /// 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() } } }; } #[cfg(test)] mod tests { // Compile-time test that the `pam_hooks` macro compiles. use crate::{PamHandleModule, PamModule}; struct Foo; impl<T: PamHandleModule> PamModule<T> for Foo {} pam_hooks!(Foo); }