diff --git a/ChangeLog b/ChangeLog index 360dfce8..2b668bb2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,14 @@ -fwknop-2.6.7 (05//2015): +fwknop-2.6.7 (07//2015): + - [server] Added sudo support for command execution mode. This was + suggested by Github user 'freegigi' (issue #159) as a means to provide + command filtering using the powerful sudoers syntax. This feature is + implemented by prefixing any incoming command from a valid SPA packet + with the sudo command along with optional user and group requirements + as defined by the following new access.conf variables: + ENABLE_CMD_SUDO_EXEC, CMD_SUDO_EXEC_USER, and CMD_SUDO_EXEC_GROUP. - [server] Kevin Layer reported a bug to the fwknop mailing list that simultaneous NAT access for two different access.conf stanza was not - functioning properly. After some diagnosis, this is a result of + functioning properly. After some diagnosis, this was a result of rule_exists() not properly detecting and differentiating existing DNAT rules from new ones with different port numbers when 'iptables -C' support is not available. This was against iptables-1.4.7, and has been diff --git a/doc/fwknopd.man.asciidoc b/doc/fwknopd.man.asciidoc index faa7d459..167eda54 100644 --- a/doc/fwknopd.man.asciidoc +++ b/doc/fwknopd.man.asciidoc @@ -543,7 +543,7 @@ directive starts a new stanza. the *fwknopd* server as the user specified by the ``CMD_EXEC_USER'' or as the user that started *fwknopd* if that is not set. -*CMD_EXEC_ALL_SUDO* '':: +*ENABLE_CMD_SUDO_EXEC* '':: *sudo* provides a powerful means of restricting the sets of commands that users can execute via the ``sudoers'' file. By enabling this feature (and in ``ENABLE_CMD_EXEC'' mode), all incoming commands from valid SPA packets diff --git a/server/access.c b/server/access.c index 4717e225..4929c68e 100644 --- a/server/access.c +++ b/server/access.c @@ -76,6 +76,58 @@ add_acc_string(char **var, const char *val) return SUCCESS; } +/* Add an access user entry +*/ +static int +add_acc_user(char **user_var, uid_t *uid_var, struct passwd *upw, + const char *val, const char *var_name) +{ + struct passwd *pw = NULL; + + if(add_acc_string(user_var, val) != SUCCESS) + return FATAL_ERR; + + errno = 0; + upw = pw = getpwnam(val); + + if(pw == NULL) + { + log_msg(LOG_ERR, "[*] Unable to determine UID for %s: %s.", + var_name, errno ? strerror(errno) : "Not a user on this system"); + return FATAL_ERR; + } + + *uid_var = pw->pw_uid; + + return SUCCESS; +} + +/* Add an access group entry +*/ +static int +add_acc_group(char **group_var, gid_t *gid_var, + const char *val, const char *var_name) +{ + struct passwd *pw = NULL; + + if(add_acc_string(group_var, val) != SUCCESS) + return FATAL_ERR; + + errno = 0; + pw = getpwnam(val); + + if(pw == NULL) + { + log_msg(LOG_ERR, "[*] Unable to determine UID for %s: %s.", + var_name, errno ? strerror(errno) : "Not a group on this system"); + return FATAL_ERR; + } + + *gid_var = pw->pw_gid; + + return SUCCESS; +} + /* Decode base64 encoded string into access entry */ static int @@ -803,6 +855,12 @@ free_acc_stanza_data(acc_stanza_t *acc) free(acc->hmac_key_base64); } + if(acc->cmd_sudo_exec_user != NULL) + free(acc->cmd_sudo_exec_user); + + if(acc->cmd_sudo_exec_group != NULL) + free(acc->cmd_sudo_exec_group); + if(acc->cmd_exec_user != NULL) free(acc->cmd_exec_user); @@ -1077,7 +1135,9 @@ set_acc_defaults(fko_srv_options_t *opts) /* Perform some sanity checks on an acc stanza data. */ static int -acc_data_is_valid(fko_srv_options_t *opts, struct passwd *user_pw, acc_stanza_t * const acc) +acc_data_is_valid(fko_srv_options_t *opts, + struct passwd *user_pw, struct passwd *sudo_user_pw, + acc_stanza_t * const acc) { if(acc == NULL) { @@ -1176,6 +1236,17 @@ acc_data_is_valid(fko_srv_options_t *opts, struct passwd *user_pw, acc_stanza_t acc->cmd_exec_gid = user_pw->pw_gid; } + if(sudo_user_pw != NULL + && acc->cmd_sudo_exec_uid != 0 && acc->cmd_sudo_exec_gid == 0) + { + log_msg(LOG_INFO, + "Setting gid to group associated with CMD_SUDO_EXEC_USER '%s' in stanza source: '%s'", + acc->cmd_exec_user, + acc->source + ); + acc->cmd_sudo_exec_gid = sudo_user_pw->pw_gid; + } + return(1); } @@ -1193,8 +1264,8 @@ parse_access_file(fko_srv_options_t *opts) char var[MAX_LINE_LEN] = {0}; char val[MAX_LINE_LEN] = {0}; - struct passwd *pw = NULL; struct passwd *user_pw = NULL; + struct passwd *sudo_user_pw = NULL; struct stat st; acc_stanza_t *curr_acc = NULL; @@ -1293,7 +1364,7 @@ parse_access_file(fko_srv_options_t *opts) * stanza for the minimum required data. */ if(curr_acc != NULL) { - if(!acc_data_is_valid(opts, user_pw, curr_acc)) + if(!acc_data_is_valid(opts, user_pw, sudo_user_pw, curr_acc)) { log_msg(LOG_ERR, "[*] Data error in access file: '%s'", opts->config[CONF_ACCESS_FILE]); @@ -1484,47 +1555,45 @@ parse_access_file(fko_srv_options_t *opts) { add_acc_bool(&(curr_acc->enable_cmd_sudo_exec), val); } + else if(CONF_VAR_IS(var, "CMD_SUDO_EXEC_USER")) + { + if(add_acc_user(&(curr_acc->cmd_sudo_exec_user), + &(curr_acc->cmd_sudo_exec_uid), sudo_user_pw, + val, "CMD_SUDO_EXEC_USER") != SUCCESS) + { + fclose(file_ptr); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + } + else if(CONF_VAR_IS(var, "CMD_SUDO_EXEC_GROUP")) + { + if(add_acc_group(&(curr_acc->cmd_sudo_exec_group), + &(curr_acc->cmd_sudo_exec_gid), val, + "CMD_SUDO_EXEC_GROUP") != SUCCESS) + { + fclose(file_ptr); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + } else if(CONF_VAR_IS(var, "CMD_EXEC_USER")) { - if(add_acc_string(&(curr_acc->cmd_exec_user), val) != SUCCESS) + if(add_acc_user(&(curr_acc->cmd_exec_user), + &(curr_acc->cmd_exec_uid), user_pw, + val, "CMD_EXEC_USER") != SUCCESS) { fclose(file_ptr); clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); } - - errno = 0; - user_pw = pw = getpwnam(val); - - if(pw == NULL) - { - log_msg(LOG_ERR, "[*] Unable to determine UID for CMD_EXEC_USER: %s.", - errno ? strerror(errno) : "Not a user on this system"); - fclose(file_ptr); - clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); - } - - curr_acc->cmd_exec_uid = pw->pw_uid; } else if(CONF_VAR_IS(var, "CMD_EXEC_GROUP")) { - if(add_acc_string(&(curr_acc->cmd_exec_group), val) != SUCCESS) + if(add_acc_group(&(curr_acc->cmd_exec_group), + &(curr_acc->cmd_exec_gid), val, + "CMD_SUDO_EXEC_GROUP") != SUCCESS) { fclose(file_ptr); clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); } - - errno = 0; - pw = getpwnam(val); - - if(pw == NULL) - { - log_msg(LOG_ERR, "[*] Unable to determine GID for CMD_EXEC_GROUP: %s.", - errno ? strerror(errno) : "Not a group on this system"); - fclose(file_ptr); - clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); - } - - curr_acc->cmd_exec_gid = pw->pw_gid; } else if(CONF_VAR_IS(var, "REQUIRE_USERNAME")) { @@ -1759,7 +1828,7 @@ parse_access_file(fko_srv_options_t *opts) /* Sanity check the last stanza */ - if(!acc_data_is_valid(opts, user_pw, curr_acc)) + if(!acc_data_is_valid(opts, user_pw, sudo_user_pw, curr_acc)) { log_msg(LOG_ERR, "[*] Data error in access file: '%s'", @@ -1961,6 +2030,8 @@ dump_access_list(const fko_srv_options_t *opts) " FW_ACCESS_TIMEOUT: %i\n" " ENABLE_CMD_EXEC: %s\n" " ENABLE_CMD_SUDO_EXEC: %s\n" + " CMD_SUDO_EXEC_USER: %s\n" + " CMD_SUDO_EXEC_GROUP: %s\n" " CMD_EXEC_USER: %s\n" " CMD_EXEC_GROUP: %s\n" " REQUIRE_USERNAME: %s\n" @@ -1996,6 +2067,8 @@ dump_access_list(const fko_srv_options_t *opts) acc->fw_access_timeout, acc->enable_cmd_exec ? "Yes" : "No", acc->enable_cmd_sudo_exec ? "Yes" : "No", + (acc->cmd_sudo_exec_user == NULL) ? "" : acc->cmd_sudo_exec_user, + (acc->cmd_sudo_exec_group == NULL) ? "" : acc->cmd_sudo_exec_group, (acc->cmd_exec_user == NULL) ? "" : acc->cmd_exec_user, (acc->cmd_exec_group == NULL) ? "" : acc->cmd_exec_group, (acc->require_username == NULL) ? "" : acc->require_username, diff --git a/server/config_init.c b/server/config_init.c index d1456820..fcf5d197 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -1322,6 +1322,19 @@ config_init(fko_srv_options_t *opts, int argc, char **argv) case 'S': opts->status = 1; break; + case SUDO_EXE_PATH: + if (is_valid_exe(optarg)) + { + set_config_entry(opts, CONF_SUDO_EXE, optarg); + } + else + { + log_msg(LOG_ERR, + "[*] gpg path '%s' could not stat()/does not exist?", + optarg); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + break; case 't': opts->test = 1; break; diff --git a/server/extcmd.c b/server/extcmd.c index 83ed3452..5e003429 100644 --- a/server/extcmd.c +++ b/server/extcmd.c @@ -111,7 +111,7 @@ copy_or_search(char *so_read_buf, char *so_buf, const size_t so_buf_sz, } /* Run an external command returning exit status, and optionally filling - * provided buffer with STDOUT output up to the size provided. + * provided buffer with STDOUT output up to the size provided. * * Note: XXX: We are not using the timeout parameter at present. We still need * to implement a reliable timeout mechanism. @@ -136,6 +136,8 @@ _run_extcmd(uid_t uid, gid_t gid, const char *cmd, char *so_buf, #endif #if AFL_FUZZING + /* Don't allow command execution in AFL fuzzing mode + */ return 0; #endif diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 2fdc2ae2..fd8c6752 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -378,6 +378,10 @@ typedef struct acc_stanza int fw_access_timeout; unsigned char enable_cmd_exec; unsigned char enable_cmd_sudo_exec; + char *cmd_sudo_exec_user; + char *cmd_sudo_exec_group; + uid_t cmd_sudo_exec_uid; + gid_t cmd_sudo_exec_gid; char *cmd_exec_user; char *cmd_exec_group; uid_t cmd_exec_uid; diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 40501f3c..c9cab7b3 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -304,6 +304,7 @@ incoming_spa(fko_srv_options_t *opts) int is_err, cmd_exec_success = 0, attempted_decrypt = 0; int conf_pkt_age = 0; char dump_buf[CTX_DUMP_BUFSIZE]; + char cmd_buf[MAX_SPA_CMD_LEN] = {0}; spa_pkt_info_t *spa_pkt = &(opts->spa_pkt); @@ -881,24 +882,54 @@ incoming_spa(fko_srv_options_t *opts) spadat.pkt_source_ip, stanza_num, spadat.spa_message_remain ); - /* Do we need to become another user? If so, we call - * run_extcmd_as and pass the cmd_exec_uid. - */ - if(acc->cmd_exec_user != NULL && strncasecmp(acc->cmd_exec_user, "root", 4) != 0) + memset(cmd_buf, 0x0, sizeof(cmd_buf)); + if(acc->enable_cmd_sudo_exec) + { + /* Run the command via sudo - this allows sudo filtering + * to apply to the incoming command + */ + strlcpy(cmd_buf, opts->config[CONF_SUDO_EXE], + sizeof(cmd_buf)); + if(acc->cmd_sudo_exec_user != NULL + && strncasecmp(acc->cmd_sudo_exec_user, "root", 4) != 0) + { + strlcat(cmd_buf, " -u ", sizeof(cmd_buf)); + strlcat(cmd_buf, acc->cmd_sudo_exec_user, sizeof(cmd_buf)); + } + if(acc->cmd_exec_group != NULL + && strncasecmp(acc->cmd_sudo_exec_group, "root", 4) != 0) + { + strlcat(cmd_buf, " -g ", sizeof(cmd_buf)); + strlcat(cmd_buf, + acc->cmd_sudo_exec_group, sizeof(cmd_buf)); + } + strlcat(cmd_buf, " ", sizeof(cmd_buf)); + strlcat(cmd_buf, spadat.spa_message_remain, sizeof(cmd_buf)); + } + else + strlcpy(cmd_buf, spadat.spa_message_remain, sizeof(cmd_buf)); + + if(acc->cmd_exec_user != NULL + && strncasecmp(acc->cmd_exec_user, "root", 4) != 0) { log_msg(LOG_INFO, - "[%s] (stanza #%d) setuid/setgid user/group to %s/%s (UID=%i,GID=%i) before running command.", - spadat.pkt_source_ip, stanza_num, acc->cmd_exec_user, + "[%s] (stanza #%d) Running command '%s' setuid/setgid user/group to %s/%s (UID=%i,GID=%i)", + spadat.pkt_source_ip, stanza_num, cmd_buf, acc->cmd_exec_user, acc->cmd_exec_group == NULL ? acc->cmd_exec_user : acc->cmd_exec_group, acc->cmd_exec_uid, acc->cmd_exec_gid); res = run_extcmd_as(acc->cmd_exec_uid, acc->cmd_exec_gid, - spadat.spa_message_remain, NULL, 0, - WANT_STDERR, NO_TIMEOUT, &pid_status, opts); + cmd_buf, NULL, 0, WANT_STDERR, NO_TIMEOUT, + &pid_status, opts); } else /* Just run it as we are (root that is). */ - res = run_extcmd(spadat.spa_message_remain, NULL, 0, - WANT_STDERR, 5, &pid_status, opts); + { + log_msg(LOG_INFO, + "[%s] (stanza #%d) Running command '%s'", + spadat.pkt_source_ip, stanza_num, cmd_buf); + res = run_extcmd(cmd_buf, NULL, 0, WANT_STDERR, + 5, &pid_status, opts); + } /* should only call WEXITSTATUS() if WIFEXITED() is true */ diff --git a/test/test-fwknop.pl b/test/test-fwknop.pl index 323d0286..27769970 100755 --- a/test/test-fwknop.pl +++ b/test/test-fwknop.pl @@ -201,6 +201,9 @@ my $fuzzing_test_tag = ''; my $fuzzing_class = 'bogus data'; my %fuzzing_spa_packets = (); my $total_fuzzing_pkts = 0; +our $sudo_access_conf = "$run_dir/sudo_access.conf"; +my $sudo_conf = '/etc/sudoers'; +my $sudo_conf_testing = ''; my $server_test_file = ''; my $client_only_mode = 0; my $server_only_mode = 0; @@ -267,6 +270,7 @@ our $valgrind_path = ''; our $fiu_run_path = ''; our $sudo_path = ''; our $gcov_path = ''; +my $touch_path = ''; my $lcov_path = ''; my $coverage_diff_path = 'coverage_diff.py'; my $genhtml_path = ''; @@ -875,6 +879,11 @@ my %test_keys = ( 'server_exec_err' => $OPTIONAL, 'fw_rule_created' => $OPTIONAL, 'fw_rule_removed' => $OPTIONAL, + 'sudo_test' => $OPTIONAL, + 'sudo_conf' => $OPTIONAL, + 'sudo_exec_user' => $OPTIONAL, + 'sudo_exec_group' => $OPTIONAL, + 'exec_user' => $OPTIONAL, 'server_conf' => $OPTIONAL, 'client_only' => $OPTIONAL_NUMERIC, 'server_only' => $OPTIONAL_NUMERIC, @@ -902,6 +911,7 @@ my %test_keys = ( 'server_conf_file' => $OPTIONAL, 'digest_cache_file' => $OPTIONAL, 'cmd_exec_file_owner' => $OPTIONAL, + 'cmd_exec_file_not_created' => $OPTIONAL, 'rm_rule_mid_cycle' => $OPTIONAL, 'server_receive_re' => $OPTIONAL, 'no_exit_intf_down' => $OPTIONAL, @@ -4672,28 +4682,103 @@ sub get_mod_paths() { return \@paths; } +sub write_sudo_access_conf() { + my $test_hr = shift; + unlink $sudo_access_conf if -e $sudo_access_conf; + + # mbr localhost = NOPASSWD: /usr/bin/cat, /usr/bin/touch + # mbr localhost = NOPASSWD: /usr/bin/cat, (root) /usr/bin/touch + # mbr localhost = NOPASSWD: /usr/bin/cat, (mbr : mbr) /usr/bin/touch + if ($test_hr->{'sudo_conf'}) { + open ST, "> $sudo_conf_testing" or die $!; + $test_hr->{'sudo_conf'} =~ s/USER/$username/g; + if ($test_hr->{'sudo_conf'} =~ /TOUCH/) { + if ($touch_path) { + $test_hr->{'sudo_conf'} =~ s/TOUCH/$touch_path/; + } else { + $test_hr->{'sudo_conf'} =~ s|TOUCH|/bin/touch|; + } + } + print ST $test_hr->{'sudo_conf'}, "\n"; + close ST; + &write_test_file( + "[+] Setting $sudo_conf_testing file to:\n$test_hr->{'sudo_conf'}\n", + $curr_test_file); + } + + copy $cf{'hmac_cmd_access'}, $sudo_access_conf or die $!; + + open CA, ">> $sudo_access_conf" or die $!; + print CA "ENABLE_CMD_SUDO_EXEC Y\n"; + + if ($test_hr->{'exec_user'} eq $YES) { + print CA "CMD_EXEC_USER $username\n"; + } + if ($test_hr->{'sudo_exec_user'} eq $YES) { + print CA "CMD_SUDO_EXEC_USER $username\n"; + } + if ($test_hr->{'sudo_exec_group'} eq $YES) { + print CA "CMD_SUDO_EXEC_GROUP $username\n"; + } + + close CA; + + return; +} + sub spa_cmd_exec_cycle() { my $test_hr = shift; unlink $cmd_exec_test_file if -e $cmd_exec_test_file; + if ($test_hr->{'sudo_test'} eq $YES) { + ### we need to write the access.conf file based on sudo + ### requirements + &write_sudo_access_conf($test_hr); + } + + if (-e $cmd_exec_test_file) { + &write_test_file("[-] $cmd_exec_test_file file exists before SPA cycle.\n", + $curr_test_file); + } else { + &write_test_file("[+] $cmd_exec_test_file does not exist before SPA cycle.\n", + $curr_test_file); + } + my $rv = &spa_cycle($test_hr); if (-e $cmd_exec_test_file) { + &run_cmd("ls -l $cmd_exec_test_file", $cmd_out_tmp, $curr_test_file); if ($test_hr->{'cmd_exec_file_owner'}) { + $test_hr->{'cmd_exec_file_owner'} =~ s/USER/$username/; my $user = (getpwuid((stat($cmd_exec_test_file))[4]))[0]; - if ($user and $user eq 'nobody') { - &write_test_file("[+] $cmd_exec_test_file is owned by user 'nobody'\n", + if ($user and $user eq $test_hr->{'cmd_exec_file_owner'}) { + &write_test_file("[+] $cmd_exec_test_file is owned by user: $user\n", + $curr_test_file); + $rv = 1; + } else { + &write_test_file("[+] $cmd_exec_test_file is not " . + "owned by user: $test_hr->{'cmd_exec_file_owner'}\n", $curr_test_file); - &run_cmd("ls -l $cmd_exec_test_file", $cmd_out_tmp, $curr_test_file); $rv = 1; } } + if ($test_hr->{'cmd_exec_file_not_created'}) { + &write_test_file("[-] $cmd_exec_test_file file exists, setting rv=0.\n", + $curr_test_file); + $rv = 0; + } unlink $cmd_exec_test_file; } else { - &write_test_file("[-] $cmd_exec_test_file file does not exist, setting rv=0.\n", - $curr_test_file); - $rv = 0; + if ($test_hr->{'cmd_exec_file_not_created'}) { + &write_test_file("[+] $cmd_exec_test_file file does not exist.\n", + $curr_test_file); + $rv = 1; + } else { + &write_test_file("[-] $cmd_exec_test_file file does not exist, setting rv=0.\n", + $curr_test_file); + $rv = 0; + } } return $rv; @@ -6936,17 +7021,32 @@ sub init() { push @tests_to_exclude, qr/perl FKO module.*FUZZING/; } - $sudo_path = &find_command('sudo') unless $sudo_path; - $killall_path = &find_command('killall') unless $killall_path; - $pgrep_path = &find_command('pgrep') unless $pgrep_path; - $lib_view_cmd = &find_command('ldd') unless $lib_view_cmd; - $git_path = &find_command('git') unless $git_path; - $perl_path = &find_command('perl') unless $perl_path; + $sudo_path = &find_command('sudo') unless $sudo_path; + $killall_path = &find_command('killall') unless $killall_path; + $pgrep_path = &find_command('pgrep') unless $pgrep_path; + $lib_view_cmd = &find_command('ldd') unless $lib_view_cmd; + $git_path = &find_command('git') unless $git_path; + $perl_path = &find_command('perl') unless $perl_path; + $touch_path = &find_command('touch') unless $touch_path; if ($sudo_path) { $username = (getpwuid((stat($test_suite_path))[4]))[0]; die "[*] Could not determine $test_suite_path owner" unless $username; + + ### see if sudo is configured to accept custom configs + if (-e $sudo_conf) { + open SR, "< $sudo_conf" or die $!; + while () { + if (/^#includedir\s+(\/\S+)/) { + $sudo_conf_testing = "$1/fwknop_testing"; + last; + } + } + close SR; + } + } else { + push @tests_to_exclude, qr/sudo/; } ### see if the 'nobody' user is on the system diff --git a/test/tests/rijndael_hmac_cmd_exec.pl b/test/tests/rijndael_hmac_cmd_exec.pl index 4cd9ac56..2428dba7 100644 --- a/test/tests/rijndael_hmac_cmd_exec.pl +++ b/test/tests/rijndael_hmac_cmd_exec.pl @@ -28,6 +28,20 @@ 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, 'server_positive_output_matches' => [qr/Command messages are not allowed/] }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => 'command execution invalid path', + 'function' => \&spa_cmd_exec_cycle, + 'cmdline' => qq|$fwknopCmd --server-cmd "badpath $cmd_exec_test_file" | . + "-a $fake_ip -D $loopback_ip --rc-file $cf{'rc_hmac_b64_key'} ". + "$verbose_str", + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $cf{'hmac_cmd_access'} " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + 'cmd_exec_file_not_created' => $YES, + }, + { 'category' => 'Rijndael+HMAC', 'subcategory' => 'client+server', @@ -87,12 +101,156 @@ 'detail' => "command execution uid/gid 'nobody'", 'function' => \&spa_cmd_exec_cycle, 'cmdline' => qq|$fwknopCmd --server-cmd "touch $cmd_exec_test_file" | . - "-a $fake_ip -D $loopback_ip --rc-file $cf{'rc_hmac_b64_key'} ". - "$verbose_str", + "-a $fake_ip -D $loopback_ip --rc-file $cf{'rc_hmac_b64_key'} " . + $verbose_str, 'cmd_exec_file_owner' => 'nobody', 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $cf{'hmac_cmd_giduid_access'} " . "-d $default_digest_file -p $default_pid_file $intf_str", 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => "command exec sudo current user (1)", + 'function' => \&spa_cmd_exec_cycle, + 'cmdline' => qq|$fwknopCmd --server-cmd "touch $cmd_exec_test_file" | . + "-a $fake_ip -D $loopback_ip --rc-file $cf{'rc_hmac_b64_key'} " . + $verbose_str, + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $sudo_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'sudo_test' => $YES, + 'sudo_conf' => 'USER localhost = NOPASSWD: /usr/bin/cat, TOUCH', + 'cmd_exec_file_owner' => 'root', + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => "command exec sudo current user (2)", + 'function' => \&spa_cmd_exec_cycle, + 'cmdline' => qq|$fwknopCmd --server-cmd "touch $cmd_exec_test_file" | . + "-a $fake_ip -D $loopback_ip --rc-file $cf{'rc_hmac_b64_key'} " . + $verbose_str, + 'cmd_exec_file_owner' => 'nobody', + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $sudo_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'sudo_test' => $YES, + 'sudo_conf' => 'USER localhost = NOPASSWD: /usr/bin/cat, (root) TOUCH', + 'sudo_exec_user' => $YES, + 'cmd_exec_file_owner' => 'root', + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => "command exec sudo current user (3)", + 'function' => \&spa_cmd_exec_cycle, + 'cmdline' => qq|$fwknopCmd --server-cmd "touch $cmd_exec_test_file" | . + "-a $fake_ip -D $loopback_ip --rc-file $cf{'rc_hmac_b64_key'} " . + $verbose_str, + 'cmd_exec_file_owner' => 'nobody', + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $sudo_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'sudo_test' => $YES, + 'exec_user' => $YES, + 'sudo_conf' => 'USER localhost = NOPASSWD: /usr/bin/cat, TOUCH', + 'sudo_exec_user' => $YES, + 'cmd_exec_file_not_created' => $YES, + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + 'server_positive_output_matches' => [qr/is not allowed to execute/] + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => "command exec sudo current user (4)", + 'function' => \&spa_cmd_exec_cycle, + 'cmdline' => qq|$fwknopCmd --server-cmd "touch $cmd_exec_test_file" | . + "-a $fake_ip -D $loopback_ip --rc-file $cf{'rc_hmac_b64_key'} " . + $verbose_str, + 'cmd_exec_file_owner' => 'nobody', + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $sudo_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'sudo_test' => $YES, + 'exec_user' => $YES, + 'sudo_conf' => 'USER localhost = NOPASSWD: /usr/bin/cat, (USER) TOUCH', + 'sudo_exec_user' => $YES, + 'cmd_exec_file_owner' => 'USER', + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => "command exec sudo current user (5)", + 'function' => \&spa_cmd_exec_cycle, + 'cmdline' => qq|$fwknopCmd --server-cmd "touch $cmd_exec_test_file" | . + "-a $fake_ip -D $loopback_ip --rc-file $cf{'rc_hmac_b64_key'} " . + $verbose_str, + 'cmd_exec_file_owner' => 'nobody', + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $sudo_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'sudo_test' => $YES, + 'exec_user' => $YES, + 'sudo_conf' => 'USER localhost = NOPASSWD: /usr/bin/cat, (baduser) TOUCH', + 'sudo_exec_user' => $YES, + 'cmd_exec_file_not_created' => $YES, + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + 'server_positive_output_matches' => [qr/is not allowed to execute/] + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => "command exec sudo current user (6)", + 'function' => \&spa_cmd_exec_cycle, + 'cmdline' => qq|$fwknopCmd --server-cmd "touch $cmd_exec_test_file" | . + "-a $fake_ip -D $loopback_ip --rc-file $cf{'rc_hmac_b64_key'} " . + $verbose_str, + 'cmd_exec_file_owner' => 'nobody', + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $sudo_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'sudo_test' => $YES, + 'exec_user' => $YES, + 'sudo_conf' => 'USER localhost = NOPASSWD: /usr/bin/cat, notouchcmd', + 'sudo_exec_user' => $YES, + 'cmd_exec_file_not_created' => $YES, + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + 'server_positive_output_matches' => [qr/is not allowed to execute/] + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => "command exec sudo current user (7)", + 'function' => \&spa_cmd_exec_cycle, + 'cmdline' => qq|$fwknopCmd --server-cmd "touch $cmd_exec_test_file" | . + "-a $fake_ip -D $loopback_ip --rc-file $cf{'rc_hmac_b64_key'} " . + $verbose_str, + 'cmd_exec_file_owner' => 'nobody', + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $sudo_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'sudo_test' => $YES, + 'exec_user' => $YES, + 'sudo_conf' => 'USER localhost = NOPASSWD: /usr/bin/cat, (USER : USER) TOUCH', + 'sudo_exec_user' => $YES, + 'cmd_exec_file_owner' => 'USER', + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => "command exec sudo current user (8)", + 'function' => \&spa_cmd_exec_cycle, + 'cmdline' => qq|$fwknopCmd --server-cmd "touch $cmd_exec_test_file" | . + "-a $fake_ip -D $loopback_ip --rc-file $cf{'rc_hmac_b64_key'} " . + $verbose_str, + 'cmd_exec_file_owner' => 'nobody', + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $sudo_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'sudo_test' => $YES, + 'exec_user' => $YES, + 'sudo_conf' => 'USER localhost = NOPASSWD: /usr/bin/cat, (USER : USER) TOUCH', + 'sudo_exec_user' => $YES, + 'sudo_exec_group' => $YES, + 'cmd_exec_file_owner' => 'USER', + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + }, );