1use std::collections::HashSet;
2use std::process::{Command, ExitStatus};
3
4pub const FIND_DANGEROUS_OPTIONS: &[&str] = &[
6 "-exec", "-execdir", "-ok", "-okdir", "-delete",
7];
8
9pub const FD_DANGEROUS_OPTIONS: &[&str] = &[
11 "-x", "--exec", "-X", "--exec-batch", "-l", "--list-details",
12];
13
14pub fn check_dangerous_options(args: &[String], dangerous_options: &[&str]) -> Result<(), String> {
16 let dangerous_set: HashSet<&str> = dangerous_options.iter().copied().collect();
17
18 for arg in args {
19 if dangerous_set.contains(arg.as_str()) {
20 return Err(format!(
21 "Error: Dangerous option '{}' is not allowed for security reasons",
22 arg
23 ));
24 }
25 }
26
27 Ok(())
28}
29
30pub fn execute_command(command_name: &str, args: &[String]) -> Result<ExitStatus, std::io::Error> {
32 let mut cmd = Command::new(command_name);
33 cmd.args(args);
34 cmd.status()
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40
41 #[test]
42 fn test_check_dangerous_options_find() {
43 let safe_args = vec![".", "-name", "*.txt", "-type", "f"]
44 .into_iter()
45 .map(String::from)
46 .collect::<Vec<_>>();
47 assert!(check_dangerous_options(&safe_args, FIND_DANGEROUS_OPTIONS).is_ok());
48
49 let dangerous_args = vec![".", "-name", "*.txt", "-exec", "rm", "{}", ";"]
50 .into_iter()
51 .map(String::from)
52 .collect::<Vec<_>>();
53 assert!(check_dangerous_options(&dangerous_args, FIND_DANGEROUS_OPTIONS).is_err());
54 }
55
56 #[test]
57 fn test_check_dangerous_options_fd() {
58 let safe_args = vec!["*.js", "--type", "f"]
59 .into_iter()
60 .map(String::from)
61 .collect::<Vec<_>>();
62 assert!(check_dangerous_options(&safe_args, FD_DANGEROUS_OPTIONS).is_ok());
63
64 let dangerous_args = vec!["*.js", "-x", "rm"]
65 .into_iter()
66 .map(String::from)
67 .collect::<Vec<_>>();
68 assert!(check_dangerous_options(&dangerous_args, FD_DANGEROUS_OPTIONS).is_err());
69 }
70}