changeset 158:d5b7b28d754e

Add `__TARGET_DEFAULT__` PamImpl and set up for docsrs build. Also fixes some formatting stuff.
author Paul Fisher <paul@pfish.zone>
date Sat, 12 Jul 2025 17:17:37 -0400
parents 0099f2f79f86
children 634cd5f2ac8b
files libpam-sys/README.md libpam-sys/libpam-sys-consts/Cargo.toml libpam-sys/libpam-sys-consts/README.md libpam-sys/libpam-sys-consts/build.rs libpam-sys/libpam-sys-helpers/src/lib.rs libpam-sys/src/lib.rs
diffstat 6 files changed, 72 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/libpam-sys/README.md	Wed Jul 09 16:59:30 2025 -0400
+++ b/libpam-sys/README.md	Sat Jul 12 17:17:37 2025 -0400
@@ -14,7 +14,7 @@
 All build-time configuration is performed by the build script of the [`libpam-sys-consts` crate](https://crates.io/crates/libpam-sys-consts).
 
 Each implementation exports all the functionality available in its respective PAM library.
-`XSso` exports only what is in the [X/SSO specification][xsso].
+`XSso` exports only the subset of the [X/SSO specification][xsso] supported by both OpenPAM and Sun PAM.
 
 ## Testing
 
@@ -23,7 +23,6 @@
 - [`ctest`][ctest] verifies the correctness of the FFI bindings (function/struct alignment, etc.).
 - A kind of scuffed homebrew thing also verifies that the constants are correct.
 
-Testing is mainly accomplished through the `libpam-sys-test` package in this crate's workspace.
 There are some unit tests of glue code and other type checks.
 
 ## Minimum Rust version
--- a/libpam-sys/libpam-sys-consts/Cargo.toml	Wed Jul 09 16:59:30 2025 -0400
+++ b/libpam-sys/libpam-sys-consts/Cargo.toml	Sat Jul 12 17:17:37 2025 -0400
@@ -8,6 +8,16 @@
 rust-version.workspace = true
 license.workspace = true
 
+
+[package.metadata.docs.rs]
+default-target = "x86_64-unknown-linux-gnu"
+
+targets = [
+    "x86_64-apple-darwin",
+    "x86_64-unknown-freebsd",
+    "x86_64-unknown-illumos",
+]
+
 [dependencies]
 libc = "0.2"
 
--- a/libpam-sys/libpam-sys-consts/README.md	Wed Jul 09 16:59:30 2025 -0400
+++ b/libpam-sys/libpam-sys-consts/README.md	Sat Jul 12 17:17:37 2025 -0400
@@ -49,11 +49,16 @@
 
 ## Configuration
 
-By default, this crate automatically detects your libpam version.
-Known implementations are listed in the `PamImpl` enum.
+Known implementations of PAM are listed in the `PamImpl` enum, and your currently installed implementation is automatically detected.
+
+If you need to configure this, you can override it **at build time** with the `LIBPAMSYS_IMPL` environment variable:
 
-You can override this **at build time** by setting the `LIBPAMSYS_IMPL` environment variable to one of those names.
-For example, `LIBPAMSYS_IMPL=OpenPam cargo build` will build this library for OpenPAM.
+- Unset or `` (the default): Probe the currently installed LibPAM to figure out which implementation it is.
+  If LibPAM is not present, this will fall back to `__TARGET_DEFAULT__`.
+- `__TARGET_DEFAULT__`: Select the version of LibPAM most likely to be installed on the current OS.
+  This is a useful setting for cross-compiling.
+- The name of a `PamEnum` entry: The named PAM implementation.
+  For instance, `LIBPAMSYS_IMPL=OpenPam cargo build` will build this library for OpenPAM.
 
 ## MSRV
 
--- a/libpam-sys/libpam-sys-consts/build.rs	Wed Jul 09 16:59:30 2025 -0400
+++ b/libpam-sys/libpam-sys-consts/build.rs	Sat Jul 12 17:17:37 2025 -0400
@@ -6,18 +6,43 @@
 
 include!("src/pam_impl.rs");
 
+/// The strategy to use to detect PAM.
+enum Detect {
+    /// Automatically detect PAM, using the installed implementation if present
+    /// or the OS default if not.
+    Auto,
+    /// Use the default PAM implementation based on the OS.
+    TargetDefault,
+    /// Use the named version of PAM.
+    Specified(PamImpl),
+}
+
+const TARGET_DEFAULT: &str = "__TARGET_DEFAULT__";
+
 fn main() {
-    let pam_impl = match option_env!("LIBPAMSYS_IMPL") {
-        // The default option: Guess what PAM impl we're using based on OS.
-        None | Some("") => LibPam::detect(),
-        Some(other) => match PamImpl::try_from(other) {
-            Ok(i) => i,
-            Err(_) => {
-                panic!(
-                    "unknown PAM implementation {other:?}. valid LIBPAMSYS_IMPLs are {:?}, or unset to detect", PamImpl::items()
-                )
-            }
+    let detection = match option_env!("LIBPAMSYS_IMPL") {
+        None | Some("") => match option_env!("DOCS_RS") {
+            // docs.rs cross-compiles, so we don't want to look at
+            // its currently-installed PAM; instead we want to use the OS.
+            Some(_) => Detect::TargetDefault,
+            // In other cases, just auto-detect the actual installed library.
+            None => Detect::Auto,
         },
+        Some(TARGET_DEFAULT) => Detect::TargetDefault,
+        Some(val) => Detect::Specified(PamImpl::try_from(val).unwrap_or_else(|_| {
+            panic!(
+                "unknown PAM implementation {val:?}. \
+                valid LIBPAMSYS_IMPLs are {:?}, \
+                {TARGET_DEFAULT:?} to use the OS default, \
+                or unset to detect",
+                PamImpl::items()
+            )
+        })),
+    };
+    let pam_impl = match detection {
+        Detect::Auto => LibPam::probe_detect(),
+        Detect::TargetDefault => LibPam::os_default(),
+        Detect::Specified(other) => other,
     };
     let impl_str = format!("{pam_impl:?}");
     println!("{}", generate_cfg(&impl_str));
@@ -48,7 +73,9 @@
 struct LibPam(NonNull<c_void>);
 
 impl LibPam {
-    fn detect() -> PamImpl {
+    /// Look at the currently-installed LibPAM, or use [`Self::os_default`]
+    /// if absent.
+    fn probe_detect() -> PamImpl {
         if let Some(lib) = Self::open() {
             if lib.has("pam_syslog") {
                 return PamImpl::LinuxPam;
@@ -58,6 +85,11 @@
                 return PamImpl::Sun;
             }
         }
+        Self::os_default()
+    }
+
+    /// Guess the PAM implementation based on the current OS.
+    fn os_default() -> PamImpl {
         if cfg!(target_os = "linux") {
             PamImpl::LinuxPam
         } else if cfg!(any(
@@ -76,7 +108,9 @@
     }
 
     fn open() -> Option<Self> {
-        NonNull::new(unsafe { libc::dlopen(b"libpam.so\0".as_ptr().cast(), libc::RTLD_LAZY) })
+        let dlopen = |s: &[u8]| unsafe { libc::dlopen(s.as_ptr().cast(), libc::RTLD_LAZY) };
+        NonNull::new(dlopen(b"libpam.so\0"))
+            .or_else(|| NonNull::new(dlopen(b"libpam.dylib\0")))
             .map(Self)
     }
 
--- a/libpam-sys/libpam-sys-helpers/src/lib.rs	Wed Jul 09 16:59:30 2025 -0400
+++ b/libpam-sys/libpam-sys-helpers/src/lib.rs	Sat Jul 12 17:17:37 2025 -0400
@@ -6,7 +6,6 @@
 use std::mem::ManuallyDrop;
 use std::ptr::NonNull;
 use std::{any, fmt, mem, ptr, slice};
-// Type aliases:
 
 // Memory management
 
@@ -572,12 +571,12 @@
         //
         // a pointer to (&str, i32) can be treated as a pointer to (&str).
         #[repr(C)]
-        struct pair(&'static str, i32);
+        struct Pair(&'static str, i32);
         let boxes = vec![
-            Box::new(pair("a", 1)),
-            Box::new(pair("b", 2)),
-            Box::new(pair("c", 3)),
-            Box::new(pair("D", 4)),
+            Box::new(Pair("a", 1)),
+            Box::new(Pair("b", 2)),
+            Box::new(Pair("c", 3)),
+            Box::new(Pair("D", 4)),
         ];
         let ptr: *const *const &str = boxes.as_ptr().cast();
         let got: Vec<&str> = unsafe { PtrPtrVec::iter_over_linux(ptr, 4) }
--- a/libpam-sys/src/lib.rs	Wed Jul 09 16:59:30 2025 -0400
+++ b/libpam-sys/src/lib.rs	Sat Jul 12 17:17:37 2025 -0400
@@ -118,7 +118,6 @@
 }
 
 // These are the functions specified in X/SSO. Everybody exports them.
-#[link(name = "pam")]
 extern "C" {
     /// Account validation.
     pub fn pam_acct_mgmt(pamh: *mut pam_handle, flags: c_int) -> c_int;
@@ -199,8 +198,6 @@
     // The pam_sm_whatever functions are prototypes for the functions that
     // a PAM module should implement, not symbols provided by PAM.
 
-    // Nobody implements pam_authenticate_secondary.
-
     /// Starts a PAM transaction.  The `conv` may or may not be copied.
     pub fn pam_start(
         service: *const c_char,
@@ -288,6 +285,7 @@
         user: *const c_char,
         group: *const c_char,
     ) -> c_int;
+
     pub fn pam_modutil_user_in_group_nam_gid(
         pamh: *mut pam_handle,
         user: *const c_char,