Mercurial > crates > nonstick
diff src/libpam/handle.rs @ 101:94b51fa4f797
Fix memory soundness issues:
- Ensure Questions are pinned in memory when sending them through PAM.
- Hold on to the PAM conversation struct after we build it.
(Linux-PAM is leninent about this and copies the pam_conv structure.)
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Tue, 24 Jun 2025 17:54:33 -0400 |
parents | b87100c5eed4 |
children | 94eb11cb1798 |
line wrap: on
line diff
--- a/src/libpam/handle.rs Tue Jun 24 17:08:01 2025 -0400 +++ b/src/libpam/handle.rs Tue Jun 24 17:54:33 2025 -0400 @@ -11,7 +11,6 @@ use num_enum::{IntoPrimitive, TryFromPrimitive}; use std::cell::Cell; use std::ffi::{c_char, c_int, CString}; -use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::ptr; @@ -33,9 +32,12 @@ /// An owned PAM handle. pub struct OwnedLibPamHandle<'a> { + /// The handle itself. handle: HandleWrap, + /// The last return value from the handle. last_return: Cell<Result<()>>, - _conversation_lifetime: PhantomData<&'a mut ()>, + /// If set, the Conversation that this PAM handle owns. + conversation: Option<Box<LibPamConversation<'a>>>, } #[derive(Debug, PartialEq)] @@ -77,20 +79,26 @@ username: Option<String>, conversation: &impl Conversation, ) -> Result<Self> { - let conv = LibPamConversation::wrap(conversation); + let conv = Box::new(LibPamConversation::wrap(conversation)); let service_cstr = CString::new(service_name).map_err(|_| ErrorCode::ConversationError)?; let username_cstr = memory::prompt_ptr(memory::option_cstr(username.as_deref())?.as_ref()); let mut handle: *mut LibPamHandle = ptr::null_mut(); // SAFETY: We've set everything up properly to call `pam_start`. // The returned value will be a valid pointer provided the result is OK. - let result = - unsafe { pam_ffi::pam_start(service_cstr.as_ptr(), username_cstr, &conv, &mut handle) }; + let result = unsafe { + pam_ffi::pam_start( + service_cstr.as_ptr(), + username_cstr, + conv.as_ref(), + &mut handle, + ) + }; ErrorCode::result_from(result)?; Ok(Self { handle: HandleWrap(handle), last_return: Cell::new(Ok(())), - _conversation_lifetime: Default::default(), + conversation: Some(conv), }) } }