Mercurial > crates > nonstick
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 74:c7c596e6388f | 75:c30811b4afae |
|---|---|
| 1 use std::ffi::CStr; | |
| 2 | |
| 3 /// Generates the dynamic library entry points for a [PamModule] implementation. | |
| 4 /// | |
| 5 /// Calling `pam_hooks!(SomeType)` on a type that implements [PamModule] will | |
| 6 /// generate the exported `extern "C"` functions that PAM uses to call into | |
| 7 /// your module. | |
| 8 /// | |
| 9 /// ## Examples: | |
| 10 /// | |
| 11 /// Here is full example of a PAM module that would authenticate and authorize everybody: | |
| 12 /// | |
| 13 /// ``` | |
| 14 /// use nonstick::{Flags, OwnedLibPamHandle, PamModule, PamHandleModule, Result as PamResult, pam_hooks}; | |
| 15 /// use std::ffi::CStr; | |
| 16 /// # fn main() {} | |
| 17 /// | |
| 18 /// struct MyPamModule; | |
| 19 /// pam_hooks!(MyPamModule); | |
| 20 /// | |
| 21 /// impl<T: PamHandleModule> PamModule<T> for MyPamModule { | |
| 22 /// fn authenticate(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | |
| 23 /// let password = handle.get_authtok(Some("what's your password?"))?; | |
| 24 /// handle.info_msg(fmt!("If you say your password is {password:?}, who am I to disagree?")); | |
| 25 /// } | |
| 26 /// | |
| 27 /// fn account_management(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | |
| 28 /// let username = handle.get_user(None)?; | |
| 29 /// handle.info_msg(fmt!("Hello {username}! I trust you unconditionally.")) | |
| 30 /// Ok(()) | |
| 31 /// } | |
| 32 /// } | |
| 33 /// ``` | |
| 34 #[macro_export] | |
| 35 macro_rules! pam_hooks { | |
| 36 ($ident:ident) => { | |
| 37 mod _pam_hooks_scope { | |
| 38 use std::ffi::{c_char, c_int, CStr}; | |
| 39 use $crate::{ErrorCode, Flags, LibPamHandle, PamModule}; | |
| 40 | |
| 41 #[no_mangle] | |
| 42 extern "C" fn pam_sm_acct_mgmt( | |
| 43 pamh: *mut libc::c_void, | |
| 44 flags: Flags, | |
| 45 argc: c_int, | |
| 46 argv: *const *const c_char, | |
| 47 ) -> c_int { | |
| 48 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
| 49 let args = extract_argv(argc, argv); | |
| 50 ErrorCode::result_to_c(super::$ident::account_management(handle, args, flags)) | |
| 51 } else { | |
| 52 ErrorCode::Ignore as c_int | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 #[no_mangle] | |
| 57 extern "C" fn pam_sm_authenticate( | |
| 58 pamh: *mut libc::c_void, | |
| 59 flags: Flags, | |
| 60 argc: c_int, | |
| 61 argv: *const *const c_char, | |
| 62 ) -> c_int { | |
| 63 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
| 64 let args = extract_argv(argc, argv); | |
| 65 ErrorCode::result_to_c(super::$ident::authenticate(handle, args, flags)) | |
| 66 } else { | |
| 67 ErrorCode::Ignore as c_int | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 #[no_mangle] | |
| 72 extern "C" fn pam_sm_chauthtok( | |
| 73 pamh: *mut libc::c_void, | |
| 74 flags: Flags, | |
| 75 argc: c_int, | |
| 76 argv: *const *const c_char, | |
| 77 ) -> c_int { | |
| 78 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
| 79 let args = extract_argv(argc, argv); | |
| 80 ErrorCode::result_to_c(super::$ident::change_authtok(handle, args, flags)) | |
| 81 } else { | |
| 82 ErrorCode::Ignore as c_int | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 #[no_mangle] | |
| 87 extern "C" fn pam_sm_close_session( | |
| 88 pamh: *mut libc::c_void, | |
| 89 flags: Flags, | |
| 90 argc: c_int, | |
| 91 argv: *const *const c_char, | |
| 92 ) -> c_int { | |
| 93 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
| 94 let args = extract_argv(argc, argv); | |
| 95 ErrorCode::result_to_c(super::$ident::close_session(handle, args, flags)) | |
| 96 } else { | |
| 97 ErrorCode::Ignore as c_int | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 #[no_mangle] | |
| 102 extern "C" fn pam_sm_open_session( | |
| 103 pamh: *mut libc::c_void, | |
| 104 flags: Flags, | |
| 105 argc: c_int, | |
| 106 argv: *const *const c_char, | |
| 107 ) -> c_int { | |
| 108 let args = extract_argv(argc, argv); | |
| 109 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
| 110 ErrorCode::result_to_c(super::$ident::open_session(handle, args, flags)) | |
| 111 } else { | |
| 112 ErrorCode::Ignore as c_int | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 #[no_mangle] | |
| 117 extern "C" fn pam_sm_setcred( | |
| 118 pamh: *mut libc::c_void, | |
| 119 flags: Flags, | |
| 120 argc: c_int, | |
| 121 argv: *const *const c_char, | |
| 122 ) -> c_int { | |
| 123 let args = extract_argv(argc, argv); | |
| 124 if let Some(handle) = unsafe { pamh.cast::<LibPamHandle>().as_mut() } { | |
| 125 ErrorCode::result_to_c(super::$ident::set_credentials(handle, args, flags)) | |
| 126 } else { | |
| 127 ErrorCode::Ignore as c_int | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 /// Turns `argc`/`argv` into a [Vec] of [CStr]s. | |
| 132 /// | |
| 133 /// # Safety | |
| 134 /// | |
| 135 /// We use this only with arguments we get from `libpam`, which we kind of have to trust. | |
| 136 fn extract_argv<'a>(argc: c_int, argv: *const *const c_char) -> Vec<&'a CStr> { | |
| 137 (0..argc) | |
| 138 .map(|o| unsafe { CStr::from_ptr(*argv.offset(o as isize) as *const c_char) }) | |
| 139 .collect() | |
| 140 } | |
| 141 } | |
| 142 }; | |
| 143 } | |
| 144 | |
| 145 #[cfg(test)] | |
| 146 mod tests { | |
| 147 // Compile-time test that the `pam_hooks` macro compiles. | |
| 148 use crate::{PamHandleModule, PamModule}; | |
| 149 struct Foo; | |
| 150 impl<T: PamHandleModule> PamModule<T> for Foo {} | |
| 151 | |
| 152 pam_hooks!(Foo); | |
| 153 } |
