[server] add sudo support, closes #159
This commit is contained in:
parent
89b2e8f477
commit
d681485e29
11
ChangeLog
11
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
|
||||
|
||||
@ -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* '<Y/N>'::
|
||||
*ENABLE_CMD_SUDO_EXEC* '<Y/N>'::
|
||||
*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
|
||||
|
||||
137
server/access.c
137
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) ? "<not set>" : acc->cmd_sudo_exec_user,
|
||||
(acc->cmd_sudo_exec_group == NULL) ? "<not set>" : acc->cmd_sudo_exec_group,
|
||||
(acc->cmd_exec_user == NULL) ? "<not set>" : acc->cmd_exec_user,
|
||||
(acc->cmd_exec_group == NULL) ? "<not set>" : acc->cmd_exec_group,
|
||||
(acc->require_username == NULL) ? "<not set>" : acc->require_username,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
@ -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 (<SR>) {
|
||||
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
|
||||
|
||||
@ -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,
|
||||
},
|
||||
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user