From 603a2a8ce81a48f855f400bef0932303e11bea40 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:42:42 +0100 Subject: [PATCH 1/2] Remove most uses of build.rs --- build.rs | 24 ++++-------------------- src/pam/mod.rs | 3 +++ src/su/context.rs | 5 +++-- src/sudo/env/environment.rs | 3 ++- src/sudo/mod.rs | 1 + src/sudoers/mod.rs | 2 +- 6 files changed, 14 insertions(+), 24 deletions(-) diff --git a/build.rs b/build.rs index c428f5d57..addb61835 100644 --- a/build.rs +++ b/build.rs @@ -1,30 +1,14 @@ -use std::path::Path; - -// Return the first existing path given a list of paths as string slices -fn get_first_path(paths: &[&'static str]) -> Option<&'static str> { - paths.iter().find(|p| Path::new(p).exists()).copied() -} - fn main() { - let path_zoneinfo: &str = get_first_path(&[ + let path_zoneinfo = [ "/usr/share/zoneinfo", "/usr/share/lib/zoneinfo", "/usr/lib/zoneinfo", "/usr/lib/zoneinfo", - ]) + ] + .into_iter() + .find(|p| std::path::Path::new(p).exists()) .expect("no zoneinfo database"); - // TODO: use _PATH_STDPATH and _PATH_DEFPATH_ROOT from paths.h - println!("cargo:rustc-env=SUDO_PATH_DEFAULT=/usr/bin:/bin:/usr/sbin:/sbin"); - println!( - "cargo:rustc-env=SU_PATH_DEFAULT_ROOT=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - ); - println!( - "cargo:rustc-env=SU_PATH_DEFAULT=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games" - ); - println!("cargo:rustc-env=PATH_ZONEINFO={path_zoneinfo}"); println!("cargo:rerun-if-changed=build.rs"); - - println!("cargo:rustc-link-lib=pam"); } diff --git a/src/pam/mod.rs b/src/pam/mod.rs index 6e034c8ea..f6c524909 100644 --- a/src/pam/mod.rs +++ b/src/pam/mod.rs @@ -25,6 +25,9 @@ mod securemem; #[allow(nonstandard_style)] pub mod sys; +#[link(name = "pam")] +extern "C" {} + #[cfg(target_os = "freebsd")] const PAM_DATA_SILENT: std::ffi::c_int = 0; diff --git a/src/su/context.rs b/src/su/context.rs index 62831234f..a5c8df634 100644 --- a/src/su/context.rs +++ b/src/su/context.rs @@ -19,8 +19,9 @@ use super::cli::SuRunOptions; const VALID_LOGIN_SHELLS_LIST: &str = "/etc/shells"; const FALLBACK_LOGIN_SHELL: &str = "/bin/sh"; -const PATH_DEFAULT: &str = env!("SU_PATH_DEFAULT"); -const PATH_DEFAULT_ROOT: &str = env!("SU_PATH_DEFAULT_ROOT"); +// TODO: use _PATH_STDPATH and _PATH_DEFPATH_ROOT from paths.h +const PATH_DEFAULT: &str = "/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"; +const PATH_DEFAULT_ROOT: &str = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; #[derive(Debug)] pub(crate) struct SuContext { diff --git a/src/sudo/env/environment.rs b/src/sudo/env/environment.rs index a60a04495..1c240fe41 100644 --- a/src/sudo/env/environment.rs +++ b/src/sudo/env/environment.rs @@ -11,7 +11,8 @@ use crate::system::PATH_MAX; use super::wildcard_match::wildcard_match; const PATH_ZONEINFO: &str = env!("PATH_ZONEINFO"); -const PATH_DEFAULT: &str = env!("SUDO_PATH_DEFAULT"); +// TODO: use _PATH_STDPATH from paths.h +pub(crate) const PATH_DEFAULT: &str = "/usr/bin:/bin:/usr/sbin:/sbin"; pub type Environment = HashMap; diff --git a/src/sudo/mod.rs b/src/sudo/mod.rs index ead20a462..4e8af9c21 100644 --- a/src/sudo/mod.rs +++ b/src/sudo/mod.rs @@ -19,6 +19,7 @@ mod edit; pub(crate) mod diagnostic; mod env; +pub(crate) use env::environment::PATH_DEFAULT; mod pam; mod pipeline; diff --git a/src/sudoers/mod.rs b/src/sudoers/mod.rs index 3e07e3e52..e6e9dad5a 100644 --- a/src/sudoers/mod.rs +++ b/src/sudoers/mod.rs @@ -321,7 +321,7 @@ fn select_editor(settings: &Settings, trusted_env: bool) -> PathBuf { editor } else if let Some(editor) = resolve_path( &editor, - &std::env::var("PATH").unwrap_or(env!("SUDO_PATH_DEFAULT").to_string()), + &std::env::var("PATH").unwrap_or(crate::sudo::PATH_DEFAULT.to_string()), ) { editor } else { From 660832c759ebb76aa39780f9df0637dc7cba43e6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:17:00 +0100 Subject: [PATCH 2/2] Detect zoneinfo location at runtime This allows getting rid of the build script. --- build.rs | 14 -------------- src/sudo/env/environment.rs | 34 ++++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 26 deletions(-) delete mode 100644 build.rs diff --git a/build.rs b/build.rs deleted file mode 100644 index addb61835..000000000 --- a/build.rs +++ /dev/null @@ -1,14 +0,0 @@ -fn main() { - let path_zoneinfo = [ - "/usr/share/zoneinfo", - "/usr/share/lib/zoneinfo", - "/usr/lib/zoneinfo", - "/usr/lib/zoneinfo", - ] - .into_iter() - .find(|p| std::path::Path::new(p).exists()) - .expect("no zoneinfo database"); - - println!("cargo:rustc-env=PATH_ZONEINFO={path_zoneinfo}"); - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/src/sudo/env/environment.rs b/src/sudo/env/environment.rs index 1c240fe41..b3c664ead 100644 --- a/src/sudo/env/environment.rs +++ b/src/sudo/env/environment.rs @@ -2,6 +2,7 @@ use std::{ collections::{HashMap, HashSet}, ffi::{OsStr, OsString}, os::unix::prelude::OsStrExt, + path::Path, }; use crate::common::{CommandAndArguments, Context, Error}; @@ -10,7 +11,17 @@ use crate::system::PATH_MAX; use super::wildcard_match::wildcard_match; -const PATH_ZONEINFO: &str = env!("PATH_ZONEINFO"); +fn path_zoneinfo() -> Option<&'static str> { + [ + "/usr/share/zoneinfo", + "/usr/share/lib/zoneinfo", + "/usr/lib/zoneinfo", + "/usr/lib/zoneinfo", + ] + .into_iter() + .find(|p| Path::new(p).exists()) +} + // TODO: use _PATH_STDPATH from paths.h pub(crate) const PATH_DEFAULT: &str = "/usr/bin:/bin:/usr/sbin:/sbin"; @@ -139,12 +150,9 @@ fn is_safe_tz(value: &[u8]) -> bool { }; if check_value.starts_with(b"/") { - // clippy 1.79 wants to us to optimise this check away; but we don't know what this will always - // be possible; and the compiler is clever enough to do that for us anyway if it can be. - #[allow(clippy::const_is_empty)] - if !PATH_ZONEINFO.is_empty() { - if !check_value.starts_with(PATH_ZONEINFO.as_bytes()) - || check_value.get(PATH_ZONEINFO.len()) != Some(&b'/') + if let Some(path_zoneinfo) = path_zoneinfo() { + if !check_value.starts_with(path_zoneinfo.as_bytes()) + || check_value.get(path_zoneinfo.len()) != Some(&b'/') { return false; } @@ -256,7 +264,7 @@ where #[cfg(test)] mod tests { - use super::{is_safe_tz, should_keep, PATH_ZONEINFO}; + use super::{is_safe_tz, path_zoneinfo, should_keep}; use std::{collections::HashSet, ffi::OsStr}; struct TestConfiguration { @@ -318,25 +326,27 @@ mod tests { #[allow(clippy::bool_assert_comparison)] #[test] fn test_tzinfo() { + let path_zoneinfo = path_zoneinfo().unwrap(); assert_eq!(is_safe_tz("Europe/Amsterdam".as_bytes()), true); assert_eq!( - is_safe_tz(format!("{PATH_ZONEINFO}/Europe/London").as_bytes()), + is_safe_tz(format!("{path_zoneinfo}/Europe/London").as_bytes()), true ); assert_eq!( - is_safe_tz(format!(":{PATH_ZONEINFO}/Europe/Amsterdam").as_bytes()), + is_safe_tz(format!(":{path_zoneinfo}/Europe/Amsterdam").as_bytes()), true ); + assert_eq!(is_safe_tz(format!("/Europe/Amsterdam").as_bytes()), false); assert_eq!( is_safe_tz(format!("/schaap/Europe/Amsterdam").as_bytes()), false ); assert_eq!( - is_safe_tz(format!("{PATH_ZONEINFO}/../Europe/London").as_bytes()), + is_safe_tz(format!("{path_zoneinfo}/../Europe/London").as_bytes()), false ); assert_eq!( - is_safe_tz(format!("{PATH_ZONEINFO}/../Europe/London").as_bytes()), + is_safe_tz(format!("{path_zoneinfo}/../Europe/London").as_bytes()), false ); }