Mercurial > crates > nonstick
comparison src/handle.rs @ 70:9f8381a1c09c
Implement low-level conversation primitives.
This change does two primary things:
1. Introduces new Conversation traits, to be implemented both
by the library and by PAM client applications.
2. Builds the memory-management infrastructure for passing messages
through the conversation.
...and it adds tests for both of the above, including ASAN tests.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Tue, 03 Jun 2025 01:21:59 -0400 |
| parents | 8f3ae0c7ab92 |
| children | 58f9d2a4df38 |
comparison
equal
deleted
inserted
replaced
| 69:8f3ae0c7ab92 | 70:9f8381a1c09c |
|---|---|
| 20 /// | 20 /// |
| 21 /// # Example | 21 /// # Example |
| 22 /// | 22 /// |
| 23 /// ```no_run | 23 /// ```no_run |
| 24 /// # use nonstick::PamHandle; | 24 /// # use nonstick::PamHandle; |
| 25 /// # fn _doc(handle: &impl PamHandle) -> Result<(), Box<dyn std::error::Error>> { | 25 /// # fn _doc(handle: &mut impl PamHandle) -> Result<(), Box<dyn std::error::Error>> { |
| 26 /// // Get the username using the default prompt. | 26 /// // Get the username using the default prompt. |
| 27 /// let user = handle.get_user(None)?; | 27 /// let user = handle.get_user(None)?; |
| 28 /// // Get the username using a custom prompt. | 28 /// // Get the username using a custom prompt. |
| 29 /// let user = handle.get_user(Some("who ARE you even???"))?; | 29 /// let user = handle.get_user(Some("who ARE you even???"))?; |
| 30 /// # Ok(()) | 30 /// # Ok(()) |
| 31 /// # } | 31 /// # } |
| 32 /// ``` | 32 /// ``` |
| 33 /// | 33 /// |
| 34 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_user.3.html | 34 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_user.3.html |
| 35 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_user | 35 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_user |
| 36 fn get_user(&self, prompt: Option<&str>) -> Result<String>; | 36 fn get_user(&mut self, prompt: Option<&str>) -> Result<String>; |
| 37 | 37 |
| 38 /// Retrieves the authentication token from the user. | 38 /// Retrieves the authentication token from the user. |
| 39 /// | 39 /// |
| 40 /// This is essentially like `handle.get_item::<Item::AuthTok>()`. | 40 /// This is essentially like `handle.get_item::<Item::AuthTok>()`. |
| 41 /// | 41 /// |
| 44 /// | 44 /// |
| 45 /// # Example | 45 /// # Example |
| 46 /// | 46 /// |
| 47 /// ```no_run | 47 /// ```no_run |
| 48 /// # use nonstick::PamHandle; | 48 /// # use nonstick::PamHandle; |
| 49 /// # fn _doc(handle: &impl PamHandle) -> Result<(), Box<dyn std::error::Error>> { | 49 /// # fn _doc(handle: &mut impl PamHandle) -> Result<(), Box<dyn std::error::Error>> { |
| 50 /// // Get the user's password using the default prompt. | 50 /// // Get the user's password using the default prompt. |
| 51 /// let pass = handle.get_authtok(None)?; | 51 /// let pass = handle.get_authtok(None)?; |
| 52 /// // Get the user's password using a custom prompt. | 52 /// // Get the user's password using a custom prompt. |
| 53 /// let pass = handle.get_authtok(Some("Reveal your secrets!"))?; | 53 /// let pass = handle.get_authtok(Some("Reveal your secrets!"))?; |
| 54 /// Ok(()) | 54 /// Ok(()) |
| 55 /// # } | 55 /// # } |
| 56 /// ``` | 56 /// ``` |
| 57 /// | 57 /// |
| 58 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_authtok.3.html | 58 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_authtok.3.html |
| 59 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_item | 59 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_item |
| 60 fn get_authtok(&self, prompt: Option<&str>) -> Result<SecureString>; | 60 fn get_authtok(&mut self, prompt: Option<&str>) -> Result<SecureString>; |
| 61 | 61 |
| 62 /// Retrieves an [Item] that has been set, possibly by the PAM client. | 62 /// Retrieves an [Item] that has been set, possibly by the PAM client. |
| 63 /// | 63 /// |
| 64 /// These items are *references to PAM memory* | 64 /// These items are *references to PAM memory* |
| 65 /// which are *owned by the PAM session* | 65 /// which are *owned by the PAM session* |
| 72 /// | 72 /// |
| 73 /// ```no_run | 73 /// ```no_run |
| 74 /// # use nonstick::PamHandle; | 74 /// # use nonstick::PamHandle; |
| 75 /// use nonstick::items::Service; | 75 /// use nonstick::items::Service; |
| 76 /// | 76 /// |
| 77 /// # fn _doc(pam_handle: &impl PamHandle) -> Result<(), Box<dyn std::error::Error>> { | 77 /// # fn _doc(pam_handle: &mut impl PamHandle) -> Result<(), Box<dyn std::error::Error>> { |
| 78 /// let svc: Option<Service> = pam_handle.get_item()?; | 78 /// let svc: Option<Service> = pam_handle.get_item()?; |
| 79 /// match svc { | 79 /// match svc { |
| 80 /// Some(name) => eprintln!("The calling service name is {:?}", name.to_string_lossy()), | 80 /// Some(name) => eprintln!("The calling service name is {:?}", name.to_string_lossy()), |
| 81 /// None => eprintln!("Who knows what the calling service is?"), | 81 /// None => eprintln!("Who knows what the calling service is?"), |
| 82 /// } | 82 /// } |
| 84 /// # } | 84 /// # } |
| 85 /// ``` | 85 /// ``` |
| 86 /// | 86 /// |
| 87 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_item.3.html | 87 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_item.3.html |
| 88 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_item | 88 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_item |
| 89 fn get_item<T: Item>(&self) -> Result<Option<T>>; | 89 fn get_item<T: Item>(&mut self) -> Result<Option<T>>; |
| 90 | 90 |
| 91 /// Sets an item in the PAM context. It can be retrieved using [`get_item`](Self::get_item). | 91 /// Sets an item in the PAM context. It can be retrieved using [`get_item`](Self::get_item). |
| 92 /// | 92 /// |
| 93 /// See the [`pam_set_item` manual page][man] | 93 /// See the [`pam_set_item` manual page][man] |
| 94 /// or [`pam_set_item` in the Module Writer's Guide][mwg]. | 94 /// or [`pam_set_item` in the Module Writer's Guide][mwg]. |
| 152 /// otherwise you'll get back a completely invalid `&T` | 152 /// otherwise you'll get back a completely invalid `&T` |
| 153 /// and further behavior is undefined. | 153 /// and further behavior is undefined. |
| 154 /// | 154 /// |
| 155 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_data.3.html | 155 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_data.3.html |
| 156 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_data | 156 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_data |
| 157 unsafe fn get_data<T>(&self, key: &str) -> Result<Option<&T>>; | 157 unsafe fn get_data<T>(&mut self, key: &str) -> Result<Option<&T>>; |
| 158 | 158 |
| 159 /// Stores a pointer that can be retrieved later with [`get_data`](Self::get_data). | 159 /// Stores a pointer that can be retrieved later with [`get_data`](Self::get_data). |
| 160 /// | 160 /// |
| 161 /// This data is accessible to this module and other PAM modules | 161 /// This data is accessible to this module and other PAM modules |
| 162 /// (using the provided `key`), but is *not* accessible to the application. | 162 /// (using the provided `key`), but is *not* accessible to the application. |
| 199 } | 199 } |
| 200 } | 200 } |
| 201 } | 201 } |
| 202 | 202 |
| 203 impl PamHandle for LibPamHandle { | 203 impl PamHandle for LibPamHandle { |
| 204 fn get_user(&self, prompt: Option<&str>) -> crate::Result<String> { | 204 fn get_user(&mut self, prompt: Option<&str>) -> crate::Result<String> { |
| 205 let prompt = memory::option_cstr(prompt)?; | 205 let prompt = memory::option_cstr(prompt)?; |
| 206 let mut output: *const c_char = std::ptr::null_mut(); | 206 let mut output: *const c_char = std::ptr::null_mut(); |
| 207 let ret = unsafe { | 207 let ret = unsafe { |
| 208 pam_ffi::pam_get_user(&self.0, &mut output, memory::prompt_ptr(prompt.as_ref())) | 208 pam_ffi::pam_get_user(&self.0, &mut output, memory::prompt_ptr(prompt.as_ref())) |
| 209 }; | 209 }; |
| 210 ErrorCode::result_from(ret)?; | 210 ErrorCode::result_from(ret)?; |
| 211 memory::copy_pam_string(output) | 211 memory::copy_pam_string(output) |
| 212 } | 212 } |
| 213 | 213 |
| 214 fn get_authtok(&self, prompt: Option<&str>) -> crate::Result<SecureString> { | 214 fn get_authtok(&mut self, prompt: Option<&str>) -> crate::Result<SecureString> { |
| 215 let prompt = memory::option_cstr(prompt)?; | 215 let prompt = memory::option_cstr(prompt)?; |
| 216 let mut output: *const c_char = std::ptr::null_mut(); | 216 let mut output: *const c_char = std::ptr::null_mut(); |
| 217 let res = unsafe { | 217 let res = unsafe { |
| 218 pam_ffi::pam_get_authtok( | 218 pam_ffi::pam_get_authtok( |
| 219 &self.0, | 219 &self.0, |
| 224 }; | 224 }; |
| 225 ErrorCode::result_from(res)?; | 225 ErrorCode::result_from(res)?; |
| 226 memory::copy_pam_string(output).map(SecureString::from) | 226 memory::copy_pam_string(output).map(SecureString::from) |
| 227 } | 227 } |
| 228 | 228 |
| 229 fn get_item<T: Item>(&self) -> crate::Result<Option<T>> { | 229 fn get_item<T: Item>(&mut self) -> crate::Result<Option<T>> { |
| 230 let mut ptr: *const libc::c_void = std::ptr::null(); | 230 let mut ptr: *const libc::c_void = std::ptr::null(); |
| 231 let out = unsafe { | 231 let out = unsafe { |
| 232 let ret = pam_ffi::pam_get_item(&self.0, T::type_id().into(), &mut ptr); | 232 let ret = pam_ffi::pam_get_item(&self.0, T::type_id().into(), &mut ptr); |
| 233 ErrorCode::result_from(ret)?; | 233 ErrorCode::result_from(ret)?; |
| 234 let typed_ptr: *const T::Raw = ptr.cast(); | 234 let typed_ptr: *const T::Raw = ptr.cast(); |
| 257 ErrorCode::result_from(result) | 257 ErrorCode::result_from(result) |
| 258 } | 258 } |
| 259 } | 259 } |
| 260 | 260 |
| 261 impl PamModuleHandle for LibPamHandle { | 261 impl PamModuleHandle for LibPamHandle { |
| 262 unsafe fn get_data<T>(&self, key: &str) -> crate::Result<Option<&T>> { | 262 unsafe fn get_data<T>(&mut self, key: &str) -> crate::Result<Option<&T>> { |
| 263 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; | 263 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; |
| 264 let mut ptr: *const libc::c_void = std::ptr::null(); | 264 let mut ptr: *const libc::c_void = std::ptr::null(); |
| 265 ErrorCode::result_from(pam_ffi::pam_get_data(&self.0, c_key.as_ptr(), &mut ptr))?; | 265 ErrorCode::result_from(pam_ffi::pam_get_data(&self.0, c_key.as_ptr(), &mut ptr))?; |
| 266 match ptr.is_null() { | 266 match ptr.is_null() { |
| 267 true => Ok(None), | 267 true => Ok(None), |
