diff options
| author | 2026-02-26 17:34:49 -0500 | |
|---|---|---|
| committer | 2026-02-26 17:34:49 -0500 | |
| commit | 44388f8de44ba13f740a5fc7e0f838c961fad084 (patch) | |
| tree | ca0e92573e6e4e52ee2c22475ec5dcbe6dd8f60b | |
| parent | proper config command handling (diff) | |
begin permissions shift for build commands
| -rw-r--r-- | Cargo.lock | 24 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | TODO | 2 | ||||
| -rw-r--r-- | src/action.rs | 6 | ||||
| -rw-r--r-- | src/config.rs | 26 | ||||
| -rw-r--r-- | src/util.rs | 21 |
6 files changed, 68 insertions, 13 deletions
@@ -27,6 +27,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -54,7 +60,7 @@ name = "forge" version = "0.1.0" dependencies = [ "git2", - "libc", + "nix", "serde", "toml", ] @@ -225,9 +231,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.182" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libgit2-sys" @@ -282,6 +288,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] +name = "nix" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225e7cfe711e0ba79a68baeddb2982723e4235247aefce1482f2f16c27865b66" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] name = "openssl-probe" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5,6 +5,6 @@ edition = "2024" [dependencies] git2 = "0.20.4" -libc = "0.2.182" +nix = { version = "0.31.1", features = ["user"] } serde = { version = "1.0.228", features = ["derive"] } toml = "1.0.3" @@ -1,3 +1,5 @@ +Make a forge user and make it own relevant paths + Add config command to set forge's values like the editor Implement update Implement upgrade diff --git a/src/action.rs b/src/action.rs index 1aeefb6..58effbe 100644 --- a/src/action.rs +++ b/src/action.rs @@ -1,5 +1,5 @@ use crate::config::{self, ConfigCommand, TEMP_CONFIG_PATH, create_config}; -use crate::util::{dir_size, get_editor, is_root, open_in_editor, yn_prompt}; +use crate::util::{dir_size, get_editor, open_in_editor, yn_prompt}; use git2::Repository; use std::fs; use std::path::{Path, PathBuf}; @@ -76,7 +76,7 @@ impl Action { } fn add(url: &str) -> Result<(), String> { - if !is_root() { + if !nix::unistd::geteuid().is_root() { return Err("add must be run as root".to_string()); } @@ -138,7 +138,7 @@ fn autoremove() { } fn remove(packages: Vec<String>) -> Result<(), String> { - if !is_root() { + if !nix::unistd::geteuid().is_root() { return Err("remove must be run as root".to_string()); } diff --git a/src/config.rs b/src/config.rs index 7c6cf2b..4976af3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,8 +1,11 @@ use serde::Deserialize; use std::fs; +use std::os::unix::process::CommandExt; use std::path::{Path, PathBuf}; use std::process::Command; +use crate::util::get_invoking_user_env; + pub const TEMP_CONFIG_PATH: &str = "/var/lib/forge/.tmp"; pub enum ConfigCommand { @@ -66,6 +69,9 @@ pub fn run_config_command( command: ConfigCommand, ) -> Result<(), String> { let config = Config::new(config_path).ok_or("config not found".to_string())?; + + let is_build = matches!(command, ConfigCommand::Build); + let cmd = match command { ConfigCommand::Build => config.build, ConfigCommand::Install => config.install, @@ -77,9 +83,23 @@ pub fn run_config_command( let cmd_base = parts.next().ok_or("empty command".to_string())?; let args: Vec<&str> = parts.collect(); - let status = Command::new(cmd_base) - .args(&args) - .current_dir(repo_path) + let mut command = Command::new(cmd_base); + command.args(&args).current_dir(repo_path); + + if is_build { + if let Some((uid, gid, home, path)) = get_invoking_user_env() { + command.env("HOME", home).env("PATH", path); + unsafe { + command.pre_exec(move || { + nix::unistd::setgid(nix::unistd::Gid::from_raw(gid))?; + nix::unistd::setuid(nix::unistd::Uid::from_raw(uid))?; + Ok(()) + }); + } + } + } + + let status = command .status() .map_err(|e| format!("failed to execute command: {}", e))?; diff --git a/src/util.rs b/src/util.rs index 90aacb6..e79124d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,4 +1,3 @@ -use libc; use std::env; use std::fs; use std::io; @@ -28,8 +27,24 @@ pub fn get_editor() -> String { .unwrap_or_else(|_| "nano".to_string()) } -pub fn is_root() -> bool { - unsafe { libc::geteuid() == 0 } +pub fn get_invoking_user_env() -> Option<(u32, u32, String, String)> { + let username = std::env::var("SUDO_USER").ok()?; + if username.is_empty() { + return None; + } + + let user = nix::unistd::User::from_name(&username).ok()??; + let uid = user.uid.as_raw(); + let gid = user.gid.as_raw(); + let home = user.dir.to_string_lossy().to_string(); + + // Reconstruct a sane PATH for the user including common tool locations + let path = format!( + "{home}/.cargo/bin:{home}/.local/bin:/usr/local/bin:/usr/bin:/bin", + home = home + ); + + Some((uid, gid, home, path)) } pub fn open_in_editor(editor: &str, file: &str) -> Result<(), String> { |
