Mercurial > crates > nonstick
view src/constants.rs @ 60:05cc2c27334f
The Big Refactor: clean up docs and exports.
- Brings the most important symbols in the library to the root
with `pub use` statements.
- Expands and updates documentation.
- Rearranges things extensively to make the external interface nicer
and make the structure easier to understand.
- Renames a few things (e.g. `Result`).
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Wed, 21 May 2025 19:00:51 -0400 |
parents | 3f4a77aa88be |
children | a7aa5ca0d00d |
line wrap: on
line source
//! Constants and enum values from the PAM library. use bitflags::bitflags; use libc::{c_int, c_uint}; use num_derive::FromPrimitive; use num_traits::FromPrimitive; use std::any; use std::marker::PhantomData; bitflags! { /// The available PAM flags. /// /// See `/usr/include/security/_pam_types.h` for more details. #[derive(Debug, PartialEq)] #[repr(transparent)] pub struct Flags: c_uint { /// Authentication service should not generate any messages. const SILENT = 0x8000; /// The service should return [ErrorCode::AuthError] if the user /// has a null authentication token. const DISALLOW_NULL_AUTHTOK = 0x0001; /// Set user credentials for an authentication service. const ESTABLISH_CRED = 0x0002; /// Delete user credentials associated with /// an authentication service. const DELETE_CRED = 0x0004; /// Reinitialize user credentials. const REINITIALIZE_CRED = 0x0008; /// Extend the lifetime of user credentials. const REFRESH_CRED = 0x0010; /// The password service should only update those passwords /// that have aged. If this flag is _not_ passed, /// the password service should update all passwords. const CHANGE_EXPIRED_AUTHTOK = 0x0020; } } /// Styles of message that are shown to the user. #[derive(Debug, PartialEq, FromPrimitive)] #[non_exhaustive] // non-exhaustive because C might give us back anything! pub enum MessageStyle { /// Requests information from the user; will be masked when typing. PromptEchoOff = 1, /// Requests information from the user; will not be masked. PromptEchoOn = 2, /// An error message. ErrorMsg = 3, /// An informational message. TextInfo = 4, /// Yes/No/Maybe conditionals. Linux-PAM specific. RadioType = 5, /// For server–client non-human interaction. /// NOT part of the X/Open PAM specification. BinaryPrompt = 7, } impl TryFrom<c_int> for MessageStyle { type Error = InvalidEnum<Self>; fn try_from(value: c_int) -> std::result::Result<Self, Self::Error> { Self::from_i32(value).ok_or(value.into()) } } impl From<MessageStyle> for c_int { fn from(val: MessageStyle) -> Self { val as Self } } /// 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, FromPrimitive)] #[non_exhaustive] // C might give us anything! pub enum ErrorCode { #[error("dlopen() failure when dynamically loading a service module")] OpenError = 1, #[error("symbol not found")] SymbolError = 2, #[error("error in service module")] ServiceError = 3, #[error("system error")] SystemError = 4, #[error("memory buffer error")] BufferError = 5, #[error("permission denied")] PermissionDenied = 6, #[error("authentication failure")] AuthenticationError = 7, #[error("cannot access authentication data due to insufficient credentials")] CredentialsInsufficient = 8, #[error("underlying authentication service cannot retrieve authentication information")] AuthInfoUnavailable = 9, #[error("user not known to the underlying authentication module")] UserUnknown = 10, #[error("retry limit reached; do not attempt further")] MaxTries = 11, #[error("new authentication token required")] NewAuthTokRequired = 12, #[error("user account has expired")] AccountExpired = 13, #[error("cannot make/remove an entry for the specified session")] SessionError = 14, #[error("underlying authentication service cannot retrieve user credentials")] CredentialsUnavailable = 15, #[error("user credentials expired")] CredentialsExpired = 16, #[error("failure setting user credentials")] CredentialsError = 17, #[error("no module-specific data is present")] NoModuleData = 18, #[error("conversation error")] ConversationError = 19, #[error("authentication token manipulation error")] AuthTokError = 20, #[error("authentication information cannot be recovered")] AuthTokRecoveryError = 21, #[error("authentication token lock busy")] AuthTokLockBusy = 22, #[error("authentication token aging disabled")] AuthTokDisableAging = 23, #[error("preliminary check by password service")] TryAgain = 24, #[error("ignore underlying account module, regardless of control flag")] Ignore = 25, #[error("critical error; this module should fail now")] Abort = 26, #[error("authentication token has expired")] AuthTokExpired = 27, #[error("module is not known")] ModuleUnknown = 28, #[error("bad item passed to pam_[whatever]_item")] BadItem = 29, #[error("conversation function is event-driven and data is not available yet")] ConversationAgain = 30, #[error("call this function again to complete authentication stack")] Incomplete = 31, } /// A PAM-specific Result type with an [ErrorCode] error. pub type Result<T> = std::result::Result<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) => 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)), } } } impl TryFrom<c_int> for ErrorCode { type Error = InvalidEnum<Self>; fn try_from(value: c_int) -> std::result::Result<Self, Self::Error> { Self::from_i32(value).ok_or(value.into()) } } impl From<ErrorCode> for c_int { fn from(val: ErrorCode) -> Self { val as Self } } /// Error returned when attempting to coerce an invalid C integer into an enum. #[derive(thiserror::Error)] #[error("{0} is not a valid {type}", type = any::type_name::<T>())] #[derive(Debug, PartialEq)] pub struct InvalidEnum<T>(c_int, PhantomData<T>); impl<T> From<InvalidEnum<T>> for c_int { fn from(value: InvalidEnum<T>) -> Self { value.0 } } impl<T> From<c_int> for InvalidEnum<T> { fn from(value: c_int) -> Self { Self(value, PhantomData) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_enums() { assert_eq!(Ok(MessageStyle::ErrorMsg), 3.try_into()); assert_eq!(Err(InvalidEnum::from(999)), ErrorCode::try_from(999)); assert_eq!(Ok(()), ErrorCode::result_from(0)); assert_eq!(Err(ErrorCode::Abort), ErrorCode::result_from(26)); assert_eq!(Err(ErrorCode::SystemError), ErrorCode::result_from(423)); assert!(InvalidEnum::<MessageStyle>(33, PhantomData) .to_string() .starts_with("33 is not a valid ")); } }