Added support for COMMAND_MSG requests. Also added CMD_EXEC_USER to access.conf to allow for fwknopd to setuid to the specified user before running the command. Other minor tweaks.
git-svn-id: file:///home/mbr/svn/fwknop/trunk@226 510a4753-2344-4c79-9c09-4d669213fbeb
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <arpa/inet.h>
|
||||
#include "pwd.h"
|
||||
|
||||
#include "fwknopd_common.h"
|
||||
#include "access.h"
|
||||
@@ -434,8 +435,8 @@ free_acc_stanza_data(acc_stanza_t *acc)
|
||||
if(acc->key != NULL)
|
||||
free(acc->key);
|
||||
|
||||
if(acc->cmd_regex != NULL)
|
||||
free(acc->cmd_regex);
|
||||
if(acc->cmd_exec_user != NULL)
|
||||
free(acc->cmd_exec_user);
|
||||
|
||||
if(acc->gpg_home_dir != NULL)
|
||||
free(acc->gpg_home_dir);
|
||||
@@ -611,6 +612,7 @@ parse_access_file(fko_srv_options_t *opts)
|
||||
char tmp1[MAX_LINE_LEN] = {0};
|
||||
char tmp2[MAX_LINE_LEN] = {0};
|
||||
|
||||
struct passwd *pw;
|
||||
struct stat st;
|
||||
|
||||
acc_stanza_t *curr_acc = NULL;
|
||||
@@ -736,9 +738,21 @@ parse_access_file(fko_srv_options_t *opts)
|
||||
{
|
||||
add_acc_bool(&(curr_acc->enable_cmd_exec), val);
|
||||
}
|
||||
else if(CONF_VAR_IS(var, "CMD_REGEX"))
|
||||
else if(CONF_VAR_IS(var, "CMD_EXEC_USER"))
|
||||
{
|
||||
add_acc_string(&(curr_acc->cmd_regex), val);
|
||||
add_acc_string(&(curr_acc->cmd_exec_user), val);
|
||||
|
||||
errno = 0;
|
||||
pw = getpwnam(val);
|
||||
|
||||
if(pw == NULL)
|
||||
{
|
||||
fprintf(stderr, "Unable to determine UID for CMD_EXEC_USER: %s.\n",
|
||||
errno ? strerror(errno) : "Not a user on this system");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
curr_acc->cmd_exec_uid = pw->pw_uid;
|
||||
}
|
||||
else if(CONF_VAR_IS(var, "REQUIRE_USERNAME"))
|
||||
{
|
||||
@@ -970,7 +984,7 @@ dump_access_list(fko_srv_options_t *opts)
|
||||
" KEY: %s\n"
|
||||
" FW_ACCESS_TIMEOUT: %i\n"
|
||||
" ENABLE_CMD_EXEC: %s\n"
|
||||
" CMD_REGEX: %s\n"
|
||||
" CMD_EXEC_USER: %s\n"
|
||||
" REQUIRE_USERNAME: %s\n"
|
||||
" REQUIRE_SOURCE_ADDRESS: %s\n"
|
||||
" GPG_HOME_DIR: %s\n"
|
||||
@@ -984,7 +998,7 @@ dump_access_list(fko_srv_options_t *opts)
|
||||
(acc->key == NULL) ? "<not set>" : acc->key,
|
||||
acc->fw_access_timeout,
|
||||
acc->enable_cmd_exec ? "Yes" : "No",
|
||||
(acc->cmd_regex == NULL) ? "<not set>" : acc->cmd_regex,
|
||||
(acc->cmd_exec_user == NULL) ? "<not set>" : acc->cmd_exec_user,
|
||||
(acc->require_username == NULL) ? "<not set>" : acc->require_username,
|
||||
acc->require_source_address ? "Yes" : "No",
|
||||
(acc->gpg_home_dir == NULL) ? "<not set>" : acc->gpg_home_dir,
|
||||
|
||||
@@ -46,7 +46,7 @@ set_nonblock(int fd)
|
||||
* buffers with STDOUT an STDERR up to the size provided.
|
||||
*/
|
||||
int
|
||||
run_extcmd(char *cmd, char *so_buf, char *se_buf, size_t so_buf_sz, size_t se_buf_sz, int *status)
|
||||
_run_extcmd(uid_t user_uid, char *cmd, char *so_buf, char *se_buf, size_t so_buf_sz, size_t se_buf_sz, int *status)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
@@ -102,9 +102,20 @@ run_extcmd(char *cmd, char *so_buf, char *se_buf, size_t so_buf_sz, size_t se_bu
|
||||
close(so[0]);
|
||||
close(se[0]);
|
||||
|
||||
/* --DSS XXX: It would be more efficient to use one of the exec()
|
||||
* calls. (i.e. 'return(execvp(ext_cmd, &argv[1]));' ).
|
||||
* but for now, we use system() and exit with the external
|
||||
/* If user is not null, then we setuid to that user before running the
|
||||
* command.
|
||||
*/
|
||||
if(user_uid > 0)
|
||||
{
|
||||
if(setuid(user_uid) < 0)
|
||||
{
|
||||
exit(EXTCMD_SETUID_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* --DSS XXX: Would it be more efficient to use one of the exec()
|
||||
* calls (i.e. 'return(execvp(ext_cmd, &argv[1]));')?
|
||||
* For now, we use system() and exit with the external
|
||||
* command exit status.
|
||||
*/
|
||||
exit(WEXITSTATUS(system(cmd)));
|
||||
@@ -267,3 +278,18 @@ run_extcmd(char *cmd, char *so_buf, char *se_buf, size_t so_buf_sz, size_t se_bu
|
||||
*/
|
||||
return(retval);
|
||||
}
|
||||
|
||||
/* Run an external command. This is wrapper around _run_extcmd()
|
||||
*/
|
||||
run_extcmd(char *cmd, char *so_buf, char *se_buf, size_t so_buf_sz, size_t se_buf_sz, int *status)
|
||||
{
|
||||
return _run_extcmd(0, cmd, so_buf, se_buf, so_buf_sz, se_buf_sz, status);
|
||||
}
|
||||
|
||||
/* Run an external command as the specified user. This is wrapper around _run_extcmd()
|
||||
*/
|
||||
run_extcmd_as(uid_t user_uid, char *cmd, char *so_buf, char *se_buf, size_t so_buf_sz, size_t se_buf_sz, int *status)
|
||||
{
|
||||
return _run_extcmd(user_uid, cmd, so_buf, se_buf, so_buf_sz, se_buf_sz, status);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
* may end up in.
|
||||
*/
|
||||
enum {
|
||||
EXTCMD_SETUID_ERROR = -4,
|
||||
EXTCMD_SELECT_ERROR = -3,
|
||||
EXTCMD_PIPE_ERROR = -2,
|
||||
EXTCMD_FORK_ERROR = -1,
|
||||
@@ -66,6 +67,7 @@ enum {
|
||||
/* Function prototypes
|
||||
*/
|
||||
int run_extcmd(char *cmd, char *so_buf, char *se_buf, size_t so_buf_sz, size_t se_buf_sz, int *status);
|
||||
int run_extcmd_as(uid_t uid, char *cmd, char *so_buf, char *se_buf, size_t so_buf_sz, size_t se_buf_sz, int *status);
|
||||
|
||||
#endif /* EXTCMD_H */
|
||||
|
||||
|
||||
@@ -372,7 +372,7 @@ fw_initialize(fko_srv_options_t *opts)
|
||||
*
|
||||
*/
|
||||
if(opts->config[CONF_SNAT_TRANSLATE_IP] != NULL
|
||||
&& strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "_CHANGEME_", 10)!=0)
|
||||
&& strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0)
|
||||
{
|
||||
if(opts->config[CONF_IPT_SNAT_ACCESS] != NULL)
|
||||
set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]);
|
||||
@@ -661,7 +661,7 @@ process_spa_request(fko_srv_options_t *opts, spa_data_t *spadat)
|
||||
* or MASQUERADE.
|
||||
*/
|
||||
if(opts->config[CONF_SNAT_TRANSLATE_IP] != NULL
|
||||
&& strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "_CHANGEME_", 10)!=0)
|
||||
&& strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0)
|
||||
{
|
||||
/* Using static SNAT */
|
||||
snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# Machine hostname. If not set, fwknopd will attempt to use gethostname()
|
||||
# to determine the local hostname and use that.
|
||||
#
|
||||
#HOSTNAME _CHANGEME_;
|
||||
#HOSTNAME __CHANGEME__;
|
||||
|
||||
# Define the firewall type. The default is "iptables" for Linux systems,
|
||||
# but this can be set to "ipfw" for *BSD systems. Also supported is
|
||||
@@ -108,7 +108,7 @@ ENABLE_IPT_LOCAL_NAT Y;
|
||||
# variable.
|
||||
#
|
||||
ENABLE_IPT_SNAT N;
|
||||
#SNAT_TRANSLATE_IP _CHANGEME_;
|
||||
#SNAT_TRANSLATE_IP __CHANGEME__;
|
||||
|
||||
# Add ACCEPT rules to the FWKNOP_OUTPUT chain. This is usually only useful
|
||||
# if there are no state tracking rules to allow connection responses out and
|
||||
|
||||
@@ -102,6 +102,7 @@ enum {
|
||||
SPA_MSG_REPLAY,
|
||||
SPA_MSG_TOO_OLD,
|
||||
SPA_MSG_ACCESS_DENIED,
|
||||
SPA_MSG_COMMAND_ERROR,
|
||||
SPA_MSG_NOT_SUPPORTED,
|
||||
SPA_MSG_ERROR
|
||||
};
|
||||
@@ -315,7 +316,8 @@ typedef struct acc_stanza
|
||||
char *key;
|
||||
int fw_access_timeout;
|
||||
unsigned char enable_cmd_exec;
|
||||
char *cmd_regex;
|
||||
char *cmd_exec_user;
|
||||
uid_t cmd_exec_uid;
|
||||
char *require_username;
|
||||
unsigned char require_source_address;
|
||||
char *gpg_home_dir;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "fwknopd_common.h"
|
||||
#include "incoming_spa.h"
|
||||
#include "access.h"
|
||||
#include "extcmd.h"
|
||||
#include "log_msg.h"
|
||||
|
||||
/* Validate and in some cases preprocess/reformat the SPA data. Return an
|
||||
@@ -36,7 +37,7 @@ preprocess_spa_data(fko_srv_options_t *opts, char *src_ip)
|
||||
{
|
||||
spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);
|
||||
|
||||
unsigned char *ndx = &(spa_pkt->packet_data);
|
||||
unsigned char *ndx = (unsigned char *)&(spa_pkt->packet_data);
|
||||
int pkt_data_len = spa_pkt->packet_data_len;
|
||||
int tc, i;
|
||||
|
||||
@@ -170,7 +171,8 @@ incoming_spa(fko_srv_options_t *opts)
|
||||
|
||||
char *spa_ip_demark;
|
||||
time_t now_ts;
|
||||
int res, ts_diff, enc_type;
|
||||
int res, status, ts_diff, enc_type;
|
||||
uid_t myuid;
|
||||
|
||||
spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);
|
||||
|
||||
@@ -423,11 +425,42 @@ incoming_spa(fko_srv_options_t *opts)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* --DSS TODO: Finish Me */
|
||||
log_msg(LOG_WARNING,
|
||||
"SPA Command message are not yet supported."
|
||||
log_msg(LOG_INFO,
|
||||
"Processing SPA Command message: command='%s'.",
|
||||
spadat.spa_message_remain
|
||||
);
|
||||
res = SPA_MSG_NOT_SUPPORTED;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
if(opts->verbose)
|
||||
log_msg(LOG_INFO, "Setting effective user to %s (UID=%i) before running command.",
|
||||
acc->cmd_exec_user, acc->cmd_exec_uid);
|
||||
|
||||
|
||||
res = run_extcmd_as(acc->cmd_exec_uid,
|
||||
spadat.spa_message_remain,
|
||||
NULL, NULL, 0, 0, &status);
|
||||
}
|
||||
else /* Just run it as we are (root that is). */
|
||||
res = run_extcmd(spadat.spa_message_remain,
|
||||
NULL, NULL, 0, 0, &status);
|
||||
|
||||
/* --DSS XXX: I have found that the status (and res for that
|
||||
* matter) have been unreliable indicators of the
|
||||
* actual exit status of some commands. Not sure
|
||||
* why yet. For now, we will take what we get.
|
||||
*/
|
||||
status = WEXITSTATUS(status);
|
||||
|
||||
if(opts->verbose > 1)
|
||||
log_msg(LOG_WARNING,
|
||||
"CMD_EXEC: result: %i, command returned %i", res, status);
|
||||
|
||||
if(res != 0 || status != 0)
|
||||
res = SPA_MSG_COMMAND_ERROR;
|
||||
}
|
||||
|
||||
goto clean_and_bail;
|
||||
@@ -450,45 +483,10 @@ incoming_spa(fko_srv_options_t *opts)
|
||||
goto clean_and_bail;
|
||||
}
|
||||
|
||||
/* If we are here we will at least need to have the base access. So we
|
||||
* can go ahead an generate that now.
|
||||
/* At this point, we can process the SPA request.
|
||||
*/
|
||||
res = process_spa_request(opts, &spadat);
|
||||
|
||||
#if 0
|
||||
if(res != FKO_SUCCESS)
|
||||
goto clean_and_bail;
|
||||
|
||||
/* Now see if we are looking for a local NAT access of some sort.
|
||||
*/
|
||||
if(spadat.message_type == FKO_LOCAL_NAT_ACCESS_MSG
|
||||
|| spadat.message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
|
||||
{
|
||||
log_msg(LOG_WARNING,
|
||||
"SPA Local NAT access messages are not yet supported."
|
||||
);
|
||||
|
||||
/* --DSS TODO: Finish Me */
|
||||
res = SPA_MSG_NOT_SUPPORTED;
|
||||
|
||||
goto clean_and_bail;
|
||||
}
|
||||
|
||||
/* NAT access messages.
|
||||
*/
|
||||
if(spadat.message_type == FKO_NAT_ACCESS_MSG
|
||||
|| spadat.message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG)
|
||||
{
|
||||
log_msg(LOG_WARNING,
|
||||
"SPA NAT access messages are not yet supported."
|
||||
);
|
||||
|
||||
res = SPA_MSG_NOT_SUPPORTED;
|
||||
|
||||
/* --DSS TODO: Finish Me */
|
||||
}
|
||||
#endif
|
||||
|
||||
clean_and_bail:
|
||||
if(ctx != NULL)
|
||||
fko_destroy(ctx);
|
||||
|
||||
Reference in New Issue
Block a user