Mercurial > crates > nonstick
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()); |
