comparison 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
comparison
equal deleted inserted replaced
117:20f7712a6857 118:39760dfc9b3b
1 //! This module contains a few non-required helpers to deal with some of the 1 //! This module contains a few non-required helpers to deal with some of the
2 //! more annoying memory management in the PAM API. 2 //! more annoying memory management in the PAM API.
3 use crate::structs::BinaryPayload; 3
4 use std::error::Error; 4 use std::error::Error;
5 use std::fmt; 5 use std::marker::{PhantomData, PhantomPinned};
6 use std::mem::ManuallyDrop; 6 use std::mem::ManuallyDrop;
7 use std::ptr::NonNull; 7 use std::ptr::NonNull;
8 use std::{fmt, slice};
8 9
9 /// Error returned when attempting to allocate a buffer that is too big. 10 /// Error returned when attempting to allocate a buffer that is too big.
10 /// 11 ///
11 /// This is specifically used in [`OwnedBinaryPayload`] when you try to allocate 12 /// This is specifically used in [`OwnedBinaryPayload`] when you try to allocate
12 /// a message larger than 2<sup>32</sup> bytes. 13 /// a message larger than 2<sup>32</sup> bytes.
94 unsafe { NonNull::new_unchecked(me.as_mut_ptr()) } 95 unsafe { NonNull::new_unchecked(me.as_mut_ptr()) }
95 } 96 }
96 97
97 unsafe fn from_ptr(ptr: NonNull<T>, bytes: usize) -> Self { 98 unsafe fn from_ptr(ptr: NonNull<T>, bytes: usize) -> Self {
98 Vec::from_raw_parts(ptr.as_ptr(), bytes, bytes) 99 Vec::from_raw_parts(ptr.as_ptr(), bytes, bytes)
100 }
101 }
102
103 /// The structure of the "binary message" payload for the `PAM_BINARY_PROMPT`
104 /// extension from Linux-PAM.
105 pub struct BinaryPayload {
106 /// The total byte size of the message, including this header,
107 /// as a u32 in network byte order (big endian).
108 pub total_bytes_u32be: [u8; 4],
109 /// A tag used to provide some kind of hint as to what the data is.
110 /// Its meaning is undefined.
111 pub data_type: u8,
112 /// Where the data itself would start, used as a marker to make this
113 /// not [`Unpin`] (since it is effectively an intrusive data structure
114 /// pointing to immediately after itself).
115 pub _marker: PhantomData<PhantomPinned>,
116 }
117
118 impl BinaryPayload {
119 /// The most data it's possible to put into a [`BinaryPayload`].
120 pub const MAX_SIZE: usize = (u32::MAX - 5) as usize;
121
122 /// Fills in the provided buffer with the given data.
123 ///
124 /// This uses [`copy_from_slice`](slice::copy_from_slice) internally,
125 /// so `buf` must be exactly 5 bytes longer than `data`, or this function
126 /// will panic.
127 pub fn fill(buf: &mut [u8], data_type: u8, data: &[u8]) {
128 let ptr: *mut Self = buf.as_mut_ptr().cast();
129 // SAFETY: We're given a slice, which always has a nonzero pointer.
130 let me = unsafe { ptr.as_mut().unwrap_unchecked() };
131 me.total_bytes_u32be = u32::to_be_bytes(buf.len() as u32);
132 me.data_type = data_type;
133 buf[5..].copy_from_slice(data)
134 }
135
136 /// The total storage needed for the message, including header.
137 pub fn total_bytes(&self) -> usize {
138 u32::from_be_bytes(self.total_bytes_u32be) as usize
139 }
140
141 /// Gets the total byte buffer of the BinaryMessage stored at the pointer.
142 ///
143 /// The returned data slice is borrowed from where the pointer points to.
144 ///
145 /// # Safety
146 ///
147 /// - The pointer must point to a valid `BinaryPayload`.
148 /// - The borrowed data must not outlive the pointer's validity.
149 pub unsafe fn buffer_of<'a>(ptr: *const Self) -> &'a [u8] {
150 let header: &Self = ptr.as_ref().unwrap_unchecked();
151 slice::from_raw_parts(ptr.cast(), header.total_bytes().max(5))
152 }
153
154 /// Gets the contents of the BinaryMessage stored at the given pointer.
155 ///
156 /// The returned data slice is borrowed from where the pointer points to.
157 /// This is a cheap operation and doesn't do *any* copying.
158 ///
159 /// We don't take a `&self` reference here because accessing beyond
160 /// the range of the `Self` data (i.e., beyond the 5 bytes of `self`)
161 /// is undefined behavior. Instead, you have to pass a raw pointer
162 /// directly to the data.
163 ///
164 /// # Safety
165 ///
166 /// - The pointer must point to a valid `BinaryPayload`.
167 /// - The borrowed data must not outlive the pointer's validity.
168 pub unsafe fn contents<'a>(ptr: *const Self) -> (u8, &'a [u8]) {
169 let header: &Self = ptr.as_ref().unwrap_unchecked();
170 (header.data_type, &Self::buffer_of(ptr)[5..])
99 } 171 }
100 } 172 }
101 173
102 /// A binary message owned by some storage. 174 /// A binary message owned by some storage.
103 /// 175 ///
130 unsafe { BinaryPayload::contents(self.as_ptr()) } 202 unsafe { BinaryPayload::contents(self.as_ptr()) }
131 } 203 }
132 204
133 /// The total bytes needed to store this, including the header. 205 /// The total bytes needed to store this, including the header.
134 pub fn total_bytes(&self) -> usize { 206 pub fn total_bytes(&self) -> usize {
135 unsafe { 207 unsafe { BinaryPayload::buffer_of(self.0.as_ptr().cast()).len() }
136 BinaryPayload::buffer_of(self.0.as_ptr().cast()).len()
137 }
138 } 208 }
139 209
140 /// Unwraps this into the raw storage backing it. 210 /// Unwraps this into the raw storage backing it.
141 pub fn into_inner(self) -> O { 211 pub fn into_inner(self) -> O {
142 self.0 212 self.0