Mercurial > crates > nonstick
comparison 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 |
comparison
equal
deleted
inserted
replaced
100:3f11b8d30f63 | 101:94b51fa4f797 |
---|---|
9 use crate::logging::Level; | 9 use crate::logging::Level; |
10 use crate::{Conversation, EnvironMap, Flags, PamHandleApplication, PamHandleModule}; | 10 use crate::{Conversation, EnvironMap, Flags, PamHandleApplication, PamHandleModule}; |
11 use num_enum::{IntoPrimitive, TryFromPrimitive}; | 11 use num_enum::{IntoPrimitive, TryFromPrimitive}; |
12 use std::cell::Cell; | 12 use std::cell::Cell; |
13 use std::ffi::{c_char, c_int, CString}; | 13 use std::ffi::{c_char, c_int, CString}; |
14 use std::marker::PhantomData; | |
15 use std::ops::{Deref, DerefMut}; | 14 use std::ops::{Deref, DerefMut}; |
16 use std::ptr; | 15 use std::ptr; |
17 | 16 |
18 /// Owner for a PAM handle. | 17 /// Owner for a PAM handle. |
19 struct HandleWrap(*mut LibPamHandle); | 18 struct HandleWrap(*mut LibPamHandle); |
31 } | 30 } |
32 } | 31 } |
33 | 32 |
34 /// An owned PAM handle. | 33 /// An owned PAM handle. |
35 pub struct OwnedLibPamHandle<'a> { | 34 pub struct OwnedLibPamHandle<'a> { |
35 /// The handle itself. | |
36 handle: HandleWrap, | 36 handle: HandleWrap, |
37 /// The last return value from the handle. | |
37 last_return: Cell<Result<()>>, | 38 last_return: Cell<Result<()>>, |
38 _conversation_lifetime: PhantomData<&'a mut ()>, | 39 /// If set, the Conversation that this PAM handle owns. |
40 conversation: Option<Box<LibPamConversation<'a>>>, | |
39 } | 41 } |
40 | 42 |
41 #[derive(Debug, PartialEq)] | 43 #[derive(Debug, PartialEq)] |
42 pub struct HandleBuilder { | 44 pub struct HandleBuilder { |
43 service_name: String, | 45 service_name: String, |
75 fn start( | 77 fn start( |
76 service_name: String, | 78 service_name: String, |
77 username: Option<String>, | 79 username: Option<String>, |
78 conversation: &impl Conversation, | 80 conversation: &impl Conversation, |
79 ) -> Result<Self> { | 81 ) -> Result<Self> { |
80 let conv = LibPamConversation::wrap(conversation); | 82 let conv = Box::new(LibPamConversation::wrap(conversation)); |
81 let service_cstr = CString::new(service_name).map_err(|_| ErrorCode::ConversationError)?; | 83 let service_cstr = CString::new(service_name).map_err(|_| ErrorCode::ConversationError)?; |
82 let username_cstr = memory::prompt_ptr(memory::option_cstr(username.as_deref())?.as_ref()); | 84 let username_cstr = memory::prompt_ptr(memory::option_cstr(username.as_deref())?.as_ref()); |
83 | 85 |
84 let mut handle: *mut LibPamHandle = ptr::null_mut(); | 86 let mut handle: *mut LibPamHandle = ptr::null_mut(); |
85 // SAFETY: We've set everything up properly to call `pam_start`. | 87 // SAFETY: We've set everything up properly to call `pam_start`. |
86 // The returned value will be a valid pointer provided the result is OK. | 88 // The returned value will be a valid pointer provided the result is OK. |
87 let result = | 89 let result = unsafe { |
88 unsafe { pam_ffi::pam_start(service_cstr.as_ptr(), username_cstr, &conv, &mut handle) }; | 90 pam_ffi::pam_start( |
91 service_cstr.as_ptr(), | |
92 username_cstr, | |
93 conv.as_ref(), | |
94 &mut handle, | |
95 ) | |
96 }; | |
89 ErrorCode::result_from(result)?; | 97 ErrorCode::result_from(result)?; |
90 Ok(Self { | 98 Ok(Self { |
91 handle: HandleWrap(handle), | 99 handle: HandleWrap(handle), |
92 last_return: Cell::new(Ok(())), | 100 last_return: Cell::new(Ok(())), |
93 _conversation_lifetime: Default::default(), | 101 conversation: Some(conv), |
94 }) | 102 }) |
95 } | 103 } |
96 } | 104 } |
97 | 105 |
98 impl PamHandleApplication for OwnedLibPamHandle<'_> { | 106 impl PamHandleApplication for OwnedLibPamHandle<'_> { |