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 }