Mercurial > crates > nonstick
view src/constants.rs @ 141:a508a69c068a
Remove a lot of Results from functions.
Many functions are documented to only return failing Results when given
improper inputs or when there is a memory allocation failure (which
can be verified by looking at the source). In cases where we know our
input is correct, we don't need to check for memory allocation errors
for the same reason that Rust doesn't do so when you, e.g., create a
new Vec.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sat, 05 Jul 2025 17:16:56 -0400 |
parents | 33b9622ed6d2 |
children | 1bc52025156b |
line wrap: on
line source
//! Constants and enum values from the PAM library. use crate::{linklist, man7, manbsd, xsso}; use bitflags::bitflags; use num_enum::{IntoPrimitive, TryFromPrimitive}; use std::error::Error; use std::ffi::c_int; use std::fmt; use std::fmt::{Display, Formatter}; use std::result::Result as StdResult; /// Values for constants not provided by certain PAM implementations. /// /// **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.** mod pam_constants { pub use libpam_sys_helpers::constants::*; macro_rules! define { ($(#[$attr:meta])* $($name:ident = $value:expr;)+) => { define!( @meta { $(#[$attr])* } $(pub const $name: i32 = $value;)+ ); }; (@meta $m:tt $($i:item)+) => { define!(@expand $($m $i)+); }; (@expand $({ $(#[$m:meta])* } $i:item)+) => {$($(#[$m])* $i)+}; } define!( /// A fictitious constant for testing purposes. #[cfg(not(pam_impl = "OpenPam"))] PAM_BAD_CONSTANT = 513; PAM_BAD_FEATURE = 514; ); define!( /// A fictitious constant for testing purposes. #[cfg(not(any(pam_impl = "LinuxPam", pam_impl = "OpenPam")))] PAM_BAD_ITEM = 515; PAM_MODULE_UNKNOWN = 516; ); define!( /// A fictitious constant for testing purposes. #[cfg(not(pam_impl = "LinuxPam"))] PAM_CONV_AGAIN = 517; PAM_INCOMPLETE = 518; ); } 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, Default, PartialEq)] #[repr(transparent)] pub struct Flags: c_int { /// The module should not generate any messages. const SILENT = pam_constants::PAM_SILENT; /// The module should return [ErrorCode::AuthError] /// if the user has an empty authentication token /// rather than immediately accepting them. const DISALLOW_NULL_AUTHTOK = pam_constants::PAM_DISALLOW_NULL_AUTHTOK; // Flag used for `set_credentials`. /// Set user credentials for an authentication service. const ESTABLISH_CREDENTIALS = pam_constants::PAM_ESTABLISH_CRED; /// Delete user credentials associated with /// an authentication service. const DELETE_CREDENTIALS = pam_constants::PAM_DELETE_CRED; /// Reinitialize user credentials. const REINITIALIZE_CREDENTIALS = pam_constants::PAM_REINITIALIZE_CRED; /// Extend the lifetime of user credentials. const REFRESH_CREDENTIALS = pam_constants::PAM_REFRESH_CRED; // 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_constants::PAM_CHANGE_EXPIRED_AUTHTOK; /// 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_constants::PAM_PRELIM_CHECK; /// 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_constants::PAM_UPDATE_AUTHTOK; } } /// The PAM error return codes. /// /// These are returned by most PAM functions if an error of some kind occurs. /// /// Instead of being an error code, success is represented by an Ok [`Result`]. /// /// # References /// #[doc = linklist!(pam: man7, manbsd)] /// - [X/SSO error code specification][xsso] /// #[doc = man7!(3 pam "RETURN_VALUES")] #[doc = manbsd!(3 pam "RETURN%20VALUES")] #[doc = xsso!("chap5.htm#tagcjh_06_02")] #[allow(non_camel_case_types, dead_code)] #[derive(Copy, Clone, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)] #[non_exhaustive] // C might give us anything! #[repr(i32)] pub enum ErrorCode { OpenError = pam_constants::PAM_OPEN_ERR, SymbolError = pam_constants::PAM_SYMBOL_ERR, ServiceError = pam_constants::PAM_SERVICE_ERR, SystemError = pam_constants::PAM_SYSTEM_ERR, BufferError = pam_constants::PAM_BUF_ERR, PermissionDenied = pam_constants::PAM_PERM_DENIED, AuthenticationError = pam_constants::PAM_AUTH_ERR, CredentialsInsufficient = pam_constants::PAM_CRED_INSUFFICIENT, AuthInfoUnavailable = pam_constants::PAM_AUTHINFO_UNAVAIL, UserUnknown = pam_constants::PAM_USER_UNKNOWN, MaxTries = pam_constants::PAM_MAXTRIES, NewAuthTokRequired = pam_constants::PAM_NEW_AUTHTOK_REQD, AccountExpired = pam_constants::PAM_ACCT_EXPIRED, SessionError = pam_constants::PAM_SESSION_ERR, CredentialsUnavailable = pam_constants::PAM_CRED_UNAVAIL, CredentialsExpired = pam_constants::PAM_CRED_EXPIRED, CredentialsError = pam_constants::PAM_CRED_ERR, NoModuleData = pam_constants::PAM_NO_MODULE_DATA, ConversationError = pam_constants::PAM_CONV_ERR, AuthTokError = pam_constants::PAM_AUTHTOK_ERR, AuthTokRecoveryError = pam_constants::PAM_AUTHTOK_RECOVERY_ERR, AuthTokLockBusy = pam_constants::PAM_AUTHTOK_LOCK_BUSY, AuthTokDisableAging = pam_constants::PAM_AUTHTOK_DISABLE_AGING, TryAgain = pam_constants::PAM_TRY_AGAIN, Ignore = pam_constants::PAM_IGNORE, Abort = pam_constants::PAM_ABORT, AuthTokExpired = pam_constants::PAM_AUTHTOK_EXPIRED, #[cfg(feature = "basic-ext")] ModuleUnknown = pam_constants::PAM_MODULE_UNKNOWN, #[cfg(feature = "basic-ext")] BadItem = pam_constants::PAM_BAD_ITEM, #[cfg(feature = "linux-pam-ext")] ConversationAgain = pam_constants::PAM_CONV_AGAIN, #[cfg(feature = "linux-pam-ext")] Incomplete = pam_constants::PAM_INCOMPLETE, } /// A PAM-specific Result type with an [ErrorCode] error. pub type Result<T> = StdResult<T, ErrorCode>; impl Display for ErrorCode { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match strerror((*self).into()) { Some(err) => f.write_str(err), None => self.fmt_internal(f), } } } impl Error for 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) => otherwise.into(), } } /// 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.try_into().unwrap_or(Self::SystemError)), } } /// A basic Display implementation for if we don't link against PAM. fn fmt_internal(self, f: &mut Formatter<'_>) -> fmt::Result { let n: c_int = self.into(); write!(f, "PAM error: {self:?} ({n})") } } /// Gets a string version of an error message. #[cfg(feature = "link")] pub fn strerror(code: c_int) -> Option<&'static str> { use std::ffi::CStr; use std::ptr; // SAFETY: PAM impls don't care about the PAM handle and always return // static strings. let strerror = unsafe { libpam_sys::pam_strerror(ptr::null(), code as c_int) }; // SAFETY: We just got this back from PAM and we checked if it's null. (!strerror.is_null()) .then(|| unsafe { CStr::from_ptr(strerror) }.to_str().ok()) .flatten() } /// Dummy implementation of strerror so that it always returns None. #[cfg(not(feature = "link"))] pub fn strerror(_: c_int) -> Option<&'static str> { None } #[cfg(test)] mod tests { use super::*; #[test] fn test_enums() { assert_eq!(Ok(()), ErrorCode::result_from(0)); assert_eq!( pam_constants::PAM_SESSION_ERR, ErrorCode::result_to_c::<()>(Err(ErrorCode::SessionError)) ); assert_eq!( Err(ErrorCode::Abort), ErrorCode::result_from(pam_constants::PAM_ABORT) ); assert_eq!(Err(ErrorCode::SystemError), ErrorCode::result_from(423)); } }