166 lines
4.8 KiB
Rust
166 lines
4.8 KiB
Rust
use std::{env, os::unix::process::CommandExt, process::Command};
|
|
mod app;
|
|
use app::App;
|
|
use cache::*;
|
|
mod cache;
|
|
mod rudoers;
|
|
mod user_info;
|
|
use libc::{close, getpwuid};
|
|
use rudoers::check_rudoers;
|
|
use users::{get_group_by_name, get_user_by_name};
|
|
mod authentication;
|
|
use authentication::check_auth;
|
|
use std::ffi::CStr;
|
|
use user_info::get_command_path;
|
|
|
|
use crate::rudoers::make_example_rudoers_file;
|
|
|
|
/// RUDOLPH THE RED NOSE REINDEER
|
|
/// HAD A VERY SHINY NOSE
|
|
/// AND IF YOU EVER SAW IT
|
|
/// YOU MIGHT EVEN SAY IT GLOWS
|
|
|
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
|
|
pub fn execute(app: App) -> Result<(), String> {
|
|
if !app.cmd.is_empty() && !app.shell {
|
|
if let Some(close_from) = app.close_from {
|
|
for i in close_from.. {
|
|
let res = unsafe { close(i) };
|
|
if res == -1 {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
let run_as_name = if let Some(nym) = app.user {
|
|
nym
|
|
} else {
|
|
String::from("root")
|
|
};
|
|
let run_as = get_user_by_name(&run_as_name).unwrap();
|
|
let command_path = get_command_path(app.cmd.first().unwrap())?;
|
|
let args = app.cmd;
|
|
let args = &args[1..];
|
|
let mut cmd = Command::new(command_path);
|
|
cmd.uid(run_as.uid()).args(args);
|
|
if let Some(chdir) = app.chdir {
|
|
cmd.current_dir(chdir);
|
|
}
|
|
if let Some(group) = app.group {
|
|
let group_id: u32 = if group.starts_with("#") {
|
|
if let Ok(id) = group[1..].parse() {
|
|
id
|
|
} else {
|
|
return Err(format!["Error: Failed to parse group ID '{}'", &group[1..]]);
|
|
}
|
|
} else {
|
|
if let Some(group) = get_group_by_name(&group) {
|
|
group.gid()
|
|
} else {
|
|
return Err(format!["Error: Group '{}' not found", group]);
|
|
}
|
|
};
|
|
cmd.gid(group_id);
|
|
}
|
|
for var in app.preserve_env {
|
|
let value = env::var(&var).unwrap_or_default();
|
|
cmd.env(var, value);
|
|
}
|
|
// if app.preserve_groups {
|
|
// if let Some(user) = get_user_by_name(&get_username()?) {}
|
|
// }
|
|
if app.set_home {
|
|
let ptr = unsafe { (*getpwuid(run_as.uid())).pw_dir };
|
|
let home_dir = match unsafe { CStr::from_ptr(ptr).to_str() } {
|
|
Ok(s) => s,
|
|
Err(e) => {
|
|
return Err(format![
|
|
"Error: Failed to read home dir for {run_as_name}: {e}"
|
|
]);
|
|
}
|
|
};
|
|
cmd.env("HOME", home_dir);
|
|
}
|
|
// execute the child
|
|
let mut child = cmd.spawn().unwrap();
|
|
if app.background {
|
|
std::process::exit(0);
|
|
} else {
|
|
child.wait().unwrap();
|
|
}
|
|
} else {
|
|
return Err(String::from("Error: No command specified."));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn run() -> Result<(), String> {
|
|
let app = App::parse()?;
|
|
if app.help {
|
|
println!["{}", App::usage()];
|
|
return Ok(());
|
|
}
|
|
if app.version {
|
|
println!["Rudo v{VERSION}"];
|
|
return Ok(());
|
|
}
|
|
if app.gen_config {
|
|
println!["{}", make_example_rudoers_file()];
|
|
}
|
|
let alias = match &app.user {
|
|
Some(x) => &x,
|
|
None => "root",
|
|
};
|
|
let parent_id = std::os::unix::process::parent_id();
|
|
let needs_password =
|
|
check_rudoers(&app)? && !check_auth_cache(alias, parent_id) || app.validate;
|
|
if needs_password {
|
|
check_auth(app.stdin)?;
|
|
}
|
|
let failed_to_update = String::from("Error: Rudo: Failed to update auth cache: ");
|
|
if !app.no_update && !app.remove_timestamp {
|
|
if let Err(e) = update_auth_cache(alias, parent_id) {
|
|
eprintln!["{failed_to_update}{e}"];
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
if app.validate {
|
|
return Ok(());
|
|
}
|
|
if app.remove_timestamp {
|
|
if let Err(e) = clear_auth_cache(alias, parent_id) {
|
|
eprintln!["{failed_to_update}{e}"];
|
|
std::process::exit(1);
|
|
}
|
|
if app.cmd.is_empty() {
|
|
return Ok(());
|
|
}
|
|
}
|
|
if app.reset_timestamp {
|
|
if let Err(e) = clear_auth_cache(alias, parent_id) {
|
|
eprintln!["{failed_to_update}{e}"];
|
|
std::process::exit(1);
|
|
}
|
|
if let Err(e) = update_auth_cache(alias, parent_id) {
|
|
eprintln!["{failed_to_update}{e}"];
|
|
std::process::exit(1);
|
|
}
|
|
if app.cmd.is_empty() {
|
|
return Ok(());
|
|
}
|
|
}
|
|
// Run the command
|
|
execute(app)?;
|
|
Ok(())
|
|
}
|
|
|
|
fn main() {
|
|
match run() {
|
|
Ok(()) => (),
|
|
Err(e) => {
|
|
eprintln!["{e}"];
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
}
|