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 } |