comparison src/pam_ffi/memory.rs @ 72:47eb242a4f88

Fill out the PamHandle trait. This updates the PamHandle trait to have methods for each Item, and implements them on the LibPamHandle.
author Paul Fisher <paul@pfish.zone>
date Wed, 04 Jun 2025 03:53:36 -0400
parents 58f9d2a4df38
children ac6881304c78
comparison
equal deleted inserted replaced
71:58f9d2a4df38 72:47eb242a4f88
26 } 26 }
27 } 27 }
28 28
29 /// Creates an owned copy of a string that is returned from a 29 /// Creates an owned copy of a string that is returned from a
30 /// <code>pam_get_<var>whatever</var></code> function. 30 /// <code>pam_get_<var>whatever</var></code> function.
31 ///
32 /// # Safety
33 ///
34 /// It's on you to provide a valid string.
31 pub unsafe fn copy_pam_string(result_ptr: *const libc::c_char) -> Result<String> { 35 pub unsafe fn copy_pam_string(result_ptr: *const libc::c_char) -> Result<String> {
32 // We really shouldn't get a null pointer back here, but if we do, return nothing. 36 // We really shouldn't get a null pointer back here, but if we do, return nothing.
33 if result_ptr.is_null() { 37 if result_ptr.is_null() {
34 return Ok(String::new()); 38 return Ok(String::new());
35 } 39 }
36 let bytes = unsafe { CStr::from_ptr(result_ptr) }; 40 let bytes = unsafe { CStr::from_ptr(result_ptr) };
37 bytes 41 bytes
38 .to_str() 42 .to_str()
39 .map(String::from) 43 .map(String::from)
40 .map_err(|_| ErrorCode::ConversationError) 44 .map_err(|_| ErrorCode::ConversationError)
45 }
46
47 /// Wraps a string returned from PAM as an `Option<&str>`.
48 pub unsafe fn wrap_string<'a>(data: *const libc::c_char) -> Result<Option<&'a str>> {
49 let ret = if data.is_null() {
50 None
51 } else {
52 Some(
53 CStr::from_ptr(data)
54 .to_str()
55 .map_err(|_| ErrorCode::ConversationError)?,
56 )
57 };
58 Ok(ret)
41 } 59 }
42 60
43 /// Allocates a string with the given contents on the C heap. 61 /// Allocates a string with the given contents on the C heap.
44 /// 62 ///
45 /// This is like [`CString::new`](std::ffi::CString::new), but: 63 /// This is like [`CString::new`](std::ffi::CString::new), but:
145 pub max: usize, 163 pub max: usize,
146 } 164 }
147 165
148 #[cfg(test)] 166 #[cfg(test)]
149 mod tests { 167 mod tests {
168 use super::{copy_pam_string, malloc_str, option_cstr, prompt_ptr, zero_c_string};
169 use crate::ErrorCode;
150 use std::ffi::CString; 170 use std::ffi::CString;
151 use crate::ErrorCode;
152 use super::{copy_pam_string, malloc_str, option_cstr, prompt_ptr, zero_c_string};
153 #[test] 171 #[test]
154 fn test_strings() { 172 fn test_strings() {
155 let str = malloc_str("hello there").unwrap(); 173 let str = malloc_str("hello there").unwrap();
156 malloc_str("hell\0 there").unwrap_err(); 174 malloc_str("hell\0 there").unwrap_err();
157 unsafe { 175 unsafe {
163 let zeroed = copy_pam_string(str.cast()).unwrap(); 181 let zeroed = copy_pam_string(str.cast()).unwrap();
164 assert!(zeroed.is_empty()); 182 assert!(zeroed.is_empty());
165 libc::free(str.cast()); 183 libc::free(str.cast());
166 } 184 }
167 } 185 }
168 186
169 #[test] 187 #[test]
170 fn test_option_str() { 188 fn test_option_str() {
171 let good = option_cstr(Some("whatever")).unwrap(); 189 let good = option_cstr(Some("whatever")).unwrap();
172 assert_eq!("whatever", good.unwrap().to_str().unwrap()); 190 assert_eq!("whatever", good.unwrap().to_str().unwrap());
173 let no_str = option_cstr(None).unwrap(); 191 let no_str = option_cstr(None).unwrap();
174 assert!(no_str.is_none()); 192 assert!(no_str.is_none());
175 let bad_str = option_cstr(Some("what\0ever")).unwrap_err(); 193 let bad_str = option_cstr(Some("what\0ever")).unwrap_err();
176 assert_eq!(ErrorCode::ConversationError, bad_str); 194 assert_eq!(ErrorCode::ConversationError, bad_str);
177 } 195 }
178 196
179 #[test] 197 #[test]
180 fn test_prompt() { 198 fn test_prompt() {
181 let prompt_cstr = CString::new("good").ok(); 199 let prompt_cstr = CString::new("good").ok();
182 let prompt = prompt_ptr(prompt_cstr.as_ref()); 200 let prompt = prompt_ptr(prompt_cstr.as_ref());
183 assert!(!prompt.is_null()); 201 assert!(!prompt.is_null());