diff src/constants.rs @ 130:80c07e5ab22f

Transfer over (almost) completely to using libpam-sys. This reimplements everything in nonstick on top of the new -sys crate. We don't yet use libpam-sys's helpers for binary message payloads. Soon.
author Paul Fisher <paul@pfish.zone>
date Tue, 01 Jul 2025 06:11:43 -0400
parents a12706e42c9d
children a632a8874131
line wrap: on
line diff
--- a/src/constants.rs	Mon Jun 30 23:49:54 2025 -0400
+++ b/src/constants.rs	Tue Jul 01 06:11:43 2025 -0400
@@ -4,29 +4,25 @@
 // between Linux-PAM and OpenPAM header files.
 #![allow(clippy::unnecessary_cast)]
 
-#[cfg(feature = "link")]
-use crate::libpam::pam_ffi;
 use crate::{linklist, man7, manbsd, xsso};
 use bitflags::bitflags;
-use libc::c_int;
+use std::ffi::c_int;
 use num_enum::{IntoPrimitive, TryFromPrimitive};
 use std::error::Error;
-use std::ffi::c_uint;
-use std::fmt;
 use std::fmt::{Display, Formatter};
 use std::result::Result as StdResult;
+use std::fmt;
 
-/// Arbitrary values for PAM constants when not linking against system PAM.
+/// Values for constants not provided by certain PAM implementations.
 ///
 /// **The values of these constants are deliberately selected _not_ to match
 /// any PAM implementations. Applications should always use the symbolic value
 /// and not a magic number.**
