use std::path::Path;
pub fn validate_command(command: &str) -> bool {
if command.is_empty() {
return false;
}
const DANGEROUS_CHARS: &[char] = &[
';', '&', '|', '>', '<', '$', '`', '\n', '\r', '(', ')', '{', '}',
];
if command.chars().any(|c| DANGEROUS_CHARS.contains(&c)) {
eprintln!("Potentially dangerous command rejected: {command}");
return false;
}
if command.contains("..") {
eprintln!("Command with path traversal rejected: {command}");
return false;
}
true
}
pub fn validate_args(args: &[&str]) -> bool {
for arg in args {
if arg.is_empty() {
continue; }
const DANGEROUS_CHARS: &[char] = &[';', '&', '|', '`', '\n', '\r', '$'];
if arg.chars().any(|c| DANGEROUS_CHARS.contains(&c)) {
eprintln!("Potentially dangerous argument rejected: {arg}");
return false;
}
}
true
}
#[allow(dead_code)]
pub fn validate_command_path(path: &Path) -> bool {
if !path.is_absolute() {
eprintln!("Non-absolute command path rejected: {path:?}");
return false;
}
if let Some(path_str) = path.to_str() {
if path_str.contains("..") {
eprintln!("Command path with traversal rejected: {path_str}");
return false;
}
}
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
if let Ok(metadata) = path.metadata() {
let permissions = metadata.permissions();
if permissions.mode() & 0o111 == 0 {
eprintln!("Non-executable command path: {path:?}");
return false;
}
} else {
eprintln!("Command path does not exist: {path:?}");
return false;
}
}
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_command() {
assert!(validate_command("nvidia-smi"));
assert!(validate_command("/usr/bin/echo"));
assert!(!validate_command(""));
assert!(!validate_command("echo; rm -rf /"));
assert!(!validate_command("echo && malicious"));
assert!(!validate_command("cat | grep"));
assert!(!validate_command("../../bin/evil"));
assert!(!validate_command("echo $(whoami)"));
}
#[test]
fn test_validate_args() {
assert!(validate_args(&["--json", "--output", "file.txt"]));
assert!(validate_args(&["-L", "-v"]));
assert!(!validate_args(&["; rm -rf /"]));
assert!(!validate_args(&["$(whoami)"]));
assert!(!validate_args(&["file.txt | cat"]));
}
#[test]
fn test_validate_command_path() {
use std::path::PathBuf;
assert!(validate_command_path(&PathBuf::from("/bin/ls")));
assert!(!validate_command_path(&PathBuf::from("relative/path")));
assert!(!validate_command_path(&PathBuf::from("/usr/../etc/passwd")));
}
}