fix(sudo): prevent sudo_command = "sudo" finding gsudo

This commit is contained in:
Andre Toerien
2025-06-26 22:35:46 +02:00
committed by Gideon
parent 0e43e0d7fc
commit 306ff3c7c5

View File

@@ -5,7 +5,6 @@ use std::path::PathBuf;
use color_eyre::eyre::Context; use color_eyre::eyre::Context;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use serde::Deserialize; use serde::Deserialize;
use strum::AsRefStr;
use strum::Display; use strum::Display;
use crate::command::CommandExt; use crate::command::CommandExt;
@@ -38,36 +37,32 @@ pub struct SudoExecuteOpts<'a> {
pub user: Option<&'a str>, pub user: Option<&'a str>,
} }
impl Sudo { #[cfg(not(target_os = "windows"))]
/// Get the `sudo` binary or the `gsudo` binary in the case of `gsudo` const DETECT_ORDER: [SudoKind; 5] = [
/// masquerading as the `sudo` binary. SudoKind::Doas,
fn determine_sudo_variant(sudo_p: PathBuf) -> (PathBuf, SudoKind) { SudoKind::Sudo,
match which("gsudo") { SudoKind::Pkexec,
Some(gsudo_p) => { SudoKind::Run0,
match std::fs::canonicalize(&gsudo_p).unwrap() == std::fs::canonicalize(&sudo_p).unwrap() { SudoKind::Please,
true => (gsudo_p, SudoKind::Gsudo), ];
false => (sudo_p, SudoKind::Sudo),
}
}
None => (sudo_p, SudoKind::Sudo),
}
}
#[cfg(target_os = "windows")]
const DETECT_ORDER: [SudoKind; 2] = [SudoKind::Gsudo, SudoKind::Sudo];
impl Sudo {
/// Get the `sudo` binary for this platform. /// Get the `sudo` binary for this platform.
pub fn detect() -> Option<Self> { pub fn detect() -> Option<Self> {
which("doas") for kind in DETECT_ORDER {
.map(|p| (p, SudoKind::Doas)) if let Some(path) = kind.which() {
.or_else(|| which("sudo").map(Self::determine_sudo_variant)) return Some(Self { path, kind });
.or_else(|| which("gsudo").map(|p| (p, SudoKind::Gsudo))) }
.or_else(|| which("pkexec").map(|p| (p, SudoKind::Pkexec))) }
.or_else(|| which("run0").map(|p| (p, SudoKind::Run0))) None
.or_else(|| which("please").map(|p| (p, SudoKind::Please)))
.map(|(path, kind)| Self { path, kind })
} }
/// Create Sudo from SudoKind, if found in the system /// Create Sudo from SudoKind, if found in the system
pub fn new(kind: SudoKind) -> Option<Self> { pub fn new(kind: SudoKind) -> Option<Self> {
which(kind.as_ref()).map(|path| Self { path, kind }) kind.which().map(|path| Self { path, kind })
} }
/// Gets the path to the `sudo` binary. Do not use this to execute `sudo` directly - either use /// Gets the path to the `sudo` binary. Do not use this to execute `sudo` directly - either use
@@ -277,7 +272,7 @@ impl Sudo {
} }
} }
#[derive(Clone, Copy, Debug, Display, Deserialize, AsRefStr)] #[derive(Clone, Copy, Debug, Display, Deserialize)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase")] #[strum(serialize_all = "lowercase")]
pub enum SudoKind { pub enum SudoKind {
@@ -288,3 +283,23 @@ pub enum SudoKind {
Run0, Run0,
Please, Please,
} }
impl SudoKind {
fn binary_name(self) -> &'static str {
match self {
SudoKind::Doas => "doas",
SudoKind::Sudo if cfg!(not(target_os = "windows")) => "sudo",
// on windows, hardcode the sudo path to ensure we find Windows Sudo
// rather than gsudo masquerading as sudo
SudoKind::Sudo => r"C:\Windows\System32\sudo.exe",
SudoKind::Gsudo => "gsudo",
SudoKind::Pkexec => "pkexec",
SudoKind::Run0 => "run0",
SudoKind::Please => "please",
}
}
fn which(self) -> Option<PathBuf> {
which(self.binary_name())
}
}