From 30d02775c20b0629992a1b1717d8e4d00e0c736f Mon Sep 17 00:00:00 2001 From: h7x4 Date: Tue, 11 Nov 2025 00:27:27 +0900 Subject: [PATCH] Make compile-time feature for SUID/SGID mode --- Cargo.toml | 1 + src/core/bootstrap.rs | 13 +++++++++++-- src/core/common.rs | 43 +++++++++++++++++++++++++------------------ 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b247f68..5955609 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ uuid = { version = "1.18.1", features = ["v4"] } default = ["mysql-admutils-compatibility"] tui = ["dep:ratatui"] mysql-admutils-compatibility = [] +suid-sgid-mode = [] [[bin]] name = "mysqladm" diff --git a/src/core/bootstrap.rs b/src/core/bootstrap.rs index a3a7e9e..bee84ca 100644 --- a/src/core/bootstrap.rs +++ b/src/core/bootstrap.rs @@ -19,12 +19,14 @@ use crate::{ /// If neither is feasible, an error is returned. fn will_connect_to_external_server( server_socket_path: Option<&PathBuf>, - config_path: Option<&PathBuf>, + // This parameter is only used in suid-sgid-mode + #[allow(unused_variables)] config_path: Option<&PathBuf>, ) -> anyhow::Result { if server_socket_path.is_some() { return Ok(true); } + #[cfg(feature = "suid-sgid-mode")] if config_path.is_some() { return Ok(false); } @@ -33,11 +35,16 @@ fn will_connect_to_external_server( return Ok(true); } + #[cfg(feature = "suid-sgid-mode")] if fs::metadata(DEFAULT_CONFIG_PATH).is_ok() { return Ok(false); } + #[cfg(feature = "suid-sgid-mode")] anyhow::bail!("No socket path or config path provided, and no default socket or config found"); + + #[cfg(not(feature = "suid-sgid-mode"))] + anyhow::bail!("No socket path provided, and no default socket found"); } /// This function is used to bootstrap the connection to the server. @@ -77,7 +84,7 @@ pub fn bootstrap_server_connection_and_drop_privileges( .init(); connect_to_external_server(server_socket_path) - } else { + } else if cfg!(feature = "suid-sgid-mode") { // NOTE: We need to be really careful with the code up until this point, // as we might be running with elevated privileges. let server_connection = bootstrap_internal_server_and_drop_privs(config)?; @@ -87,6 +94,8 @@ pub fn bootstrap_server_connection_and_drop_privileges( .init(); Ok(server_connection) + } else { + anyhow::bail!("SUID/SGID support is not enabled, cannot start internal server"); } } diff --git a/src/core/common.rs b/src/core/common.rs index 254e369..aa1218c 100644 --- a/src/core/common.rs +++ b/src/core/common.rs @@ -1,6 +1,5 @@ use anyhow::Context; use nix::unistd::{Group as LibcGroup, User as LibcUser}; -use std::{fs, os::unix::fs::PermissionsExt}; #[cfg(not(target_os = "macos"))] use std::ffi::CString; @@ -21,23 +20,6 @@ fn get_unix_groups(_user: &LibcUser) -> anyhow::Result> { Ok(vec![]) } -/// Check if the current executable is SUID or SGID. -/// -/// If the check fails, an error is returned. -pub fn executable_is_suid_or_sgid() -> anyhow::Result { - let result = std::env::current_exe() - .context("Failed to get current executable path") - .and_then(|executable| { - fs::metadata(executable).context("Failed to get executable metadata") - }) - .context("Failed to check SUID/SGID bits on executable") - .map(|metadata| { - let mode = metadata.permissions().mode(); - mode & 0o4000 != 0 || mode & 0o2000 != 0 - })?; - Ok(result) -} - #[cfg(not(target_os = "macos"))] fn get_unix_groups(user: &LibcUser) -> anyhow::Result> { let user_cstr = @@ -61,6 +43,31 @@ fn get_unix_groups(user: &LibcUser) -> anyhow::Result> { Ok(groups) } +/// Check if the current executable is SUID or SGID. +/// +/// If the check fails, an error is returned. +#[cfg(feature = "suid-sgid-mode")] +pub fn executable_is_suid_or_sgid() -> anyhow::Result { + use std::{fs, os::unix::fs::PermissionsExt}; + let result = std::env::current_exe() + .context("Failed to get current executable path") + .and_then(|executable| { + fs::metadata(executable).context("Failed to get executable metadata") + }) + .context("Failed to check SUID/SGID bits on executable") + .map(|metadata| { + let mode = metadata.permissions().mode(); + mode & 0o4000 != 0 || mode & 0o2000 != 0 + })?; + Ok(result) +} + +#[cfg(not(feature = "suid-sgid-mode"))] +#[inline] +pub fn executable_is_suid_or_sgid() -> anyhow::Result { + Ok(false) +} + impl UnixUser { pub fn from_uid(uid: u32) -> anyhow::Result { let libc_uid = nix::unistd::Uid::from_raw(uid);