Mercurial > crates > nonstick
comparison src/constants.rs @ 175:e30775c80b49
Separate #[cfg(feature = "link")] from other features.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Wed, 30 Jul 2025 14:57:12 -0400 |
| parents | 6727cbe56f4a |
| children | 0730f5f2ee2a |
comparison
equal
deleted
inserted
replaced
| 174:9e4ce1631bd3 | 175:e30775c80b49 |
|---|---|
| 1 //! Constants and enum values from the PAM library. | 1 //! Constants and enum values from the PAM library. |
| 2 | 2 |
| 3 use crate::_doc::{linklist, man7, manbsd, mansun, xsso}; | 3 use crate::_doc::{linklist, man7, manbsd, mansun, xsso}; |
| 4 use bitflags::bitflags; | 4 use bitflags::bitflags; |
| 5 use std::error::Error; | 5 use std::error::Error; |
| 6 use std::ffi::c_int; | |
| 7 use std::fmt; | 6 use std::fmt; |
| 8 use std::fmt::{Display, Formatter}; | |
| 9 use std::result::Result as StdResult; | 7 use std::result::Result as StdResult; |
| 10 | 8 |
| 11 macro_rules! wrapper { | 9 macro_rules! wrapper { |
| 12 ( | 10 ( |
| 13 $(#[$m:meta])* | 11 $(#[$m:meta])* |
| 31 } | 29 } |
| 32 } | 30 } |
| 33 | 31 |
| 34 wrapper! { | 32 wrapper! { |
| 35 /// Type of the flags that PAM passes to us (or that we pass to PAM). | 33 /// Type of the flags that PAM passes to us (or that we pass to PAM). |
| 36 pub RawFlags(c_int); | 34 pub RawFlags(i32); |
| 37 } | 35 } |
| 38 wrapper! { | 36 wrapper! { |
| 39 /// The error code that we return to PAM. | 37 /// The error code that we return to PAM. |
| 40 pub ReturnCode(c_int); | 38 pub ReturnCode(i32); |
| 41 } | 39 } |
| 42 | 40 |
| 43 impl ReturnCode { | 41 impl ReturnCode { |
| 44 /// A successful return. | 42 /// A successful return. |
| 45 pub const SUCCESS: Self = Self(0); | 43 pub const SUCCESS: Self = Self(0); |
| 68 | 66 |
| 69 #[cfg(feature = "link")] | 67 #[cfg(feature = "link")] |
| 70 impl From<RawFlags> for $name { | 68 impl From<RawFlags> for $name { |
| 71 #[allow(unused_doc_comments)] | 69 #[allow(unused_doc_comments)] |
| 72 fn from(value: RawFlags) -> Self { | 70 fn from(value: RawFlags) -> Self { |
| 73 let value: c_int = value.into(); | 71 let value: i32 = value.into(); |
| 74 let result = Self::empty(); | 72 let result = Self::empty(); |
| 75 $( | 73 $( |
| 76 $(#[$m_ident $($m_arg)*])* | 74 $(#[$m_ident $($m_arg)*])* |
| 77 let result = result | if value & $value_value == 0 { | 75 let result = result | if value & $value_value == 0 { |
| 78 Self::empty() | 76 Self::empty() |
| 126 /// only be changed if it is expired. If not passed, | 124 /// only be changed if it is expired. If not passed, |
| 127 /// the authentication token should be changed unconditionally. | 125 /// the authentication token should be changed unconditionally. |
| 128 const CHANGE_EXPIRED_AUTHTOK = (link = libpam_sys::PAM_CHANGE_EXPIRED_AUTHTOK, else = 0b10); | 126 const CHANGE_EXPIRED_AUTHTOK = (link = libpam_sys::PAM_CHANGE_EXPIRED_AUTHTOK, else = 0b10); |
| 129 | 127 |
| 130 /// Don't check if the password is any good (Sun only). | 128 /// Don't check if the password is any good (Sun only). |
| 131 #[cfg(pam_impl = "Sun")] | 129 #[cfg(feature = "sun-ext")] |
| 132 const NO_AUTHTOK_CHECK = (link = libpam_sys::PAM_NO_AUTHTOK_CHECK, else = 0b100); | 130 const NO_AUTHTOK_CHECK = (link = libpam_sys::PAM_NO_AUTHTOK_CHECK, else = 0b100); |
| 133 } | 131 } |
| 134 } | 132 } |
| 135 | 133 |
| 136 pam_flags! { | 134 pam_flags! { |
| 138 BaseFlags { | 136 BaseFlags { |
| 139 /// The PAM module should not generate any messages. | 137 /// The PAM module should not generate any messages. |
| 140 const SILENT = (link = libpam_sys::PAM_SILENT, else = 0x8000); | 138 const SILENT = (link = libpam_sys::PAM_SILENT, else = 0x8000); |
| 141 } | 139 } |
| 142 } | 140 } |
| 143 | |
| 144 #[cfg(feature = "openpam-ext")] | |
| 145 const BAD_CONST: ErrorCode = ErrorCode::BadConstant; | |
| 146 #[cfg(not(feature = "openpam-ext"))] | |
| 147 const BAD_CONST: ErrorCode = ErrorCode::SystemError; | |
| 148 | 141 |
| 149 macro_rules! flag_enum { | 142 macro_rules! flag_enum { |
| 150 ( | 143 ( |
| 151 $(#[$m:meta])* | 144 $(#[$m:meta])* |
| 152 $name:ident { | 145 $name:ident { |
| 171 fn try_from(value: RawFlags) -> Result<$name> { | 164 fn try_from(value: RawFlags) -> Result<$name> { |
| 172 match value.0 { | 165 match value.0 { |
| 173 $( | 166 $( |
| 174 $item_value => Ok(Self::$item_name), | 167 $item_value => Ok(Self::$item_name), |
| 175 )* | 168 )* |
| 176 _ => Err(BAD_CONST), | 169 _ => Err(ErrorCode::BAD_CONST), |
| 177 } | 170 } |
| 178 } | 171 } |
| 179 } | 172 } |
| 180 | 173 |
| 181 #[cfg(feature = "link")] | 174 #[cfg(feature = "link")] |
| 196 fn split(value: RawFlags) -> Result<(Option<Self>, RawFlags)> { | 189 fn split(value: RawFlags) -> Result<(Option<Self>, RawFlags)> { |
| 197 let me = value.0 & Self::ALL_VALUES; | 190 let me = value.0 & Self::ALL_VALUES; |
| 198 let them = (value.0 & !Self::ALL_VALUES).into(); | 191 let them = (value.0 & !Self::ALL_VALUES).into(); |
| 199 let me = match RawFlags(me) { | 192 let me = match RawFlags(me) { |
| 200 RawFlags(0) => None, | 193 RawFlags(0) => None, |
| 201 other => Some(Self::try_from(other).map_err(|_| BAD_CONST)?), | 194 other => Some(Self::try_from(other).map_err(|_| ErrorCode::BAD_CONST)?), |
| 202 }; | 195 }; |
| 203 Ok((me, them)) | 196 Ok((me, them)) |
| 204 } | 197 } |
| 205 } | 198 } |
| 206 } | 199 } |
| 252 impl AuthtokAction { | 245 impl AuthtokAction { |
| 253 /// Separates this enum from the remaining [`AuthtokFlags`]. | 246 /// Separates this enum from the remaining [`AuthtokFlags`]. |
| 254 pub(crate) fn extract(value: RawFlags) -> Result<(Self, AuthtokFlags)> { | 247 pub(crate) fn extract(value: RawFlags) -> Result<(Self, AuthtokFlags)> { |
| 255 match Self::split(value)? { | 248 match Self::split(value)? { |
| 256 (Some(act), rest) => Ok((act, AuthtokFlags::from(rest))), | 249 (Some(act), rest) => Ok((act, AuthtokFlags::from(rest))), |
| 257 (None, _) => Err(BAD_CONST), | 250 (None, _) => Err(ErrorCode::BAD_CONST), |
| 258 } | 251 } |
| 259 } | 252 } |
| 260 } | 253 } |
| 261 | 254 |
| 262 /// Constructs an enum which has the values if it's linked | 255 /// Constructs an enum which has the values if it's linked |
| 286 match value.into() { | 279 match value.into() { |
| 287 $( | 280 $( |
| 288 $(#[$im])* | 281 $(#[$im])* |
| 289 $value => Ok(Self::$key), | 282 $value => Ok(Self::$key), |
| 290 )* | 283 )* |
| 291 _ => Err(BAD_CONST), | 284 _ => Err(ErrorCode::BAD_CONST), |
| 292 } | 285 } |
| 293 } | 286 } |
| 294 } | 287 } |
| 295 | 288 |
| 296 #[cfg(feature = "link")] | 289 #[cfg(feature = "link")] |
| 378 } | 371 } |
| 379 | 372 |
| 380 /// A PAM-specific Result type with an [ErrorCode] error. | 373 /// A PAM-specific Result type with an [ErrorCode] error. |
| 381 pub type Result<T> = StdResult<T, ErrorCode>; | 374 pub type Result<T> = StdResult<T, ErrorCode>; |
| 382 | 375 |
| 383 impl Display for ErrorCode { | 376 #[cfg(feature = "link")] |
| 384 #[cfg(all( | 377 impl fmt::Display for ErrorCode { |
| 385 feature = "link", | 378 #[cfg(any(pam_impl = "LinuxPam", pam_impl = "OpenPam", pam_impl = "Sun"))] |
| 386 any(pam_impl = "LinuxPam", pam_impl = "OpenPam", pam_impl = "Sun") | 379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 387 ))] | |
| 388 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { | |
| 389 use std::ffi::CStr; | 380 use std::ffi::CStr; |
| 390 use std::ptr; | 381 use std::ptr; |
| 391 // SAFETY: PAM impls don't care about the PAM handle and always return | 382 // SAFETY: PAM impls don't care about the PAM handle and always return |
| 392 // static strings. | 383 // static strings. |
| 393 let got = unsafe { libpam_sys::pam_strerror(ptr::null(), *self as c_int) }; | 384 let got = unsafe { libpam_sys::pam_strerror(ptr::null(), *self as i32) }; |
| 394 if got.is_null() { | 385 if got.is_null() { |
| 395 // This shouldn't happen. | 386 // This shouldn't happen. |
| 396 write!(f, "PAM error: {self:?} ({:?})", *self as c_int) | 387 write!(f, "PAM error: {self:?} ({:?})", *self as i32) |
| 397 } else { | 388 } else { |
| 398 // SAFETY: We just got this back from PAM and we checked if it's null. | 389 // SAFETY: We just got this back from PAM and we checked if it's null. |
| 399 f.write_str(&unsafe { CStr::from_ptr(got) }.to_string_lossy()) | 390 f.write_str(&unsafe { CStr::from_ptr(got) }.to_string_lossy()) |
| 400 } | 391 } |
| 401 } | 392 } |
| 402 #[cfg(not(all( | 393 #[cfg(not(any(pam_impl = "LinuxPam", pam_impl = "OpenPam", pam_impl = "Sun")))] |
| 403 feature = "link", | 394 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 404 any(pam_impl = "LinuxPam", pam_impl = "OpenPam", pam_impl = "Sun") | 395 fmt::Debug::fmt(self, f) |
| 405 )))] | 396 } |
| 406 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { | 397 } |
| 398 | |
| 399 #[cfg(not(feature = "link"))] | |
| 400 impl fmt::Display for ErrorCode { | |
| 401 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 407 fmt::Debug::fmt(self, f) | 402 fmt::Debug::fmt(self, f) |
| 408 } | 403 } |
| 409 } | 404 } |
| 410 | 405 |
| 411 impl Error for ErrorCode {} | 406 impl Error for ErrorCode {} |
| 412 | 407 |
| 413 #[cfg(feature = "link")] | 408 #[cfg(feature = "link")] |
| 414 impl ErrorCode { | 409 impl ErrorCode { |
| 415 pub(crate) fn result_from(ret: c_int) -> Result<()> { | 410 #[cfg(feature = "openpam-ext")] |
| 411 const BAD_CONST: ErrorCode = ErrorCode::BadConstant; | |
| 412 #[cfg(not(feature = "openpam-ext"))] | |
| 413 const BAD_CONST: ErrorCode = ErrorCode::SystemError; | |
| 414 | |
| 415 | |
| 416 pub(crate) fn result_from(ret: i32) -> Result<()> { | |
| 416 match ret { | 417 match ret { |
| 417 0 => Ok(()), | 418 0 => Ok(()), |
| 418 value => Err(ReturnCode(value).try_into().unwrap_or(BAD_CONST)), | 419 value => Err(ReturnCode(value).try_into().unwrap_or(Self::BAD_CONST)), |
| 419 } | 420 } |
| 420 } | 421 } |
| 421 } | 422 } |
| 422 | 423 |
| 424 #[cfg(feature = "link")] | |
| 423 impl<T> From<Result<T>> for ReturnCode { | 425 impl<T> From<Result<T>> for ReturnCode { |
| 424 fn from(value: Result<T>) -> Self { | 426 fn from(value: Result<T>) -> Self { |
| 425 match value { | 427 match value { |
| 426 Ok(_) => ReturnCode::SUCCESS, | 428 Ok(_) => ReturnCode::SUCCESS, |
| 427 Err(otherwise) => otherwise.into(), | 429 Err(otherwise) => otherwise.into(), |
| 442 ); | 444 ); |
| 443 assert_eq!( | 445 assert_eq!( |
| 444 Result::<()>::Err(ErrorCode::Abort), | 446 Result::<()>::Err(ErrorCode::Abort), |
| 445 ErrorCode::result_from(libpam_sys::PAM_ABORT) | 447 ErrorCode::result_from(libpam_sys::PAM_ABORT) |
| 446 ); | 448 ); |
| 447 assert_eq!(Err(BAD_CONST), ErrorCode::result_from(423)); | 449 assert_eq!(Err(ErrorCode::BAD_CONST), ErrorCode::result_from(423)); |
| 448 } | 450 } |
| 449 | 451 |
| 450 #[test] | 452 #[test] |
| 451 fn test_flags() { | 453 fn test_flags() { |
| 452 assert_eq!( | 454 assert_eq!( |
