Mercurial > crates > nonstick
view src/constants.rs @ 88:c9fc7e6257d3 default tip
This is a v0.0.7 if I ever saw one.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Tue, 10 Jun 2025 05:36:58 -0400 |
parents | 05291b601f0a |
children |
line wrap: on
line source
//! Constants and enum values from the PAM library. // We have a lot of dumb casts that we just gotta do because of differences // between Linux-PAM and OpenPAM header files. #![allow(clippy::unnecessary_cast)] #[cfg(feature = "link")] use crate::libpam::pam_ffi; use bitflags::bitflags; use libc::c_int; use num_enum::{IntoPrimitive, TryFromPrimitive}; use std::ffi::c_uint; use std::result::Result as StdResult; /// Arbitrary values for PAM constants when not linking against system PAM. /// /// **The values of these constants are deliberately selected _not_ to match /// any PAM implementations. Applications should always use the symbolic value /// and not a magic number.** #[cfg(not(feature = "link"))] mod pam_ffi { macro_rules! define { ($(#[$attr:meta])* $($name:ident = $value:expr),+) => { define!( @meta { $(#[$attr])* } $(pub const $name: u32 = $value;)+ ); }; (@meta $m:tt $($i:item)+) => { define!(@expand $($m $i)+); }; (@expand $({ $(#[$m:meta])* } $i:item)+) => {$($(#[$m])* $i)+}; } const fn bit(n: u8) -> u32 { 1 << n } define!( PAM_SILENT = bit(13), PAM_DISALLOW_NULL_AUTHTOK = bit(14), PAM_ESTABLISH_CRED = bit(15), PAM_DELETE_CRED = bit(16), PAM_REINITIALIZE_CRED = bit(17), PAM_REFRESH_CRED = bit(18), PAM_CHANGE_EXPIRED_AUTHTOK = bit(19), PAM_PRELIM_CHECK = bit(20), PAM_UPDATE_AUTHTOK = bit(21) ); define!( PAM_ABORT = 513, PAM_ACCT_EXPIRED = 514, PAM_AUTHINFO_UNAVAIL = 515, PAM_AUTHTOK_DISABLE_AGING = 516, PAM_AUTHTOK_ERR = 517, PAM_AUTHTOK_EXPIRED = 518, PAM_AUTHTOK_LOCK_BUSY = 519, PAM_AUTHTOK_RECOVERY_ERR = 520, PAM_AUTH_ERR = 521, PAM_BAD_ITEM = 522, PAM_BUF_ERR = 533, PAM_CONV_AGAIN = 534, PAM_CONV_ERR = 535, PAM_CRED_ERR = 536, PAM_CRED_EXPIRED = 537, PAM_CRED_INSUFFICIENT = 538, PAM_CRED_UNAVAIL = 539, PAM_IGNORE = 540, PAM_INCOMPLETE = 541, PAM_MAXTRIES = 542, PAM_MODULE_UNKNOWN = 543, PAM_NEW_AUTHTOK_REQD = 544, PAM_NO_MODULE_DATA = 545, PAM_OPEN_ERR = 546, PAM_PERM_DENIED = 547, PAM_SERVICE_ERR = 548, PAM_SESSION_ERR = 549, PAM_SYMBOL_ERR = 550, PAM_SYSTEM_ERR = 551, PAM_TRY_AGAIN = 552, PAM_USER_UNKNOWN = 553 ); } bitflags! { /// The available PAM flags. /// /// See `/usr/include/security/_pam_types.h` and /// See `/usr/include/security/pam_modules.h` for more details. #[derive(Debug, PartialEq)] #[repr(transparent)] pub struct Flags: c_uint { /// The module should not generate any messages. const SILENT = pam_ffi::PAM_SILENT as u32; /// The module should return [ErrorCode::AuthError] /// if the user has an empty authentication token /// rather than immediately accepting them. const DISALLOW_NULL_AUTHTOK = pam_ffi::PAM_DISALLOW_NULL_AUTHTOK as u32; // Flag used for `set_credentials`. /// Set user credentials for an authentication service. const ESTABLISH_CREDENTIALS = pam_ffi::PAM_ESTABLISH_CRED as u32; /// Delete user credentials associated with /// an authentication service. const DELETE_CREDENTIALS = pam_ffi::PAM_DELETE_CRED as u32; /// Reinitialize user credentials. const REINITIALIZE_CREDENTIALS = pam_ffi::PAM_REINITIALIZE_CRED as u32; /// Extend the lifetime of user credentials. const REFRESH_CREDENTIALS = pam_ffi::PAM_REFRESH_CRED as u32; // Flags used for password changing. /// The password service should only update those passwords /// that have aged. If this flag is _not_ passed, /// the password service should update all passwords. /// /// This flag is only used by `change_authtok`. const CHANGE_EXPIRED_AUTHTOK = pam_ffi::PAM_CHANGE_EXPIRED_AUTHTOK as u32; /// This is a preliminary check for password changing. /// The password should not be changed. /// /// This is only used between PAM and a module. /// Applications may not use this flag. /// /// This flag is only used by `change_authtok`. const PRELIMINARY_CHECK = pam_ffi::PAM_PRELIM_CHECK as u32; /// The password should actuallyPR be updated. /// This and [Self::PRELIMINARY_CHECK] are mutually exclusive. /// /// This is only used between PAM and a module. /// Applications may not use this flag. /// /// This flag is only used by `change_authtok`. const UPDATE_AUTHTOK = pam_ffi::PAM_UPDATE_AUTHTOK as u32; } } /// The Linux-PAM error return values. Success is an Ok [Result]. /// /// Most abbreviations (except `AuthTok` and `Max`) are now full words. /// For more detailed information, see /// `/usr/include/security/_pam_types.h`. #[allow(non_camel_case_types, dead_code)] #[derive(Copy, Clone, Debug, PartialEq, thiserror::Error, TryFromPrimitive, IntoPrimitive)] #[non_exhaustive] // C might give us anything! #[repr(u32)] pub enum ErrorCode { #[error("dlopen() failure when dynamically loading a service module")] OpenError = pam_ffi::PAM_OPEN_ERR, #[error("symbol not found")] SymbolError = pam_ffi::PAM_SYMBOL_ERR, #[error("error in service module")] ServiceError = pam_ffi::PAM_SERVICE_ERR, #[error("system error")] SystemError = pam_ffi::PAM_SYSTEM_ERR, #[error("memory buffer error")] BufferError = pam_ffi::PAM_BUF_ERR, #[error("permission denied")] PermissionDenied = pam_ffi::PAM_PERM_DENIED, #[error("authentication failure")] AuthenticationError = pam_ffi::PAM_AUTH_ERR, #[error("cannot access authentication data due to insufficient credentials")] CredentialsInsufficient = pam_ffi::PAM_CRED_INSUFFICIENT, #[error("underlying authentication service cannot retrieve authentication information")] AuthInfoUnavailable = pam_ffi::PAM_AUTHINFO_UNAVAIL, #[error("user not known to the underlying authentication module")] UserUnknown = pam_ffi::PAM_USER_UNKNOWN, #[error("retry limit reached; do not attempt further")] MaxTries = pam_ffi::PAM_MAXTRIES, #[error("new authentication token required")] NewAuthTokRequired = pam_ffi::PAM_NEW_AUTHTOK_REQD, #[error("user account has expired")] AccountExpired = pam_ffi::PAM_ACCT_EXPIRED, #[error("cannot make/remove an entry for the specified session")] SessionError = pam_ffi::PAM_SESSION_ERR, #[error("underlying authentication service cannot retrieve user credentials")] CredentialsUnavailable = pam_ffi::PAM_CRED_UNAVAIL, #[error("user credentials expired")] CredentialsExpired = pam_ffi::PAM_CRED_EXPIRED, #[error("failure setting user credentials")] CredentialsError = pam_ffi::PAM_CRED_ERR, #[error("no module-specific data is present")] NoModuleData = pam_ffi::PAM_NO_MODULE_DATA, #[error("conversation error")] ConversationError = pam_ffi::PAM_CONV_ERR, #[error("authentication token manipulation error")] AuthTokError = pam_ffi::PAM_AUTHTOK_ERR, #[error("authentication information cannot be recovered")] AuthTokRecoveryError = pam_ffi::PAM_AUTHTOK_RECOVERY_ERR, #[error("authentication token lock busy")] AuthTokLockBusy = pam_ffi::PAM_AUTHTOK_LOCK_BUSY, #[error("authentication token aging disabled")] AuthTokDisableAging = pam_ffi::PAM_AUTHTOK_DISABLE_AGING, #[error("preliminary password check failed")] TryAgain = pam_ffi::PAM_TRY_AGAIN, #[error("ignore underlying account module, regardless of control flag")] Ignore = pam_ffi::PAM_IGNORE, #[error("critical error; this module should fail now")] Abort = pam_ffi::PAM_ABORT, #[error("authentication token has expired")] AuthTokExpired = pam_ffi::PAM_AUTHTOK_EXPIRED, #[error("module is not known")] ModuleUnknown = pam_ffi::PAM_MODULE_UNKNOWN, #[error("bad item passed to pam_[whatever]_item")] BadItem = pam_ffi::PAM_BAD_ITEM, #[cfg(feature = "linux-pam-extensions")] #[error("conversation function is event-driven and data is not available yet")] ConversationAgain = pam_ffi::PAM_CONV_AGAIN, #[cfg(feature = "linux-pam-extensions")] #[error("call this function again to complete authentication stack")] Incomplete = pam_ffi::PAM_INCOMPLETE, } /// A PAM-specific Result type with an [ErrorCode] error. pub type Result<T> = StdResult<T, ErrorCode>; impl ErrorCode { /// Converts this [Result] into a C-compatible result code. pub fn result_to_c<T>(value: Result<T>) -> c_int { match value { Ok(_) => 0, // PAM_SUCCESS Err(otherwise) => u32::from(otherwise) as i32, } } /// Converts a C result code into a [Result], with success as Ok. /// Invalid values are returned as a [Self::SystemError]. pub fn result_from(value: c_int) -> Result<()> { match value { 0 => Ok(()), value => Err((value as u32).try_into().unwrap_or(Self::SystemError)), } } } /// Returned when text that should not have any `\0` bytes in it does. /// Analogous to [`std::ffi::NulError`], but the data it was created from /// is borrowed. #[cfg(test)] mod tests { use super::*; #[test] fn test_enums() { assert_eq!(Ok(()), ErrorCode::result_from(0)); assert_eq!( pam_ffi::PAM_BAD_ITEM as i32, ErrorCode::result_to_c::<()>(Err(ErrorCode::BadItem)) ); assert_eq!( Err(ErrorCode::Abort), ErrorCode::result_from(pam_ffi::PAM_ABORT as i32) ); assert_eq!(Err(ErrorCode::SystemError), ErrorCode::result_from(423)); } }