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 } |