Example #1
0
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;
}
Example #2
0
/*
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;
} 
Example #3
0
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);
}
Example #4
0
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);
}
Example #5
0
/* 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;
}
Example #6
0
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);
}
Example #7
0
File: extcmd.c Project: sgh7/fwknop
/* 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);
}
Example #8
0
/* 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;
}
Example #9
0
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;
}
Example #10
0
/* 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);
}
Example #11
0
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);
}