use chrono::NaiveDate; use std::collections::HashMap; mod basic_ro; #[cfg(test)] mod test { use super::*; use basic_ro::*; use pleaser::*; #[test] fn test_execute_config() { let config = "[ed_all_dated] name=ed target=root notbefore=20200101 notafter=20201225 regex =^.*$ [ed_false_oracle] name=ed target=oracle permit=false regex=^/bin/bash .*$ [ed_root_bash_all] name=ed target=root regex=^/bin/bash .*$ " .to_string(); let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut vec_eo: Vec = vec![]; let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/bash"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_user_bash() { let config = " [ed_edn] name = ed type = list target = root regex = (edn?) [ed] name = ed target = root regex = /bin/bash " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/bash"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_execute_user_does_not_exist() { let config = "[ed_root_all] name=ed target=root notbefore=20200101 notafter=20201225 regex= ^.*$ [ed_oracle_bash] name=ed target=oracle regex=^/bin/bash .*$ [ed_root_bash] name=ed target=root regex=^/bin/bash .*$ [user_all_todo] name=.* target=thingy regex=^/bin/bash" .to_string(); let mut ro = basic_ro("ed", "root"); ro.date = NaiveDate::from_ymd(2019, 12, 31).and_hms(0, 0, 0); basic_cmd(&mut ro, "/bin/bash"); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.name = "other".to_string(); ro.target = "thingy".to_string(); let mut vec_eo: Vec = vec![]; let mut ini_list: HashMap = HashMap::new(); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.name = "other".to_string(); ro.target = "oracle".to_string(); let mut vec_eo: Vec = vec![]; let mut ini_list: HashMap = HashMap::new(); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_execute_config_too_early() { let config = " [ed] name=ed target=root notbefore=20200101 notafter=20201225 regex =^.*$ [ed_oracle] name=ed target=oracle ^/bin/bash .*$ [ed_dated] name=ed target=root notbefore=20200101 notafter=20200125 regex =^.* [name_all_todo] name=m{} target=^ " .to_string(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/bash"); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); ro.date = NaiveDate::from_ymd(2019, 12, 31).and_hms(0, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.date = NaiveDate::from_ymd(2020, 12, 25).and_hms(0, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.date = NaiveDate::from_ymd(2020, 01, 25).and_hms(0, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.date = NaiveDate::from_ymd(2020, 03, 25).and_hms(0, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_list_regex() { let config = " [ed_root] name = (floppy) group = true permit = true require_pass = false target = ^.* [ed_list] name = (ed) type = list target = %{USER} require_pass = false " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.acl_type = Acltype::List; ro.target = "ed".to_string(); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.target = "root".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_execute_config_too_early_long() { let config = " [ed_too_early] name=ed target=root notbefore=20200808 notafter=20200810235959 regex=^.* " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); basic_cmd(&mut ro, "/bin/bash"); ro.date = NaiveDate::from_ymd(2020, 8, 8).and_hms(0, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.date = NaiveDate::from_ymd(2020, 8, 10).and_hms(0, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.date = NaiveDate::from_ymd(2020, 8, 10).and_hms(23, 59, 59); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.date = NaiveDate::from_ymd(2020, 8, 11).and_hms(0, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.date = NaiveDate::from_ymd(2020, 8, 7).and_hms(0, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_execute_config_oracle() { let config = "[ed_oracle] name=ed target=oracle notbefore=20200101 notafter=20201225 regex=^/bin/bash .*$ [ed_oracle_permit] name=ed target=oracle notbefore=20190101 notafter=20201225 permit=true regex=^/bin/bash .*$ " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.target = "oracle".to_string(); ro.date = NaiveDate::from_ymd(2019, 12, 31).and_hms(0, 0, 0); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); basic_cmd(&mut ro, "/bin/bash /usr/local/oracle/backup_script"); assert_eq!(can(&vec_eo, &mut ro).permit(), true); basic_cmd(&mut ro, "/bin/sh /usr/local/oracle/backup_script"); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.hostname = "web1".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.hostname = "".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.hostname = "localhost".to_string(); ro.target = "grid".to_string(); basic_cmd(&mut ro, "/bin/bash /usr/local/oracle/backup_script"); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.target = "root".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_execute_config_hostname_any() { let config = " [ed_config_hostname] name=ed target=oracle hostname=any regex=^/bin/bash.*$ " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.target = "oracle".to_string(); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); basic_cmd(&mut ro, "/bin/bash /usr/local/oracle/backup_script"); assert_eq!(can(&vec_eo, &mut ro).permit(), true); basic_cmd(&mut ro, "/bin/sh /usr/local/oracle/backup_script"); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.hostname = "web1".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.hostname = "".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.target = "grid".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_execute_config_hostname_locahost() { let config = " [ed_oralce_web1] name=ed target=oracle hostname=web1 regex=^/bin/bash .*$ [ed_oracle_localhost] name=ed target=oracle hostname=localhost regex=^/bin/sh.*$ " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.target = "oracle".to_string(); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); basic_cmd(&mut ro, "/bin/bash /usr/local/oracle/backup_script"); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.hostname = "web1".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.hostname = "web2".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.hostname = "localhost".to_string(); basic_cmd(&mut ro, "/bin/sh /usr/local/oracle/backup_script"); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.hostname = "web1".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.hostname = "web2".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_missing_user() { let config = " [missing_user] target=oracle hostname=localhost regex=/bin/sh\\b.* " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.name = "".to_string(); ro.target = "oracle".to_string(); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_regex_line_anchor() { let config = " [regex_anchor] name=ed target=oracle hostname=localhost regex=.* " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.target = "oracle".to_string(); basic_cmd(&mut ro, "/bin/bash"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_edit_apache() { let config = " [ed_edit_root] name=ed target=root notbefore=20200101 notafter=20201225 type = edit regex = .* [ed_edit_apache] name=ed target=oracle permit=false type = edit regex = /etc/apache [ed_edit_hosts] name=ed target=root regex = /etc/hosts type = edit [user_all_todo] name=m{} target=^ type = edit regex = ^" .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.acl_type = Acltype::Edit; basic_cmd(&mut ro, "/etc/apache/httpd2.conf"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_edit_user_macro() { let config = " [ed] name=ed target=root regex =^/bin/cat /etc/%{USER}" .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/cat /etc/ed"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.name = "ned".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_parse_regex_fail() { let mut vec_eo: Vec = vec![]; let config = " [ed] name=ed target=root regex = ^/bin/cat /etc/(" .to_string(); let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/cat /etc/ed"); assert_eq!( read_ini_config_str(&config, &mut vec_eo, &ro, true, &mut bytes, &mut ini_list), true ); let mut vec_eo: Vec = vec![]; let config = " [ed] name=ed target=root regex = ^/bin/cat /etc/ " .to_string(); let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/cat /etc/ed"); assert_eq!( read_ini_config_str(&config, &mut vec_eo, &ro, true, &mut bytes, &mut ini_list), false ); } #[test] fn test_group_assignment() { let config = " [users] name=users group=true target=root notbefore=20200101 notafter=20201225 regex = ^.*$ " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/cat /etc/ed"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.groups.insert(String::from("users"), 1); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.groups = HashMap::new(); ro.groups.insert(String::from("wwwadm"), 1); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_list_other_user() { let config = " [ed_all] name=ed notbefore=20200101 notafter=20201225 type = list target = ^.*$ [bob_all] name=bob type=edit target = ^.*$ [bob_all] name=bob type = list permit=false target = ^.*$ [meh_ed] name=meh type =list target=^ed$ [root_all] name=root type=run regex =^.*$ [ben_ops] name=ben permit=true type=list target = ^(eng|dba|net)ops$ " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/cat /etc/ed"); ro.acl_type = Acltype::List; read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.name = "meh".to_string(); ro.target = "ed".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.target = "bob".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.target = "root".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.name = "bob".to_string(); ro.target = "ed".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.name = "ben".to_string(); ro.target = "dbaops".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.target = "engops".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.target = "netops".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.target = "wwwops".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_edit_regression() { let config = " [www-data-bio] name = root group = true permit = true type = edit require_pass = false regex = ^/var/www/html/%{USER}.html " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/etc/please.ini"); ro.acl_type = Acltype::Edit; read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.groups.insert(String::from("root"), 1); assert_eq!(can(&vec_eo, &mut ro).permit(), false); basic_cmd(&mut ro, "/var/www/html/ed.html"); assert_eq!(can(&vec_eo, &mut ro).permit(), true); basic_cmd(&mut ro, "/var/www/html/%{USER}.html"); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.groups = HashMap::new(); ro.groups.insert(String::from("wwwadm"), 1); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_edit_user_expansion() { let config = " [www-data-bio] name = root group = true permit = true type = edit require_pass = false regex = ^/var/www/html/%{USER}.html$ " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/var/www/html/ed.html"); ro.acl_type = Acltype::Edit; ro.groups.insert(String::from("root"), 1); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_edit_user_expansion_unescaped() { let config = " [www-data-bio] name = root group = true permit = true type = edit require_pass = false regex = ^/var/www/html/%USER.html$" .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.acl_type = Acltype::Edit; basic_cmd(&mut ro, "/var/www/html/ed.html"); ro.groups.insert(String::from("root"), 1); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_edit_user_expansion_escapes() { let config = " [www-data-bio] name = root group = true permit = true type = edit require_pass = false regex = ^/var/www/html/%{USER}.html$" .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.acl_type = Acltype::Edit; basic_cmd(&mut ro, "/var/www/html/ed.html"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); ro.groups.insert(String::from("root"), 1); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_target_regex() { let config = " [ed_target_ot] name = .*ot group = true target = .*ot permit = true require_pass = false regex = /bin/bash" .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/bash"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!( vec_eo .iter() .next() .unwrap() .rule .as_ref() .unwrap() .as_str(), "/bin/bash" ); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.groups.insert(String::from("root"), 1); basic_cmd(&mut ro, "/bin/sh"); assert_eq!(can(&vec_eo, &mut ro).permit(), false); basic_cmd(&mut ro, "/bin/bash"); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.target = "woot".to_string(); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_edit_regression_empty() { let mut vec_eo: Vec = vec![]; let config = "".to_string(); let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.acl_type = Acltype::Edit; basic_cmd(&mut ro, "/etc/please.ini"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_dir_any() { let config = " [regex_anchor] name=ed target=oracle hostname=localhost regex=.* dir=.* " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.target = "oracle".to_string(); basic_cmd(&mut ro, "/bin/bash"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.directory = Some("/".to_string()); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_dir_fixed() { let config = " [regex_anchor] name=ed target=oracle hostname=localhost regex=.* dir=/var/www " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.target = "oracle".to_string(); basic_cmd(&mut ro, "/bin/bash"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false, "no directory given",); ro.directory = Some("/".to_string()); assert_eq!( can(&vec_eo, &mut ro).permit(), false, "change outside permitted", ); ro.directory = Some("/var/www".to_string()); assert_eq!(can(&vec_eo, &mut ro).permit(), true, "permitted"); } #[test] fn test_dir_tmp() { let config = " [regex_anchor] name=ed target=root regex=/bin/bash dir=/tmp " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/bash"); ro.directory = Some("/tmp".to_string()); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true, "dir_tmp",); } #[test] fn test_dir_given_but_none_in_match() { let config = " [regex_anchor] name=ed target=oracle hostname=localhost regex=.* " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.target = "oracle".to_string(); basic_cmd(&mut ro, "/bin/bash"); ro.directory = Some("/".to_string()); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false, "directory given",); ro.directory = Some("".to_string()); assert_eq!(can(&vec_eo, &mut ro).permit(), false, "directory given",); } #[test] fn test_date_match() { let config = " [regex_anchor] name=ed target=root hostname=localhost regex=.* datematch=Fri.*UTC.* " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.date = NaiveDate::from_ymd(2020, 10, 02).and_hms(22, 0, 0); basic_cmd(&mut ro, "/bin/bash"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); ro.date = NaiveDate::from_ymd(2020, 10, 01).and_hms(22, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), false); let config = " [regex_anchor] name=ed target=root hostname=localhost regex=.* datematch=Fri.*\\s22:00:00\\s+UTC\\s2020 " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); ro.date = NaiveDate::from_ymd(2020, 10, 02).and_hms(21, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.date = NaiveDate::from_ymd(2020, 10, 02).and_hms(23, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.date = NaiveDate::from_ymd(2020, 10, 02).and_hms(22, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), true); let config = " [regex_anchor] name=ed target=root hostname=localhost regex=.* datematch=Thu\\s+1\\s+Oct\\s+22:00:00\\s+UTC\\s+2020 " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); ro.date = NaiveDate::from_ymd(2020, 10, 01).and_hms(21, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.date = NaiveDate::from_ymd(2020, 10, 01).and_hms(23, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), false); ro.date = NaiveDate::from_ymd(2020, 10, 01).and_hms(22, 0, 0); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_edit_mode() { let config = " [edit_filemode] name=ed target=root regex=/etc/please.ini.* type=edit editmode=0644 " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.acl_type = Acltype::Edit; basic_cmd(&mut ro, "/etc/please.ini"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); let entry = can(&vec_eo, &mut ro); assert!(matches!(entry.edit_mode, Some(EditMode::Mode(420)))); let config = " [edit_filemode] name=ed target=root regex=/etc/please.ini.* type=edit editmode=keep " .to_string(); bytes = 0; let mut ini_list: HashMap = HashMap::new(); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); let entry = can(&vec_eo, &mut ro); assert!(matches!(entry.edit_mode, Some(EditMode::Keep(true)))); } #[test] fn test_read_ini_config_file() { let mut vec_eo: Vec = vec![]; let mut ro = basic_ro("ed", "root"); ro.acl_type = Acltype::Edit; basic_cmd(&mut ro, "/etc/please.ini"); let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); assert_eq!( read_ini_config_file(".", &mut vec_eo, &ro, true, &mut bytes, &mut ini_list), true ); let mut ini_list: HashMap = HashMap::new(); assert_eq!( read_ini_config_file("", &mut vec_eo, &ro, true, &mut bytes, &mut ini_list), true ); let mut ini_list: HashMap = HashMap::new(); assert_eq!( read_ini_config_file( "./faulty", &mut vec_eo, &ro, true, &mut bytes, &mut ini_list ), true ); } #[test] fn test_last() { let config = " [first] name=ed target=root regex=/bin/bash permit=false last=true [unreachable] name=ed target=root regex=/bin/bash permit=true " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/bash"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); let entry = can(&vec_eo, &mut ro); assert_eq!(entry.permit(), false); } #[test] fn test_reason() { let config = " [first] name=ed target=root regex=/bin/bash permit=false reason=true " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/bash"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); let entry = can(&vec_eo, &mut ro); assert_eq!(entry.reason, Some(ReasonType::Need(true))); } #[test] fn test_regex_build_user_expansion() { let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/bash"); let regex_re = regex_build("/var/www/html/%{USER}/page.html", &ro, "/", "none", None).unwrap(); assert_eq!(regex_re.as_str(), "^/var/www/html/ed/page.html$"); } #[test] fn test_section_name() { let config = " [first] name=ed target=root regex=/bin/bash permit=false reason=true " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/bash"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); let entry = can(&vec_eo, &mut ro); assert_eq!(entry.section, "first"); } #[test] fn test_multi_log() { let config = " [first] name=ed target=root regex=^/usr/bin/wc (/var/log/[a-zA-Z0-9-]+(\\.\\d+)?(\\s)?)+$ " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd( &mut ro, "/usr/bin/wc /var/log/messages /var/log/syslog /var/log/maillog", ); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); basic_cmd(&mut ro, "/usr/bin/wc /var/log/messages /var/log/messages.1"); assert_eq!(can(&vec_eo, &mut ro).permit(), true); basic_cmd( &mut ro, "/usr/bin/wc /var/log/messages /var/log/syslog /var/log/maillog /var/log/../../shadow", ); assert_eq!(can(&vec_eo, &mut ro).permit(), false); basic_cmd(&mut ro, "/usr/bin/wc"); assert_eq!(can(&vec_eo, &mut ro).permit(), false); basic_cmd(&mut ro, "/usr/bin/wc /etc/shadow"); assert_eq!(can(&vec_eo, &mut ro).permit(), false); basic_cmd(&mut ro, "/usr/bin/wc"); assert_eq!(can(&vec_eo, &mut ro).permit(), false); basic_cmd( &mut ro, "/usr/bin/wc /var/log/messages /var/log/messages.1 /var/log/../../etc/shadow", ); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_edit_group_regression() { let config = " [please_ini] name = lpadmin group = true regex = /etc/please.ini reason = true type = edit exitcmd = /usr/bin/please -c %{NEW} " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.groups.insert(String::from("lpadmin"), 1); ro.acl_type = Acltype::Edit; basic_cmd(&mut ro, "/etc/please.ini"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_ini_relative() { let mut vec_eo: Vec = vec![]; let config = " [inc] include = ./some.ini " .to_string(); let mut ro = basic_ro("ed", "root"); ro.target = "ed".to_string(); ro.acl_type = Acltype::List; basic_cmd(&mut ro, ""); let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); assert_eq!( read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list), true ); let config = " [inc] includedir = ./dir.d/some.ini " .to_string(); let mut ini_list: HashMap = HashMap::new(); assert_eq!( read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list), true ); let config = " [inc] includedir = /dev/null " .to_string(); let mut ini_list: HashMap = HashMap::new(); assert_eq!( read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list), false ); } #[test] fn test_ini_repeat() { let mut vec_eo: Vec = vec![]; let config = " [ed] name=ed rule=.* syslog=false reason=false " .to_string(); let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.target = "ed".to_string(); ro.acl_type = Acltype::List; basic_cmd(&mut ro, ""); let _ = read_ini( &config, &mut vec_eo, &ro, false, "/etc/please.ini", &mut bytes, &mut ini_list, ); assert_eq!(ini_list.contains_key("/etc/please.ini"), true); } #[test] fn test_can_include() { assert_eq!(can_dir_include("/etc/please.ini.z"), false); assert_eq!(can_dir_include("/etc/.please.ini"), false); assert_eq!(can_dir_include("/etc/.please.ini."), false); } #[test] fn test_can_include_pattern() { assert_eq!(can_include_file_pattern("/etc/please.ini"), true); assert_eq!(can_include_file_pattern("/etc/please.please.ini"), true); assert_eq!(can_include_file_pattern("/etc/please.d/ini.z"), false); assert_eq!(can_include_file_pattern("/etc/please.d/file.ini"), true); assert_eq!(can_include_file_pattern("/etc/please.d/.file.ini"), false); assert_eq!(can_include_file_pattern("/etc/please.d/.file"), false); } #[test] fn test_argument_replace() { assert_eq!( replace_new_args(vec![ "/bin/bash".to_string(), "-c".to_string(), "/bin/id".to_string(), "you're not the boss of me".to_string() ]), "/bin/bash -c /bin/id you're\\ not\\ the\\ boss\\ of\\ me" ); } #[test] fn test_syslog_format() { assert_eq!( escape_log(&"multiple \"strings\""), "multiple \\\"strings\\\"".to_string() ); } #[test] fn test_prng_alpha_num_string() { assert_eq!(prng_alpha_num_string(2).len(), 2); } #[test] // this will fail at a point in the future - if so, try and run it again // we need some random assurance fn test_prng_alpha_num_unique() { let length = 8; let a = prng_alpha_num_string(length); for _ in 1..100 { assert_ne!(a, prng_alpha_num_string(length)); } } #[test] fn test_list_output() { let config = " [list] name = %{USER} reason = false type = list " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.target = "ed".to_string(); ro.acl_type = Acltype::List; basic_cmd(&mut ro, ""); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); let list = produce_list(&vec_eo, &ro); assert_eq!(list, [" in file: static", " list:list: root"]); } #[test] fn test_environment_provided_but_not_allowed() { let config = " [env_nopes] name = %{USER} reason = false " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, ""); ro.allow_env_list = Some(vec!["PATH".to_string()]); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_environment_assign_env_list() { let config = " [ed_part_allowed] name = %{USER} reason = false type = run env_assign.ILIKETO = moveitmoveit env_assign.JOE = 90 regex = .* " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, ""); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); let entry = can(&vec_eo, &mut ro); assert_eq!( entry.env_assign.as_ref().unwrap().get("ILIKETO").unwrap(), "moveitmoveit" ); assert_eq!(entry.env_assign.as_ref().unwrap().get("JOE").unwrap(), "90"); } #[test] fn test_environment_provided_and_allowed() { let config = " [ed_part_allowed] name = %{USER} reason = false type = run permit_env = (HOME|PATH) rule = .* " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, ""); ro.allow_env_list = Some(vec!["PATH".to_string(), "HOME".to_string()]); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_environment_provided_but_some_allowed() { let config = " [ed_part_allowed] name = %{USER} reason = false type = run permit_env = (HOME|PATH) rule = .* " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, ""); ro.allow_env_list = Some(vec![ "PATH".to_string(), "HOME".to_string(), "DISASTER".to_string(), ]); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), false); } #[test] fn test_environment_not_provided_others_allowed() { let config = " [ed_part_allowed] name = %{USER} type = run permit_env = (HOME|PATH) rule = .* " .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, ""); ro.allow_env_list = None; read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_percent_user() { let config = r#" [ed] name = ed type = run target = root regex = /bin/echo [%]\{USER\} "# .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/echo %{USER}"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_percent_user_as_hex() { let config = r#" [ed] name = ed type = run target = root regex = /bin/echo \x25\{USER\} "# .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, "/bin/echo %{USER}"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_internal_backslash() { let config = r#" [ed] name = ed type = run target = root regex = /bin/echo hello\x5c\x5cworld "# .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.new_args = vec!["/bin/echo".to_string(), r#"hello\world"#.to_string()]; read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_internal_backslash_as_class() { let config = r#" [ed] name = ed type = run target = root regex = /bin/echo hello[\\][\\]world "# .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); basic_cmd(&mut ro, r#"/bin/echo hello\world"#); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_replace_new_args_spaces_exact_rule() { let config = r#" [ed] name = ed type = run target = root exact_rule = /bin/echo hello\ world "# .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.new_args = vec!["/bin/echo".to_string(), "hello world".to_string()]; read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_replace_new_args_spaces_rule() { let config = r#" [ed] name = ed type = run target = root rule = /bin/echo hello\\ world "# .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.new_args = vec!["/bin/echo".to_string(), "hello world".to_string()]; read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_replace_new_args_internal_backslash_spaces_rule() { let config = r#" [ed] name = ed type = run target = root rule = /bin/echo hello\\ \\\\\\\\\\ world "# .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.new_args = vec!["/bin/echo".to_string(), r#"hello \\ world"#.to_string()]; read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).permit(), true); } #[test] fn test_default_edit_file_mode() { let config = r#" [ed] name = ed type = edit target = root rule = /etc/fstab "# .to_string(); let mut vec_eo: Vec = vec![]; let mut bytes = 0; let mut ini_list: HashMap = HashMap::new(); let mut ro = basic_ro("ed", "root"); ro.acl_type = Acltype::Edit; basic_cmd(&mut ro, "/etc/fstab"); read_ini_config_str(&config, &mut vec_eo, &ro, false, &mut bytes, &mut ini_list); assert_eq!(can(&vec_eo, &mut ro).edit_mode, None); } }