Mercurial > crates > nonstick
comparison libpam-sys/libpam-sys-consts/build.rs @ 160:09dff285ff5e
Switch default PAM detection strategy to target-based.
To make cross-compilation easier (like for docs.rs), this change
makes OS-based detection of PAM the default, only falling back
to probing the actual installed PAM as a last resort.
I haven't been able to find a Linux distribution that uses
anything but Linux-PAM.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sun, 13 Jul 2025 15:38:00 -0400 |
parents | d5b7b28d754e |
children | 46e8ce5cd5d1 |
comparison
equal
deleted
inserted
replaced
159:634cd5f2ac8b | 160:09dff285ff5e |
---|---|
6 | 6 |
7 include!("src/pam_impl.rs"); | 7 include!("src/pam_impl.rs"); |
8 | 8 |
9 /// The strategy to use to detect PAM. | 9 /// The strategy to use to detect PAM. |
10 enum Detect { | 10 enum Detect { |
11 /// Automatically detect PAM, using the installed implementation if present | 11 /// Use the default PAM implementation based on the OS, |
12 /// or the OS default if not. | 12 /// or the currently-installed version if the OS is not recognized. |
13 Auto, | |
14 /// Use the default PAM implementation based on the OS. | |
15 TargetDefault, | 13 TargetDefault, |
14 /// Detect the installed implementation. | |
15 Installed, | |
16 /// Use the named version of PAM. | 16 /// Use the named version of PAM. |
17 Specified(PamImpl), | 17 Specified(PamImpl), |
18 } | 18 } |
19 | 19 |
20 const TARGET_DEFAULT: &str = "__TARGET_DEFAULT__"; | 20 const INSTALLED: &str = "__installed__"; |
21 | 21 |
22 fn main() { | 22 fn main() { |
23 let detection = match option_env!("LIBPAMSYS_IMPL") { | 23 let detection = match option_env!("LIBPAMSYS_IMPL") { |
24 None | Some("") => match option_env!("DOCS_RS") { | 24 Some("") | None => Detect::TargetDefault, |
25 // docs.rs cross-compiles, so we don't want to look at | 25 Some(INSTALLED) => Detect::Installed, |
26 // its currently-installed PAM; instead we want to use the OS. | |
27 Some(_) => Detect::TargetDefault, | |
28 // In other cases, just auto-detect the actual installed library. | |
29 None => Detect::Auto, | |
30 }, | |
31 Some(TARGET_DEFAULT) => Detect::TargetDefault, | |
32 Some(val) => Detect::Specified(PamImpl::try_from(val).unwrap_or_else(|_| { | 26 Some(val) => Detect::Specified(PamImpl::try_from(val).unwrap_or_else(|_| { |
33 panic!( | 27 panic!( |
34 "unknown PAM implementation {val:?}. \ | 28 "unknown PAM implementation {val:?}. \ |
35 valid LIBPAMSYS_IMPLs are {:?}, \ | 29 valid LIBPAMSYS_IMPLs are {:?}, \ |
36 {TARGET_DEFAULT:?} to use the OS default, \ | 30 {INSTALLED:?} to use the OS default, \ |
37 or unset to detect", | 31 or unset to detect", |
38 PamImpl::items() | 32 PamImpl::items() |
39 ) | 33 ) |
40 })), | 34 })), |
41 }; | 35 }; |
42 let pam_impl = match detection { | 36 let pam_impl = match detection { |
43 Detect::Auto => LibPam::probe_detect(), | 37 Detect::TargetDefault => LibPam::target_default(), |
44 Detect::TargetDefault => LibPam::os_default(), | 38 Detect::Installed => LibPam::probe_detect(), |
45 Detect::Specified(other) => other, | 39 Detect::Specified(other) => other, |
46 }; | 40 }; |
47 let impl_str = format!("{pam_impl:?}"); | 41 let impl_str = format!("{pam_impl:?}"); |
48 println!("{}", generate_cfg(&impl_str)); | 42 println!("{}", generate_cfg(&impl_str)); |
49 // We set this environment variable to substitute into docstrings. | 43 // We set this environment variable to substitute into docstrings. |
71 } | 65 } |
72 | 66 |
73 struct LibPam(NonNull<c_void>); | 67 struct LibPam(NonNull<c_void>); |
74 | 68 |
75 impl LibPam { | 69 impl LibPam { |
76 /// Look at the currently-installed LibPAM, or use [`Self::os_default`] | |
77 /// if absent. | |
78 fn probe_detect() -> PamImpl { | |
79 if let Some(lib) = Self::open() { | |
80 if lib.has("pam_syslog") { | |
81 return PamImpl::LinuxPam; | |
82 } else if lib.has("_openpam_log") { | |
83 return PamImpl::OpenPam; | |
84 } else if lib.has("__pam_get_authtok") { | |
85 return PamImpl::Sun; | |
86 } | |
87 } | |
88 Self::os_default() | |
89 } | |
90 | |
91 /// Guess the PAM implementation based on the current OS. | 70 /// Guess the PAM implementation based on the current OS. |
92 fn os_default() -> PamImpl { | 71 fn target_default() -> PamImpl { |
93 if cfg!(target_os = "linux") { | 72 if cfg!(target_os = "linux") { |
94 PamImpl::LinuxPam | 73 PamImpl::LinuxPam |
95 } else if cfg!(any( | 74 } else if cfg!(any( |
96 target_os = "macos", | 75 target_os = "macos", |
97 target_os = "freebsd", | 76 target_os = "freebsd", |
101 )) { | 80 )) { |
102 PamImpl::OpenPam | 81 PamImpl::OpenPam |
103 } else if cfg!(any(target_os = "illumos", target_os = "solaris")) { | 82 } else if cfg!(any(target_os = "illumos", target_os = "solaris")) { |
104 PamImpl::Sun | 83 PamImpl::Sun |
105 } else { | 84 } else { |
106 PamImpl::XSso | 85 Self::probe_detect() |
107 } | 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 | |
108 } | 102 } |
109 | 103 |
110 fn open() -> Option<Self> { | 104 fn open() -> Option<Self> { |
111 let dlopen = |s: &[u8]| unsafe { libc::dlopen(s.as_ptr().cast(), libc::RTLD_LAZY) }; | 105 let dlopen = |s: &[u8]| unsafe { libc::dlopen(s.as_ptr().cast(), libc::RTLD_LAZY) }; |
112 NonNull::new(dlopen(b"libpam.so\0")) | 106 NonNull::new(dlopen(b"libpam.so\0")) |