Mercurial > crates > nonstick
comparison src/module.rs @ 60:05cc2c27334f
The Big Refactor: clean up docs and exports.
- Brings the most important symbols in the library to the root
with `pub use` statements.
- Expands and updates documentation.
- Rearranges things extensively to make the external interface nicer
and make the structure easier to understand.
- Renames a few things (e.g. `Result`).
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Wed, 21 May 2025 19:00:51 -0400 |
parents | 3f4a77aa88be |
children | bbe84835d6db |
comparison
equal
deleted
inserted
replaced
59:3f4a77aa88be | 60:05cc2c27334f |
---|---|
1 //! Functions for use in pam modules. | 1 //! Functions and types useful for implementing a PAM module. |
2 | 2 |
3 use crate::constants::{ErrorCode, Flags, PamResult}; | 3 use crate::constants::{ErrorCode, Flags, Result}; |
4 use crate::items::{Item, ItemType}; | 4 use crate::items::{Item, ItemType}; |
5 use crate::memory; | |
5 use libc::c_char; | 6 use libc::c_char; |
6 use secure_string::SecureString; | 7 use secure_string::SecureString; |
7 use std::ffi::{c_int, CStr, CString}; | 8 use std::ffi::{c_int, CStr, CString}; |
8 | 9 |
9 /// Opaque type, used as a pointer when making pam API calls. | 10 use crate::pam_ffi; |
10 /// | |
11 /// A module is invoked via an external function such as `pam_sm_authenticate`. | |
12 /// Such a call provides a pam handle pointer. The same pointer should be given | |
13 /// as an argument when making API calls. | |
14 #[repr(C)] | |
15 pub struct PamHandle { | |
16 _data: [u8; 0], | |
17 } | |
18 | |
19 #[link(name = "pam")] | |
20 extern "C" { | |
21 fn pam_get_data( | |
22 pamh: *const PamHandle, | |
23 module_data_name: *const c_char, | |
24 data: &mut *const libc::c_void, | |
25 ) -> c_int; | |
26 | |
27 fn pam_set_data( | |
28 pamh: *const PamHandle, | |
29 module_data_name: *const c_char, | |
30 data: *const libc::c_void, | |
31 cleanup: extern "C" fn( | |
32 pamh: *const PamHandle, | |
33 data: *mut libc::c_void, | |
34 error_status: c_int, | |
35 ), | |
36 ) -> c_int; | |
37 | |
38 fn pam_get_item( | |
39 pamh: *const PamHandle, | |
40 item_type: c_int, | |
41 item: &mut *const libc::c_void, | |
42 ) -> c_int; | |
43 | |
44 fn pam_set_item(pamh: *mut PamHandle, item_type: c_int, item: *const libc::c_void) -> c_int; | |
45 | |
46 fn pam_get_user( | |
47 pamh: *const PamHandle, | |
48 user: &mut *const c_char, | |
49 prompt: *const c_char, | |
50 ) -> c_int; | |
51 | |
52 fn pam_get_authtok( | |
53 pamh: *const PamHandle, | |
54 item_type: c_int, | |
55 data: &mut *const c_char, | |
56 prompt: *const c_char, | |
57 ) -> c_int; | |
58 | |
59 } | |
60 | 11 |
61 /// Function called at the end of a PAM session that is called to clean up | 12 /// Function called at the end of a PAM session that is called to clean up |
62 /// a value previously provided to PAM in a `pam_set_data` call. | 13 /// a value previously provided to PAM in a `pam_set_data` call. |
63 /// | 14 /// |
64 /// You should never call this yourself. | 15 /// You should never call this yourself. |
65 extern "C" fn cleanup<T>(_: *const PamHandle, c_data: *mut libc::c_void, _: c_int) { | 16 extern "C" fn cleanup<T>(_: *const libc::c_void, c_data: *mut libc::c_void, _: c_int) { |
66 unsafe { | 17 unsafe { |
67 let _data: Box<T> = Box::from_raw(c_data.cast()); | 18 let _data: Box<T> = Box::from_raw(c_data.cast()); |
68 } | 19 } |
69 } | 20 } |
21 | |
22 /// An opaque structure pointing to a PAM handle. | |
23 #[repr(transparent)] | |
24 pub struct PamHandle(*mut libc::c_void); | |
70 | 25 |
71 impl PamHandle { | 26 impl PamHandle { |
72 /// Gets some value, identified by `key`, that has been set by the module | 27 /// Gets some value, identified by `key`, that has been set by the module |
73 /// previously. | 28 /// previously. |
74 /// | 29 /// |
75 /// See the [`pam_get_data` manual page]( | 30 /// See the [`pam_get_data` manual page]( |
76 /// https://www.man7.org/linux/man-pages/man3/pam_get_data.3.html). | 31 /// https://www.man7.org/linux/man-pages/man3/pam_get_data.3.html). |
77 /// | 32 /// |
78 /// # Errors | |
79 /// | |
80 /// Returns an error if the underlying PAM function call fails. | |
81 /// | |
82 /// # Safety | 33 /// # Safety |
83 /// | 34 /// |
84 /// The data stored under the provided key must be of type `T` otherwise the | 35 /// The data stored under the provided key must be of type `T` otherwise the |
85 /// behaviour of this function is undefined. | 36 /// behaviour of this function is undefined. |
86 /// | 37 /// |
87 /// The data, if present, is owned by the current PAM conversation. | 38 /// The data, if present, is owned by the current PAM conversation. |
88 pub unsafe fn get_data<T>(&self, key: &str) -> PamResult<Option<&T>> { | 39 pub unsafe fn get_data<T>(&self, key: &str) -> Result<Option<&T>> { |
89 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; | 40 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; |
90 let mut ptr: *const libc::c_void = std::ptr::null(); | 41 let mut ptr: *const libc::c_void = std::ptr::null(); |
91 ErrorCode::result_from(pam_get_data(self, c_key.as_ptr(), &mut ptr))?; | 42 ErrorCode::result_from(pam_ffi::pam_get_data(self.0, c_key.as_ptr(), &mut ptr))?; |
92 match ptr.is_null() { | 43 match ptr.is_null() { |
93 true => Ok(None), | 44 true => Ok(None), |
94 false => { | 45 false => { |
95 let typed_ptr = ptr.cast(); | 46 let typed_ptr = ptr.cast(); |
96 Ok(Some(&*typed_ptr)) | 47 Ok(Some(&*typed_ptr)) |
101 /// Stores a value that can be retrieved later with `get_data`. | 52 /// Stores a value that can be retrieved later with `get_data`. |
102 /// The conversation takes ownership of the data. | 53 /// The conversation takes ownership of the data. |
103 /// | 54 /// |
104 /// See the [`pam_set_data` manual page]( | 55 /// See the [`pam_set_data` manual page]( |
105 /// https://www.man7.org/linux/man-pages/man3/pam_set_data.3.html). | 56 /// https://www.man7.org/linux/man-pages/man3/pam_set_data.3.html). |
106 /// | 57 pub fn set_data<T>(&mut self, key: &str, data: Box<T>) -> Result<()> { |
107 /// # Errors | |
108 /// | |
109 /// Returns an error if the underlying PAM function call fails. | |
110 pub fn set_data<T>(&mut self, key: &str, data: Box<T>) -> PamResult<()> { | |
111 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; | 58 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; |
112 let ret = unsafe { | 59 let ret = unsafe { |
113 pam_set_data( | 60 pam_ffi::pam_set_data( |
114 self, | 61 self.0, |
115 c_key.as_ptr(), | 62 c_key.as_ptr(), |
116 Box::into_raw(data).cast(), | 63 Box::into_raw(data).cast(), |
117 cleanup::<T>, | 64 cleanup::<T>, |
118 ) | 65 ) |
119 }; | 66 }; |
126 /// These items are *references to PAM memory* | 73 /// These items are *references to PAM memory* |
127 /// which are *owned by the conversation*. | 74 /// which are *owned by the conversation*. |
128 /// | 75 /// |
129 /// See the [`pam_get_item` manual page]( | 76 /// See the [`pam_get_item` manual page]( |
130 /// https://www.man7.org/linux/man-pages/man3/pam_get_item.3.html). | 77 /// https://www.man7.org/linux/man-pages/man3/pam_get_item.3.html). |
131 /// | 78 pub fn get_item<T: crate::items::Item>(&self) -> Result<Option<T>> { |
132 /// # Errors | |
133 /// | |
134 /// Returns an error if the underlying PAM function call fails. | |
135 pub fn get_item<T: crate::items::Item>(&self) -> PamResult<Option<T>> { | |
136 let mut ptr: *const libc::c_void = std::ptr::null(); | 79 let mut ptr: *const libc::c_void = std::ptr::null(); |
137 let out = unsafe { | 80 let out = unsafe { |
138 let ret = pam_get_item(self, T::type_id().into(), &mut ptr); | 81 let ret = pam_ffi::pam_get_item(self.0, T::type_id().into(), &mut ptr); |
139 ErrorCode::result_from(ret)?; | 82 ErrorCode::result_from(ret)?; |
140 let typed_ptr: *const T::Raw = ptr.cast(); | 83 let typed_ptr: *const T::Raw = ptr.cast(); |
141 match typed_ptr.is_null() { | 84 match typed_ptr.is_null() { |
142 true => None, | 85 true => None, |
143 false => Some(T::from_raw(typed_ptr)), | 86 false => Some(T::from_raw(typed_ptr)), |
148 | 91 |
149 /// Sets an item in the pam context. It can be retrieved using `get_item`. | 92 /// Sets an item in the pam context. It can be retrieved using `get_item`. |
150 /// | 93 /// |
151 /// See the [`pam_set_item` manual page]( | 94 /// See the [`pam_set_item` manual page]( |
152 /// https://www.man7.org/linux/man-pages/man3/pam_set_item.3.html). | 95 /// https://www.man7.org/linux/man-pages/man3/pam_set_item.3.html). |
153 /// | 96 pub fn set_item<T: Item>(&mut self, item: T) -> Result<()> { |
154 /// # Errors | 97 let ret = |
155 /// | 98 unsafe { pam_ffi::pam_set_item(self.0, T::type_id().into(), item.into_raw().cast()) }; |
156 /// Returns an error if the underlying PAM function call fails. | |
157 pub fn set_item<T: Item>(&mut self, item: T) -> PamResult<()> { | |
158 let ret = unsafe { pam_set_item(self, T::type_id().into(), item.into_raw().cast()) }; | |
159 ErrorCode::result_from(ret) | 99 ErrorCode::result_from(ret) |
160 } | 100 } |
161 | 101 |
162 /// Retrieves the name of the user who is authenticating or logging in. | 102 /// Retrieves the name of the user who is authenticating or logging in. |
163 /// | 103 /// |
164 /// This is really a specialization of `get_item`. | 104 /// This is really a specialization of `get_item`. |
165 /// | 105 /// |
166 /// See the [`pam_get_user` manual page]( | 106 /// See the [`pam_get_user` manual page]( |
167 /// https://www.man7.org/linux/man-pages/man3/pam_get_user.3.html). | 107 /// https://www.man7.org/linux/man-pages/man3/pam_get_user.3.html). |
168 /// | 108 pub fn get_user(&self, prompt: Option<&str>) -> Result<String> { |
169 /// # Errors | 109 let prompt = memory::option_cstr(prompt)?; |
170 /// | |
171 /// Returns an error if the underlying PAM function call fails. | |
172 pub fn get_user(&self, prompt: Option<&str>) -> PamResult<String> { | |
173 let prompt = option_cstr(prompt)?; | |
174 let mut output: *const c_char = std::ptr::null_mut(); | 110 let mut output: *const c_char = std::ptr::null_mut(); |
175 let ret = unsafe { pam_get_user(self, &mut output, prompt_ptr(prompt.as_ref())) }; | 111 let ret = unsafe { |
112 pam_ffi::pam_get_user(self.0, &mut output, memory::prompt_ptr(prompt.as_ref())) | |
113 }; | |
176 ErrorCode::result_from(ret)?; | 114 ErrorCode::result_from(ret)?; |
177 copy_pam_string(output) | 115 memory::copy_pam_string(output) |
178 } | 116 } |
179 | 117 |
180 /// Retrieves the authentication token from the user. | 118 /// Retrieves the authentication token from the user. |
181 /// | 119 /// |
182 /// This is really a specialization of `get_item`. | 120 /// This is really a specialization of `get_item`. |
183 /// | 121 /// |
184 /// See the [`pam_get_authtok` manual page]( | 122 /// See the [`pam_get_authtok` manual page]( |
185 /// https://www.man7.org/linux/man-pages/man3/pam_get_authtok.3.html). | 123 /// https://www.man7.org/linux/man-pages/man3/pam_get_authtok.3.html). |
186 /// | 124 pub fn get_authtok(&self, prompt: Option<&str>) -> Result<SecureString> { |
187 /// # Errors | 125 let prompt = memory::option_cstr(prompt)?; |
188 /// | |
189 /// Returns an error if the underlying PAM function call fails. | |
190 pub fn get_authtok(&self, prompt: Option<&str>) -> PamResult<SecureString> { | |
191 let prompt = option_cstr(prompt)?; | |
192 let mut output: *const c_char = std::ptr::null_mut(); | 126 let mut output: *const c_char = std::ptr::null_mut(); |
193 let res = unsafe { | 127 let res = unsafe { |
194 pam_get_authtok( | 128 pam_ffi::pam_get_authtok( |
195 self, | 129 self.0, |
196 ItemType::AuthTok.into(), | 130 ItemType::AuthTok.into(), |
197 &mut output, | 131 &mut output, |
198 prompt_ptr(prompt.as_ref()), | 132 memory::prompt_ptr(prompt.as_ref()), |
199 ) | 133 ) |
200 }; | 134 }; |
201 ErrorCode::result_from(res)?; | 135 ErrorCode::result_from(res)?; |
202 copy_pam_string(output).map(SecureString::from) | 136 memory::copy_pam_string(output).map(SecureString::from) |
203 } | 137 } |
204 } | 138 } |
205 | 139 |
206 /// Safely converts a `&str` option to a `CString` option. | 140 impl From<*mut libc::c_void> for PamHandle { |
207 fn option_cstr(prompt: Option<&str>) -> PamResult<Option<CString>> { | 141 /// Wraps an internal Handle pointer. |
208 prompt | 142 fn from(value: *mut libc::c_void) -> Self { |
209 .map(CString::new) | 143 Self(value) |
210 .transpose() | 144 } |
211 .map_err(|_| ErrorCode::ConversationError) | 145 } |
212 } | 146 |
213 | 147 /// Trait representing what a PAM module can do. |
214 /// The pointer to the prompt CString, or null if absent. | 148 /// |
215 pub(crate) fn prompt_ptr(prompt: Option<&CString>) -> *const c_char { | 149 /// By default, all the functions in this trait are ignored. |
216 match prompt { | 150 /// Implement any functions you wish to handle in your module. |
217 Some(c_str) => c_str.as_ptr(), | 151 /// After implementing this trait, use the [crate::pam_hooks!] macro |
218 None => std::ptr::null(), | 152 /// to export your functions. |
219 } | 153 /// |
220 } | 154 /// For more information, see [`pam(3)`’s root manual page][manpage] |
221 | 155 /// and the [PAM Module Writer’s Guide][module-guide]. |
222 /// Creates an owned copy of a string that is returned from a | 156 /// |
223 /// <code>pam_get_<var>whatever</var></code> function. | 157 /// [manpage]: https://www.man7.org/linux/man-pages/man3/pam.3.html |
224 pub(crate) fn copy_pam_string(result_ptr: *const c_char) -> PamResult<String> { | 158 /// [module-guide]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/Linux-PAM_MWG.html |
225 // We really shouldn't get a null pointer back here, but if we do, return nothing. | |
226 if result_ptr.is_null() { | |
227 return Ok(String::new()); | |
228 } | |
229 let bytes = unsafe { CStr::from_ptr(result_ptr) }; | |
230 bytes | |
231 .to_str() | |
232 .map(String::from) | |
233 .map_err(|_| ErrorCode::ConversationError) | |
234 } | |
235 | |
236 /// Provides functions that are invoked by the entrypoints generated by the | |
237 /// [`pam_hooks!` macro](../macro.pam_hooks.html). | |
238 /// | |
239 /// All hooks are ignored by PAM dispatch by default given the default return value of `PAM_IGNORE`. | |
240 /// Override any functions that you want to handle with your module. See [PAM’s root manual page]( | |
241 /// https://www.man7.org/linux/man-pages/man3/pam.3.html). | |
242 #[allow(unused_variables)] | 159 #[allow(unused_variables)] |
243 pub trait PamHooks { | 160 pub trait PamModule { |
244 /// This function performs the task of establishing whether the user is permitted to gain access at | 161 /// This function performs the task of establishing whether the user is permitted to gain access at |
245 /// this time. It should be understood that the user has previously been validated by an | 162 /// this time. It should be understood that the user has previously been validated by an |
246 /// authentication module. This function checks for other things. Such things might be: the time of | 163 /// authentication module. This function checks for other things. Such things might be: the time of |
247 /// day or the date, the terminal line, remote hostname, etc. This function may also determine | 164 /// day or the date, the terminal line, remote hostname, etc. This function may also determine |
248 /// things like the expiration on passwords, and respond that the user change it before continuing. | 165 /// things like the expiration on passwords, and respond that the user change it before continuing. |
249 fn acct_mgmt(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | 166 fn acct_mgmt(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { |
250 Err(ErrorCode::Ignore) | 167 Err(ErrorCode::Ignore) |
251 } | 168 } |
252 | 169 |
253 /// This function performs the task of authenticating the user. | 170 /// This function performs the task of authenticating the user. |
254 fn sm_authenticate(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | 171 fn sm_authenticate(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { |
255 Err(ErrorCode::Ignore) | 172 Err(ErrorCode::Ignore) |
256 } | 173 } |
257 | 174 |
258 /// This function is used to (re-)set the authentication token of the user. | 175 /// This function is used to (re-)set the authentication token of the user. |
259 /// | 176 /// |
260 /// The PAM library calls this function twice in succession. The first time with | 177 /// The PAM library calls this function twice in succession. The first time with |
261 /// `PAM_PRELIM_CHECK` and then, if the module does not return `PAM_TRY_AGAIN`, subsequently with | 178 /// `PAM_PRELIM_CHECK` and then, if the module does not return `PAM_TRY_AGAIN`, subsequently with |
262 /// `PAM_UPDATE_AUTHTOK`. It is only on the second call that the authorization token is | 179 /// `PAM_UPDATE_AUTHTOK`. It is only on the second call that the authorization token is |
263 /// (possibly) changed. | 180 /// (possibly) changed. |
264 fn sm_chauthtok(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | 181 fn sm_chauthtok(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { |
265 Err(ErrorCode::Ignore) | 182 Err(ErrorCode::Ignore) |
266 } | 183 } |
267 | 184 |
268 /// This function is called to terminate a session. | 185 /// This function is called to terminate a session. |
269 fn sm_close_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | 186 fn sm_close_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { |
270 Err(ErrorCode::Ignore) | 187 Err(ErrorCode::Ignore) |
271 } | 188 } |
272 | 189 |
273 /// This function is called to commence a session. | 190 /// This function is called to commence a session. |
274 fn sm_open_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | 191 fn sm_open_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { |
275 Err(ErrorCode::Ignore) | 192 Err(ErrorCode::Ignore) |
276 } | 193 } |
277 | 194 |
278 /// This function performs the task of altering the credentials of the user with respect to the | 195 /// This function performs the task of altering the credentials of the user with respect to the |
279 /// corresponding authorization scheme. Generally, an authentication module may have access to more | 196 /// corresponding authorization scheme. Generally, an authentication module may have access to more |
280 /// information about a user than their authentication token. This function is used to make such | 197 /// information about a user than their authentication token. This function is used to make such |
281 /// information available to the application. It should only be called after the user has been | 198 /// information available to the application. It should only be called after the user has been |
282 /// authenticated but before a session has been established. | 199 /// authenticated but before a session has been established. |
283 fn sm_setcred(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | 200 fn sm_setcred(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { |
284 Err(ErrorCode::Ignore) | 201 Err(ErrorCode::Ignore) |
285 } | 202 } |
286 } | 203 } |
204 | |
205 /// Generates the dynamic library entry points for a [PamModule] implementation. | |
206 /// | |
207 /// Calling `pam_hooks!(SomeType)` on a type that implements [PamModule] will | |
208 /// generate the exported `extern "C"` functions that PAM uses to call into | |
209 /// your module. | |
210 /// | |
211 /// ## Examples: | |
212 /// | |
213 /// Here is full example of a PAM module that would authenticate and authorize everybody: | |
214 /// | |
215 /// ``` | |
216 /// use nonstick::{Flags, PamHandle, PamModule, Result as PamResult, pam_hooks}; | |
217 /// use std::ffi::CStr; | |
218 /// | |
219 /// # fn main() {} | |
220 /// struct MyPamModule; | |
221 /// pam_hooks!(MyPamModule); | |
222 /// | |
223 /// impl PamModule for MyPamModule { | |
224 /// fn acct_mgmt(pamh: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | |
225 /// // You should use a Conversation to communicate with the user | |
226 /// // instead of writing to the console, but this is just an example. | |
227 /// eprintln!("Everybody is authorized!"); | |
228 /// Ok(()) | |
229 /// } | |
230 /// | |
231 /// fn sm_authenticate(pamh: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { | |
232 /// eprintln!("Everybody is authenticated!"); | |
233 /// Ok(()) | |
234 /// } | |
235 /// } | |
236 /// ``` | |
237 #[macro_export] | |
238 macro_rules! pam_hooks { | |
239 ($ident:ident) => { | |
240 mod _pam_hooks_scope { | |
241 use std::ffi::{c_char, c_int, CStr}; | |
242 use $crate::{ErrorCode, Flags, PamModule}; | |
243 | |
244 #[no_mangle] | |
245 extern "C" fn pam_sm_acct_mgmt( | |
246 pamh: *mut libc::c_void, | |
247 flags: Flags, | |
248 argc: c_int, | |
249 argv: *const *const c_char, | |
250 ) -> c_int { | |
251 let args = extract_argv(argc, argv); | |
252 ErrorCode::result_to_c(super::$ident::acct_mgmt(&mut pamh.into(), args, flags)) | |
253 } | |
254 | |
255 #[no_mangle] | |
256 extern "C" fn pam_sm_authenticate( | |
257 pamh: *mut libc::c_void, | |
258 flags: Flags, | |
259 argc: c_int, | |
260 argv: *const *const c_char, | |
261 ) -> c_int { | |
262 let args = extract_argv(argc, argv); | |
263 ErrorCode::result_to_c(super::$ident::sm_authenticate( | |
264 &mut pamh.into(), | |
265 args, | |
266 flags, | |
267 )) | |
268 } | |
269 | |
270 #[no_mangle] | |
271 extern "C" fn pam_sm_chauthtok( | |
272 pamh: *mut libc::c_void, | |
273 flags: Flags, | |
274 argc: c_int, | |
275 argv: *const *const c_char, | |
276 ) -> c_int { | |
277 let args = extract_argv(argc, argv); | |
278 ErrorCode::result_to_c(super::$ident::sm_chauthtok(&mut pamh.into(), args, flags)) | |
279 } | |
280 | |
281 #[no_mangle] | |
282 extern "C" fn pam_sm_close_session( | |
283 pamh: *mut libc::c_void, | |
284 flags: Flags, | |
285 argc: c_int, | |
286 argv: *const *const c_char, | |
287 ) -> c_int { | |
288 let args = extract_argv(argc, argv); | |
289 ErrorCode::result_to_c(super::$ident::sm_close_session( | |
290 &mut pamh.into(), | |
291 args, | |
292 flags, | |
293 )) | |
294 } | |
295 | |
296 #[no_mangle] | |
297 extern "C" fn pam_sm_open_session( | |
298 pamh: *mut libc::c_void, | |
299 flags: Flags, | |
300 argc: c_int, | |
301 argv: *const *const c_char, | |
302 ) -> c_int { | |
303 let args = extract_argv(argc, argv); | |
304 ErrorCode::result_to_c(super::$ident::sm_open_session( | |
305 &mut pamh.into(), | |
306 args, | |
307 flags, | |
308 )) | |
309 } | |
310 | |
311 #[no_mangle] | |
312 extern "C" fn pam_sm_setcred( | |
313 pamh: *mut libc::c_void, | |
314 flags: Flags, | |
315 argc: c_int, | |
316 argv: *const *const c_char, | |
317 ) -> c_int { | |
318 let args = extract_argv(argc, argv); | |
319 ErrorCode::result_to_c(super::$ident::sm_setcred(&mut pamh.into(), args, flags)) | |
320 } | |
321 | |
322 /// Turns `argc`/`argv` into a [Vec] of [CStr]s. | |
323 /// | |
324 /// # Safety | |
325 /// | |
326 /// We use this only with arguments we get from `libpam`, which we kind of have to trust. | |
327 fn extract_argv<'a>(argc: c_int, argv: *const *const c_char) -> Vec<&'a CStr> { | |
328 (0..argc) | |
329 .map(|o| unsafe { CStr::from_ptr(*argv.offset(o as isize) as *const c_char) }) | |
330 .collect() | |
331 } | |
332 } | |
333 }; | |
334 } | |
335 | |
336 #[cfg(test)] | |
337 pub mod test { | |
338 use crate::module::PamModule; | |
339 | |
340 struct Foo; | |
341 impl PamModule for Foo {} | |
342 | |
343 pam_hooks!(Foo); | |
344 } |