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), |