static void copy_or_search(char *so_read_buf, char *so_buf, const size_t so_buf_sz, const char *substr_search, const int cflag, int *found_str, int *do_break) { if(so_buf != NULL) { if(cflag & WANT_STDOUT_GETLINE) { memset(so_buf, 0x0, so_buf_sz); strlcpy(so_buf, so_read_buf, so_buf_sz); } else { strlcat(so_buf, so_read_buf, so_buf_sz); if(strlen(so_buf) >= so_buf_sz-1) *do_break = 1; } } if(substr_search != NULL) /* we are looking for a substring */ { /* Search the current line in so_read_buf instead of * so_buf (which may contain a partial line at the * end at this point). */ if(!IS_EMPTY_LINE(so_read_buf[0]) && strstr(so_read_buf, substr_search) != NULL) { *found_str = 1; *do_break = 1; } } return; }
/* returns: 0 in case of succes 1 in ... (still not in use) 2 in syntax error -1 in unexpected error */ int parse_cmd_line (cmd_line_t *cmd_line, const char *cmd) { size_t prv_cmd_beg = 0, i, cmd_len; /*used to get return of functions*/ int raux; /*STDIN, STDOUT, STDERR*/ int io_redir_seen=-1; /*return status*/ int ret = 0; sysfail (cmd_line==NULL, -1); cmd_len = strlen (cmd); /*assuming that the last thing is io redirection or nonblocking indicator*/ for (i=0; i < cmd_len && !IS_IO_REDIR (cmd[i]) && !IS_NONBLOCK (cmd[i]); ++i) { if (IS_PIPE (cmd[i])) { raux = pipe_list_push_cmd (cmd_line, cmd + prv_cmd_beg, i-prv_cmd_beg); sysfail (raux<0, -1); prv_cmd_beg = i + 1; } } /*last command (the one that comes after the last pipe)*/ if (prv_cmd_beg < cmd_len) { raux = pipe_list_push_cmd (cmd_line, cmd + prv_cmd_beg, i-prv_cmd_beg); sysfail (raux<0, -1); if (IS_EMPTY_LINE (raux)) { if (cmd_line->pipe_list_head != NULL) ret |= SYNTAX_ERROR; else ret |= EMPTY_LINE; return ret; } prv_cmd_beg = i + 1; } for (;i < cmd_len && !IS_NONBLOCK(cmd[i]); ++i) { /*todo: recognize output redir*/ if (IS_IO_REDIR (cmd[i])) { if (io_redir_seen != -1) cmd_line->io[io_redir_seen] = stringndup (cmd + prv_cmd_beg, i-prv_cmd_beg); prv_cmd_beg = i + 1; io_redir_seen = (IS_INPUT_REDIR (cmd[i])) ? 0 : 1; } else if (IS_PIPE (cmd[i])) ret |= SYNTAX_ERROR; } if (prv_cmd_beg < cmd_len && io_redir_seen != -1) cmd_line->io[io_redir_seen] = stringndup (cmd + prv_cmd_beg, i-prv_cmd_beg); /*if it is non_block it must be the last thing*/ cmd_line->is_nonblock = i < cmd_len && IS_NONBLOCK (cmd[i]); if (i < cmd_len-1) ret |= SYNTAX_ERROR; return ret; }
static int jump_rule_exists_no_chk_support(const fko_srv_options_t * const opts, const int chain_num) { int exists = 0; char cmd_buf[CMD_BUFSIZE] = {0}; char chain_search[CMD_BUFSIZE] = {0}; char line_buf[CMD_BUFSIZE] = {0}; FILE *ipt; snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].from_chain ); ipt = popen(cmd_buf, "r"); if(ipt == NULL) { log_msg(LOG_ERR, "Got error %i trying to get rules list.\n", errno); return(exists); } /* include spaces on either side as produced by 'iptables -L' output */ snprintf(chain_search, CMD_BUFSIZE-1, " %s ", fwc.chain[chain_num].to_chain); while((fgets(line_buf, CMD_BUFSIZE-1, ipt)) != NULL) { /* Get past comments and empty lines (note: we only look at the * first character). */ if(IS_EMPTY_LINE(line_buf[0])) continue; if(strstr(line_buf, chain_search) != NULL) { exists = 1; break; } } pclose(ipt); if(exists) log_msg(LOG_DEBUG, "jump_rule_exists_no_chk_support() jump rule found"); else log_msg(LOG_DEBUG, "jump_rule_exists_no_chk_support() jump rule not found"); return(exists); }
static int jump_rule_exists(const int chain_num) { int num, pos = 0; char cmd_buf[CMD_BUFSIZE] = {0}; char target[CMD_BUFSIZE] = {0}; char line_buf[CMD_BUFSIZE] = {0}; FILE *ipt; sprintf(cmd_buf, "%s " IPT_LIST_RULES_ARGS, fwc.fw_command, fwc.chain[chain_num].table, fwc.chain[chain_num].from_chain ); ipt = popen(cmd_buf, "r"); if(ipt == NULL) { log_msg(LOG_ERR, "Got error %i trying to get rules list.\n", errno); return(-1); } while((fgets(line_buf, CMD_BUFSIZE-1, ipt)) != NULL) { /* Get past comments and empty lines (note: we only look at the * first character). */ if(IS_EMPTY_LINE(line_buf[0])) continue; if(sscanf(line_buf, "%i %s ", &num, target) == 2) { if(strcmp(target, fwc.chain[chain_num].to_chain) == 0) { pos = num; break; } } } pclose(ipt); return(pos); }
/* Read and parse the access file, popluating the access data as we go. */ void parse_access_file(fko_srv_options_t *opts) { FILE *file_ptr; char *ndx; int got_source = 0; unsigned int num_lines = 0; char access_line_buf[MAX_LINE_LEN] = {0}; char var[MAX_LINE_LEN] = {0}; char val[MAX_LINE_LEN] = {0}; struct passwd *pw; struct stat st; acc_stanza_t *curr_acc = NULL; /* First see if the access file exists. If it doesn't, complain * and bail. */ if(stat(opts->config[CONF_ACCESS_FILE], &st) != 0) { fprintf(stderr, "[*] Access file: '%s' was not found.\n", opts->config[CONF_ACCESS_FILE]); exit(EXIT_FAILURE); } if ((file_ptr = fopen(opts->config[CONF_ACCESS_FILE], "r")) == NULL) { fprintf(stderr, "[*] Could not open access file: %s\n", opts->config[CONF_ACCESS_FILE]); perror(NULL); exit(EXIT_FAILURE); } /* Initialize the access list. */ acc_stanza_init(opts); /* Now walk through access file pulling the access entries into the * current stanza. */ while ((fgets(access_line_buf, MAX_LINE_LEN, file_ptr)) != NULL) { num_lines++; access_line_buf[MAX_LINE_LEN-1] = '\0'; /* Get past comments and empty lines (note: we only look at the * first character. */ if(IS_EMPTY_LINE(access_line_buf[0])) continue; if(sscanf(access_line_buf, "%s %[^;\n\r]", var, val) != 2) { fprintf(stderr, "*Invalid access file entry in %s at line %i.\n - '%s'", opts->config[CONF_ACCESS_FILE], num_lines, access_line_buf ); continue; } /* Remove any colon that may be on the end of the var */ if((ndx = strrchr(var, ':')) != NULL) *ndx = '\0'; /* */ if(opts->verbose > 3) fprintf(stderr, "ACCESS FILE: %s, LINE: %s\tVar: %s, Val: '%s'\n", opts->config[CONF_ACCESS_FILE], access_line_buf, var, val ); /* Process the entry. * * NOTE: If a new access.conf parameter is created. It also needs * to be accounted for in the following if/if else construct. */ if(CONF_VAR_IS(var, "SOURCE")) { /* If this is not the first stanza, sanity check the previous * stanza for the minimum required data. */ if(curr_acc != NULL) { if(!acc_data_is_valid(curr_acc)) { fprintf(stderr, "[*] Data error in access file: '%s'\n", opts->config[CONF_ACCESS_FILE]); exit(EXIT_FAILURE); } } /* Start new stanza. */ curr_acc = acc_stanza_add(opts); add_acc_string(&(curr_acc->source), val); got_source++; } else if (curr_acc == NULL) { /* The stanza must start with the "SOURCE" variable */ continue; } else if(CONF_VAR_IS(var, "OPEN_PORTS")) { add_acc_string(&(curr_acc->open_ports), val); } else if(CONF_VAR_IS(var, "RESTRICT_PORTS")) { add_acc_string(&(curr_acc->restrict_ports), val); } else if(CONF_VAR_IS(var, "KEY")) { if(strcasecmp(val, "__CHANGEME__") == 0) { fprintf(stderr, "[*] KEY value is not properly set in stanza source '%s' in access file: '%s'\n", curr_acc->source, opts->config[CONF_ACCESS_FILE]); exit(EXIT_FAILURE); } add_acc_string(&(curr_acc->key), val); } else if(CONF_VAR_IS(var, "FW_ACCESS_TIMEOUT")) { add_acc_int(&(curr_acc->fw_access_timeout), val); } else if(CONF_VAR_IS(var, "ENABLE_CMD_EXEC")) { add_acc_bool(&(curr_acc->enable_cmd_exec), val); } else if(CONF_VAR_IS(var, "CMD_EXEC_USER")) { 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")) { add_acc_string(&(curr_acc->require_username), val); } else if(CONF_VAR_IS(var, "REQUIRE_SOURCE_ADDRESS")) { add_acc_bool(&(curr_acc->require_source_address), val); } else if(CONF_VAR_IS(var, "GPG_HOME_DIR")) { if (is_valid_dir(val)) { add_acc_string(&(curr_acc->gpg_home_dir), val); } else { fprintf(stderr, "[*] GPG_HOME_DIR directory '%s' stat()/existence problem in stanza source '%s' in access file: '%s'\n", val, curr_acc->source, opts->config[CONF_ACCESS_FILE]); exit(EXIT_FAILURE); } } else if(CONF_VAR_IS(var, "GPG_DECRYPT_ID")) { add_acc_string(&(curr_acc->gpg_decrypt_id), val); } else if(CONF_VAR_IS(var, "GPG_DECRYPT_PW")) { if(strcasecmp(val, "__CHANGEME__") == 0) { fprintf(stderr, "[*] GPG_DECRYPT_PW value is not properly set in stanza source '%s' in access file: '%s'\n", curr_acc->source, opts->config[CONF_ACCESS_FILE]); exit(EXIT_FAILURE); } add_acc_string(&(curr_acc->gpg_decrypt_pw), val); } else if(CONF_VAR_IS(var, "GPG_REQUIRE_SIG")) { add_acc_bool(&(curr_acc->gpg_require_sig), val); } else if(CONF_VAR_IS(var, "GPG_IGNORE_SIG_VERIFY_ERROR")) { add_acc_bool(&(curr_acc->gpg_ignore_sig_error), val); } else if(CONF_VAR_IS(var, "GPG_REMOTE_ID")) { add_acc_string(&(curr_acc->gpg_remote_id), val); } else { fprintf(stderr, "*Ignoring unknown access parameter: '%s' in %s\n", var, opts->config[CONF_ACCESS_FILE] ); } } fclose(file_ptr); /* Basic check to ensure that we got at least one SOURCE stanza with * a valid KEY defined (valid meaning it has a value that is not * "__CHANGEME__". */ if (got_source == 0) { fprintf(stderr, "[*] Could not find valid SOURCE stanza in access file: '%s'\n", opts->config[CONF_ACCESS_FILE]); exit(EXIT_FAILURE); } /* Sanity check the last stanza */ if(!acc_data_is_valid(curr_acc)) { fprintf(stderr, "[*] Data error in access file: '%s'\n", opts->config[CONF_ACCESS_FILE]); exit(EXIT_FAILURE); } /* Expand our the expandable fields into their respective data buckets. */ expand_acc_ent_lists(opts); /* Make sure default values are set where needed. * a default value. */ set_acc_defaults(opts); return; }
static int replay_file_cache_init(fko_srv_options_t *opts) { FILE *digest_file_ptr = NULL; unsigned int num_lines = 0, digest_ctr = 0; char line_buf[MAX_LINE_LEN] = {0}; char src_ip[INET_ADDRSTRLEN+1] = {0}; char dst_ip[INET_ADDRSTRLEN+1] = {0}; long int time_tmp; int digest_file_fd = -1; char digest_header[] = "# <digest> <proto> <src_ip> <src_port> <dst_ip> <dst_port> <time>\n"; struct digest_cache_list *digest_elm = NULL; /* if the file exists, import the previous SPA digests into * the cache list */ if (access(opts->config[CONF_DIGEST_FILE], F_OK) == 0) { /* Check permissions */ if (access(opts->config[CONF_DIGEST_FILE], R_OK|W_OK) != 0) { log_msg(LOG_WARNING, "Digest file '%s' exists but: '%s'", opts->config[CONF_DIGEST_FILE], strerror(errno)); return(-1); } } else { /* the file does not exist yet, so it will be created when the first * successful SPA packet digest is written to disk */ digest_file_fd = open(opts->config[CONF_DIGEST_FILE], O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR); if (digest_file_fd == -1) { log_msg(LOG_WARNING, "Could not create digest cache: %s: %s", opts->config[CONF_DIGEST_FILE], strerror(errno)); return(-1); } else { if(write(digest_file_fd, digest_header, strlen(digest_header)) != strlen(digest_header)) { log_msg(LOG_WARNING, "Did not write expected number of bytes to digest cache: %s", opts->config[CONF_DIGEST_FILE]); } close(digest_file_fd); return(0); } } if(verify_file_perms_ownership(opts->config[CONF_DIGEST_FILE]) != 1) return(-1); /* File exists, and we have access - create in-memory digest cache */ if ((digest_file_ptr = fopen(opts->config[CONF_DIGEST_FILE], "r")) == NULL) { log_msg(LOG_WARNING, "Could not open digest cache: %s: %s", opts->config[CONF_DIGEST_FILE], strerror(errno)); return(-1); } /* Line format: * <digest> <proto> <src_ip> <src_port> <dst_ip> <dst_port> <time> * Example: * 7XgadOyqv0tF5xG8uhg2iIrheeNKglCWKmxQDgYP1dY 17 127.0.0.1 40305 127.0.0.1 62201 1313283481 */ while ((fgets(line_buf, MAX_LINE_LEN, digest_file_ptr)) != NULL) { num_lines++; line_buf[MAX_LINE_LEN-1] = '\0'; if(IS_EMPTY_LINE(line_buf[0])) continue; /* Initialize a digest cache list element, and add it into the list if * valid. */ if ((digest_elm = calloc(1, sizeof(struct digest_cache_list))) == NULL) { log_msg(LOG_ERR, "[*] Could not allocate digest list element"); continue; } if ((digest_elm->cache_info.digest = calloc(1, MAX_DIGEST_SIZE+1)) == NULL) { free(digest_elm); log_msg(LOG_ERR, "[*] Could not allocate digest string"); continue; } src_ip[0] = '\0'; dst_ip[0] = '\0'; if(sscanf(line_buf, "%64s %hhu %16s %hu %16s %hu %ld", digest_elm->cache_info.digest, /* %64s, buffer size is MAX_DIGEST_SIZE+1 */ &(digest_elm->cache_info.proto), src_ip, /* %16s, buffer size is INET_ADDRSTRLEN+1 */ &(digest_elm->cache_info.src_port), dst_ip, /* %16s, buffer size is INET_ADDRSTRLEN+1 */ &(digest_elm->cache_info.dst_port), &time_tmp) != 7) { log_msg(LOG_INFO, "*Skipping invalid digest file entry in %s at line %i.\n - %s", opts->config[CONF_DIGEST_FILE], num_lines, line_buf ); free(digest_elm->cache_info.digest); free(digest_elm); continue; } digest_elm->cache_info.created = time_tmp; if (inet_pton(AF_INET, src_ip, &(digest_elm->cache_info.src_ip)) != 1) { free(digest_elm->cache_info.digest); free(digest_elm); continue; } if (inet_pton(AF_INET, dst_ip, &(digest_elm->cache_info.dst_ip)) != 1) { free(digest_elm->cache_info.digest); free(digest_elm); continue; } digest_elm->next = opts->digest_cache; opts->digest_cache = digest_elm; digest_ctr++; if(opts->verbose > 3) log_msg(LOG_DEBUG, "DIGEST FILE: %s, VALID LINE: %s", opts->config[CONF_DIGEST_FILE], line_buf ); } fclose(digest_file_ptr); return(digest_ctr); }
/* Run an external command returning exit status, and optionally filling * 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. */ static int _run_extcmd(uid_t uid, gid_t gid, const char *cmd, char *so_buf, const size_t so_buf_sz, const int want_stderr, const int timeout, const char *substr_search, int *pid_status, const fko_srv_options_t * const opts) { char so_read_buf[IO_READ_BUF_LEN] = {0}; pid_t pid=0; FILE *output; int retval = EXTCMD_SUCCESS_ALL_OUTPUT; int line_ctr = 0, found_str = 0; char *argv_new[MAX_CMDLINE_ARGS]; /* for validation and/or execvpe() */ int argc_new=0; #if HAVE_EXECVPE int pipe_fd[2]; #endif #if AFL_FUZZING return 0; #endif *pid_status = 0; /* Even without execvpe() we examine the command for basic validity * in term of number of args */ memset(argv_new, 0x0, sizeof(argv_new)); if(strtoargv(cmd, argv_new, &argc_new, opts) != 1) { log_msg(LOG_ERR, "run_extcmd(): Error converting cmd str to argv via strtoargv()"); return EXTCMD_ARGV_ERROR; } #if !HAVE_EXECVPE /* if we are not using execvpe() then free up argv_new unconditionally * since was used only for validation */ free_argv(argv_new, &argc_new); #endif #if HAVE_EXECVPE if(opts->verbose > 1) log_msg(LOG_INFO, "run_extcmd() (with execvpe()): running CMD: %s", cmd); if(so_buf != NULL || substr_search != NULL) { if(pipe(pipe_fd) < 0) { log_msg(LOG_ERR, "run_extcmd(): pipe() failed: %s", strerror(errno)); free_argv(argv_new, &argc_new); return EXTCMD_PIPE_ERROR; } } pid = fork(); if (pid == 0) { if(chdir("/") != 0) exit(EXTCMD_CHDIR_ERROR); if(so_buf != NULL || substr_search != NULL) { close(pipe_fd[0]); dup2(pipe_fd[1], STDOUT_FILENO); if(want_stderr) dup2(pipe_fd[1], STDERR_FILENO); else close(STDERR_FILENO); } /* Take care of gid/uid settings before running the command. */ if(gid > 0) if(setgid(gid) < 0) exit(EXTCMD_SETGID_ERROR); if(uid > 0) if(setuid(uid) < 0) exit(EXTCMD_SETUID_ERROR); /* don't use env */ execvpe(argv_new[0], argv_new, (char * const *)NULL); } else if(pid == -1) { log_msg(LOG_ERR, "run_extcmd(): fork() failed: %s", strerror(errno)); free_argv(argv_new, &argc_new); return EXTCMD_FORK_ERROR; } /* Only the parent process makes it here */ if(so_buf != NULL || substr_search != NULL) { close(pipe_fd[1]); if ((output = fdopen(pipe_fd[0], "r")) != NULL) { if(so_buf != NULL) memset(so_buf, 0x0, so_buf_sz); while((fgets(so_read_buf, IO_READ_BUF_LEN, output)) != NULL) { line_ctr++; if(so_buf != NULL) { strlcat(so_buf, so_read_buf, so_buf_sz); if(strlen(so_buf) >= so_buf_sz-1) break; } else /* we are looking for a substring */ { /* Get past comments and empty lines (note: we only look at the * first character). */ if(IS_EMPTY_LINE(so_read_buf[0])) continue; if(strstr(so_read_buf, substr_search) != NULL) { found_str = 1; break; } } } fclose(output); } else { log_msg(LOG_ERR, "run_extcmd(): could not fdopen() pipe output file descriptor."); free_argv(argv_new, &argc_new); return EXTCMD_OPEN_ERROR; } } free_argv(argv_new, &argc_new); waitpid(pid, pid_status, 0); #else if(opts->verbose > 1) log_msg(LOG_INFO, "run_extcmd() (without execvpe()): running CMD: %s", cmd); if(so_buf == NULL && substr_search == NULL) { /* Since we do not have to capture output, we will fork here (which we * * would have to do anyway if we are running as another user as well). * */ pid = fork(); if(pid == -1) { log_msg(LOG_ERR, "run_extcmd: fork failed: %s", strerror(errno)); return(EXTCMD_FORK_ERROR); } else if (pid == 0) { /* We are the child */ if(chdir("/") != 0) exit(EXTCMD_CHDIR_ERROR); /* Take care of gid/uid settings before running the command. */ if(gid > 0) if(setgid(gid) < 0) exit(EXTCMD_SETGID_ERROR); if(uid > 0) if(setuid(uid) < 0) exit(EXTCMD_SETUID_ERROR); *pid_status = system(cmd); exit(*pid_status); } /* Retval is forced to 0 as we don't care about the exit status of * the child (for now) */ retval = EXTCMD_SUCCESS_ALL_OUTPUT; } else { /* Looking for output use popen and fill the buffer to its limit. */ output = popen(cmd, "r"); if(output == NULL) { log_msg(LOG_ERR, "Got popen error %i: %s", errno, strerror(errno)); retval = EXTCMD_OPEN_ERROR; } else { if(so_buf != NULL) memset(so_buf, 0x0, so_buf_sz); while((fgets(so_read_buf, IO_READ_BUF_LEN, output)) != NULL) { line_ctr++; if(so_buf != NULL) { strlcat(so_buf, so_read_buf, so_buf_sz); if(strlen(so_buf) >= so_buf_sz-1) break; } else /* we are looking for a substring */ { /* Get past comments and empty lines (note: we only look at the * first character). */ if(IS_EMPTY_LINE(so_read_buf[0])) continue; if(strstr(so_read_buf, substr_search) != NULL) { found_str = 1; break; } } } pclose(output); } } #endif if(substr_search != NULL) { /* The semantics of the return value changes in search mode to the line * number where the substring match was found, or zero if it wasn't found */ if(found_str) retval = line_ctr; else retval = 0; } else { if(WIFEXITED(*pid_status)) { /* Even if the child exited with an error condition, if we make it here * then the child exited normally as far as the OS is concerned (i.e. didn't * crash or get hit with a signal) */ retval = EXTCMD_SUCCESS_ALL_OUTPUT; } else retval = EXTCMD_EXECUTION_ERROR; } if(opts->verbose > 1) log_msg(LOG_INFO, "run_extcmd(): returning %d, pid_status: %d", retval, WIFEXITED(*pid_status) ? WEXITSTATUS(*pid_status) : *pid_status); return(retval); }
/* Parse the config file... */ static void parse_config_file(fko_srv_options_t *opts, const char *config_file) { FILE *cfile_ptr; unsigned int numLines = 0; unsigned int i, good_ent; int cndx; char conf_line_buf[MAX_LINE_LEN] = {0}; char var[MAX_LINE_LEN] = {0}; char val[MAX_LINE_LEN] = {0}; char tmp1[MAX_LINE_LEN] = {0}; char tmp2[MAX_LINE_LEN] = {0}; struct stat st; /* Make sure the config file exists. */ if(stat(config_file, &st) != 0) { log_msg(LOG_ERR, "[*] Config file: '%s' was not found.", config_file); clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); } if(verify_file_perms_ownership(config_file) != 1) clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); /* See the comment in the parse_access_file() function regarding security * here relative to a TOCTOU bug flagged by Coverity. */ if ((cfile_ptr = fopen(config_file, "r")) == NULL) { log_msg(LOG_ERR, "[*] Could not open config file: %s", config_file); perror(NULL); clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); } while ((fgets(conf_line_buf, MAX_LINE_LEN, cfile_ptr)) != NULL) { numLines++; conf_line_buf[MAX_LINE_LEN-1] = '\0'; /* Get past comments and empty lines (note: we only look at the * first character. */ if(IS_EMPTY_LINE(conf_line_buf[0])) continue; if(sscanf(conf_line_buf, "%s %[^;\n\r]", var, val) != 2) { log_msg(LOG_ERR, "*Invalid config file entry in %s at line %i.\n - '%s'", config_file, numLines, conf_line_buf ); continue; } /* fprintf(stderr, "CONF FILE: %s, LINE: %s\tVar: %s, Val: '%s'\n", config_file, conf_line_buf, var, val ); */ good_ent = 0; for(i=0; i<NUMBER_OF_CONFIG_ENTRIES; i++) { if(CONF_VAR_IS(config_map[i], var)) { /* First check to see if we need to do a varable expansion * on this value. Note: this only supports one expansion and * only if the value starts with the variable. */ if(*val == '$') { if(sscanf((val+1), "%[A-Z_]%s", tmp1, tmp2)) { if((cndx = config_entry_index(opts, tmp1)) >= 0) { strlcpy(val, opts->config[cndx], sizeof(val)); strlcat(val, tmp2, sizeof(val)); } } } set_config_entry(opts, i, val); good_ent++; break; } } if(good_ent == 0) log_msg(LOG_ERR, "[*] Ignoring unknown configuration parameter: '%s' in %s", var, config_file ); } fclose(cfile_ptr); return; }
static void spa_encoded_msg_fuzzing(void) { fko_ctx_t decode_ctx = NULL; int res = 0, pkt_id, require_success, require_digest, digest_type, msg_len; int line_ctr = 0, spa_payload_ctr = 0; FILE *fz = NULL; char line[MAX_LINE_LEN] = {0}; char b64_encoded_msg[MAX_LINE_LEN] = {0}; unsigned char b64_decoded_msg[MAX_LINE_LEN] = {0}; /* fuzzing file contents (or from stdin) are formatted like this: * * <pkt_ID> <status: success|fail> <digest: yes|no> <digest type> <base64_SPA_payload> */ if ((fz = fopen("fuzz_spa_payloads", "r")) == NULL) return; while ((fgets(line, MAX_LINE_LEN, fz)) != NULL) { line_ctr++; line[MAX_LINE_LEN-1] = '\0'; if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0'; if(IS_EMPTY_LINE(line[0])) continue; if(sscanf(line, "%d %d %d %d %s", &pkt_id, &require_success, &require_digest, &digest_type, b64_encoded_msg) != 5) { printf("[+] fuzzing parsing error at line: %d\n", line_ctr); continue; } msg_len = fko_base64_decode(b64_encoded_msg, b64_decoded_msg); spa_payload_ctr++; fko_new(&decode_ctx); if ((res = fko_set_encoded_data(decode_ctx, (char *) b64_decoded_msg, msg_len, require_digest, digest_type)) != FKO_SUCCESS) { printf("[-] pkt_id: %d, fko_set_encoded_data(): %s\n", pkt_id, fko_errstr(res)); } res = fko_decode_spa_data(decode_ctx); if (require_success) { if (res != FKO_SUCCESS) { printf("[-] pkt_id: %d, expected decode success but: fko_decode_spa_data(): %s\n", pkt_id, fko_errstr(res)); } } else { if (res == FKO_SUCCESS) { printf("[-] pkt_id: %d, expected decode failure but: fko_decode_spa_data(): %s\n", pkt_id, fko_errstr(res)); } } fko_destroy(decode_ctx); memset(line, 0x0, MAX_LINE_LEN); memset(b64_encoded_msg, 0x0, MAX_LINE_LEN); } fclose(fz); printf("[+] Sent %d SPA payloads through libfko encode/decode cycle...\n", spa_payload_ctr); return; }
/* Process (create if necessary) the users ~/.fwknoprc file. */ static void process_rc(fko_cli_options_t *options) { FILE *rc; int line_num = 0; int rcf_offset; char line[MAX_LINE_LEN]; char rcfile[MAX_PATH_LEN]; char curr_stanza[MAX_LINE_LEN] = {0}; char var[MAX_LINE_LEN] = {0}; char val[MAX_LINE_LEN] = {0}; char *ndx, *emark, *homedir; #ifdef WIN32 homedir = getenv("USERPROFILE"); #else homedir = getenv("HOME"); #endif if(homedir == NULL) { fprintf(stderr, "Warning: Unable to determine HOME directory.\n" " No .fwknoprc file processed.\n"); return; } memset(rcfile, 0x0, MAX_PATH_LEN); strlcpy(rcfile, homedir, MAX_PATH_LEN); rcf_offset = strlen(rcfile); /* Sanity check the path to .fwknoprc. * The preceeding path plus the path separator and '.fwknoprc' = 11 * cannot exceed MAX_PATH_LEN. */ if(rcf_offset > (MAX_PATH_LEN - 11)) { fprintf(stderr, "Warning: Path to .fwknoprc file is too long.\n" " No .fwknoprc file processed.\n"); return; } rcfile[rcf_offset] = PATH_SEP; strlcat(rcfile, ".fwknoprc", MAX_PATH_LEN); /* Check rc file permissions - if anything other than user read/write, * then throw a warning. This change was made to help ensure that the * client consumes a proper rc file with strict permissions set (thanks * to Fernando Arnaboldi from IOActive for pointing this out). */ verify_file_perms_ownership(rcfile); /* Open the rc file for reading, if it does not exist, then create * an initial .fwknoprc file with defaults and go on. */ if ((rc = fopen(rcfile, "r")) == NULL) { if(errno == ENOENT) { if(create_fwknoprc(rcfile) != 0) return; } else fprintf(stderr, "Unable to open rc file: %s: %s\n", rcfile, strerror(errno)); return; } /* Read in and parse the rc file parameters. */ while ((fgets(line, MAX_LINE_LEN, rc)) != NULL) { line_num++; line[MAX_LINE_LEN-1] = '\0'; ndx = line; /* Skip any leading whitespace. */ while(isspace(*ndx)) ndx++; /* Get past comments and empty lines (note: we only look at the * first character. */ if(IS_EMPTY_LINE(line[0])) continue; if(*ndx == '[') { ndx++; emark = strchr(ndx, ']'); if(emark == NULL) { fprintf(stderr, "Unterminated stanza line: '%s'. Skipping.\n", line); continue; } *emark = '\0'; strlcpy(curr_stanza, ndx, MAX_LINE_LEN); if(options->verbose > 3) fprintf(stderr, "RC FILE: %s, LINE: %s\tSTANZA: %s:\n", rcfile, line, curr_stanza ); continue; } if(sscanf(line, "%s %[^ ;\t\n\r#]", var, val) != 2) { fprintf(stderr, "*Invalid entry in %s at line %i.\n - '%s'", rcfile, line_num, line ); continue; } /* Remove any colon that may be on the end of the var */ if((ndx = strrchr(var, ':')) != NULL) *ndx = '\0'; if(options->verbose > 3) fprintf(stderr, "RC FILE: %s, LINE: %s\tVar: %s, Val: '%s'\n", rcfile, line, var, val ); /* We do not proceed with parsing until we know we are in * a stanza. */ if(strlen(curr_stanza) < 1) continue; /* Process the values. We assume we will see the default stanza * first, then if a named-stanza is specified, we process its * entries as well. */ if(strcasecmp(curr_stanza, "default") == 0) { if(parse_rc_param(options, var, val) < 0) fprintf(stderr, "Parameter error in %s, line %i: var=%s, val=%s\n", rcfile, line_num, var, val); } else if(options->use_rc_stanza[0] != '\0' && strncasecmp(curr_stanza, options->use_rc_stanza, MAX_LINE_LEN)==0) { options->got_named_stanza = 1; if(parse_rc_param(options, var, val) < 0) fprintf(stderr, "Parameter error in %s, stanza: %s, line %i: var=%s, val=%s\n", rcfile, curr_stanza, line_num, var, val); } } /* end while fgets rc */ fclose(rc); }
static int rule_exists_no_chk_support(const fko_srv_options_t * const opts, const struct fw_chain * const fwc, const unsigned int proto, const char * const ip, const unsigned int port, const unsigned int exp_ts) { int rule_exists = 0; char cmd_buf[CMD_BUFSIZE] = {0}; char line_buf[CMD_BUFSIZE] = {0}; char target_search[CMD_BUFSIZE] = {0}; char proto_search[CMD_BUFSIZE] = {0}; char ip_search[CMD_BUFSIZE] = {0}; char port_search[CMD_BUFSIZE] = {0}; char exp_ts_search[CMD_BUFSIZE] = {0}; FILE *ipt; snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, opts->fw_config->fw_command, fwc->table, fwc->to_chain ); ipt = popen(cmd_buf, "r"); if(ipt == NULL) { log_msg(LOG_ERR, "Got error %i trying to get rules list.\n", errno); return(rule_exists); } if(proto == IPPROTO_TCP) snprintf(proto_search, CMD_BUFSIZE-1, " tcp "); else if(proto == IPPROTO_UDP) snprintf(proto_search, CMD_BUFSIZE-1, " udp "); else if(proto == IPPROTO_ICMP) snprintf(proto_search, CMD_BUFSIZE-1, " icmp "); else snprintf(proto_search, CMD_BUFSIZE-1, " %u ", proto); snprintf(port_search, CMD_BUFSIZE-1, ":%u ", port); snprintf(target_search, CMD_BUFSIZE-1, " %s ", fwc->target); snprintf(ip_search, CMD_BUFSIZE-1, " %s ", ip); snprintf(exp_ts_search, CMD_BUFSIZE-1, "%u ", exp_ts); while((fgets(line_buf, CMD_BUFSIZE-1, ipt)) != NULL) { /* Get past comments and empty lines (note: we only look at the * first character). */ if(IS_EMPTY_LINE(line_buf[0])) continue; if((strstr(line_buf, exp_ts_search) != NULL) && (strstr(line_buf, proto_search) != NULL) && (strstr(line_buf, ip_search) != NULL) && (strstr(line_buf, target_search) != NULL) && (strstr(line_buf, port_search) != NULL)) { rule_exists = 1; break; } } pclose(ipt); if(rule_exists) log_msg(LOG_DEBUG, "rule_exists_no_chk_support() %s %u -> %s expires: %u rule (already exists", proto_search, port, ip, exp_ts); else log_msg(LOG_DEBUG, "rule_exists_no_chk_support() %s %u -> %s expires: %u rule does not exist", proto_search, port, ip, exp_ts); return(rule_exists); }