diff libpam-sys/src/structs.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/structs.rs	Sun Jun 29 18:48:14 2025 -0400
+++ b/libpam-sys/src/structs.rs	Sun Jun 29 20:13:03 2025 -0400
@@ -1,76 +1,71 @@
-use core::marker::{PhantomData, PhantomPinned};
-use core::slice;
+use std::ffi::{c_int, c_void};
+use std::fmt;
+use std::marker::{PhantomData, PhantomPinned};
+
+/// A marker struct to make whatever it's in `!Sync`, `!Send`, and `!Unpin`.
+#[derive(Default, PartialOrd, PartialEq, Ord, Eq)]
+#[repr(transparent)]
+struct ExtremelyUnsafe(PhantomData<(PhantomPinned, *mut c_void)>);
+
+impl fmt::Debug for ExtremelyUnsafe {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("ExtremelyUnsafe")
+    }
+}
 
-/// 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>,
+/// An opaque structure that PAM uses to communicate.
+///
+/// This is only ever returned in pointer form and cannot be constructed.
+#[repr(C)]
+pub struct PamHandle {
+    _marker: ExtremelyUnsafe,
+}
+
+impl fmt::Debug for PamHandle {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "PamHandle({self:p}")
+    }
+}
+
+/// An opaque structure that is passed through PAM in a conversation.
+pub struct AppData {
+    _marker: ExtremelyUnsafe,
 }
 
-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..]
-        )
+impl fmt::Debug for AppData {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "AppData({self:p}")
     }
 }
+
+/// The callback that PAM uses to get information in a conversation.
+///
+/// For important details about the format of `messages`,
+/// see the [`helpers`](crate::helpers) module.
+pub type ConversationCallback = unsafe extern "C" fn(
+    num_msg: c_int,
+    messages: *const *const Message,
+    responses: &mut *mut Response,
+    appdata: *const AppData,
+) -> c_int;
+
+/// Used by PAM to communicate between the module and the application.
+#[repr(C)]
+pub struct Conversation {
+    pub callback: ConversationCallback,
+    pub appdata: *const AppData,
+}
+
+/// A message sent into a PAM conversation.
+#[repr(C)]
+pub struct Message {
+    pub style: c_int,
+    pub data: *const c_void,
+}
+
+/// A response returned from a PAM conversation.
+#[repr(C)]
+pub struct Response {
+    pub data: *mut c_void,
+    pub _unused: c_int,
+}