-#[cfg(not(feature = "link"))]
 mod pam_ffi {
-    use std::ffi::c_uint;
+    pub use libpam_sys::*;
 
     macro_rules! define {
-        ($(#[$attr:meta])* $($name:ident = $value:expr),+) => {
+        ($(#[$attr:meta])* $($name:ident = $value:expr;)+) => {
             define!(
                 @meta { $(#[$attr])* }
                 $(pub const $name: i32 = $value;)+
@@ -35,60 +31,32 @@
         (@meta $m:tt $($i:item)+) => { define!(@expand $($m $i)+); };
         (@expand $({ $(#[$m:meta])* } $i:item)+) => {$($(#[$m])* $i)+};
     }
-    const fn bit(n: u8) -> i32 {
-        1 << n
-    }
+
+
     define!(
-        PAM_SILENT = bit(13),
-        PAM_DISALLOW_NULL_AUTHTOK = bit(14),
-        PAM_ESTABLISH_CRED = bit(15),
-        PAM_DELETE_CRED = bit(16),
-        PAM_REINITIALIZE_CRED = bit(17),
-        PAM_REFRESH_CRED = bit(18),
-        PAM_CHANGE_EXPIRED_AUTHTOK = bit(19),
-        PAM_PRELIM_CHECK = bit(20),
-        PAM_UPDATE_AUTHTOK = bit(21)
+        /// A fictitious constant for testing purposes.
+        #[cfg(not(feature = "link"))]
+        #[cfg_pam_impl(not("OpenPam"))]
+        PAM_BAD_CONSTANT = 513;
+        PAM_BAD_FEATURE = 514;
     );
 
     define!(
-        PAM_ABORT = 513,
-        PAM_ACCT_EXPIRED = 514,
-        PAM_AUTHINFO_UNAVAIL = 515,
-        PAM_AUTHTOK_DISABLE_AGING = 516,
-        PAM_AUTHTOK_ERR = 517,
-        PAM_AUTHTOK_EXPIRED = 518,
-        PAM_AUTHTOK_LOCK_BUSY = 519,
-        PAM_AUTHTOK_RECOVERY_ERR = 520,
-        PAM_AUTH_ERR = 521,
-        PAM_BAD_ITEM = 522,
-        PAM_BUF_ERR = 533,
-        PAM_CONV_AGAIN = 534,
-        PAM_CONV_ERR = 535,
-        PAM_CRED_ERR = 536,
-        PAM_CRED_EXPIRED = 537,
-        PAM_CRED_INSUFFICIENT = 538,
-        PAM_CRED_UNAVAIL = 539,
-        PAM_IGNORE = 540,
-        PAM_INCOMPLETE = 541,
-        PAM_MAXTRIES = 542,
-        PAM_MODULE_UNKNOWN = 543,
-        PAM_NEW_AUTHTOK_REQD = 544,
-        PAM_NO_MODULE_DATA = 545,
-        PAM_OPEN_ERR = 546,
-        PAM_PERM_DENIED = 547,
-        PAM_SERVICE_ERR = 548,
-        PAM_SESSION_ERR = 549,
-        PAM_SYMBOL_ERR = 550,
-        PAM_SYSTEM_ERR = 551,
-        PAM_TRY_AGAIN = 552,
-        PAM_USER_UNKNOWN = 553
+        /// A fictitious constant for testing purposes.
+        #[cfg(not(feature = "link"))]
+        #[cfg_pam_impl(not(any("LinuxPam", "OpenPam")))]
+        PAM_BAD_ITEM = 515;
+        PAM_MODULE_UNKNOWN = 516;
     );
 
-    /// Dummy implementation of strerror so that it always returns None.
-    pub fn strerror(val: c_uint) -> Option<&'static str> {
-        _ = val;
-        None
-    }
+    define!(
+        /// A fictitious constant for testing purposes.
+        #[cfg(not(feature = "link"))]
+        #[cfg_pam_impl(not("LinuxPam"))]
+        PAM_CONV_AGAIN = 517;
+        PAM_INCOMPLETE = 518;
+    );
+
 }
 
 bitflags! {
@@ -100,24 +68,24 @@
     #[repr(transparent)]
     pub struct Flags: c_int {
         /// The module should not generate any messages.
-        const SILENT = pam_ffi::PAM_SILENT;
+        const SILENT = libpam_sys::PAM_SILENT;
 
         /// The module should return [ErrorCode::AuthError]
         /// if the user has an empty authentication token
         /// rather than immediately accepting them.
-        const DISALLOW_NULL_AUTHTOK = pam_ffi::PAM_DISALLOW_NULL_AUTHTOK;
+        const DISALLOW_NULL_AUTHTOK = libpam_sys::PAM_DISALLOW_NULL_AUTHTOK;
 
         // Flag used for `set_credentials`.
 
         /// Set user credentials for an authentication service.
-        const ESTABLISH_CREDENTIALS = pam_ffi::PAM_ESTABLISH_CRED;
+        const ESTABLISH_CREDENTIALS = libpam_sys::PAM_ESTABLISH_CRED;
         /// Delete user credentials associated with
         /// an authentication service.
-        const DELETE_CREDENTIALS = pam_ffi::PAM_DELETE_CRED;
+        const DELETE_CREDENTIALS = libpam_sys::PAM_DELETE_CRED;
         /// Reinitialize user credentials.
-        const REINITIALIZE_CREDENTIALS = pam_ffi::PAM_REINITIALIZE_CRED;
+        const REINITIALIZE_CREDENTIALS = libpam_sys::PAM_REINITIALIZE_CRED;
         /// Extend the lifetime of user credentials.
-        const REFRESH_CREDENTIALS = pam_ffi::PAM_REFRESH_CRED;
+        const REFRESH_CREDENTIALS = libpam_sys::PAM_REFRESH_CRED;
 
         // Flags used for password changing.
 
@@ -126,7 +94,7 @@
         /// the password service should update all passwords.
         ///
         /// This flag is only used by `change_authtok`.
-        const CHANGE_EXPIRED_AUTHTOK = pam_ffi::PAM_CHANGE_EXPIRED_AUTHTOK;
+        const CHANGE_EXPIRED_AUTHTOK = libpam_sys::PAM_CHANGE_EXPIRED_AUTHTOK;
         /// This is a preliminary check for password changing.
         /// The password should not be changed.
         ///
@@ -134,7 +102,7 @@
         /// Applications may not use this flag.
         ///
         /// This flag is only used by `change_authtok`.
-        const PRELIMINARY_CHECK = pam_ffi::PAM_PRELIM_CHECK;
+        const PRELIMINARY_CHECK = libpam_sys::PAM_PRELIM_CHECK;
         /// The password should actuallyPR be updated.
         /// This and [Self::PRELIMINARY_CHECK] are mutually exclusive.
         ///
@@ -142,7 +110,7 @@
         /// Applications may not use this flag.
         ///
         /// This flag is only used by `change_authtok`.
-        const UPDATE_AUTHTOK = pam_ffi::PAM_UPDATE_AUTHTOK;
+        const UPDATE_AUTHTOK = libpam_sys::PAM_UPDATE_AUTHTOK;
     }
 }
 
@@ -207,7 +175,7 @@
 
 impl Display for ErrorCode {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
-        match pam_ffi::strerror((*self).into()) {
+        match strerror((*self).into()) {
             Some(err) => f.write_str(err),
             None => self.fmt_internal(f),
         }
@@ -236,10 +204,31 @@
 
     /// A basic Display implementation for if we don't link against PAM.
     fn fmt_internal(self, f: &mut Formatter<'_>) -> fmt::Result {
-        write!(f, "PAM error: {self:?} ({n})", n = self as c_uint)
+        let n : c_int = self.into();
+        write!(f, "PAM error: {self:?} ({n})")
     }
 }
 
+/// Gets a string version of an error message.
+#[cfg(feature = "link")]
+pub fn strerror(code: c_int) -> Option<&'static str> {
+    use std::ptr;
+    use std::ffi::CStr;
+    // SAFETY: PAM impls don't care about the PAM handle and always return
+    // static strings.
+    let strerror = unsafe { libpam_sys::pam_strerror(ptr::null(), code as c_int) };
+    // SAFETY: We just got this back from PAM and we checked if it's null.
+    (!strerror.is_null())
+        .then(|| unsafe { CStr::from_ptr(strerror) }.to_str().ok())
+        .flatten()
+}
+
+/// Dummy implementation of strerror so that it always returns None.
+#[cfg(not(feature = "link"))]
+pub fn strerror(_: c_int) -> Option<&'static str> {
+    None
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;