Mercurial > crates > nonstick
comparison src/module.rs @ 59:3f4a77aa88be
Fix string copyting and improve error situation.
This change is too big and includes several things:
- Fix copying strings from PAM by fixing const and mut on pam funcs.
- Improve error enums by simplifying conversions and removing
unnecessary and ambiguous "success" variants.
- Make a bunch of casts nicer.
- Assorted other cleanup.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Wed, 21 May 2025 00:27:18 -0400 |
| parents | daa2cde64601 |
| children | 05cc2c27334f |
comparison
equal
deleted
inserted
replaced
| 58:868a278a362c | 59:3f4a77aa88be |
|---|---|
| 1 //! Functions for use in pam modules. | 1 //! Functions for use in pam modules. |
| 2 | 2 |
| 3 use crate::constants::{Flags, PamResult, ErrorCode}; | 3 use crate::constants::{ErrorCode, Flags, PamResult}; |
| 4 use crate::items::{Item, ItemType}; | 4 use crate::items::{Item, ItemType}; |
| 5 use libc::c_char; | 5 use libc::c_char; |
| 6 use secure_string::SecureString; | |
| 6 use std::ffi::{c_int, CStr, CString}; | 7 use std::ffi::{c_int, CStr, CString}; |
| 7 use secure_string::SecureString; | |
| 8 | 8 |
| 9 /// Opaque type, used as a pointer when making pam API calls. | 9 /// Opaque type, used as a pointer when making pam API calls. |
| 10 /// | 10 /// |
| 11 /// A module is invoked via an external function such as `pam_sm_authenticate`. | 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 | 12 /// Such a call provides a pam handle pointer. The same pointer should be given |
| 25 ) -> c_int; | 25 ) -> c_int; |
| 26 | 26 |
| 27 fn pam_set_data( | 27 fn pam_set_data( |
| 28 pamh: *const PamHandle, | 28 pamh: *const PamHandle, |
| 29 module_data_name: *const c_char, | 29 module_data_name: *const c_char, |
| 30 data: *mut libc::c_void, | 30 data: *const libc::c_void, |
| 31 cleanup: extern "C" fn( | 31 cleanup: extern "C" fn( |
| 32 pamh: *const PamHandle, | 32 pamh: *const PamHandle, |
| 33 data: *mut libc::c_void, | 33 data: *mut libc::c_void, |
| 34 error_status: c_int, | 34 error_status: c_int, |
| 35 ), | 35 ), |
| 41 item: &mut *const libc::c_void, | 41 item: &mut *const libc::c_void, |
| 42 ) -> c_int; | 42 ) -> c_int; |
| 43 | 43 |
| 44 fn pam_set_item(pamh: *mut PamHandle, item_type: c_int, item: *const libc::c_void) -> c_int; | 44 fn pam_set_item(pamh: *mut PamHandle, item_type: c_int, item: *const libc::c_void) -> c_int; |
| 45 | 45 |
| 46 fn pam_get_user(pamh: *const PamHandle, user: &*mut c_char, prompt: *const c_char) -> c_int; | 46 fn pam_get_user( |
| 47 pamh: *const PamHandle, | |
| 48 user: &mut *const c_char, | |
| 49 prompt: *const c_char, | |
| 50 ) -> c_int; | |
| 47 | 51 |
| 48 fn pam_get_authtok( | 52 fn pam_get_authtok( |
| 49 pamh: *const PamHandle, | 53 pamh: *const PamHandle, |
| 50 item_type: c_int, | 54 item_type: c_int, |
| 51 data: &*mut c_char, | 55 data: &mut *const c_char, |
| 52 prompt: *const c_char, | 56 prompt: *const c_char, |
| 53 ) -> c_int; | 57 ) -> c_int; |
| 54 | 58 |
| 55 } | 59 } |
| 56 | 60 |
| 58 /// a value previously provided to PAM in a `pam_set_data` call. | 62 /// a value previously provided to PAM in a `pam_set_data` call. |
| 59 /// | 63 /// |
| 60 /// You should never call this yourself. | 64 /// You should never call this yourself. |
| 61 extern "C" fn cleanup<T>(_: *const PamHandle, c_data: *mut libc::c_void, _: c_int) { | 65 extern "C" fn cleanup<T>(_: *const PamHandle, c_data: *mut libc::c_void, _: c_int) { |
| 62 unsafe { | 66 unsafe { |
| 63 let _data: Box<T> = Box::from_raw(c_data.cast::<T>()); | 67 let _data: Box<T> = Box::from_raw(c_data.cast()); |
| 64 } | 68 } |
| 65 } | 69 } |
| 66 | 70 |
| 67 impl PamHandle { | 71 impl PamHandle { |
| 68 /// Gets some value, identified by `key`, that has been set by the module | 72 /// Gets some value, identified by `key`, that has been set by the module |
| 86 let mut ptr: *const libc::c_void = std::ptr::null(); | 90 let mut ptr: *const libc::c_void = std::ptr::null(); |
| 87 ErrorCode::result_from(pam_get_data(self, c_key.as_ptr(), &mut ptr))?; | 91 ErrorCode::result_from(pam_get_data(self, c_key.as_ptr(), &mut ptr))?; |
| 88 match ptr.is_null() { | 92 match ptr.is_null() { |
| 89 true => Ok(None), | 93 true => Ok(None), |
| 90 false => { | 94 false => { |
| 91 let typed_ptr = ptr.cast::<T>(); | 95 let typed_ptr = ptr.cast(); |
| 92 Ok(Some(&*typed_ptr)) | 96 Ok(Some(&*typed_ptr)) |
| 93 } | 97 } |
| 94 } | 98 } |
| 95 } | 99 } |
| 96 | 100 |
| 107 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; | 111 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; |
| 108 let ret = unsafe { | 112 let ret = unsafe { |
| 109 pam_set_data( | 113 pam_set_data( |
| 110 self, | 114 self, |
| 111 c_key.as_ptr(), | 115 c_key.as_ptr(), |
| 112 Box::into_raw(data).cast::<libc::c_void>(), | 116 Box::into_raw(data).cast(), |
| 113 cleanup::<T>, | 117 cleanup::<T>, |
| 114 ) | 118 ) |
| 115 }; | 119 }; |
| 116 ErrorCode::result_from(ret) | 120 ErrorCode::result_from(ret) |
| 117 } | 121 } |
| 131 pub fn get_item<T: crate::items::Item>(&self) -> PamResult<Option<T>> { | 135 pub fn get_item<T: crate::items::Item>(&self) -> PamResult<Option<T>> { |
| 132 let mut ptr: *const libc::c_void = std::ptr::null(); | 136 let mut ptr: *const libc::c_void = std::ptr::null(); |
| 133 let out = unsafe { | 137 let out = unsafe { |
| 134 let ret = pam_get_item(self, T::type_id().into(), &mut ptr); | 138 let ret = pam_get_item(self, T::type_id().into(), &mut ptr); |
| 135 ErrorCode::result_from(ret)?; | 139 ErrorCode::result_from(ret)?; |
| 136 let typed_ptr = ptr.cast::<T::Raw>(); | 140 let typed_ptr: *const T::Raw = ptr.cast(); |
| 137 match typed_ptr.is_null() { | 141 match typed_ptr.is_null() { |
| 138 true => None, | 142 true => None, |
| 139 false => Some(T::from_raw(typed_ptr)), | 143 false => Some(T::from_raw(typed_ptr)), |
| 140 } | 144 } |
| 141 }; | 145 }; |
| 149 /// | 153 /// |
| 150 /// # Errors | 154 /// # Errors |
| 151 /// | 155 /// |
| 152 /// Returns an error if the underlying PAM function call fails. | 156 /// Returns an error if the underlying PAM function call fails. |
| 153 pub fn set_item<T: Item>(&mut self, item: T) -> PamResult<()> { | 157 pub fn set_item<T: Item>(&mut self, item: T) -> PamResult<()> { |
| 154 let ret = | 158 let ret = unsafe { pam_set_item(self, T::type_id().into(), item.into_raw().cast()) }; |
| 155 unsafe { pam_set_item(self, T::type_id().into(), item.into_raw().cast::<libc::c_void>()) }; | |
| 156 ErrorCode::result_from(ret) | 159 ErrorCode::result_from(ret) |
| 157 } | 160 } |
| 158 | 161 |
| 159 /// Retrieves the name of the user who is authenticating or logging in. | 162 /// Retrieves the name of the user who is authenticating or logging in. |
| 160 /// | 163 /// |
| 166 /// # Errors | 169 /// # Errors |
| 167 /// | 170 /// |
| 168 /// Returns an error if the underlying PAM function call fails. | 171 /// Returns an error if the underlying PAM function call fails. |
| 169 pub fn get_user(&self, prompt: Option<&str>) -> PamResult<String> { | 172 pub fn get_user(&self, prompt: Option<&str>) -> PamResult<String> { |
| 170 let prompt = option_cstr(prompt)?; | 173 let prompt = option_cstr(prompt)?; |
| 171 let output: *mut c_char = std::ptr::null_mut(); | 174 let mut output: *const c_char = std::ptr::null_mut(); |
| 172 let ret = unsafe { pam_get_user(self, &output, prompt_ptr(prompt.as_ref())) }; | 175 let ret = unsafe { pam_get_user(self, &mut output, prompt_ptr(prompt.as_ref())) }; |
| 173 ErrorCode::result_from(ret)?; | 176 ErrorCode::result_from(ret)?; |
| 174 copy_pam_string(output) | 177 copy_pam_string(output) |
| 175 } | 178 } |
| 176 | 179 |
| 177 /// Retrieves the authentication token from the user. | 180 /// Retrieves the authentication token from the user. |
| 184 /// # Errors | 187 /// # Errors |
| 185 /// | 188 /// |
| 186 /// Returns an error if the underlying PAM function call fails. | 189 /// Returns an error if the underlying PAM function call fails. |
| 187 pub fn get_authtok(&self, prompt: Option<&str>) -> PamResult<SecureString> { | 190 pub fn get_authtok(&self, prompt: Option<&str>) -> PamResult<SecureString> { |
| 188 let prompt = option_cstr(prompt)?; | 191 let prompt = option_cstr(prompt)?; |
| 189 let output: *mut c_char = std::ptr::null_mut(); | 192 let mut output: *const c_char = std::ptr::null_mut(); |
| 190 let res = unsafe { | 193 let res = unsafe { |
| 191 pam_get_authtok( | 194 pam_get_authtok( |
| 192 self, | 195 self, |
| 193 ItemType::AuthTok.into(), | 196 ItemType::AuthTok.into(), |
| 194 &output, | 197 &mut output, |
| 195 prompt_ptr(prompt.as_ref()), | 198 prompt_ptr(prompt.as_ref()), |
| 196 ) | 199 ) |
| 197 }; | 200 }; |
| 198 ErrorCode::result_from(res)?; | 201 ErrorCode::result_from(res)?; |
| 199 copy_pam_string(output).map(SecureString::from) | 202 copy_pam_string(output).map(SecureString::from) |
