comparison src/handle.rs @ 71:58f9d2a4df38

Reorganize everything again??? - Splits ffi/memory stuff into a bunch of stuff in the pam_ffi module. - Builds infrastructure for passing Messages and Responses. - Adds tests for some things at least.
author Paul Fisher <paul@pfish.zone>
date Tue, 03 Jun 2025 21:54:58 -0400
parents 9f8381a1c09c
children 47eb242a4f88
comparison
equal deleted inserted replaced
70:9f8381a1c09c 71:58f9d2a4df38
1 //! The wrapper types and traits for handles into the PAM library. 1 //! The wrapper types and traits for handles into the PAM library.
2 use crate::constants::{ErrorCode, Result}; 2 use crate::constants::{ErrorCode, Result};
3 use crate::items::{Item, ItemType}; 3 use crate::items::{Item, ItemType};
4 use crate::{memory, pam_ffi}; 4 use crate::pam_ffi;
5 use libc::c_char; 5 use crate::pam_ffi::memory;
6 use secure_string::SecureString; 6 use secure_string::SecureString;
7 use std::ffi::{c_int, CString}; 7 use std::ffi::{c_char, c_int, c_void, CString};
8 use std::mem; 8 use std::{mem, ptr};
9 9
10 /// Features of a PAM handle that are available to applications and modules. 10 /// Features of a PAM handle that are available to applications and modules.
11 /// 11 ///
12 /// You probably want [`LibPamHandle`]. This trait is intended to allow creating 12 /// You probably want [`LibPamHandle`]. This trait is intended to allow creating
13 /// mock PAM handle types used for testing PAM modules and applications. 13 /// mock PAM handle types used for testing PAM modules and applications.
175 /// 175 ///
176 /// This structure wraps an opaque PAM handle and gives you a nice Rusty 176 /// This structure wraps an opaque PAM handle and gives you a nice Rusty
177 /// interface to use PAM. 177 /// interface to use PAM.
178 #[repr(C)] 178 #[repr(C)]
179 pub struct LibPamHandle(pam_ffi::Handle); 179 pub struct LibPamHandle(pam_ffi::Handle);
180
181 impl LibPamHandle {
182 /// Converts a pointer passed from PAM into a borrowed handle.
183 ///
184 /// # Safety
185 ///
186 /// It is your responsibility to provide a valid pointer.
187 pub unsafe fn from_ptr<'a>(ptr: *mut libc::c_void) -> &'a mut LibPamHandle {
188 &mut *(ptr as *mut LibPamHandle)
189 }
190 }
191 180
192 impl Drop for LibPamHandle { 181 impl Drop for LibPamHandle {
193 /// Ends the PAM session with a zero error code. 182 /// Ends the PAM session with a zero error code.
194 /// You probably want to call [`close`](Self::close) instead of 183 /// You probably want to call [`close`](Self::close) instead of
195 /// letting this drop by itself. 184 /// letting this drop by itself.
201 } 190 }
202 191
203 impl PamHandle for LibPamHandle { 192 impl PamHandle for LibPamHandle {
204 fn get_user(&mut self, prompt: Option<&str>) -> crate::Result<String> { 193 fn get_user(&mut self, prompt: Option<&str>) -> crate::Result<String> {
205 let prompt = memory::option_cstr(prompt)?; 194 let prompt = memory::option_cstr(prompt)?;
206 let mut output: *const c_char = std::ptr::null_mut(); 195 let mut output: *const c_char = ptr::null_mut();
207 let ret = unsafe { 196 let ret = unsafe {
208 pam_ffi::pam_get_user(&self.0, &mut output, memory::prompt_ptr(prompt.as_ref())) 197 pam_ffi::pam_get_user(&self.0, &mut output, memory::prompt_ptr(prompt.as_ref()))
209 }; 198 };
210 ErrorCode::result_from(ret)?; 199 ErrorCode::result_from(ret)?;
211 memory::copy_pam_string(output) 200 unsafe {memory::copy_pam_string(output)}
212 } 201 }
213 202
214 fn get_authtok(&mut self, prompt: Option<&str>) -> crate::Result<SecureString> { 203 fn get_authtok(&mut self, prompt: Option<&str>) -> crate::Result<SecureString> {
215 let prompt = memory::option_cstr(prompt)?; 204 let prompt = memory::option_cstr(prompt)?;
216 let mut output: *const c_char = std::ptr::null_mut(); 205 let mut output: *const c_char = ptr::null_mut();
217 let res = unsafe { 206 let res = unsafe {
218 pam_ffi::pam_get_authtok( 207 pam_ffi::pam_get_authtok(
219 &self.0, 208 &self.0,
220 ItemType::AuthTok.into(), 209 ItemType::AuthTok.into(),
221 &mut output, 210 &mut output,
222 memory::prompt_ptr(prompt.as_ref()), 211 memory::prompt_ptr(prompt.as_ref()),
223 ) 212 )
224 }; 213 };
225 ErrorCode::result_from(res)?; 214 ErrorCode::result_from(res)?;
226 memory::copy_pam_string(output).map(SecureString::from) 215 unsafe {memory::copy_pam_string(output)}.map(SecureString::from)
227 } 216 }
228 217
229 fn get_item<T: Item>(&mut self) -> crate::Result<Option<T>> { 218 fn get_item<T: Item>(&mut self) -> Result<Option<T>> {
230 let mut ptr: *const libc::c_void = std::ptr::null(); 219 let mut ptr: *const c_void = ptr::null();
231 let out = unsafe { 220 let out = unsafe {
232 let ret = pam_ffi::pam_get_item(&self.0, T::type_id().into(), &mut ptr); 221 let ret = pam_ffi::pam_get_item(&self.0, T::type_id().into(), &mut ptr);
233 ErrorCode::result_from(ret)?; 222 ErrorCode::result_from(ret)?;
234 let typed_ptr: *const T::Raw = ptr.cast(); 223 (ptr as *const T::Raw).as_ref().map(|p| T::from_raw(p))
235 match typed_ptr.is_null() {
236 true => None,
237 false => Some(T::from_raw(typed_ptr)),
238 }
239 }; 224 };
240 Ok(out) 225 Ok(out)
241 } 226 }
242 227
243 fn set_item<T: Item>(&mut self, item: T) -> crate::Result<()> { 228 fn set_item<T: Item>(&mut self, item: T) -> Result<()> {
244 let ret = unsafe { 229 let ret = unsafe {
245 pam_ffi::pam_set_item(&mut self.0, T::type_id().into(), item.into_raw().cast()) 230 pam_ffi::pam_set_item(&mut self.0, T::type_id().into(), item.into_raw().cast())
246 }; 231 };
247 ErrorCode::result_from(ret) 232 ErrorCode::result_from(ret)
248 } 233 }
259 } 244 }
260 245
261 impl PamModuleHandle for LibPamHandle { 246 impl PamModuleHandle for LibPamHandle {
262 unsafe fn get_data<T>(&mut self, key: &str) -> crate::Result<Option<&T>> { 247 unsafe fn get_data<T>(&mut self, key: &str) -> crate::Result<Option<&T>> {
263 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; 248 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?;
264 let mut ptr: *const libc::c_void = std::ptr::null(); 249 let mut ptr: *const c_void = ptr::null();
265 ErrorCode::result_from(pam_ffi::pam_get_data(&self.0, c_key.as_ptr(), &mut ptr))?; 250 ErrorCode::result_from(pam_ffi::pam_get_data(&self.0, c_key.as_ptr(), &mut ptr))?;
266 match ptr.is_null() { 251 Ok((ptr as *const T).as_ref())
267 true => Ok(None),
268 false => {
269 let typed_ptr = ptr.cast();
270 Ok(Some(&*typed_ptr))
271 }
272 }
273 } 252 }
274 253
275 fn set_data<T>(&mut self, key: &str, data: Box<T>) -> crate::Result<()> { 254 fn set_data<T>(&mut self, key: &str, data: Box<T>) -> crate::Result<()> {
276 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; 255 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?;
277 let ret = unsafe { 256 let ret = unsafe {