diff libpam-sys/src/structs.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 libpam-sys/src/helpers.rs@49d9e2b5c189
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpam-sys/src/structs.rs	Sat Jun 28 02:49:35 2025 -0400
@@ -0,0 +1,63 @@
+use core::marker::{PhantomData, PhantomPinned};
+use core::slice;
+
+/// The structure of the "binary message" payload for the `PAM_BINARY_PROMPT`
+/// extension from Linux-PAM.
+pub struct BinaryPayload {
+    /// The total byte size of the message, including this header,
+    /// as a u32 in network byte order (big endian).
+    pub total_bytes_u32be: [u8; 4],
+    /// A tag used to provide some kind of hint as to what the data is.
+    /// Its meaning is undefined.
+    pub data_type: u8,
+    /// Where the data itself would start, used as a marker to make this
+    /// not [`Unpin`] (since it is effectively an intrusive data structure
+    /// pointing to immediately after itself).
+    pub _marker: PhantomData<PhantomPinned>,
+}
+
+impl BinaryPayload {
+    /// The most data it's possible to put into a [`BinaryPayload`].
+    pub const MAX_SIZE: usize = (u32::MAX - 5) as usize;
+
+    /// Fills in the provided buffer with the given data.
+    ///
+    /// This uses [`copy_from_slice`](slice::copy_from_slice) internally,
+    /// so `buf` must be exactly 5 bytes longer than `data`, or this function
+    /// will panic.
+    pub fn fill(buf: &mut [u8], data_type: u8, data: &[u8]) {
+        let ptr: *mut Self = buf.as_mut_ptr().cast();
+        // SAFETY: We're given a slice, which always has a nonzero pointer.
+        let me = unsafe { ptr.as_mut().unwrap_unchecked() };
+        me.total_bytes_u32be = u32::to_be_bytes(buf.len() as u32);
+        me.data_type = data_type;
+        buf[5..].copy_from_slice(data)
+    }
+
+    /// The size of the message contained in the buffer.
+    fn len(&self) -> usize {
+        self.total_bytes().saturating_sub(5)
+    }
+
+    /// The total storage needed for the message, including header.
+    pub fn total_bytes(&self) -> usize {
+        u32::from_be_bytes(self.total_bytes_u32be) as usize
+    }
+
+    /// Gets the contents of the BinaryMessage stored at the given pointer.
+    ///
+    /// The returned data slice is borrowed from where the pointer points to.
+    ///
+    /// # Safety
+    ///
+    /// - The pointer must point to a valid `BinaryPayload`.
+    /// - The borrowed data must not outlive the validity of this pointer.
+    pub unsafe fn contents<'a>(ptr: *const Self) -> (u8, &'a [u8]) {
+        let header: &Self = ptr.as_ref().unwrap_unchecked();
+        let typ = header.data_type;
+        (
+            typ,
+            slice::from_raw_parts(ptr.cast::<u8>().offset(5), header.len()),
+        )
+    }
+}