comparison src/constants.rs @ 130:80c07e5ab22f

Transfer over (almost) completely to using libpam-sys. This reimplements everything in nonstick on top of the new -sys crate. We don't yet use libpam-sys's helpers for binary message payloads. Soon.
author Paul Fisher <paul@pfish.zone>
date Tue, 01 Jul 2025 06:11:43 -0400
parents a12706e42c9d
children a632a8874131
comparison
equal deleted inserted replaced
129:5b2de52dd8b2 130:80c07e5ab22f
2 2
3 // We have a lot of dumb casts that we just gotta do because of differences 3 // We have a lot of dumb casts that we just gotta do because of differences
4 // between Linux-PAM and OpenPAM header files. 4 // between Linux-PAM and OpenPAM header files.
5 #![allow(clippy::unnecessary_cast)] 5 #![allow(clippy::unnecessary_cast)]
6 6
7 #[cfg(feature = "link")]
8 use crate::libpam::pam_ffi;
9 use crate::{linklist, man7, manbsd, xsso}; 7 use crate::{linklist, man7, manbsd, xsso};
10 use bitflags::bitflags; 8 use bitflags::bitflags;
11 use libc::c_int; 9 use std::ffi::c_int;
12 use num_enum::{IntoPrimitive, TryFromPrimitive}; 10 use num_enum::{IntoPrimitive, TryFromPrimitive};
13 use std::error::Error; 11 use std::error::Error;
14 use std::ffi::c_uint;
15 use std::fmt;
16 use std::fmt::{Display, Formatter}; 12 use std::fmt::{Display, Formatter};
17 use std::result::Result as StdResult; 13 use std::result::Result as StdResult;
18 14 use std::fmt;
19 /// Arbitrary values for PAM constants when not linking against system PAM. 15
16 /// Values for constants not provided by certain PAM implementations.
20 /// 17 ///
21 /// **The values of these constants are deliberately selected _not_ to match 18 /// **The values of these constants are deliberately selected _not_ to match
22 /// any PAM implementations. Applications should always use the symbolic value 19 /// any PAM implementations. Applications should always use the symbolic value
23 /// and not a magic number.** 20 /// and not a magic number.**
24 #[cfg(not(feature = "link"))]
25 mod pam_ffi { 21 mod pam_ffi {
26 use std::ffi::c_uint; 22 pub use libpam_sys::*;
27 23
28 macro_rules! define { 24 macro_rules! define {
29 ($(#[$attr:meta])* $($name:ident = $value:expr),+) => { 25 ($(#[$attr:meta])* $($name:ident = $value:expr;)+) => {
30 define!( 26 define!(
31 @meta { $(#[$attr])* } 27 @meta { $(#[$attr])* }
32 $(pub const $name: i32 = $value;)+ 28 $(pub const $name: i32 = $value;)+
33 ); 29 );
34 }; 30 };
35 (@meta $m:tt $($i:item)+) => { define!(@expand $($m $i)+); }; 31 (@meta $m:tt $($i:item)+) => { define!(@expand $($m $i)+); };
36 (@expand $({ $(#[$m:meta])* } $i:item)+) => {$($(#[$m])* $i)+}; 32 (@expand $({ $(#[$m:meta])* } $i:item)+) => {$($(#[$m])* $i)+};
37 } 33 }
38 const fn bit(n: u8) -> i32 { 34
39 1 << n 35
40 }
41 define!( 36 define!(
42 PAM_SILENT = bit(13), 37 /// A fictitious constant for testing purposes.
43 PAM_DISALLOW_NULL_AUTHTOK = bit(14), 38 #[cfg(not(feature = "link"))]
44 PAM_ESTABLISH_CRED = bit(15), 39 #[cfg_pam_impl(not("OpenPam"))]
45 PAM_DELETE_CRED = bit(16), 40 PAM_BAD_CONSTANT = 513;
46 PAM_REINITIALIZE_CRED = bit(17), 41 PAM_BAD_FEATURE = 514;
47 PAM_REFRESH_CRED = bit(18),
48 PAM_CHANGE_EXPIRED_AUTHTOK = bit(19),
49 PAM_PRELIM_CHECK = bit(20),
50 PAM_UPDATE_AUTHTOK = bit(21)
51 ); 42 );
52 43
53 define!( 44 define!(
54 PAM_ABORT = 513, 45 /// A fictitious constant for testing purposes.
55 PAM_ACCT_EXPIRED = 514, 46 #[cfg(not(feature = "link"))]
56 PAM_AUTHINFO_UNAVAIL = 515, 47 #[cfg_pam_impl(not(any("LinuxPam", "OpenPam")))]
57 PAM_AUTHTOK_DISABLE_AGING = 516, 48 PAM_BAD_ITEM = 515;
58 PAM_AUTHTOK_ERR = 517, 49 PAM_MODULE_UNKNOWN = 516;
59 PAM_AUTHTOK_EXPIRED = 518,
60 PAM_AUTHTOK_LOCK_BUSY = 519,
61 PAM_AUTHTOK_RECOVERY_ERR = 520,
62 PAM_AUTH_ERR = 521,
63 PAM_BAD_ITEM = 522,
64 PAM_BUF_ERR = 533,
65 PAM_CONV_AGAIN = 534,
66 PAM_CONV_ERR = 535,
67 PAM_CRED_ERR = 536,
68 PAM_CRED_EXPIRED = 537,
69 PAM_CRED_INSUFFICIENT = 538,
70 PAM_CRED_UNAVAIL = 539,
71 PAM_IGNORE = 540,
72 PAM_INCOMPLETE = 541,
73 PAM_MAXTRIES = 542,
74 PAM_MODULE_UNKNOWN = 543,
75 PAM_NEW_AUTHTOK_REQD = 544,
76 PAM_NO_MODULE_DATA = 545,
77 PAM_OPEN_ERR = 546,
78 PAM_PERM_DENIED = 547,
79 PAM_SERVICE_ERR = 548,
80 PAM_SESSION_ERR = 549,
81 PAM_SYMBOL_ERR = 550,
82 PAM_SYSTEM_ERR = 551,
83 PAM_TRY_AGAIN = 552,
84 PAM_USER_UNKNOWN = 553
85 ); 50 );
86 51
87 /// Dummy implementation of strerror so that it always returns None. 52 define!(
88 pub fn strerror(val: c_uint) -> Option<&'static str> { 53 /// A fictitious constant for testing purposes.
89 _ = val; 54 #[cfg(not(feature = "link"))]
90 None 55 #[cfg_pam_impl(not("LinuxPam"))]
91 } 56 PAM_CONV_AGAIN = 517;
57 PAM_INCOMPLETE = 518;
58 );
59
92 } 60 }
93 61
94 bitflags! { 62 bitflags! {
95 /// The available PAM flags. 63 /// The available PAM flags.
96 /// 64 ///
98 /// See `/usr/include/security/pam_modules.h` for more details. 66 /// See `/usr/include/security/pam_modules.h` for more details.
99 #[derive(Debug, Default, PartialEq)] 67 #[derive(Debug, Default, PartialEq)]
100 #[repr(transparent)] 68 #[repr(transparent)]
101 pub struct Flags: c_int { 69 pub struct Flags: c_int {
102 /// The module should not generate any messages. 70 /// The module should not generate any messages.
103 const SILENT = pam_ffi::PAM_SILENT; 71 const SILENT = libpam_sys::PAM_SILENT;
104 72
105 /// The module should return [ErrorCode::AuthError] 73 /// The module should return [ErrorCode::AuthError]
106 /// if the user has an empty authentication token 74 /// if the user has an empty authentication token
107 /// rather than immediately accepting them. 75 /// rather than immediately accepting them.
108 const DISALLOW_NULL_AUTHTOK = pam_ffi::PAM_DISALLOW_NULL_AUTHTOK; 76 const DISALLOW_NULL_AUTHTOK = libpam_sys::PAM_DISALLOW_NULL_AUTHTOK;
109 77
110 // Flag used for `set_credentials`. 78 // Flag used for `set_credentials`.
111 79
112 /// Set user credentials for an authentication service. 80 /// Set user credentials for an authentication service.
113 const ESTABLISH_CREDENTIALS = pam_ffi::PAM_ESTABLISH_CRED; 81 const ESTABLISH_CREDENTIALS = libpam_sys::PAM_ESTABLISH_CRED;
114 /// Delete user credentials associated with 82 /// Delete user credentials associated with
115 /// an authentication service. 83 /// an authentication service.
116 const DELETE_CREDENTIALS = pam_ffi::PAM_DELETE_CRED; 84 const DELETE_CREDENTIALS = libpam_sys::PAM_DELETE_CRED;
117 /// Reinitialize user credentials. 85 /// Reinitialize user credentials.
118 const REINITIALIZE_CREDENTIALS = pam_ffi::PAM_REINITIALIZE_CRED; 86 const REINITIALIZE_CREDENTIALS = libpam_sys::PAM_REINITIALIZE_CRED;
119 /// Extend the lifetime of user credentials. 87 /// Extend the lifetime of user credentials.
120 const REFRESH_CREDENTIALS = pam_ffi::PAM_REFRESH_CRED; 88 const REFRESH_CREDENTIALS = libpam_sys::PAM_REFRESH_CRED;
121 89
122 // Flags used for password changing. 90 // Flags used for password changing.
123 91
124 /// The password service should only update those passwords 92 /// The password service should only update those passwords
125 /// that have aged. If this flag is _not_ passed, 93 /// that have aged. If this flag is _not_ passed,
126 /// the password service should update all passwords. 94 /// the password service should update all passwords.
127 /// 95 ///
128 /// This flag is only used by `change_authtok`. 96 /// This flag is only used by `change_authtok`.
129 const CHANGE_EXPIRED_AUTHTOK = pam_ffi::PAM_CHANGE_EXPIRED_AUTHTOK; 97 const CHANGE_EXPIRED_AUTHTOK = libpam_sys::PAM_CHANGE_EXPIRED_AUTHTOK;
130 /// This is a preliminary check for password changing. 98 /// This is a preliminary check for password changing.
131 /// The password should not be changed. 99 /// The password should not be changed.
132 /// 100 ///
133 /// This is only used between PAM and a module. 101 /// This is only used between PAM and a module.
134 /// Applications may not use this flag. 102 /// Applications may not use this flag.
135 /// 103 ///
136 /// This flag is only used by `change_authtok`. 104 /// This flag is only used by `change_authtok`.
137 const PRELIMINARY_CHECK = pam_ffi::PAM_PRELIM_CHECK; 105 const PRELIMINARY_CHECK = libpam_sys::PAM_PRELIM_CHECK;
138 /// The password should actuallyPR be updated. 106 /// The password should actuallyPR be updated.
139 /// This and [Self::PRELIMINARY_CHECK] are mutually exclusive. 107 /// This and [Self::PRELIMINARY_CHECK] are mutually exclusive.
140 /// 108 ///
141 /// This is only used between PAM and a module. 109 /// This is only used between PAM and a module.
142 /// Applications may not use this flag. 110 /// Applications may not use this flag.
143 /// 111 ///
144 /// This flag is only used by `change_authtok`. 112 /// This flag is only used by `change_authtok`.
145 const UPDATE_AUTHTOK = pam_ffi::PAM_UPDATE_AUTHTOK; 113 const UPDATE_AUTHTOK = libpam_sys::PAM_UPDATE_AUTHTOK;
146 } 114 }
147 } 115 }
148 116
149 /// The PAM error return codes. 117 /// The PAM error return codes.
150 /// 118 ///
205 /// A PAM-specific Result type with an [ErrorCode] error. 173 /// A PAM-specific Result type with an [ErrorCode] error.
206 pub type Result<T> = StdResult<T, ErrorCode>; 174 pub type Result<T> = StdResult<T, ErrorCode>;
207 175
208 impl Display for ErrorCode { 176 impl Display for ErrorCode {
209 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 177 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
210 match pam_ffi::strerror((*self).into()) { 178 match strerror((*self).into()) {
211 Some(err) => f.write_str(err), 179 Some(err) => f.write_str(err),
212 None => self.fmt_internal(f), 180 None => self.fmt_internal(f),
213 } 181 }
214 } 182 }
215 } 183 }
234 } 202 }
235 } 203 }
236 204
237 /// A basic Display implementation for if we don't link against PAM. 205 /// A basic Display implementation for if we don't link against PAM.
238 fn fmt_internal(self, f: &mut Formatter<'_>) -> fmt::Result { 206 fn fmt_internal(self, f: &mut Formatter<'_>) -> fmt::Result {
239 write!(f, "PAM error: {self:?} ({n})", n = self as c_uint) 207 let n : c_int = self.into();
240 } 208 write!(f, "PAM error: {self:?} ({n})")
209 }
210 }
211
212 /// Gets a string version of an error message.
213 #[cfg(feature = "link")]
214 pub fn strerror(code: c_int) -> Option<&'static str> {
215 use std::ptr;
216 use std::ffi::CStr;
217 // SAFETY: PAM impls don't care about the PAM handle and always return
218 // static strings.
219 let strerror = unsafe { libpam_sys::pam_strerror(ptr::null(), code as c_int) };
220 // SAFETY: We just got this back from PAM and we checked if it's null.
221 (!strerror.is_null())
222 .then(|| unsafe { CStr::from_ptr(strerror) }.to_str().ok())
223 .flatten()
224 }
225
226 /// Dummy implementation of strerror so that it always returns None.
227 #[cfg(not(feature = "link"))]
228 pub fn strerror(_: c_int) -> Option<&'static str> {
229 None
241 } 230 }
242 231
243 #[cfg(test)] 232 #[cfg(test)]
244 mod tests { 233 mod tests {
245 use super::*; 234 use super::*;