view libpam-sys/libpam-sys-impls/build.rs @ 124:f469b8d9ad78 default tip

Add tests for the original X/SSO constants list.
author Paul Fisher <paul@pfish.zone>
date Mon, 30 Jun 2025 04:54:38 -0400
parents 39760dfc9b3b
children
line wrap: on
line source

//! This absurd build script basically sets up everything for libpam-sys-impl.
//!
//!  1. It's the definition site for the [`PamImpl`] enum, which then gets
//!     output to the `OUT_DIR/pam_impl_enum.rs` file for parsing/inclusion
//!     into the `__pam_impl_enum__` macro.
//!  2. It detects the current PAM implementation and sets an env var for
//!     the macros in `libpam-sys-impl`.

use dlopen::raw::Library;
use proc_macro2::TokenStream;
use quote::quote;
use std::ffi::c_void;
use std::{env, fs};
use strum::{EnumIter, EnumString, IntoEnumIterator};

const DETECT: &str = "__detect__";

fn main() {
    let pam_impl = match option_env!("LIBPAMSYS_IMPL") {
        // The default option: Guess what PAM impl we're using based on OS.
        None => {
            if cfg!(target_os = "linux") {
                PamImpl::LinuxPam
            } else if cfg!(any(
                target_os = "macos",
                target_os = "freebsd",
                target_os = "netbsd",
                target_os = "dragonfly",
                target_os = "openbsd"
            )) {
                PamImpl::OpenPam
            } else if cfg!(any(target_os = "illumos", target_os = "solaris",)) {
                PamImpl::Sun
            } else {
                PamImpl::XSso
            }
        }
        Some(DETECT) => {
            // Detect the library based on the symbols in libpam.so.
            let lib = Library::open("libpam.so").unwrap();
            if symbol_exists(&lib, "pam_syslog") {
                PamImpl::LinuxPam
            } else if symbol_exists(&lib, "_openpam_log") {
                PamImpl::OpenPam
            } else if symbol_exists(&lib, "__pam_get_authtok") {
                PamImpl::Sun
            } else {
                // If all else fails, assume the bare minimum.
                PamImpl::XSso
            }
        }
        Some(other) => match PamImpl::try_from(other) {
            Ok(i) => i,
            Err(_) => {
                let valid: Vec<_> = PamImpl::iter().collect();
                panic!(
                    "unknown PAM implementation {other:?}. valid LIBPAMSYS_IMPLs are {valid:?}, or use {DETECT:?}"
                )
            }
        },
    };
    fs::write(
        format!("{}/pam_impl_enum.rs", env::var("OUT_DIR").unwrap()),
        PamImpl::enum_tokens().to_string(),
    )
    .unwrap();
    println!("cargo:rustc-env=LIBPAMSYS_IMPL={pam_impl:?}");
}

fn symbol_exists(lib: &Library, symbol: &str) -> bool {
    unsafe { lib.symbol::<*mut c_void>(symbol) }.is_ok()
}

/// This defines a local enum with an `enum_tokens()` method that can spit out
/// its own contents.
macro_rules! self_aware_enum {
    (
        $(#here[$here:meta])*
        $(#[$attr:meta])*
        $name:ident {
            $($tt:tt)*
        }
    ) => {
        $(#[$here])*
        $(#[$attr])*
        pub enum $name {
            $($tt)*
        }

        impl $name {
            fn enum_tokens() -> TokenStream {
                quote!(
                    $(#[$attr])*
                    pub enum $name {
                        $($tt)*
                    }
                )
            }
        }
    }
}

self_aware_enum!(
    #here[derive(EnumString, strum::Display, EnumIter)]
    /// The PAM implementations supported by `libpam-sys`.
    #[derive(Clone, Copy, Debug, PartialEq)]
    PamImpl {
        /// [Linux-PAM] is provided by most Linux distributions.
        ///
        /// [Linux-PAM]: https://github.com/linux-pam/linux-pam
        LinuxPam,
        /// [OpenPAM] is used by most BSDs, including Mac OS X.
        ///
        /// [OpenPAM]: https://git.des.dev/OpenPAM/OpenPAM
        OpenPam,
        /// Illumos and Solaris use a derivative of [Sun's implementation][sun].
        ///
        /// [sun]: https://code.illumos.org/plugins/gitiles/illumos-gate/+/refs/heads/master/usr/src/lib/libpam
        Sun,
        /// Only the functionality and constants in [the PAM spec].
        ///
        /// [the PAM spec]: https://pubs.opengroup.org/onlinepubs/8329799/toc.htm
        XSso,
    }
);