Mercurial > crates > nonstick
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::*; |
