Mercurial > crates > nonstick
comparison src/constants.rs @ 56:daa2cde64601
Big big refactor. Probably should have been multiple changes.
- Makes FFI safer by explicitly specifying c_int in calls.
- Uses ToPrimitive/FromPrimitive to make this easier.
- Pulls PamFlag variables into a bitflags! struct.
- Pulls PamMessageStyle variables into an enum.
- Renames ResultCode to ErrorCode.
- Switches from PAM_SUCCESS to using a Result<(), ErrorCode>.
- Uses thiserror to make ErrorCode into an Error.
- Gets rid of pam_try! because now we have Results.
- Expands some names (e.g. Conv to Conversation).
- Adds more doc comments.
- Returns passwords as a SecureString, to avoid unnecessarily
keeping it around in memory.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Sun, 04 May 2025 02:56:55 -0400 |
| parents | 676675c3d434 |
| children | 3f4a77aa88be |
comparison
equal
deleted
inserted
replaced
| 55:676675c3d434 | 56:daa2cde64601 |
|---|---|
| 1 use bitflags::bitflags; | |
| 1 use libc::{c_int, c_uint}; | 2 use libc::{c_int, c_uint}; |
| 2 | 3 use num_derive::{FromPrimitive, ToPrimitive}; |
| 4 use num_traits::{FromPrimitive, ToPrimitive}; | |
| 3 // TODO: Import constants from C header file at compile time. | 5 // TODO: Import constants from C header file at compile time. |
| 4 | |
| 5 pub type PamFlag = c_uint; | |
| 6 pub type PamItemType = c_int; | |
| 7 pub type PamMessageStyle = c_int; | |
| 8 | 6 |
| 9 // The Linux-PAM flags | 7 // The Linux-PAM flags |
| 10 // see /usr/include/security/_pam_types.h | 8 // see /usr/include/security/_pam_types.h |
| 11 pub const PAM_SILENT: PamFlag = 0x8000; | 9 bitflags! { |
| 12 pub const PAM_DISALLOW_NULL_AUTHTOK: PamFlag = 0x0001; | 10 #[derive(Debug, PartialEq)] |
| 13 pub const PAM_ESTABLISH_CRED: PamFlag = 0x0002; | 11 #[repr(transparent)] |
| 14 pub const PAM_DELETE_CRED: PamFlag = 0x0004; | 12 pub struct Flags: c_uint { |
| 15 pub const PAM_REINITIALIZE_CRED: PamFlag = 0x0008; | 13 const SILENT = 0x8000; |
| 16 pub const PAM_REFRESH_CRED: PamFlag = 0x0010; | 14 const DISALLOW_NULL_AUTHTOK = 0x0001; |
| 17 pub const PAM_CHANGE_EXPIRED_AUTHTOK: PamFlag = 0x0020; | 15 const ESTABLISH_CRED = 0x0002; |
| 16 const DELETE_CRED = 0x0004; | |
| 17 const REINITIALIZE_CRED = 0x0008; | |
| 18 const REFRESH_CRED = 0x0010; | |
| 19 const CHANGE_EXPIRED_AUTHTOK= 0x0020; | |
| 20 } | |
| 21 } | |
| 18 | 22 |
| 19 // Message styles | 23 /// Styles of message that are shown to the user. |
| 20 pub const PAM_PROMPT_ECHO_OFF: PamMessageStyle = 1; | 24 #[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)] |
| 21 pub const PAM_PROMPT_ECHO_ON: PamMessageStyle = 2; | 25 #[non_exhaustive] // non-exhaustive because C might give us back anything! |
| 22 pub const PAM_ERROR_MSG: PamMessageStyle = 3; | 26 pub enum MessageStyle { |
| 23 pub const PAM_TEXT_INFO: PamMessageStyle = 4; | 27 /// Requests information from the user; will be masked when typing. |
| 24 /// yes/no/maybe conditionals | 28 PromptEchoOff = 1, |
| 25 pub const PAM_RADIO_TYPE: PamMessageStyle = 5; | 29 /// Requests information from the user; will not be masked. |
| 26 pub const PAM_BINARY_PROMPT: PamMessageStyle = 7; | 30 PromptEchoOn = 2, |
| 31 /// An error message. | |
| 32 ErrorMsg = 3, | |
| 33 /// An informational message. | |
| 34 TextInfo = 4, | |
| 35 /// Yes/No/Maybe conditionals. Linux-PAM specific. | |
| 36 RadioType = 5, | |
| 37 /// For server–client non-human interaction. | |
| 38 /// NOT part of the X/Open PAM specification. | |
| 39 BinaryPrompt = 7, | |
| 40 } | |
| 27 | 41 |
| 28 /// The Linux-PAM return values. | 42 impl From<MessageStyle> for c_int { |
| 43 fn from(val: MessageStyle) -> Self { | |
| 44 val.to_i32().unwrap_or(0) | |
| 45 } | |
| 46 } | |
| 47 | |
| 48 /// The Linux-PAM error return values. | |
| 49 /// Success is instead represented by the `Ok` entry of a `Result`. | |
| 50 /// Most abbreviations (except `AuthTok` and `Max`) are now full words. | |
| 29 /// For more detailed information, see | 51 /// For more detailed information, see |
| 30 /// /usr/include/security/_pam_types.h | 52 /// `/usr/include/security/_pam_types.h`. |
| 31 #[allow(non_camel_case_types, dead_code)] | 53 #[allow(non_camel_case_types, dead_code)] |
| 32 #[derive(Debug, PartialEq, thiserror::Error)] | 54 #[derive(Copy, Clone, Debug, PartialEq, thiserror::Error, FromPrimitive, ToPrimitive)] |
| 33 #[repr(C)] | 55 #[non_exhaustive] // C might give us anything! |
| 34 pub enum PamResultCode { | 56 pub enum ErrorCode { |
| 35 #[error("Not an error")] | |
| 36 PAM_SUCCESS = 0, | |
| 37 #[error("dlopen() failure when dynamically loading a service module")] | 57 #[error("dlopen() failure when dynamically loading a service module")] |
| 38 PAM_OPEN_ERR = 1, | 58 OpenError = 1, |
| 39 #[error("symbol not found")] | 59 #[error("symbol not found")] |
| 40 PAM_SYMBOL_ERR = 2, | 60 SymbolError = 2, |
| 41 #[error("error in service module")] | 61 #[error("error in service module")] |
| 42 PAM_SERVICE_ERR = 3, | 62 ServiceError = 3, |
| 43 #[error("system error")] | 63 #[error("system error")] |
| 44 PAM_SYSTEM_ERR = 4, | 64 SystemError = 4, |
| 45 #[error("memory buffer error")] | 65 #[error("memory buffer error")] |
| 46 PAM_BUF_ERR = 5, | 66 BufferError = 5, |
| 47 #[error("permission denied")] | 67 #[error("permission denied")] |
| 48 PAM_PERM_DENIED = 6, | 68 PermissionDenied = 6, |
| 49 #[error("authentication failure")] | 69 #[error("authentication failure")] |
| 50 PAM_AUTH_ERR = 7, | 70 AuthenticationError = 7, |
| 51 #[error("cannot access authentication data due to insufficient credentials")] | 71 #[error("cannot access authentication data due to insufficient credentials")] |
| 52 PAM_CRED_INSUFFICIENT = 8, | 72 CredentialsInsufficient = 8, |
| 53 #[error("underlying authentication service cannot retrieve authentication information")] | 73 #[error("underlying authentication service cannot retrieve authentication information")] |
| 54 PAM_AUTHINFO_UNAVAIL = 9, | 74 AuthInfoUnavailable = 9, |
| 55 #[error("user not known to the underlying authentication module")] | 75 #[error("user not known to the underlying authentication module")] |
| 56 PAM_USER_UNKNOWN = 10, | 76 UserUnknown = 10, |
| 57 #[error("retry limit reached; do not attempt further")] | 77 #[error("retry limit reached; do not attempt further")] |
| 58 PAM_MAXTRIES = 11, | 78 MaxTries = 11, |
| 59 #[error("new authentication token required")] | 79 #[error("new authentication token required")] |
| 60 PAM_NEW_AUTHTOK_REQD = 12, | 80 NewAuthTokRequired = 12, |
| 61 #[error("user account has expired")] | 81 #[error("user account has expired")] |
| 62 PAM_ACCT_EXPIRED = 13, | 82 AccountExpired = 13, |
| 63 #[error("cannot make/remove an entry for the specified session")] | 83 #[error("cannot make/remove an entry for the specified session")] |
| 64 PAM_SESSION_ERR = 14, | 84 SessionError = 14, |
| 65 #[error("underlying authentication service cannot retrieve user credentials")] | 85 #[error("underlying authentication service cannot retrieve user credentials")] |
| 66 PAM_CRED_UNAVAIL = 15, | 86 CredentialsUnavailable = 15, |
| 67 #[error("user credentials expired")] | 87 #[error("user credentials expired")] |
| 68 PAM_CRED_EXPIRED = 16, | 88 CredentialsExpired = 16, |
| 69 #[error("failure setting user credentials")] | 89 #[error("failure setting user credentials")] |
| 70 PAM_CRED_ERR = 17, | 90 CredentialsError = 17, |
| 71 #[error("no module-specific data is present")] | 91 #[error("no module-specific data is present")] |
| 72 PAM_NO_MODULE_DATA = 18, | 92 NoModuleData = 18, |
| 73 #[error("conversation error")] | 93 #[error("conversation error")] |
| 74 PAM_CONV_ERR = 19, | 94 ConversationError = 19, |
| 75 #[error("authentication token manipulation error")] | 95 #[error("authentication token manipulation error")] |
| 76 PAM_AUTHTOK_ERR = 20, | 96 AuthTokError = 20, |
| 77 #[error("authentication information cannot be recovered")] | 97 #[error("authentication information cannot be recovered")] |
| 78 PAM_AUTHTOK_RECOVERY_ERR = 21, | 98 AuthTokRecoveryError = 21, |
| 79 #[error("authentication token lock busy")] | 99 #[error("authentication token lock busy")] |
| 80 PAM_AUTHTOK_LOCK_BUSY = 22, | 100 AuthTokLockBusy = 22, |
| 81 #[error("authentication token aging disabled")] | 101 #[error("authentication token aging disabled")] |
| 82 PAM_AUTHTOK_DISABLE_AGING = 23, | 102 AuthTokDisableAging = 23, |
| 83 #[error("preliminary check by password service")] | 103 #[error("preliminary check by password service")] |
| 84 PAM_TRY_AGAIN = 24, | 104 TryAgain = 24, |
| 85 #[error("ignore underlying account module, regardless of control flag")] | 105 #[error("ignore underlying account module, regardless of control flag")] |
| 86 PAM_IGNORE = 25, | 106 Ignore = 25, |
| 87 #[error("critical error; this module should fail now")] | 107 #[error("critical error; this module should fail now")] |
| 88 PAM_ABORT = 26, | 108 Abort = 26, |
| 89 #[error("authentication token has expired")] | 109 #[error("authentication token has expired")] |
| 90 PAM_AUTHTOK_EXPIRED = 27, | 110 AuthTokExpired = 27, |
| 91 #[error("module is not known")] | 111 #[error("module is not known")] |
| 92 PAM_MODULE_UNKNOWN = 28, | 112 ModuleUnknown = 28, |
| 93 #[error("bad item passed to pam_[whatever]_item")] | 113 #[error("bad item passed to pam_[whatever]_item")] |
| 94 PAM_BAD_ITEM = 29, | 114 BadItem = 29, |
| 95 #[error("conversation function is event-driven and data is not available yet")] | 115 #[error("conversation function is event-driven and data is not available yet")] |
| 96 PAM_CONV_AGAIN = 30, | 116 ConversationAgain = 30, |
| 97 #[error("call this function again to complete authentication stack")] | 117 #[error("call this function again to complete authentication stack")] |
| 98 PAM_INCOMPLETE = 31, | 118 Incomplete = 31, |
| 99 } | 119 } |
| 120 | |
| 121 pub type PamResult<T> = Result<T, ErrorCode>; | |
| 122 impl ErrorCode { | |
| 123 /// Converts a PamResult into the result code that C wants. | |
| 124 pub fn result_to_c(value: PamResult<()>) -> c_int { | |
| 125 match value { | |
| 126 Ok(_) => 0, // PAM_SUCCESS | |
| 127 Err(otherwise) => otherwise.into(), | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 /// Converts a C result code into a PamResult, with success as Ok. | |
| 132 pub fn result_from(value: c_int) -> PamResult<()> { | |
| 133 match value { | |
| 134 0 => Ok(()), | |
| 135 value => Err(Self::from_i64(value as i64).unwrap_or(Self::ConversationError)) | |
| 136 } | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 impl From<ErrorCode> for c_int { | |
| 141 fn from(val: ErrorCode) -> Self { | |
| 142 val.to_i32().unwrap_or(0) | |
| 143 } | |
| 144 } |
