Mercurial > crates > nonstick
comparison src/constants.rs @ 90:f6186e41399b
Miscellaneous fixes and cleanup:
- Rename `get_user` to `username` and `get_authtok` to `authtok`.
- Use pam_strerror for error messages.
- Add library linkage to build.rs (it was missing???).
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sat, 14 Jun 2025 09:30:16 -0400 |
parents | 05291b601f0a |
children | 5ddbcada30f2 |
comparison
equal
deleted
inserted
replaced
89:dd3e9c4bcde3 | 90:f6186e41399b |
---|---|
7 #[cfg(feature = "link")] | 7 #[cfg(feature = "link")] |
8 use crate::libpam::pam_ffi; | 8 use crate::libpam::pam_ffi; |
9 use bitflags::bitflags; | 9 use bitflags::bitflags; |
10 use libc::c_int; | 10 use libc::c_int; |
11 use num_enum::{IntoPrimitive, TryFromPrimitive}; | 11 use num_enum::{IntoPrimitive, TryFromPrimitive}; |
12 use std::error::Error; | |
12 use std::ffi::c_uint; | 13 use std::ffi::c_uint; |
14 use std::fmt; | |
15 use std::fmt::{Display, Formatter}; | |
13 use std::result::Result as StdResult; | 16 use std::result::Result as StdResult; |
14 | 17 |
15 /// Arbitrary values for PAM constants when not linking against system PAM. | 18 /// Arbitrary values for PAM constants when not linking against system PAM. |
16 /// | 19 /// |
17 /// **The values of these constants are deliberately selected _not_ to match | 20 /// **The values of these constants are deliberately selected _not_ to match |
75 PAM_SYMBOL_ERR = 550, | 78 PAM_SYMBOL_ERR = 550, |
76 PAM_SYSTEM_ERR = 551, | 79 PAM_SYSTEM_ERR = 551, |
77 PAM_TRY_AGAIN = 552, | 80 PAM_TRY_AGAIN = 552, |
78 PAM_USER_UNKNOWN = 553 | 81 PAM_USER_UNKNOWN = 553 |
79 ); | 82 ); |
83 | |
84 fn strerror(val: c_uint) -> Option<&'static str> { | |
85 None | |
86 } | |
80 } | 87 } |
81 | 88 |
82 bitflags! { | 89 bitflags! { |
83 /// The available PAM flags. | 90 /// The available PAM flags. |
84 /// | 91 /// |
138 /// | 145 /// |
139 /// Most abbreviations (except `AuthTok` and `Max`) are now full words. | 146 /// Most abbreviations (except `AuthTok` and `Max`) are now full words. |
140 /// For more detailed information, see | 147 /// For more detailed information, see |
141 /// `/usr/include/security/_pam_types.h`. | 148 /// `/usr/include/security/_pam_types.h`. |
142 #[allow(non_camel_case_types, dead_code)] | 149 #[allow(non_camel_case_types, dead_code)] |
143 #[derive(Copy, Clone, Debug, PartialEq, thiserror::Error, TryFromPrimitive, IntoPrimitive)] | 150 #[derive(Copy, Clone, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)] |
144 #[non_exhaustive] // C might give us anything! | 151 #[non_exhaustive] // C might give us anything! |
145 #[repr(u32)] | 152 #[repr(u32)] |
146 pub enum ErrorCode { | 153 pub enum ErrorCode { |
147 #[error("dlopen() failure when dynamically loading a service module")] | |
148 OpenError = pam_ffi::PAM_OPEN_ERR, | 154 OpenError = pam_ffi::PAM_OPEN_ERR, |
149 #[error("symbol not found")] | |
150 SymbolError = pam_ffi::PAM_SYMBOL_ERR, | 155 SymbolError = pam_ffi::PAM_SYMBOL_ERR, |
151 #[error("error in service module")] | |
152 ServiceError = pam_ffi::PAM_SERVICE_ERR, | 156 ServiceError = pam_ffi::PAM_SERVICE_ERR, |
153 #[error("system error")] | |
154 SystemError = pam_ffi::PAM_SYSTEM_ERR, | 157 SystemError = pam_ffi::PAM_SYSTEM_ERR, |
155 #[error("memory buffer error")] | |
156 BufferError = pam_ffi::PAM_BUF_ERR, | 158 BufferError = pam_ffi::PAM_BUF_ERR, |
157 #[error("permission denied")] | |
158 PermissionDenied = pam_ffi::PAM_PERM_DENIED, | 159 PermissionDenied = pam_ffi::PAM_PERM_DENIED, |
159 #[error("authentication failure")] | |
160 AuthenticationError = pam_ffi::PAM_AUTH_ERR, | 160 AuthenticationError = pam_ffi::PAM_AUTH_ERR, |
161 #[error("cannot access authentication data due to insufficient credentials")] | |
162 CredentialsInsufficient = pam_ffi::PAM_CRED_INSUFFICIENT, | 161 CredentialsInsufficient = pam_ffi::PAM_CRED_INSUFFICIENT, |
163 #[error("underlying authentication service cannot retrieve authentication information")] | |
164 AuthInfoUnavailable = pam_ffi::PAM_AUTHINFO_UNAVAIL, | 162 AuthInfoUnavailable = pam_ffi::PAM_AUTHINFO_UNAVAIL, |
165 #[error("user not known to the underlying authentication module")] | |
166 UserUnknown = pam_ffi::PAM_USER_UNKNOWN, | 163 UserUnknown = pam_ffi::PAM_USER_UNKNOWN, |
167 #[error("retry limit reached; do not attempt further")] | |
168 MaxTries = pam_ffi::PAM_MAXTRIES, | 164 MaxTries = pam_ffi::PAM_MAXTRIES, |
169 #[error("new authentication token required")] | |
170 NewAuthTokRequired = pam_ffi::PAM_NEW_AUTHTOK_REQD, | 165 NewAuthTokRequired = pam_ffi::PAM_NEW_AUTHTOK_REQD, |
171 #[error("user account has expired")] | |
172 AccountExpired = pam_ffi::PAM_ACCT_EXPIRED, | 166 AccountExpired = pam_ffi::PAM_ACCT_EXPIRED, |
173 #[error("cannot make/remove an entry for the specified session")] | |
174 SessionError = pam_ffi::PAM_SESSION_ERR, | 167 SessionError = pam_ffi::PAM_SESSION_ERR, |
175 #[error("underlying authentication service cannot retrieve user credentials")] | |
176 CredentialsUnavailable = pam_ffi::PAM_CRED_UNAVAIL, | 168 CredentialsUnavailable = pam_ffi::PAM_CRED_UNAVAIL, |
177 #[error("user credentials expired")] | |
178 CredentialsExpired = pam_ffi::PAM_CRED_EXPIRED, | 169 CredentialsExpired = pam_ffi::PAM_CRED_EXPIRED, |
179 #[error("failure setting user credentials")] | |
180 CredentialsError = pam_ffi::PAM_CRED_ERR, | 170 CredentialsError = pam_ffi::PAM_CRED_ERR, |
181 #[error("no module-specific data is present")] | |
182 NoModuleData = pam_ffi::PAM_NO_MODULE_DATA, | 171 NoModuleData = pam_ffi::PAM_NO_MODULE_DATA, |
183 #[error("conversation error")] | |
184 ConversationError = pam_ffi::PAM_CONV_ERR, | 172 ConversationError = pam_ffi::PAM_CONV_ERR, |
185 #[error("authentication token manipulation error")] | |
186 AuthTokError = pam_ffi::PAM_AUTHTOK_ERR, | 173 AuthTokError = pam_ffi::PAM_AUTHTOK_ERR, |
187 #[error("authentication information cannot be recovered")] | |
188 AuthTokRecoveryError = pam_ffi::PAM_AUTHTOK_RECOVERY_ERR, | 174 AuthTokRecoveryError = pam_ffi::PAM_AUTHTOK_RECOVERY_ERR, |
189 #[error("authentication token lock busy")] | |
190 AuthTokLockBusy = pam_ffi::PAM_AUTHTOK_LOCK_BUSY, | 175 AuthTokLockBusy = pam_ffi::PAM_AUTHTOK_LOCK_BUSY, |
191 #[error("authentication token aging disabled")] | |
192 AuthTokDisableAging = pam_ffi::PAM_AUTHTOK_DISABLE_AGING, | 176 AuthTokDisableAging = pam_ffi::PAM_AUTHTOK_DISABLE_AGING, |
193 #[error("preliminary password check failed")] | |
194 TryAgain = pam_ffi::PAM_TRY_AGAIN, | 177 TryAgain = pam_ffi::PAM_TRY_AGAIN, |
195 #[error("ignore underlying account module, regardless of control flag")] | |
196 Ignore = pam_ffi::PAM_IGNORE, | 178 Ignore = pam_ffi::PAM_IGNORE, |
197 #[error("critical error; this module should fail now")] | |
198 Abort = pam_ffi::PAM_ABORT, | 179 Abort = pam_ffi::PAM_ABORT, |
199 #[error("authentication token has expired")] | |
200 AuthTokExpired = pam_ffi::PAM_AUTHTOK_EXPIRED, | 180 AuthTokExpired = pam_ffi::PAM_AUTHTOK_EXPIRED, |
201 #[error("module is not known")] | |
202 ModuleUnknown = pam_ffi::PAM_MODULE_UNKNOWN, | 181 ModuleUnknown = pam_ffi::PAM_MODULE_UNKNOWN, |
203 #[error("bad item passed to pam_[whatever]_item")] | |
204 BadItem = pam_ffi::PAM_BAD_ITEM, | 182 BadItem = pam_ffi::PAM_BAD_ITEM, |
205 #[cfg(feature = "linux-pam-extensions")] | 183 #[cfg(feature = "linux-pam-extensions")] |
206 #[error("conversation function is event-driven and data is not available yet")] | |
207 ConversationAgain = pam_ffi::PAM_CONV_AGAIN, | 184 ConversationAgain = pam_ffi::PAM_CONV_AGAIN, |
208 #[cfg(feature = "linux-pam-extensions")] | 185 #[cfg(feature = "linux-pam-extensions")] |
209 #[error("call this function again to complete authentication stack")] | |
210 Incomplete = pam_ffi::PAM_INCOMPLETE, | 186 Incomplete = pam_ffi::PAM_INCOMPLETE, |
211 } | 187 } |
212 | 188 |
213 /// A PAM-specific Result type with an [ErrorCode] error. | 189 /// A PAM-specific Result type with an [ErrorCode] error. |
214 pub type Result<T> = StdResult<T, ErrorCode>; | 190 pub type Result<T> = StdResult<T, ErrorCode>; |
191 | |
192 impl Display for ErrorCode { | |
193 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { | |
194 match pam_ffi::strerror((*self).into()) { | |
195 Some(err) => f.write_str(err), | |
196 None => self.fmt_internal(f), | |
197 } | |
198 } | |
199 } | |
200 | |
201 impl Error for ErrorCode {} | |
215 | 202 |
216 impl ErrorCode { | 203 impl ErrorCode { |
217 /// Converts this [Result] into a C-compatible result code. | 204 /// Converts this [Result] into a C-compatible result code. |
218 pub fn result_to_c<T>(value: Result<T>) -> c_int { | 205 pub fn result_to_c<T>(value: Result<T>) -> c_int { |
219 match value { | 206 match value { |
227 pub fn result_from(value: c_int) -> Result<()> { | 214 pub fn result_from(value: c_int) -> Result<()> { |
228 match value { | 215 match value { |
229 0 => Ok(()), | 216 0 => Ok(()), |
230 value => Err((value as u32).try_into().unwrap_or(Self::SystemError)), | 217 value => Err((value as u32).try_into().unwrap_or(Self::SystemError)), |
231 } | 218 } |
219 } | |
220 | |
221 /// A basic Display implementation for if we don't link against PAM. | |
222 fn fmt_internal(self, f: &mut Formatter<'_>) -> fmt::Result { | |
223 write!(f, "PAM error: {self:?} ({n})", n = self as c_uint) | |
232 } | 224 } |
233 } | 225 } |
234 | 226 |
235 /// Returned when text that should not have any `\0` bytes in it does. | 227 /// Returned when text that should not have any `\0` bytes in it does. |
236 /// Analogous to [`std::ffi::NulError`], but the data it was created from | 228 /// Analogous to [`std::ffi::NulError`], but the data it was created from |