comparison 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
comparison
equal deleted inserted replaced
117:20f7712a6857 118:39760dfc9b3b
1 use core::marker::{PhantomData, PhantomPinned}; 1 use std::ffi::{c_int, c_void};
2 use core::slice; 2 use std::fmt;
3 use std::marker::{PhantomData, PhantomPinned};
3 4
4 /// The structure of the "binary message" payload for the `PAM_BINARY_PROMPT` 5 /// A marker struct to make whatever it's in `!Sync`, `!Send`, and `!Unpin`.
5 /// extension from Linux-PAM. 6 #[derive(Default, PartialOrd, PartialEq, Ord, Eq)]
6 pub struct BinaryPayload { 7 #[repr(transparent)]
7 /// The total byte size of the message, including this header, 8 struct ExtremelyUnsafe(PhantomData<(PhantomPinned, *mut c_void)>);
8 /// as a u32 in network byte order (big endian). 9
9 pub total_bytes_u32be: [u8; 4], 10 impl fmt::Debug for ExtremelyUnsafe {
10 /// A tag used to provide some kind of hint as to what the data is. 11 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11 /// Its meaning is undefined. 12 f.write_str("ExtremelyUnsafe")
12 pub data_type: u8, 13 }
13 /// Where the data itself would start, used as a marker to make this
14 /// not [`Unpin`] (since it is effectively an intrusive data structure
15 /// pointing to immediately after itself).
16 pub _marker: PhantomData<PhantomPinned>,
17 } 14 }
18 15
19 impl BinaryPayload { 16 /// An opaque structure that PAM uses to communicate.
20 /// The most data it's possible to put into a [`BinaryPayload`]. 17 ///
21 pub const MAX_SIZE: usize = (u32::MAX - 5) as usize; 18 /// This is only ever returned in pointer form and cannot be constructed.
19 #[repr(C)]
20 pub struct PamHandle {
21 _marker: ExtremelyUnsafe,
22 }
22 23
23 /// Fills in the provided buffer with the given data. 24 impl fmt::Debug for PamHandle {
24 /// 25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 /// This uses [`copy_from_slice`](slice::copy_from_slice) internally, 26 write!(f, "PamHandle({self:p}")
26 /// so `buf` must be exactly 5 bytes longer than `data`, or this function
27 /// will panic.
28 pub fn fill(buf: &mut [u8], data_type: u8, data: &[u8]) {
29 let ptr: *mut Self = buf.as_mut_ptr().cast();
30 // SAFETY: We're given a slice, which always has a nonzero pointer.
31 let me = unsafe { ptr.as_mut().unwrap_unchecked() };
32 me.total_bytes_u32be = u32::to_be_bytes(buf.len() as u32);
33 me.data_type = data_type;
34 buf[5..].copy_from_slice(data)
35 }
36
37 /// The total storage needed for the message, including header.
38 pub fn total_bytes(&self) -> usize {
39 u32::from_be_bytes(self.total_bytes_u32be) as usize
40 }
41
42 /// Gets the total byte buffer of the BinaryMessage stored at the pointer.
43 ///
44 /// The returned data slice is borrowed from where the pointer points to.
45 ///
46 /// # Safety
47 ///
48 /// - The pointer must point to a valid `BinaryPayload`.
49 /// - The borrowed data must not outlive the pointer's validity.
50 pub unsafe fn buffer_of<'a>(ptr: *const Self) -> &'a [u8] {
51 let header: &Self = ptr.as_ref().unwrap_unchecked();
52 slice::from_raw_parts(ptr.cast(), header.total_bytes().max(5))
53 }
54
55 /// Gets the contents of the BinaryMessage stored at the given pointer.
56 ///
57 /// The returned data slice is borrowed from where the pointer points to.
58 /// This is a cheap operation and doesn't do *any* copying.
59 ///
60 /// We don't take a `&self` reference here because accessing beyond
61 /// the range of the `Self` data (i.e., beyond the 5 bytes of `self`)
62 /// is undefined behavior. Instead, you have to pass a raw pointer
63 /// directly to the data.
64 ///
65 /// # Safety
66 ///
67 /// - The pointer must point to a valid `BinaryPayload`.
68 /// - The borrowed data must not outlive the pointer's validity.
69 pub unsafe fn contents<'a>(ptr: *const Self) -> (u8, &'a [u8]) {
70 let header: &Self = ptr.as_ref().unwrap_unchecked();
71 (
72 header.data_type,
73 &Self::buffer_of(ptr)[5..]
74 )
75 } 27 }
76 } 28 }
29
30 /// An opaque structure that is passed through PAM in a conversation.
31 pub struct AppData {
32 _marker: ExtremelyUnsafe,
33 }
34
35 impl fmt::Debug for AppData {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 write!(f, "AppData({self:p}")
38 }
39 }
40
41 /// The callback that PAM uses to get information in a conversation.
42 ///
43 /// For important details about the format of `messages`,
44 /// see the [`helpers`](crate::helpers) module.
45 pub type ConversationCallback = unsafe extern "C" fn(
46 num_msg: c_int,
47 messages: *const *const Message,
48 responses: &mut *mut Response,
49 appdata: *const AppData,
50 ) -> c_int;
51
52 /// Used by PAM to communicate between the module and the application.
53 #[repr(C)]
54 pub struct Conversation {
55 pub callback: ConversationCallback,
56 pub appdata: *const AppData,
57 }
58
59 /// A message sent into a PAM conversation.
60 #[repr(C)]
61 pub struct Message {
62 pub style: c_int,
63 pub data: *const c_void,
64 }
65
66 /// A response returned from a PAM conversation.
67 #[repr(C)]
68 pub struct Response {
69 pub data: *mut c_void,
70 pub _unused: c_int,
71 }