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