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 }