Mercurial > crates > nonstick
comparison libpam-sys/src/helpers.rs @ 109:bb465393621f
Minor cleanup and reorg.
- Use those nice new macros we just implemented.
- Straighten out the macro file.
- Move the `BinaryPayload` into `structs.rs`, leaving helpers behind.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Sat, 28 Jun 2025 02:49:35 -0400 |
| parents | 49d9e2b5c189 |
| children | 2346fd501b7a |
comparison
equal
deleted
inserted
replaced
| 108:e97534be35e3 | 109:bb465393621f |
|---|---|
| 1 //! This module contains a few non-required helpers to deal with some of the | 1 //! This module contains a few non-required helpers to deal with some of the |
| 2 //! more annoying memory-twiddling in the PAM API. | 2 //! more annoying memory management in the PAM API. |
| 3 //! | 3 use crate::structs::BinaryPayload; |
| 4 //! Using these is optional but you might find it useful. | 4 use std::fmt; |
| 5 use std::ptr::NonNull; | |
| 5 use std::error::Error; | 6 use std::error::Error; |
| 6 use std::marker::{PhantomData, PhantomPinned}; | |
| 7 use std::mem::ManuallyDrop; | 7 use std::mem::ManuallyDrop; |
| 8 use std::ptr::NonNull; | |
| 9 use std::{fmt, slice}; | |
| 10 | 8 |
| 11 /// Error returned when attempting to allocate a buffer that is too big. | 9 /// Error returned when attempting to allocate a buffer that is too big. |
| 12 /// | 10 /// |
| 13 /// This is specifically used in [`OwnedBinaryPayload`] when you try to allocate | 11 /// This is specifically used in [`OwnedBinaryPayload`] when you try to allocate |
| 14 /// a message larger than 2<sup>32</sup> bytes. | 12 /// a message larger than 2<sup>32</sup> bytes. |
| 121 max: BinaryPayload::MAX_SIZE, | 119 max: BinaryPayload::MAX_SIZE, |
| 122 })?; | 120 })?; |
| 123 let total_len = total_len as usize; | 121 let total_len = total_len as usize; |
| 124 let mut buf = O::allocate(total_len); | 122 let mut buf = O::allocate(total_len); |
| 125 // SAFETY: We just allocated this exact size. | 123 // SAFETY: We just allocated this exact size. |
| 126 BinaryPayload::fill(unsafe { &mut buf.as_mut_slice(total_len) }, data_type, data); | 124 BinaryPayload::fill(unsafe { buf.as_mut_slice(total_len) }, data_type, data); |
| 127 Ok(Self(buf)) | 125 Ok(Self(buf)) |
| 128 } | 126 } |
| 129 | 127 |
| 130 /// The contents of the buffer. | 128 /// The contents of the buffer. |
| 131 pub fn contents(&self) -> (u8, &[u8]) { | 129 pub fn contents(&self) -> (u8, &[u8]) { |
| 169 /// | 167 /// |
| 170 /// You must provide a valid pointer, allocated by (or equivalent to one | 168 /// You must provide a valid pointer, allocated by (or equivalent to one |
| 171 /// allocated by) [`Self::new`]. For instance, passing a pointer allocated | 169 /// allocated by) [`Self::new`]. For instance, passing a pointer allocated |
| 172 /// by `malloc` to `OwnedBinaryPayload::<Vec<u8>>::from_ptr` is not allowed. | 170 /// by `malloc` to `OwnedBinaryPayload::<Vec<u8>>::from_ptr` is not allowed. |
| 173 pub unsafe fn from_ptr(ptr: NonNull<BinaryPayload>) -> Self { | 171 pub unsafe fn from_ptr(ptr: NonNull<BinaryPayload>) -> Self { |
| 174 Self(O::from_ptr(ptr.cast(), ptr.as_ref().total_bytes() as usize)) | 172 Self(O::from_ptr(ptr.cast(), ptr.as_ref().total_bytes())) |
| 175 } | |
| 176 } | |
| 177 | |
| 178 /// The structure of the "binary message" payload for the `PAM_BINARY_PROMPT` | |
| 179 /// extension from Linux-PAM. | |
| 180 pub struct BinaryPayload { | |
| 181 /// The total length of the message, including this header, | |
| 182 /// as a u32 in network byte order (big endian). | |
| 183 total_length: [u8; 4], | |
| 184 /// A tag used to provide some kind of hint as to what the data is. | |
| 185 /// This is not defined by PAM. | |
| 186 data_type: u8, | |
| 187 /// Where the data itself would start, used as a marker to make this | |
| 188 /// not [`Unpin`] (since it is effectively an intrusive data structure | |
| 189 /// pointing to immediately after itself). | |
| 190 _marker: PhantomData<PhantomPinned>, | |
| 191 } | |
| 192 | |
| 193 impl BinaryPayload { | |
| 194 /// The most data it's possible to put into a [`BinaryPayload`]. | |
| 195 pub const MAX_SIZE: usize = (u32::MAX - 5) as usize; | |
| 196 | |
| 197 /// Fills in the provided buffer with the given data. | |
| 198 /// | |
| 199 /// This uses [`copy_from_slice`](slice::copy_from_slice) internally, | |
| 200 /// so `buf` must be exactly 5 bytes longer than `data`, or this function | |
| 201 /// will panic. | |
| 202 pub fn fill(buf: &mut [u8], data_type: u8, data: &[u8]) { | |
| 203 let ptr: *mut Self = buf.as_mut_ptr().cast(); | |
| 204 // SAFETY: We're given a slice, which always has a nonzero pointer. | |
| 205 let me = unsafe { ptr.as_mut().unwrap_unchecked() }; | |
| 206 me.total_length = u32::to_be_bytes(buf.len() as u32); | |
| 207 me.data_type = data_type; | |
| 208 buf[5..].copy_from_slice(data) | |
| 209 } | |
| 210 | |
| 211 /// The size of the message contained in the buffer. | |
| 212 fn len(&self) -> usize { | |
| 213 self.total_bytes().saturating_sub(5) | |
| 214 } | |
| 215 | |
| 216 /// The total storage needed for the message, including header. | |
| 217 pub fn total_bytes(&self) -> usize { | |
| 218 u32::from_be_bytes(self.total_length) as usize | |
| 219 } | |
| 220 | |
| 221 /// Gets the contents of the BinaryMessage starting at the given location. | |
| 222 /// | |
| 223 /// # Safety | |
| 224 /// | |
| 225 /// You must pass in a valid pointer, and ensure that the pointer passed in | |
| 226 /// outlives your borrow lifetime `'a`. | |
| 227 unsafe fn contents<'a>(ptr: *const Self) -> (u8, &'a [u8]) { | |
| 228 let header: &Self = ptr.as_ref().unwrap_unchecked(); | |
| 229 let typ = header.data_type; | |
| 230 ( | |
| 231 typ, | |
| 232 slice::from_raw_parts(ptr.cast::<u8>().offset(5), header.len()), | |
| 233 ) | |
| 234 } | 173 } |
| 235 } | 174 } |
| 236 | 175 |
| 237 #[cfg(test)] | 176 #[cfg(test)] |
| 238 mod tests { | 177 mod tests { |
