Mercurial > crates > nonstick
diff libpam-sys/src/helpers.rs @ 118:39760dfc9b3b
Detect PAM library based only on system lib; rename minimal lib to XSso.
Also formats and assorted other cleanup.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sun, 29 Jun 2025 20:13:03 -0400 |
parents | 20f7712a6857 |
children | 476a22db8639 |
line wrap: on
line diff
--- a/libpam-sys/src/helpers.rs Sun Jun 29 18:48:14 2025 -0400 +++ b/libpam-sys/src/helpers.rs Sun Jun 29 20:13:03 2025 -0400 @@ -1,10 +1,11 @@ //! This module contains a few non-required helpers to deal with some of the //! more annoying memory management in the PAM API. -use crate::structs::BinaryPayload; + use std::error::Error; -use std::fmt; +use std::marker::{PhantomData, PhantomPinned}; use std::mem::ManuallyDrop; use std::ptr::NonNull; +use std::{fmt, slice}; /// Error returned when attempting to allocate a buffer that is too big. /// @@ -99,6 +100,77 @@ } } +/// 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 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 total byte buffer of the BinaryMessage stored at the 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 pointer's validity. + pub unsafe fn buffer_of<'a>(ptr: *const Self) -> &'a [u8] { + let header: &Self = ptr.as_ref().unwrap_unchecked(); + slice::from_raw_parts(ptr.cast(), header.total_bytes().max(5)) + } + + /// Gets the contents of the BinaryMessage stored at the given pointer. + /// + /// The returned data slice is borrowed from where the pointer points to. + /// This is a cheap operation and doesn't do *any* copying. + /// + /// We don't take a `&self` reference here because accessing beyond + /// the range of the `Self` data (i.e., beyond the 5 bytes of `self`) + /// is undefined behavior. Instead, you have to pass a raw pointer + /// directly to the data. + /// + /// # Safety + /// + /// - The pointer must point to a valid `BinaryPayload`. + /// - The borrowed data must not outlive the pointer's validity. + pub unsafe fn contents<'a>(ptr: *const Self) -> (u8, &'a [u8]) { + let header: &Self = ptr.as_ref().unwrap_unchecked(); + (header.data_type, &Self::buffer_of(ptr)[5..]) + } +} + /// A binary message owned by some storage. /// /// This is an owned, memory-managed version of [`BinaryPayload`]. @@ -132,9 +204,7 @@ /// The total bytes needed to store this, including the header. pub fn total_bytes(&self) -> usize { - unsafe { - BinaryPayload::buffer_of(self.0.as_ptr().cast()).len() - } + unsafe { BinaryPayload::buffer_of(self.0.as_ptr().cast()).len() } } /// Unwraps this into the raw storage backing it.