Mercurial > crates > nonstick
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 |