From 2b97e8b2e60a78f3de632b2c98c487841fe8e94e Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Sat, 17 Oct 2015 06:30:33 -0700 Subject: [PATCH] [server] command IP,SRC,PKT_SRC,DST,PORT,PROTO substitutions work for open/close cycles now --- server/cmd_cycle.c | 229 +++++++++++++++++++++++++++++++++--------- server/incoming_spa.c | 15 ++- server/utils.c | 1 + 3 files changed, 199 insertions(+), 46 deletions(-) diff --git a/server/cmd_cycle.c b/server/cmd_cycle.c index 26497f76..f9ed662d 100644 --- a/server/cmd_cycle.c +++ b/server/cmd_cycle.c @@ -31,6 +31,7 @@ #include "log_msg.h" #include "extcmd.h" #include "cmd_cycle.h" +#include "access.h" static char cmd_buf[CMD_CYCLE_BUFSIZE]; static char err_buf[CMD_CYCLE_BUFSIZE]; @@ -46,45 +47,165 @@ zero_cmd_buffers(void) static int pid_status = 0; static int -do_var_subs(const char * const str) +is_var(const char * const var, const char * const cmd_str) { int i; - - /* Look for a '$' char - */ - if (str != NULL && str[0] != 0x0) + for(i=0; i < strlen(var); i++) { - for (i=0; itest) + if(expand_acc_port_list(&port_list, spadat->spa_message_remain) != 1) { - log_msg(LOG_WARNING, - "[%s] (stanza #%d) --test mode enabled, skipping CMD_CYCLE_OPEN execution.", + free_acc_port_list(port_list); + return 0; + } + + /* We only look at the first port/proto combination for command + * open/close cycles even if the SPA message had multiple ports + * and protocols set. + */ + snprintf(port_str, MAX_PORT_STR_LEN+1, "%d", port_list->port); + snprintf(proto_str, MAX_PROTO_STR_LEN+1, "%d", port_list->proto); + + zero_cmd_buffers(); + + /* Look for the following variables for substitution: + * IP, SRC, PKT_SRC, DST, PORT, and PROTO + */ + for(i=0; i < strnlen(cmd_cycle_str, CMD_CYCLE_BUFSIZE); i++) + { + if(cmd_cycle_str[i] == '$') + { + /* Found the start of a variable, now validate it and + * swap in the IP/port/proto. + */ + if(is_var("IP", (cmd_cycle_str+i+1))) + { + strlcat(cmd_buf, spadat->use_src_ip, + CMD_CYCLE_BUFSIZE); + i += strlen("IP"); + buf_idx += strlen(spadat->use_src_ip); + } + /* SRC is a synonym for IP + */ + else if(is_var("SRC", (cmd_cycle_str+i+1))) + { + strlcat(cmd_buf, spadat->use_src_ip, + CMD_CYCLE_BUFSIZE); + i += strlen("SRC"); + buf_idx += strlen(spadat->use_src_ip); + } + /* Special case for the SPA packet source IP in + * the IP header (i.e. not from the decrypted SPA + * payload) if the user really wants this. + */ + else if(is_var("PKT_SRC", (cmd_cycle_str+i+1))) + { + strlcat(cmd_buf, spadat->pkt_source_ip, + CMD_CYCLE_BUFSIZE); + i += strlen("PKT_SRC"); + buf_idx += strlen(spadat->pkt_source_ip); + } + else if(is_var("DST", (cmd_cycle_str+i+1))) + { + strlcat(cmd_buf, spadat->pkt_destination_ip, + CMD_CYCLE_BUFSIZE); + i += strlen("DST"); + buf_idx += strlen(spadat->pkt_destination_ip); + } + else if (is_var("PORT", (cmd_cycle_str+i+1))) + { + strlcat(cmd_buf, port_str, CMD_CYCLE_BUFSIZE); + i += strlen("PORT"); + buf_idx += strlen(port_str); + } + else if (is_var("PROTO", (cmd_cycle_str+i+1))) + { + strlcat(cmd_buf, proto_str, CMD_CYCLE_BUFSIZE); + i += strlen("PROTO"); + buf_idx += strlen(proto_str); + } + continue; + } + cmd_buf[buf_idx++] = cmd_cycle_str[i]; + if(buf_idx == CMD_CYCLE_BUFSIZE) + { + free_acc_port_list(port_list); + return 0; + } + } + + free_acc_port_list(port_list); + return 1; +} + +static int +cmd_open(fko_srv_options_t *opts, acc_stanza_t *acc, + spa_data_t *spadat, const int stanza_num) +{ + /* CMD_CYCLE_OPEN: Build the open command by taking care of variable + * substitutions if necessary. + */ + if(build_cmd(spadat, acc->cmd_cycle_open)) + { + log_msg(LOG_INFO, "[%s] (stanza #%d) Running CMD_CYCLE_OPEN command: %s", + spadat->pkt_source_ip, stanza_num, cmd_buf); + + /* Run the open command + */ + run_extcmd(cmd_buf, err_buf, CMD_CYCLE_BUFSIZE, + WANT_STDERR, NO_TIMEOUT, &pid_status, opts); + } + else + { + log_msg(LOG_ERR, + "[%s] (stanza #%d) Could not build CMD_CYCLE_OPEN command.", spadat->pkt_source_ip, stanza_num ); return 0; } + return 1; +} - log_msg(LOG_INFO, "[%s] (stanza #%d) CMD_CYCLE_OPEN: %s", - spadat->pkt_source_ip, stanza_num, acc->cmd_cycle_open); - log_msg(LOG_INFO, "[%s] (stanza #%d) expected CMD_CYCLE_CLOSE: %s", - spadat->pkt_source_ip, stanza_num, acc->cmd_cycle_close); +static int +add_cmd_close(fko_srv_options_t *opts, acc_stanza_t *acc, + spa_data_t *spadat, const int stanza_num) +{ + cmd_cycle_list_t *last_clist=NULL, *new_clist=NULL, *tmp_clist=NULL; + time_t now; + int cmd_close_len = 0; + + /* CMD_CYCLE_CLOSE: Build the close command, but don't execute it until + * the expiration timer has passed. + */ + if(build_cmd(spadat, acc->cmd_cycle_close)) + { + /* Now the corresponding close command is now in cmd_buf + */ + cmd_close_len = strnlen(cmd_buf, CMD_CYCLE_BUFSIZE-1); + log_msg(LOG_INFO, "[%s] (stanza #%d) Running CMD_CYCLE_CLOSE command in %d seconds: %s", + spadat->pkt_source_ip, stanza_num, acc->cmd_cycle_timer, cmd_buf); + } + else + { + log_msg(LOG_ERR, + "[%s] (stanza #%d) Could not build CMD_CYCLE_CLOSE command.", + spadat->pkt_source_ip, stanza_num + ); + return 0; + } /* Add the corresponding close command - to be executed after the * designated timer has expired. @@ -94,7 +215,7 @@ cmd_cycle_open(fko_srv_options_t *opts, acc_stanza_t *acc, log_msg(LOG_ERR, "[*] Fatal memory allocation error creating string list entry" ); - return 0; // FIXME: handle this + clean_exit(opts, FW_CLEANUP, EXIT_FAILURE); } if(opts->cmd_cycle_list == NULL) @@ -112,36 +233,51 @@ cmd_cycle_open(fko_srv_options_t *opts, acc_stanza_t *acc, last_clist->next = new_clist; } - /* Set the source IP, expiration timer, and close command + /* Set the source IP */ - strlcpy(new_clist->src_ip, spadat->pkt_source_ip, + strlcpy(new_clist->src_ip, spadat->use_src_ip, sizeof(new_clist->src_ip)); + /* Set the expiration timer + */ time(&now); new_clist->expire = now + acc->cmd_cycle_timer; - /* Now, execute the open command + /* Set the close command */ - if(do_var_subs(acc->cmd_cycle_open)) + if((new_clist->close_cmd = calloc(1, cmd_close_len)) == NULL) { + log_msg(LOG_ERR, + "[*] Fatal memory allocation error creating command close string" + ); + clean_exit(opts, FW_CLEANUP, EXIT_FAILURE); } - else - { - /* Run the open command as-is - */ - open_cmd = acc->cmd_cycle_open; - } + strlcpy(new_clist->close_cmd, cmd_buf, cmd_close_len); - zero_cmd_buffers(); + /* Set the access.conf stanza number + */ + new_clist->stanza_num = stanza_num; - snprintf(cmd_buf, CMD_CYCLE_BUFSIZE-1, "%s", open_cmd); - - run_extcmd(cmd_buf, err_buf, CMD_CYCLE_BUFSIZE, - WANT_STDERR, NO_TIMEOUT, &pid_status, opts); - - return FKO_SUCCESS; + return 1; } +/* This is the main driver for open/close command cycles +*/ +int +cmd_cycle_open(fko_srv_options_t *opts, acc_stanza_t *acc, + spa_data_t *spadat, const int stanza_num, int *res) +{ + if(! cmd_open(opts, acc, spadat, stanza_num)) + return 0; + + if(! add_cmd_close(opts, acc, spadat, stanza_num)) + return 0; + + return FKO_SUCCESS; +} + +/* Run all close commands based on the expiration timer +*/ void cmd_cycle_close(fko_srv_options_t *opts) { @@ -160,11 +296,13 @@ cmd_cycle_close(fko_srv_options_t *opts) { tmp_clist = opts->cmd_cycle_list; do { - log_msg(LOG_INFO, "close command for src IP: %s", tmp_clist->src_ip); if(tmp_clist->expire <= now) { + log_msg(LOG_INFO, + "[%s] (stanza #%d) Timer expired, running CMD_CYCLE_CLOSE command: %s", + tmp_clist->src_ip, tmp_clist->stanza_num, + tmp_clist->close_cmd); // FIXME: must remove this element from the list - log_msg(LOG_INFO, "EXPIRED!", tmp_clist->src_ip); } } while((tmp_clist = tmp_clist->next)); } @@ -182,6 +320,7 @@ free_cmd_cycle_list(fko_srv_options_t *opts) while(clist != NULL) { tmp_clist = clist->next; + free(clist->close_cmd); free(clist); clist = tmp_clist; } diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 61279654..e85a867b 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -1178,7 +1178,20 @@ incoming_spa(fko_srv_options_t *opts) } else { - process_spa_request(opts, acc, &spadat); + if(acc->cmd_cycle_open != NULL) + { + if(cmd_cycle_open(opts, acc, &spadat, stanza_num, &res)) + break; /* successfully processed a matching access stanza */ + else + { + acc = acc->next; + continue; + } + } + else + { + process_spa_request(opts, acc, &spadat); + } } /* If we made it here, then the SPA packet was processed according diff --git a/server/utils.c b/server/utils.c index 9b3cc142..b71f794d 100644 --- a/server/utils.c +++ b/server/utils.c @@ -31,6 +31,7 @@ #include "replay_cache.h" #include "config_init.h" #include "fw_util.h" +#include "cmd_cycle.h" #include