Mercurial > crates > nonstick
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 59:3f4a77aa88be | 60:05cc2c27334f |
|---|---|
| 1 //! Constants and enum values from the PAM library. | |
| 2 | |
| 1 use bitflags::bitflags; | 3 use bitflags::bitflags; |
| 2 use libc::{c_int, c_uint}; | 4 use libc::{c_int, c_uint}; |
| 3 use num_derive::FromPrimitive; | 5 use num_derive::FromPrimitive; |
| 4 use num_traits::FromPrimitive; | 6 use num_traits::FromPrimitive; |
| 5 use std::any; | 7 use std::any; |
| 6 use std::marker::PhantomData; | 8 use std::marker::PhantomData; |
| 7 // TODO: Import constants from C header file at compile time. | 9 |
| 8 | |
| 9 // The Linux-PAM flags | |
| 10 // see /usr/include/security/_pam_types.h | |
| 11 bitflags! { | 10 bitflags! { |
| 11 /// The available PAM flags. | |
| 12 /// | |
| 13 /// See `/usr/include/security/_pam_types.h` for more details. | |
| 12 #[derive(Debug, PartialEq)] | 14 #[derive(Debug, PartialEq)] |
| 13 #[repr(transparent)] | 15 #[repr(transparent)] |
| 14 pub struct Flags: c_uint { | 16 pub struct Flags: c_uint { |
| 17 /// Authentication service should not generate any messages. | |
| 15 const SILENT = 0x8000; | 18 const SILENT = 0x8000; |
| 19 /// The service should return [ErrorCode::AuthError] if the user | |
| 20 /// has a null authentication token. | |
| 16 const DISALLOW_NULL_AUTHTOK = 0x0001; | 21 const DISALLOW_NULL_AUTHTOK = 0x0001; |
| 22 /// Set user credentials for an authentication service. | |
| 17 const ESTABLISH_CRED = 0x0002; | 23 const ESTABLISH_CRED = 0x0002; |
| 24 /// Delete user credentials associated with | |
| 25 /// an authentication service. | |
| 18 const DELETE_CRED = 0x0004; | 26 const DELETE_CRED = 0x0004; |
| 27 /// Reinitialize user credentials. | |
| 19 const REINITIALIZE_CRED = 0x0008; | 28 const REINITIALIZE_CRED = 0x0008; |
| 29 /// Extend the lifetime of user credentials. | |
| 20 const REFRESH_CRED = 0x0010; | 30 const REFRESH_CRED = 0x0010; |
| 21 const CHANGE_EXPIRED_AUTHTOK= 0x0020; | 31 /// The password service should only update those passwords |
| 32 /// that have aged. If this flag is _not_ passed, | |
| 33 /// the password service should update all passwords. | |
| 34 const CHANGE_EXPIRED_AUTHTOK = 0x0020; | |
| 22 } | 35 } |
| 23 } | 36 } |
| 24 | 37 |
| 25 /// Styles of message that are shown to the user. | 38 /// Styles of message that are shown to the user. |
| 26 #[derive(Debug, PartialEq, FromPrimitive)] | 39 #[derive(Debug, PartialEq, FromPrimitive)] |
| 41 BinaryPrompt = 7, | 54 BinaryPrompt = 7, |
| 42 } | 55 } |
| 43 | 56 |
| 44 impl TryFrom<c_int> for MessageStyle { | 57 impl TryFrom<c_int> for MessageStyle { |
| 45 type Error = InvalidEnum<Self>; | 58 type Error = InvalidEnum<Self>; |
| 46 fn try_from(value: c_int) -> Result<Self, Self::Error> { | 59 fn try_from(value: c_int) -> std::result::Result<Self, Self::Error> { |
| 47 Self::from_i32(value).ok_or(value.into()) | 60 Self::from_i32(value).ok_or(value.into()) |
| 48 } | 61 } |
| 49 } | 62 } |
| 50 | 63 |
| 51 impl From<MessageStyle> for c_int { | 64 impl From<MessageStyle> for c_int { |
| 52 fn from(val: MessageStyle) -> Self { | 65 fn from(val: MessageStyle) -> Self { |
| 53 val as Self | 66 val as Self |
| 54 } | 67 } |
| 55 } | 68 } |
| 56 | 69 |
| 57 /// The Linux-PAM error return values. | 70 /// The Linux-PAM error return values. Success is an Ok [Result]. |
| 58 /// Success is instead represented by the `Ok` entry of a `Result`. | 71 /// |
| 59 /// Most abbreviations (except `AuthTok` and `Max`) are now full words. | 72 /// Most abbreviations (except `AuthTok` and `Max`) are now full words. |
| 60 /// For more detailed information, see | 73 /// For more detailed information, see |
| 61 /// `/usr/include/security/_pam_types.h`. | 74 /// `/usr/include/security/_pam_types.h`. |
| 62 #[allow(non_camel_case_types, dead_code)] | 75 #[allow(non_camel_case_types, dead_code)] |
| 63 #[derive(Copy, Clone, Debug, PartialEq, thiserror::Error, FromPrimitive)] | 76 #[derive(Copy, Clone, Debug, PartialEq, thiserror::Error, FromPrimitive)] |
| 125 ConversationAgain = 30, | 138 ConversationAgain = 30, |
| 126 #[error("call this function again to complete authentication stack")] | 139 #[error("call this function again to complete authentication stack")] |
| 127 Incomplete = 31, | 140 Incomplete = 31, |
| 128 } | 141 } |
| 129 | 142 |
| 130 pub type PamResult<T> = Result<T, ErrorCode>; | 143 /// A PAM-specific Result type with an [ErrorCode] error. |
| 144 pub type Result<T> = std::result::Result<T, ErrorCode>; | |
| 145 | |
| 131 impl ErrorCode { | 146 impl ErrorCode { |
| 132 /// Converts a PamResult into the result code that C wants. | 147 /// Converts this [Result] into a C-compatible result code. |
| 133 pub fn result_to_c(value: PamResult<()>) -> c_int { | 148 pub fn result_to_c<T>(value: Result<T>) -> c_int { |
| 134 match value { | 149 match value { |
| 135 Ok(_) => 0, // PAM_SUCCESS | 150 Ok(_) => 0, // PAM_SUCCESS |
| 136 Err(otherwise) => otherwise.into(), | 151 Err(otherwise) => otherwise.into(), |
| 137 } | 152 } |
| 138 } | 153 } |
| 139 | 154 |
| 140 /// Converts a C result code into a PamResult, with success as Ok. | 155 /// Converts a C result code into a [Result], with success as Ok. |
| 141 /// Invalid values are returned as a [Self::SystemError]. | 156 /// Invalid values are returned as a [Self::SystemError]. |
| 142 pub fn result_from(value: c_int) -> PamResult<()> { | 157 pub fn result_from(value: c_int) -> Result<()> { |
| 143 match value { | 158 match value { |
| 144 0 => Ok(()), | 159 0 => Ok(()), |
| 145 value => Err(value.try_into().unwrap_or(Self::SystemError)), | 160 value => Err(value.try_into().unwrap_or(Self::SystemError)), |
| 146 } | 161 } |
| 147 } | 162 } |
| 148 } | 163 } |
| 149 | 164 |
| 150 impl TryFrom<c_int> for ErrorCode { | 165 impl TryFrom<c_int> for ErrorCode { |
| 151 type Error = InvalidEnum<Self>; | 166 type Error = InvalidEnum<Self>; |
| 152 | 167 |
| 153 fn try_from(value: c_int) -> Result<Self, Self::Error> { | 168 fn try_from(value: c_int) -> std::result::Result<Self, Self::Error> { |
| 154 Self::from_i32(value).ok_or(value.into()) | 169 Self::from_i32(value).ok_or(value.into()) |
| 155 } | 170 } |
| 156 } | 171 } |
| 157 | 172 |
| 158 impl From<ErrorCode> for c_int { | 173 impl From<ErrorCode> for c_int { |
| 161 } | 176 } |
| 162 } | 177 } |
| 163 | 178 |
| 164 /// Error returned when attempting to coerce an invalid C integer into an enum. | 179 /// Error returned when attempting to coerce an invalid C integer into an enum. |
| 165 #[derive(thiserror::Error)] | 180 #[derive(thiserror::Error)] |
| 166 #[error("{} is not a valid {}", .0, any::type_name::<T>())] | 181 #[error("{0} is not a valid {type}", type = any::type_name::<T>())] |
| 167 #[derive(Debug, PartialEq)] | 182 #[derive(Debug, PartialEq)] |
| 168 pub struct InvalidEnum<T>(std::ffi::c_int, PhantomData<T>); | 183 pub struct InvalidEnum<T>(c_int, PhantomData<T>); |
| 169 | 184 |
| 170 impl<T> From<std::ffi::c_int> for InvalidEnum<T> { | 185 impl<T> From<InvalidEnum<T>> for c_int { |
| 171 fn from(value: std::ffi::c_int) -> Self { | 186 fn from(value: InvalidEnum<T>) -> Self { |
| 187 value.0 | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 impl<T> From<c_int> for InvalidEnum<T> { | |
| 192 fn from(value: c_int) -> Self { | |
| 172 Self(value, PhantomData) | 193 Self(value, PhantomData) |
| 173 } | 194 } |
| 174 } | 195 } |
| 175 | 196 |
| 176 #[cfg(test)] | 197 #[cfg(test)] |
| 178 use super::*; | 199 use super::*; |
| 179 | 200 |
| 180 #[test] | 201 #[test] |
| 181 fn test_enums() { | 202 fn test_enums() { |
| 182 assert_eq!(Ok(MessageStyle::ErrorMsg), 3.try_into()); | 203 assert_eq!(Ok(MessageStyle::ErrorMsg), 3.try_into()); |
| 183 assert_eq!(Err(999.into()), ErrorCode::try_from(999)); | 204 assert_eq!(Err(InvalidEnum::from(999)), ErrorCode::try_from(999)); |
| 184 assert_eq!(Ok(()), ErrorCode::result_from(0)); | 205 assert_eq!(Ok(()), ErrorCode::result_from(0)); |
| 185 assert_eq!(Err(ErrorCode::Abort), ErrorCode::result_from(26)); | 206 assert_eq!(Err(ErrorCode::Abort), ErrorCode::result_from(26)); |
| 186 assert_eq!(Err(ErrorCode::SystemError), ErrorCode::result_from(423)); | 207 assert_eq!(Err(ErrorCode::SystemError), ErrorCode::result_from(423)); |
| 187 } | 208 assert!(InvalidEnum::<MessageStyle>(33, PhantomData) |
| 188 } | 209 .to_string() |
| 210 .starts_with("33 is not a valid ")); | |
| 211 } | |
| 212 } |
