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 } |