view libpam-sys/src/structs.rs @ 115:1e11a52b4665 default tip

Don't promise ordering for the log level.
author Paul Fisher <paul@pfish.zone>
date Sun, 29 Jun 2025 03:35:59 -0400
parents bb465393621f
children
line wrap: on
line source

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()),
        )
    }
}