Mercurial > crates > nonstick
comparison src/libpam/memory.rs @ 77:351bdc13005e
Update the libpam module to work with the new structure.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Sun, 08 Jun 2025 01:03:46 -0400 |
| parents | c30811b4afae |
| children | 002adfb98c5c |
comparison
equal
deleted
inserted
replaced
| 76:e58d24849e82 | 77:351bdc13005e |
|---|---|
| 1 //! Things for dealing with memory. | 1 //! Things for dealing with memory. |
| 2 | 2 |
| 3 use crate::ErrorCode; | 3 use crate::conv::BorrowedBinaryData; |
| 4 use crate::Result; | 4 use crate::Result; |
| 5 use crate::{BinaryData, ErrorCode}; | |
| 5 use std::ffi::{c_char, c_void, CStr, CString}; | 6 use std::ffi::{c_char, c_void, CStr, CString}; |
| 6 use std::marker::{PhantomData, PhantomPinned}; | 7 use std::marker::{PhantomData, PhantomPinned}; |
| 7 use std::result::Result as StdResult; | |
| 8 use std::{ptr, slice}; | 8 use std::{ptr, slice}; |
| 9 | 9 |
| 10 /// Makes whatever it's in not [`Send`], [`Sync`], or [`Unpin`]. | 10 /// Makes whatever it's in not [`Send`], [`Sync`], or [`Unpin`]. |
| 11 #[repr(C)] | 11 #[repr(C)] |
| 12 #[derive(Debug)] | 12 #[derive(Debug)] |
| 64 /// | 64 /// |
| 65 /// This is like [`CString::new`](std::ffi::CString::new), but: | 65 /// This is like [`CString::new`](std::ffi::CString::new), but: |
| 66 /// | 66 /// |
| 67 /// - it allocates data on the C heap with [`libc::malloc`]. | 67 /// - it allocates data on the C heap with [`libc::malloc`]. |
| 68 /// - it doesn't take ownership of the data passed in. | 68 /// - it doesn't take ownership of the data passed in. |
| 69 pub fn malloc_str(text: impl AsRef<str>) -> StdResult<*mut c_char, NulError> { | 69 pub fn malloc_str(text: &str) -> Result<*mut c_char> { |
| 70 let data = text.as_ref().as_bytes(); | 70 let data = text.as_bytes(); |
| 71 if let Some(nul) = data.iter().position(|x| *x == 0) { | 71 if data.contains(&0) { |
| 72 return Err(NulError(nul)); | 72 return Err(ErrorCode::ConversationError); |
| 73 } | 73 } |
| 74 unsafe { | 74 unsafe { |
| 75 let data_alloc = libc::calloc(data.len() + 1, 1); | 75 let data_alloc = libc::calloc(data.len() + 1, 1); |
| 76 libc::memcpy(data_alloc, data.as_ptr().cast(), data.len()); | 76 libc::memcpy(data_alloc, data.as_ptr().cast(), data.len()); |
| 77 Ok(data_alloc.cast()) | 77 Ok(data_alloc.cast()) |
| 108 _marker: Immovable, | 108 _marker: Immovable, |
| 109 } | 109 } |
| 110 | 110 |
| 111 impl CBinaryData { | 111 impl CBinaryData { |
| 112 /// Copies the given data to a new BinaryData on the heap. | 112 /// Copies the given data to a new BinaryData on the heap. |
| 113 pub fn alloc(source: &[u8], data_type: u8) -> StdResult<*mut CBinaryData, TooBigError> { | 113 pub fn alloc(source: &[u8], data_type: u8) -> Result<*mut CBinaryData> { |
| 114 let buffer_size = u32::try_from(source.len() + 5).map_err(|_| TooBigError { | 114 let buffer_size = |
| 115 max: (u32::MAX - 5) as usize, | 115 u32::try_from(source.len() + 5).map_err(|_| ErrorCode::ConversationError)?; |
| 116 actual: source.len(), | |
| 117 })?; | |
| 118 // SAFETY: We're only allocating here. | 116 // SAFETY: We're only allocating here. |
| 119 let data = unsafe { | 117 let data = unsafe { |
| 120 let dest_buffer: *mut CBinaryData = libc::malloc(buffer_size as usize).cast(); | 118 let dest_buffer: *mut CBinaryData = libc::malloc(buffer_size as usize).cast(); |
| 121 let data = &mut *dest_buffer; | 119 let data = &mut *dest_buffer; |
| 122 data.total_length = buffer_size.to_be_bytes(); | 120 data.total_length = buffer_size.to_be_bytes(); |
| 130 | 128 |
| 131 fn length(&self) -> usize { | 129 fn length(&self) -> usize { |
| 132 u32::from_be_bytes(self.total_length).saturating_sub(5) as usize | 130 u32::from_be_bytes(self.total_length).saturating_sub(5) as usize |
| 133 } | 131 } |
| 134 | 132 |
| 135 pub fn contents(&self) -> &[u8] { | |
| 136 unsafe { slice::from_raw_parts(self.data.as_ptr(), self.length()) } | |
| 137 } | |
| 138 pub fn data_type(&self) -> u8 { | |
| 139 self.data_type | |
| 140 } | |
| 141 | |
| 142 /// Clears this data and frees it. | 133 /// Clears this data and frees it. |
| 143 pub unsafe fn zero_contents(&mut self) { | 134 pub unsafe fn zero_contents(&mut self) { |
| 144 let contents = slice::from_raw_parts_mut(self.data.as_mut_ptr(), self.length()); | 135 let contents = slice::from_raw_parts_mut(self.data.as_mut_ptr(), self.length()); |
| 145 for v in contents { | 136 for v in contents { |
| 146 *v = 0 | 137 *v = 0 |
| 148 self.data_type = 0; | 139 self.data_type = 0; |
| 149 self.total_length = [0; 4]; | 140 self.total_length = [0; 4]; |
| 150 } | 141 } |
| 151 } | 142 } |
| 152 | 143 |
| 153 #[derive(Debug, thiserror::Error)] | 144 impl<'a> From<&'a CBinaryData> for BorrowedBinaryData<'a> { |
| 154 #[error("null byte within input at byte {0}")] | 145 fn from(value: &'a CBinaryData) -> Self { |
| 155 pub struct NulError(pub usize); | 146 BorrowedBinaryData::new( |
| 147 unsafe { slice::from_raw_parts(value.data.as_ptr(), value.length()) }, | |
| 148 value.data_type, | |
| 149 ) | |
| 150 } | |
| 151 } | |
| 156 | 152 |
| 157 /// Returned when trying to fit too much data into a binary message. | 153 impl From<Option<&'_ CBinaryData>> for BinaryData { |
| 158 #[derive(Debug, thiserror::Error)] | 154 fn from(value: Option<&CBinaryData>) -> Self { |
| 159 #[error("cannot create a message of {actual} bytes; maximum is {max}")] | 155 value.map(BorrowedBinaryData::from).map(Into::into).unwrap_or_default() |
| 160 pub struct TooBigError { | 156 } |
| 161 pub actual: usize, | |
| 162 pub max: usize, | |
| 163 } | 157 } |
| 164 | 158 |
| 165 #[cfg(test)] | 159 #[cfg(test)] |
| 166 mod tests { | 160 mod tests { |
| 167 use super::{copy_pam_string, malloc_str, option_cstr, prompt_ptr, zero_c_string}; | 161 use super::{copy_pam_string, malloc_str, option_cstr, prompt_ptr, zero_c_string}; |
