Mercurial > crates > nonstick
comparison libpam-sys/libpam-sys-impls/build.rs @ 176:0730f5f2ee2a
Turn `libpam-sys-consts` back into `libpam-sys-impls`.
This moves the constants into `libpam-sys` and makes `libpam-sys-impls`
responsible solely for detecting the current PAM implementation.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Wed, 30 Jul 2025 17:53:31 -0400 |
| parents | libpam-sys/libpam-sys-consts/build.rs@46e8ce5cd5d1 |
| children |
comparison
equal
deleted
inserted
replaced
| 175:e30775c80b49 | 176:0730f5f2ee2a |
|---|---|
| 1 #![allow(unexpected_cfgs)] | |
| 2 | |
| 3 use std::ffi::{c_void, CString}; | |
| 4 use std::ptr::NonNull; | |
| 5 use std::{env, fs}; | |
| 6 | |
| 7 include!("src/pam_impl.rs"); | |
| 8 | |
| 9 /// The strategy to use to detect PAM. | |
| 10 enum Detect { | |
| 11 /// Use the default PAM implementation based on the OS, | |
| 12 /// or the currently-installed version if the OS is not recognized. | |
| 13 TargetDefault, | |
| 14 /// Detect the installed implementation. | |
| 15 Installed, | |
| 16 /// Use the named version of PAM. | |
| 17 Specified(PamImpl), | |
| 18 } | |
| 19 | |
| 20 const INSTALLED: &str = "__installed__"; | |
| 21 | |
| 22 fn main() { | |
| 23 let detection = match option_env!("LIBPAMSYS_IMPL") { | |
| 24 Some("") | None => Detect::TargetDefault, | |
| 25 Some(INSTALLED) => Detect::Installed, | |
| 26 Some(val) => Detect::Specified(PamImpl::try_from(val).unwrap_or_else(|_| { | |
| 27 panic!( | |
| 28 "unknown PAM implementation {val:?}. \ | |
| 29 valid LIBPAMSYS_IMPLs are {:?}, \ | |
| 30 {INSTALLED:?} to use the currently-installed version, \ | |
| 31 or unset to use the OS default", | |
| 32 PamImpl::items() | |
| 33 ) | |
| 34 })), | |
| 35 }; | |
| 36 let pam_impl = match detection { | |
| 37 Detect::TargetDefault => LibPam::target_default(), | |
| 38 Detect::Installed => LibPam::probe_detect(), | |
| 39 Detect::Specified(other) => other, | |
| 40 }; | |
| 41 let impl_str = format!("{pam_impl:?}"); | |
| 42 println!("{}", generate_cfg(&impl_str)); | |
| 43 // We set this environment variable to substitute into docstrings. | |
| 44 println!("cargo:rustc-env=LIBPAMSYS_IMPL={impl_str}"); | |
| 45 fs::write( | |
| 46 format!("{}/pam_impl_const.rs", env::var("OUT_DIR").unwrap()), | |
| 47 generate_consts(&impl_str), | |
| 48 ) | |
| 49 .unwrap(); | |
| 50 } | |
| 51 | |
| 52 fn generate_consts(impl_str: &str) -> String { | |
| 53 format!( | |
| 54 "\ | |
| 55 impl PamImpl {{ | |
| 56 /// The implementation of libpam this was built for (`{impl_str}`). | |
| 57 pub const CURRENT: Self = Self::{impl_str}; | |
| 58 }} | |
| 59 | |
| 60 /// String name of [`PamImpl::CURRENT`], for substituting into docs. | |
| 61 #[macro_export] | |
| 62 macro_rules! pam_impl_name {{ () => ({impl_str:?}) }} | |
| 63 " | |
| 64 ) | |
| 65 } | |
| 66 | |
| 67 struct LibPam(NonNull<c_void>); | |
| 68 | |
| 69 impl LibPam { | |
| 70 /// Guess the PAM implementation based on the current OS. | |
| 71 fn target_default() -> PamImpl { | |
| 72 if cfg!(target_os = "linux") { | |
| 73 PamImpl::LinuxPam | |
| 74 } else if cfg!(any( | |
| 75 target_os = "macos", | |
| 76 target_os = "freebsd", | |
| 77 target_os = "netbsd", | |
| 78 target_os = "dragonfly", | |
| 79 target_os = "openbsd", | |
| 80 )) { | |
| 81 PamImpl::OpenPam | |
| 82 } else if cfg!(any(target_os = "illumos", target_os = "solaris")) { | |
| 83 PamImpl::Sun | |
| 84 } else { | |
| 85 Self::probe_detect() | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 /// Look at the currently-installed LibPAM. | |
| 90 fn probe_detect() -> PamImpl { | |
| 91 if let Some(lib) = Self::open() { | |
| 92 if lib.has("pam_syslog") { | |
| 93 return PamImpl::LinuxPam; | |
| 94 } else if lib.has("_openpam_log") { | |
| 95 return PamImpl::OpenPam; | |
| 96 } else if lib.has("__pam_get_authtok") { | |
| 97 return PamImpl::Sun; | |
| 98 } | |
| 99 } | |
| 100 // idk | |
| 101 PamImpl::XSso | |
| 102 } | |
| 103 | |
| 104 fn open() -> Option<Self> { | |
| 105 let dlopen = |s: &[u8]| unsafe { libc::dlopen(s.as_ptr().cast(), libc::RTLD_LAZY) }; | |
| 106 NonNull::new(dlopen(b"libpam.so\0")) | |
| 107 .or_else(|| NonNull::new(dlopen(b"libpam.dylib\0"))) | |
| 108 .map(Self) | |
| 109 } | |
| 110 | |
| 111 fn has(&self, name: &str) -> bool { | |
| 112 let name = CString::new(name).unwrap(); | |
| 113 let symbol = unsafe { libc::dlsym(self.0.as_ptr(), name.as_ptr()) }; | |
| 114 !symbol.is_null() | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 impl Drop for LibPam { | |
| 119 fn drop(&mut self) { | |
| 120 unsafe { | |
| 121 libc::dlclose(self.0.as_ptr()); | |
| 122 } | |
| 123 } | |
| 124 } |
