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")) |
