Mercurial > crates > nonstick
diff src/constants.rs @ 90:f6186e41399b
Miscellaneous fixes and cleanup:
- Rename `get_user` to `username` and `get_authtok` to `authtok`.
- Use pam_strerror for error messages.
- Add library linkage to build.rs (it was missing???).
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sat, 14 Jun 2025 09:30:16 -0400 |
parents | 05291b601f0a |
children | 5ddbcada30f2 |
line wrap: on
line diff
--- a/src/constants.rs Fri Jun 13 05:22:48 2025 -0400 +++ b/src/constants.rs Sat Jun 14 09:30:16 2025 -0400 @@ -9,7 +9,10 @@ use bitflags::bitflags; use libc::c_int; use num_enum::{IntoPrimitive, TryFromPrimitive}; +use std::error::Error; use std::ffi::c_uint; +use std::fmt; +use std::fmt::{Display, Formatter}; use std::result::Result as StdResult; /// Arbitrary values for PAM constants when not linking against system PAM. @@ -77,6 +80,10 @@ PAM_TRY_AGAIN = 552, PAM_USER_UNKNOWN = 553 ); + + fn strerror(val: c_uint) -> Option<&'static str> { + None + } } bitflags! { @@ -140,79 +147,59 @@ /// 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)] +#[derive(Copy, Clone, Debug, PartialEq, 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 Display for ErrorCode { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match pam_ffi::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 { @@ -230,6 +217,11 @@ value => Err((value as u32).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 { + write!(f, "PAM error: {self:?} ({n})", n = self as c_uint) + } } /// Returned when text that should not have any `\0` bytes in it does.