Mercurial > crates > nonstick
comparison src/constants.rs @ 59:3f4a77aa88be
Fix string copyting and improve error situation.
This change is too big and includes several things:
- Fix copying strings from PAM by fixing const and mut on pam funcs.
- Improve error enums by simplifying conversions and removing
unnecessary and ambiguous "success" variants.
- Make a bunch of casts nicer.
- Assorted other cleanup.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Wed, 21 May 2025 00:27:18 -0400 |
| parents | daa2cde64601 |
| children | 05cc2c27334f |
comparison
equal
deleted
inserted
replaced
| 58:868a278a362c | 59:3f4a77aa88be |
|---|---|
| 1 use bitflags::bitflags; | 1 use bitflags::bitflags; |
| 2 use libc::{c_int, c_uint}; | 2 use libc::{c_int, c_uint}; |
| 3 use num_derive::{FromPrimitive, ToPrimitive}; | 3 use num_derive::FromPrimitive; |
| 4 use num_traits::{FromPrimitive, ToPrimitive}; | 4 use num_traits::FromPrimitive; |
| 5 use std::any; | |
| 6 use std::marker::PhantomData; | |
| 5 // TODO: Import constants from C header file at compile time. | 7 // TODO: Import constants from C header file at compile time. |
| 6 | 8 |
| 7 // The Linux-PAM flags | 9 // The Linux-PAM flags |
| 8 // see /usr/include/security/_pam_types.h | 10 // see /usr/include/security/_pam_types.h |
| 9 bitflags! { | 11 bitflags! { |
| 19 const CHANGE_EXPIRED_AUTHTOK= 0x0020; | 21 const CHANGE_EXPIRED_AUTHTOK= 0x0020; |
| 20 } | 22 } |
| 21 } | 23 } |
| 22 | 24 |
| 23 /// Styles of message that are shown to the user. | 25 /// Styles of message that are shown to the user. |
| 24 #[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)] | 26 #[derive(Debug, PartialEq, FromPrimitive)] |
| 25 #[non_exhaustive] // non-exhaustive because C might give us back anything! | 27 #[non_exhaustive] // non-exhaustive because C might give us back anything! |
| 26 pub enum MessageStyle { | 28 pub enum MessageStyle { |
| 27 /// Requests information from the user; will be masked when typing. | 29 /// Requests information from the user; will be masked when typing. |
| 28 PromptEchoOff = 1, | 30 PromptEchoOff = 1, |
| 29 /// Requests information from the user; will not be masked. | 31 /// Requests information from the user; will not be masked. |
| 37 /// For server–client non-human interaction. | 39 /// For server–client non-human interaction. |
| 38 /// NOT part of the X/Open PAM specification. | 40 /// NOT part of the X/Open PAM specification. |
| 39 BinaryPrompt = 7, | 41 BinaryPrompt = 7, |
| 40 } | 42 } |
| 41 | 43 |
| 44 impl TryFrom<c_int> for MessageStyle { | |
| 45 type Error = InvalidEnum<Self>; | |
| 46 fn try_from(value: c_int) -> Result<Self, Self::Error> { | |
| 47 Self::from_i32(value).ok_or(value.into()) | |
| 48 } | |
| 49 } | |
| 50 | |
| 42 impl From<MessageStyle> for c_int { | 51 impl From<MessageStyle> for c_int { |
| 43 fn from(val: MessageStyle) -> Self { | 52 fn from(val: MessageStyle) -> Self { |
| 44 val.to_i32().unwrap_or(0) | 53 val as Self |
| 45 } | 54 } |
| 46 } | 55 } |
| 47 | 56 |
| 48 /// The Linux-PAM error return values. | 57 /// The Linux-PAM error return values. |
| 49 /// Success is instead represented by the `Ok` entry of a `Result`. | 58 /// Success is instead represented by the `Ok` entry of a `Result`. |
| 50 /// Most abbreviations (except `AuthTok` and `Max`) are now full words. | 59 /// Most abbreviations (except `AuthTok` and `Max`) are now full words. |
| 51 /// For more detailed information, see | 60 /// For more detailed information, see |
| 52 /// `/usr/include/security/_pam_types.h`. | 61 /// `/usr/include/security/_pam_types.h`. |
| 53 #[allow(non_camel_case_types, dead_code)] | 62 #[allow(non_camel_case_types, dead_code)] |
| 54 #[derive(Copy, Clone, Debug, PartialEq, thiserror::Error, FromPrimitive, ToPrimitive)] | 63 #[derive(Copy, Clone, Debug, PartialEq, thiserror::Error, FromPrimitive)] |
| 55 #[non_exhaustive] // C might give us anything! | 64 #[non_exhaustive] // C might give us anything! |
| 56 pub enum ErrorCode { | 65 pub enum ErrorCode { |
| 57 #[error("dlopen() failure when dynamically loading a service module")] | 66 #[error("dlopen() failure when dynamically loading a service module")] |
| 58 OpenError = 1, | 67 OpenError = 1, |
| 59 #[error("symbol not found")] | 68 #[error("symbol not found")] |
| 127 Err(otherwise) => otherwise.into(), | 136 Err(otherwise) => otherwise.into(), |
| 128 } | 137 } |
| 129 } | 138 } |
| 130 | 139 |
| 131 /// Converts a C result code into a PamResult, with success as Ok. | 140 /// Converts a C result code into a PamResult, with success as Ok. |
| 141 /// Invalid values are returned as a [Self::SystemError]. | |
| 132 pub fn result_from(value: c_int) -> PamResult<()> { | 142 pub fn result_from(value: c_int) -> PamResult<()> { |
| 133 match value { | 143 match value { |
| 134 0 => Ok(()), | 144 0 => Ok(()), |
| 135 value => Err(Self::from_i64(value as i64).unwrap_or(Self::ConversationError)) | 145 value => Err(value.try_into().unwrap_or(Self::SystemError)), |
| 136 } | 146 } |
| 147 } | |
| 148 } | |
| 149 | |
| 150 impl TryFrom<c_int> for ErrorCode { | |
| 151 type Error = InvalidEnum<Self>; | |
| 152 | |
| 153 fn try_from(value: c_int) -> Result<Self, Self::Error> { | |
| 154 Self::from_i32(value).ok_or(value.into()) | |
| 137 } | 155 } |
| 138 } | 156 } |
| 139 | 157 |
| 140 impl From<ErrorCode> for c_int { | 158 impl From<ErrorCode> for c_int { |
| 141 fn from(val: ErrorCode) -> Self { | 159 fn from(val: ErrorCode) -> Self { |
| 142 val.to_i32().unwrap_or(0) | 160 val as Self |
| 143 } | 161 } |
| 144 } | 162 } |
| 163 | |
| 164 /// Error returned when attempting to coerce an invalid C integer into an enum. | |
| 165 #[derive(thiserror::Error)] | |
| 166 #[error("{} is not a valid {}", .0, any::type_name::<T>())] | |
| 167 #[derive(Debug, PartialEq)] | |
| 168 pub struct InvalidEnum<T>(std::ffi::c_int, PhantomData<T>); | |
| 169 | |
| 170 impl<T> From<std::ffi::c_int> for InvalidEnum<T> { | |
| 171 fn from(value: std::ffi::c_int) -> Self { | |
| 172 Self(value, PhantomData) | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 #[cfg(test)] | |
| 177 mod tests { | |
| 178 use super::*; | |
| 179 | |
| 180 #[test] | |
| 181 fn test_enums() { | |
| 182 assert_eq!(Ok(MessageStyle::ErrorMsg), 3.try_into()); | |
| 183 assert_eq!(Err(999.into()), ErrorCode::try_from(999)); | |
| 184 assert_eq!(Ok(()), ErrorCode::result_from(0)); | |
| 185 assert_eq!(Err(ErrorCode::Abort), ErrorCode::result_from(26)); | |
| 186 assert_eq!(Err(ErrorCode::SystemError), ErrorCode::result_from(423)); | |
| 187 } | |
| 188 } |
