예제 #1
0
static int
chain_exists(const fko_srv_options_t * const opts, const int chain_num)
{
    int res = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHAIN_EXISTS_ARGS,
        fwc.fw_command,
        fwc.chain[chain_num].table,
        fwc.chain[chain_num].to_chain
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "chain_exists() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    if(EXTCMD_IS_SUCCESS(res))
        log_msg(LOG_DEBUG, "'%s' table '%s' chain exists",
            fwc.chain[chain_num].table,
            fwc.chain[chain_num].to_chain);
    else
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

    return res;
}
예제 #2
0
static int
add_jump_rule(const fko_srv_options_t *opts, const int chain_num)
{
    int res = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS,
        fwc.fw_command,
        fwc.chain[chain_num].table,
        fwc.chain[chain_num].from_chain,
        fwc.chain[chain_num].jump_rule_pos,
        fwc.chain[chain_num].to_chain
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

    if (opts->verbose)
        log_msg(LOG_INFO, "add_jump_rule() CMD: '%s' (res: %d, err: %s)",
            cmd_buf, res, err_buf);

    if(EXTCMD_IS_SUCCESS(res))
        log_msg(LOG_INFO, "Added jump rule from chain: %s to chain: %s",
            fwc.chain[chain_num].from_chain,
            fwc.chain[chain_num].to_chain);
    else
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

    return res;
}
예제 #3
0
static int
rule_exists_chk_support(const fko_srv_options_t * const opts,
        const char * const chain, const char * const rule)
{
    int     rule_exists = 0;
    int     res = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHK_RULE_ARGS,
            opts->fw_config->fw_command, chain, rule);

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "rule_exists_chk_support() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    if(EXTCMD_IS_SUCCESS(res) && strlen(err_buf))
    {
        log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s does not exist",
                rule, chain);
    }
    else
    {
        rule_exists = 1;
        log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s already exists",
                rule, chain);
    }

    return(rule_exists);
}
예제 #4
0
static int
create_chain(const fko_srv_options_t * const opts, const int chain_num)
{
    int res = 0, rv = 0;

    zero_cmd_buffers();

    /* Create the custom chain.
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS,
        fwc.fw_command,
        fwc.chain[chain_num].table,
        fwc.chain[chain_num].to_chain
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
                NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "create_chain() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    /* Expect full success on this */
    if(EXTCMD_IS_SUCCESS(res))
        rv = 1;
    else
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

    return rv;
}
예제 #5
0
static int
create_rule(const fko_srv_options_t * const opts,
        const char * const fw_chain, const char * const fw_rule)
{
    int res = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s -A %s %s",
            opts->fw_config->fw_command, fw_chain, fw_rule);

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
                NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "create_rule() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    if(EXTCMD_IS_SUCCESS(res))
    {
        log_msg(LOG_DEBUG, "create_rule() Rule: '%s' added to %s",
                fw_rule, fw_chain);
        res = 1;
    }
    else
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

    return res;
}
예제 #6
0
static int
ipfw_set_exists(const fko_srv_options_t *opts,
    const char *fw_command, const unsigned short set_num)
{
    int res = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_LIST_SET_RULES_ARGS,
        fw_command,
        set_num
    );

    res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);

    if (opts->verbose)
        log_msg(LOG_INFO, "ipfw_set_exists() CMD: '%s' (res: %d)",
            cmd_buf, res);

    if(!EXTCMD_IS_SUCCESS(res))
        return(0);

    if(cmd_out[0] == '\0')
        return(0);

    return(1);
}
예제 #7
0
static int
add_jump_rule(const fko_srv_options_t * const opts, const int chain_num)
{
    int res = 0, rv = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS,
        fwc.fw_command,
        fwc.chain[chain_num].table,
        fwc.chain[chain_num].from_chain,
        fwc.chain[chain_num].jump_rule_pos,
        fwc.chain[chain_num].to_chain
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);

    log_msg(LOG_DEBUG, "add_jump_rule() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    if(EXTCMD_IS_SUCCESS(res))
    {
        log_msg(LOG_INFO, "Added jump rule from chain: %s to chain: %s",
            fwc.chain[chain_num].from_chain,
            fwc.chain[chain_num].to_chain);
        rv = 1;
    }
    else
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

    return rv;
}
예제 #8
0
/* Check to see if the fwknop anchor is linked into the main policy.  If not,
 * any rules added/deleted by fwknopd will have no effect on real traffic.
*/
static int
anchor_active(const fko_srv_options_t *opts)
{
    int    res = 0;
    char   anchor_search_str[MAX_PF_ANCHOR_SEARCH_LEN] = {0};

    /* Build our anchor search string
    */
    snprintf(anchor_search_str, MAX_PF_ANCHOR_SEARCH_LEN-1, "%s\n",
        opts->fw_config->anchor);

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " PF_ANCHOR_CHECK_ARGS,
        opts->fw_config->fw_command
    );

    res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);

    if(!EXTCMD_IS_SUCCESS(res))
    {
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
        return 0;
    }

    /* Check to see if the anchor exists and is linked into the main policy
    */

    if(strstr(cmd_out, anchor_search_str) == NULL)
        return 0;

    return 1;
}
예제 #9
0
/* Create the fwknop custom chains (at least those that are configured).
*/
static int
create_fw_chains(const fko_srv_options_t *opts)
{
    int     i;
    int     res, got_err = 0;

    for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
    {
        if(fwc.chain[i].target[0] == '\0')
            continue;

        zero_cmd_buffers();

        /* Create the custom chain.
        */
        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS,
            fwc.fw_command,
            fwc.chain[i].table,
            fwc.chain[i].to_chain
        );

        res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

        if (opts->verbose)
            log_msg(LOG_INFO, "create_fw_chains() CMD: '%s' (res: %d, err: %s)",
                cmd_buf, res, err_buf);

        /* Expect full success on this */
        if(! EXTCMD_IS_SUCCESS(res))
        {
            log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
            got_err++;
        }

        /* Then create the jump rule to that chain.
        */
        res = add_jump_rule(opts, i);

        /* Expect full success on this */
        if(! EXTCMD_IS_SUCCESS(res))
            got_err++;
    }

    return(got_err);
}
예제 #10
0
static void
delete_all_anchor_rules(const fko_srv_options_t *opts)
{
    int res = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " PF_DEL_ALL_ANCHOR_RULES,
        fwc.fw_command,
        fwc.anchor
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

    /* Expect full success on this */
    if(! EXTCMD_IS_SUCCESS(res))
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

    return;
}
예제 #11
0
static int
ipfw_set_exists(const char *fw_command, const unsigned short set_num)
{
    int res = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_LIST_SET_RULES_ARGS,
        fw_command,
        set_num
    );

    res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);

    if(!EXTCMD_IS_SUCCESS(res))
        return(0);

    if(cmd_out[0] == '\0')
        return(0);

    return(1);
}
예제 #12
0
파일: incoming_spa.c 프로젝트: haron/fwknop
/* Process the SPA packet data
*/
void
incoming_spa(fko_srv_options_t *opts)
{
    /* Always a good idea to initialize ctx to null if it will be used
     * repeatedly (especially when using fko_new_with_data()).
    */
    fko_ctx_t       ctx = NULL;

    char            *spa_ip_demark, *gpg_id, *raw_digest = NULL;
    time_t          now_ts;
    int             res, status, ts_diff, enc_type, stanza_num=0;
    int             added_replay_digest = 0, pkt_data_len=0;
    int             is_err, cmd_exec_success = 0, attempted_decrypt = 0;
    int             conf_pkt_age = 0;
    char            dump_buf[CTX_DUMP_BUFSIZE];

    spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);

    /* This will hold our pertinent SPA data.
    */
    spa_data_t spadat;

    /* Loop through all access stanzas looking for a match
    */
    acc_stanza_t        *acc = opts->acc_stanzas;
    acc_string_list_t   *gpg_id_ndx;
    unsigned char        is_gpg_match = 0;

    inet_ntop(AF_INET, &(spa_pkt->packet_src_ip),
        spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip));

    /* At this point, we want to validate and (if needed) preprocess the
     * SPA data and/or to be reasonably sure we have a SPA packet (i.e
     * try to eliminate obvious non-spa packets).
    */
    pkt_data_len = spa_pkt->packet_data_len;
    res = preprocess_spa_data(opts, spadat.pkt_source_ip);
    if(res != FKO_SUCCESS)
    {
        log_msg(LOG_DEBUG, "[%s] preprocess_spa_data() returned error %i: '%s' for incoming packet.",
            spadat.pkt_source_ip, res, get_errstr(res));
        return;
    }

    if(opts->foreground == 1 && opts->verbose > 2)
    {
        printf("[+] candidate SPA packet payload:\n");
        hex_dump(spa_pkt->packet_data, pkt_data_len);
    }

    if(strncasecmp(opts->config[CONF_ENABLE_SPA_PACKET_AGING], "Y", 1) == 0)
    {
        conf_pkt_age = strtol_wrapper(opts->config[CONF_MAX_SPA_PACKET_AGE],
                0, RCHK_MAX_SPA_PACKET_AGE, NO_EXIT_UPON_ERR, &is_err);
        if(is_err != FKO_SUCCESS)
        {
            log_msg(LOG_ERR, "[*] [%s] invalid MAX_SPA_PACKET_AGE", spadat.pkt_source_ip);
            return;
        }
    }

    if (is_src_match(opts->acc_stanzas, ntohl(spa_pkt->packet_src_ip)))
    {
        if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
        {
            /* Check for a replay attack
            */
            res = get_raw_digest(&raw_digest, (char *)spa_pkt->packet_data);
            if(res != FKO_SUCCESS)
            {
                if (raw_digest != NULL)
                    free(raw_digest);
                return;
            }
            if (raw_digest == NULL)
                return;

            if (is_replay(opts, raw_digest) != SPA_MSG_SUCCESS)
            {
                free(raw_digest);
                return;
            }
        }
    }
    else
    {
        log_msg(LOG_WARNING,
            "No access data found for source IP: %s", spadat.pkt_source_ip
        );
        return;
    }

    /* Now that we know there is a matching access.conf stanza and the
     * incoming SPA packet is not a replay, see if we should grant any
     * access
    */
    while(acc)
    {
        res = FKO_SUCCESS;
        cmd_exec_success  = 0;
        attempted_decrypt = 0;
        stanza_num++;

        /* Start access loop with a clean FKO context
        */
        if(ctx != NULL)
        {
            if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
                log_msg(LOG_WARNING,
                    "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
                    spadat.pkt_source_ip, stanza_num, fko_errstr(res)
                );
            ctx = NULL;
        }

        /* Check for a match for the SPA source IP and the access stanza
        */
        if(! compare_addr_list(acc->source_list, ntohl(spa_pkt->packet_src_ip)))
        {
            acc = acc->next;
            continue;
        }

        log_msg(LOG_INFO, "(stanza #%d) SPA Packet from IP: %s received with access source match",
            stanza_num, spadat.pkt_source_ip);

        log_msg(LOG_DEBUG, "SPA Packet: '%s'", spa_pkt->packet_data);

        /* Make sure this access stanza has not expired
        */
        if(acc->access_expire_time > 0)
        {
            if(acc->expired)
            {
                acc = acc->next;
                continue;
            }
            else
            {
                if(time(NULL) > acc->access_expire_time)
                {
                    log_msg(LOG_INFO, "[%s] (stanza #%d) Access stanza has expired",
                        spadat.pkt_source_ip, stanza_num);
                    acc->expired = 1;
                    acc = acc->next;
                    continue;
                }
            }
        }

        /* Get encryption type and try its decoding routine first (if the key
         * for that type is set)
        */
        enc_type = fko_encryption_type((char *)spa_pkt->packet_data);

        if(acc->use_rijndael)
        {
            if (acc->key == NULL)
            {
                log_msg(LOG_ERR,
                    "[%s] (stanza #%d) No KEY for RIJNDAEL encrypted messages",
                    spadat.pkt_source_ip, stanza_num
                );
                acc = acc->next;
                continue;
            }

            /* Command mode messages may be quite long
            */
            if(acc->enable_cmd_exec || enc_type == FKO_ENCRYPTION_RIJNDAEL)
            {
                res = fko_new_with_data(&ctx, (char *)spa_pkt->packet_data,
                    acc->key, acc->key_len, acc->encryption_mode, acc->hmac_key,
                    acc->hmac_key_len, acc->hmac_type);
                attempted_decrypt = 1;
                if(res == FKO_SUCCESS)
                    cmd_exec_success = 1;
            }
        }

        if(acc->use_gpg && enc_type == FKO_ENCRYPTION_GPG && cmd_exec_success == 0)
        {
            /* For GPG we create the new context without decrypting on the fly
             * so we can set some GPG parameters first.
            */
            if(acc->gpg_decrypt_pw != NULL || acc->gpg_allow_no_pw)
            {
                res = fko_new_with_data(&ctx, (char *)spa_pkt->packet_data, NULL,
                        0, FKO_ENC_MODE_ASYMMETRIC, acc->hmac_key,
                        acc->hmac_key_len, acc->hmac_type);

                if(res != FKO_SUCCESS)
                {
                    log_msg(LOG_WARNING,
                        "[%s] (stanza #%d) Error creating fko context (before decryption): %s",
                        spadat.pkt_source_ip, stanza_num, fko_errstr(res)
                    );
                    acc = acc->next;
                    continue;
                }

                /* Set whatever GPG parameters we have.
                */
                if(acc->gpg_exe != NULL)
                {
                    res = fko_set_gpg_exe(ctx, acc->gpg_exe);
                    if(res != FKO_SUCCESS)
                    {
                        log_msg(LOG_WARNING,
                            "[%s] (stanza #%d) Error setting GPG path %s: %s",
                            spadat.pkt_source_ip, stanza_num, acc->gpg_exe,
                            fko_errstr(res)
                        );
                        acc = acc->next;
                        continue;
                    }
                }

                if(acc->gpg_home_dir != NULL)
                {
                    res = fko_set_gpg_home_dir(ctx, acc->gpg_home_dir);
                    if(res != FKO_SUCCESS)
                    {
                        log_msg(LOG_WARNING,
                            "[%s] (stanza #%d) Error setting GPG keyring path to %s: %s",
                            spadat.pkt_source_ip, stanza_num, acc->gpg_home_dir,
                            fko_errstr(res)
                        );
                        acc = acc->next;
                        continue;
                    }
                }

                if(acc->gpg_decrypt_id != NULL)
                    fko_set_gpg_recipient(ctx, acc->gpg_decrypt_id);

                /* If GPG_REQUIRE_SIG is set for this acc stanza, then set
                 * the FKO context accordingly and check the other GPG Sig-
                 * related parameters. This also applies when REMOTE_ID is
                 * set.
                */
                if(acc->gpg_require_sig)
                {
                    fko_set_gpg_signature_verify(ctx, 1);

                    /* Set whether or not to ignore signature verification errors.
                    */
                    fko_set_gpg_ignore_verify_error(ctx, acc->gpg_ignore_sig_error);
                }
                else
                {
                    fko_set_gpg_signature_verify(ctx, 0);
                    fko_set_gpg_ignore_verify_error(ctx, 1);
                }

                /* Now decrypt the data.
                */
                res = fko_decrypt_spa_data(ctx, acc->gpg_decrypt_pw, 0);
                attempted_decrypt = 1;
            }
        }

        if(attempted_decrypt == 0)
        {
            log_msg(LOG_ERR,
                "(stanza #%d) No stanza encryption mode match for encryption type: %i.",
                stanza_num, enc_type);
            acc = acc->next;
            continue;
        }

        /* Do we have a valid FKO context?  Did the SPA decrypt properly?
        */
        if(res != FKO_SUCCESS)
        {
            log_msg(LOG_WARNING, "[%s] (stanza #%d) Error creating fko context: %s",
                spadat.pkt_source_ip, stanza_num, fko_errstr(res));

            if(IS_GPG_ERROR(res))
                log_msg(LOG_WARNING, "[%s] (stanza #%d) - GPG ERROR: %s",
                    spadat.pkt_source_ip, stanza_num, fko_gpg_errstr(ctx));

            acc = acc->next;
            continue;
        }

        /* Add this SPA packet into the replay detection cache
        */
        if (added_replay_digest == 0
                && strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
        {

            res = add_replay(opts, raw_digest);
            if (res != SPA_MSG_SUCCESS)
            {
                log_msg(LOG_WARNING, "[%s] (stanza #%d) Could not add digest to replay cache",
                    spadat.pkt_source_ip, stanza_num);
                acc = acc->next;
                continue;
            }
            added_replay_digest = 1;
        }

        /* At this point, we assume the SPA data is valid.  Now we need to see
         * if it meets our access criteria.
        */
        log_msg(LOG_DEBUG, "[%s] (stanza #%d) SPA Decode (res=%i):",
            spadat.pkt_source_ip, stanza_num, res);

        res = dump_ctx_to_buffer(ctx, dump_buf, sizeof(dump_buf));
        if (res == FKO_SUCCESS)
            log_msg(LOG_DEBUG, "%s", dump_buf);
        else
            log_msg(LOG_WARNING, "Unable to dump FKO context: %s", fko_errstr(res));

        /* First, if this is a GPG message, and GPG_REMOTE_ID list is not empty,
         * then we need to make sure this incoming message is signer ID matches
         * an entry in the list.
        */
        if(enc_type == FKO_ENCRYPTION_GPG && acc->gpg_require_sig)
        {
            res = fko_get_gpg_signature_id(ctx, &gpg_id);
            if(res != FKO_SUCCESS)
            {
                log_msg(LOG_WARNING,
                    "[%s] (stanza #%d) Error pulling the GPG signature ID from the context: %s",
                    spadat.pkt_source_ip, stanza_num, fko_gpg_errstr(ctx));
                acc = acc->next;
                continue;
            }

            log_msg(LOG_INFO, "[%s] (stanza #%d) Incoming SPA data signed by '%s'.",
                spadat.pkt_source_ip, stanza_num, gpg_id);

            if(acc->gpg_remote_id != NULL)
            {
                is_gpg_match = 0;
                for(gpg_id_ndx = acc->gpg_remote_id_list;
                        gpg_id_ndx != NULL; gpg_id_ndx=gpg_id_ndx->next)
                {
                    res = fko_gpg_signature_id_match(ctx,
                            gpg_id_ndx->str, &is_gpg_match);
                    if(res != FKO_SUCCESS)
                    {
                        log_msg(LOG_WARNING,
                            "[%s] (stanza #%d) Error in GPG siganture comparision: %s",
                            spadat.pkt_source_ip, stanza_num, fko_gpg_errstr(ctx));
                        acc = acc->next;
                        continue;
                    }
                    if(is_gpg_match)
                        break;
                }

                if(! is_gpg_match)
                {
                    log_msg(LOG_WARNING,
                        "[%s] (stanza #%d) Incoming SPA packet signed by ID: %s, but that ID is not the GPG_REMOTE_ID list.",
                        spadat.pkt_source_ip, stanza_num, gpg_id);
                    acc = acc->next;
                    continue;
                }
            }
        }

        /* Populate our spa data struct for future reference.
        */
        res = get_spa_data_fields(ctx, &spadat);

        /* Figure out what our timeout will be. If it is specified in the SPA
         * data, then use that.  If not, try the FW_ACCESS_TIMEOUT from the
         * access.conf file (if there is one).  Otherwise use the default.
        */
        if(spadat.client_timeout > 0)
            spadat.fw_access_timeout = spadat.client_timeout;
        else if(acc->fw_access_timeout > 0)
            spadat.fw_access_timeout = acc->fw_access_timeout;
        else
            spadat.fw_access_timeout = DEF_FW_ACCESS_TIMEOUT;

        if(res != FKO_SUCCESS)
        {
            log_msg(LOG_ERR, "[%s] (stanza #%d) Unexpected error pulling SPA data from the context: %s",
                spadat.pkt_source_ip, stanza_num, fko_errstr(res));

            acc = acc->next;
            continue;
        }

        /* Check packet age if so configured.
        */
        if(strncasecmp(opts->config[CONF_ENABLE_SPA_PACKET_AGING], "Y", 1) == 0)
        {
            time(&now_ts);

            ts_diff = abs(now_ts - spadat.timestamp);

            if(ts_diff > conf_pkt_age)
            {
                log_msg(LOG_WARNING, "[%s] (stanza #%d) SPA data time difference is too great (%i seconds).",
                    spadat.pkt_source_ip, stanza_num, ts_diff);

                acc = acc->next;
                continue;
            }
        }

        /* At this point, we have enough to check the embedded (or packet source)
         * IP address against the defined access rights.  We start by splitting
         * the spa msg source IP from the remainder of the message.
        */
        spa_ip_demark = strchr(spadat.spa_message, ',');
        if(spa_ip_demark == NULL)
        {
            log_msg(LOG_WARNING, "[%s] (stanza #%d) Error parsing SPA message string: %s",
                spadat.pkt_source_ip, stanza_num, fko_errstr(res));

            acc = acc->next;
            continue;
        }

        if((spa_ip_demark-spadat.spa_message) < MIN_IPV4_STR_LEN-1
                || (spa_ip_demark-spadat.spa_message) > MAX_IPV4_STR_LEN)
        {
            log_msg(LOG_WARNING, "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet",
                spadat.pkt_source_ip, stanza_num, fko_errstr(res));

            if(ctx != NULL)
            {
                if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
                    log_msg(LOG_WARNING,
                        "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
                        spadat.pkt_source_ip, stanza_num, fko_errstr(res)
                    );
                ctx = NULL;
            }
            break;
        }

        strlcpy(spadat.spa_message_src_ip,
            spadat.spa_message, (spa_ip_demark-spadat.spa_message)+1);

        if(! is_valid_ipv4_addr(spadat.spa_message_src_ip))
        {
            log_msg(LOG_WARNING, "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet",
                spadat.pkt_source_ip, stanza_num, fko_errstr(res));

            if(ctx != NULL)
            {
                if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
                    log_msg(LOG_WARNING,
                        "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
                        spadat.pkt_source_ip, stanza_num, fko_errstr(res)
                    );
                ctx = NULL;
            }
            break;
        }

        strlcpy(spadat.spa_message_remain, spa_ip_demark+1, MAX_DECRYPTED_SPA_LEN);

        /* If use source IP was requested (embedded IP of 0.0.0.0), make sure it
         * is allowed.
        */
        if(strcmp(spadat.spa_message_src_ip, "0.0.0.0") == 0)
        {
            if(acc->require_source_address)
            {
                log_msg(LOG_WARNING,
                    "[%s] (stanza #%d) Got 0.0.0.0 when valid source IP was required.",
                    spadat.pkt_source_ip, stanza_num
                );

                acc = acc->next;
                continue;
            }

            spadat.use_src_ip = spadat.pkt_source_ip;
        }
        else
            spadat.use_src_ip = spadat.spa_message_src_ip;

        /* If REQUIRE_USERNAME is set, make sure the username in this SPA data
         * matches.
        */
        if(acc->require_username != NULL)
        {
            if(strcmp(spadat.username, acc->require_username) != 0)
            {
                log_msg(LOG_WARNING,
                    "[%s] (stanza #%d) Username in SPA data (%s) does not match required username: %s",
                    spadat.pkt_source_ip, stanza_num, spadat.username, acc->require_username
                );

                acc = acc->next;
                continue;
            }
        }

        /* Take action based on SPA message type.
        */
        if(spadat.message_type == FKO_LOCAL_NAT_ACCESS_MSG
              || spadat.message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG
              || spadat.message_type == FKO_NAT_ACCESS_MSG
              || spadat.message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG)
        {
#if FIREWALL_IPTABLES
            if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)!=0)
            {
                log_msg(LOG_WARNING,
                    "(stanza #%d) SPA packet from %s requested NAT access, but is not enabled",
                    stanza_num, spadat.pkt_source_ip
                );

                acc = acc->next;
                continue;
            }
#else
            log_msg(LOG_WARNING,
                "(stanza #%d) SPA packet from %s requested unsupported NAT access",
                stanza_num, spadat.pkt_source_ip
            );

            acc = acc->next;
            continue;
#endif
        }

        /* Command messages.
        */
        if(spadat.message_type == FKO_COMMAND_MSG)
        {
            if(!acc->enable_cmd_exec)
            {
                log_msg(LOG_WARNING,
                    "[%s] (stanza #%d) SPA Command message are not allowed in the current configuration.",
                    spadat.pkt_source_ip, stanza_num
                );

                acc = acc->next;
                continue;
            }
            else
            {
                log_msg(LOG_INFO,
                    "[%s] (stanza #%d) Processing SPA Command message: command='%s'.",
                    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)
                {
                    log_msg(LOG_INFO, "[%s] (stanza #%d) Setting effective user to %s (UID=%i) before running command.",
                        spadat.pkt_source_ip, stanza_num, acc->cmd_exec_user, acc->cmd_exec_uid);

                    res = run_extcmd_as(acc->cmd_exec_uid,
                                        spadat.spa_message_remain, NULL, 0, 0);
                }
                else /* Just run it as we are (root that is). */
                    res = run_extcmd(spadat.spa_message_remain, NULL, 0, 5);

                /* --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(res);

                if(opts->verbose > 1)
                    log_msg(LOG_WARNING,
                        "[%s] (stanza #%d) CMD_EXEC: command returned %i",
                        spadat.pkt_source_ip, stanza_num, status);

                if(status != 0)
                    res = SPA_MSG_COMMAND_ERROR;

                if(ctx != NULL)
                {
                    if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
                        log_msg(LOG_WARNING,
                            "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
                            spadat.pkt_source_ip, stanza_num, fko_errstr(res)
                        );
                    ctx = NULL;
                }

                /* we processed the command on a matching access stanza, so we
                 * don't look for anything else to do with this SPA packet
                */
                break;
            }
        }

        /* From this point forward, we have some kind of access message. So
         * we first see if access is allowed by checking access against
         * restrict_ports and open_ports.
         *
         *  --DSS TODO: We should add BLACKLIST support here as well.
        */
        if(! acc_check_port_access(acc, spadat.spa_message_remain))
        {
            log_msg(LOG_WARNING,
                "[%s] (stanza #%d) One or more requested protocol/ports was denied per access.conf.",
                spadat.pkt_source_ip, stanza_num
            );

            acc = acc->next;
            continue;
        }

        /* At this point, we process the SPA request and break out of the
         * access stanza loop (first valid access stanza stops us looking
         * for others).
        */
        process_spa_request(opts, acc, &spadat);
        if(ctx != NULL)
        {
            if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
                log_msg(LOG_WARNING,
                    "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
                    spadat.pkt_source_ip, stanza_num
                );
            ctx = NULL;
        }
        break;
    }

    if (raw_digest != NULL)
        free(raw_digest);

    if(ctx != NULL)
    {
        if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
            log_msg(LOG_WARNING,
                "[%s] fko_destroy() could not zero out sensitive data buffer.",
                spadat.pkt_source_ip
            );
        ctx = NULL;
    }

    return;
}
예제 #13
0
/* Iterate over the expired rule set and purge those that no longer have
 * corresponding dynamic rules.
*/
void
ipfw_purge_expired_rules(const fko_srv_options_t *opts)
{
    char           *ndx, *co_end;

    int             i, res;

    unsigned short  curr_rule;

    /* First, we get the current active dynamic rules for the expired rule
     * set. Then we compare it to the expired rules in the rule_map. Any
     * rules in the map that do not have a dynamic rule, can be deleted.
    */
    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_LIST_SET_DYN_RULES_ARGS,
        opts->fw_config->fw_command,
        fwc.expire_set_num
    );

    res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);

    if (opts->verbose)
        log_msg(LOG_INFO, "ipfw_purge_expired_rules() CMD: '%s' (res: %d)",
            cmd_buf, res);

    if(!EXTCMD_IS_SUCCESS(res))
    {
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
        return;
    }

    /* We may not have any dynamic rules at all - someone might not have
     * initiated a connection (for example)
    */
    if (cmd_out[0] != '\0')
    {
        co_end = cmd_out + strlen(cmd_out);

        if(opts->verbose > 1)
            log_msg(LOG_INFO, "EXP RULES LIST: %s", cmd_out);

        /* Find the "## Dynamic rules" string.
        */
        ndx = strcasestr(cmd_out, "## Dynamic rules");

        if(ndx == NULL)
        {
            log_msg(LOG_ERR,
                "Unexpected error: did not find 'Dynamic rules' string in list output."
            );
            return;
        }

        /* Jump to the next newline char.
        */
        ndx = strchr(ndx, '\n');

        if(ndx == NULL)
        {
            log_msg(LOG_ERR,
                "Unexpected error: did not find 'Dynamic rules' line terminating newline."
            );
            return;
        }

        /* Walk the list of dynamic rules (if any).
        */
        while(ndx != NULL)
        {
            ndx++;

            while(!isdigit(*ndx) && ndx < co_end)
                ndx++;

            if(ndx >= co_end)
                break;

            /* If we are at a digit, assume it is a rule number, extract it,
             * and if it falls in the correct range, mark it (so it is not
             * removed in the next step.
            */
            if(isdigit(*ndx))
            {
                curr_rule = atoi(ndx);

                if(curr_rule >= fwc.start_rule_num
                  && curr_rule < fwc.start_rule_num + fwc.max_rules)
                    fwc.rule_map[curr_rule - fwc.start_rule_num] = RULE_TMP_MARKED;
            }

            ndx = strchr(ndx, '\n');
        }
    }

    /* Now, walk the rule map and remove any still marked as expired.
    */
    for(i=0; i<fwc.max_rules; i++)
    {
        /* If it is TMP_MARKED, set it back to EXPIRED and move on.
        */
        if(fwc.rule_map[i] == RULE_TMP_MARKED)
        {
            fwc.rule_map[i] = RULE_EXPIRED;
            continue;
        }

        /* If it is not expired, move on.
        */
        if(fwc.rule_map[i] != RULE_EXPIRED)
            continue;

        /* This rule is ready to go away.
        */
        zero_cmd_buffers();

        curr_rule = fwc.start_rule_num + i;

        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_DEL_RULE_ARGS,
            opts->fw_config->fw_command,
#ifndef __APPLE__
            fwc.expire_set_num,
#endif
            curr_rule
        );

        res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);

        if (opts->verbose)
            log_msg(LOG_INFO, "ipfw_purge_expired_rules() CMD: '%s' (res: %d)",
                cmd_buf, res);

        if(!EXTCMD_IS_SUCCESS(res))
        {
            log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
            continue;
        }

        log_msg(LOG_INFO, "Purged rule %u from set %u", curr_rule, fwc.expire_set_num);

        fwc.rule_map[curr_rule - fwc.start_rule_num] = RULE_FREE;

        fwc.total_rules--;
    }
}
예제 #14
0
/* Iterate over the current rule set and purge expired
 * firewall rules.
*/
void
check_firewall_rules(const fko_srv_options_t *opts)
{
    char            exp_str[12];
    char            rule_num_str[6];
    char           *ndx, *rn_start, *rn_end, *tmp_mark;

    int             i=0, res=0;
    time_t          now, rule_exp, min_exp = 0;
    unsigned short  curr_rule;

    /* Just in case we somehow lose track and fall out-of-whack.
    */
    if(fwc.active_rules > fwc.max_rules)
        fwc.active_rules = 0;

    /* If there are no active rules or we have not yet
     * reached our expected next expire time, continue.
    */
    if(fwc.active_rules == 0)
        return;

    time(&now);

    if (fwc.next_expire > now)
        return;

    zero_cmd_buffers();

    /* There should be a rule to delete.  Get the current list of
     * rules for this chain and delete the ones that are expired.
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_LIST_SET_RULES_ARGS,
        opts->fw_config->fw_command,
        fwc.active_set_num
    );

    res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);

    if (opts->verbose)
        log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d)",
            cmd_buf, res);

    if(!EXTCMD_IS_SUCCESS(res))
    {
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
        return;
    }

    if(opts->verbose > 1)
        log_msg(LOG_INFO, "RULES LIST: %s", cmd_out);

    /* Find the first _exp_ string (if any).
    */
    ndx = strstr(cmd_out, EXPIRE_COMMENT_PREFIX);

    if(ndx == NULL)
    {
        /* we did not find an expected rule.
        */
        log_msg(LOG_ERR,
            "Did not find expire comment in rules list %i.\n", i);

        if (fwc.active_rules > 0)
            fwc.active_rules--;

        return;
    }

    /* Walk the list and process rules as needed.
    */
    while (ndx != NULL) {
        /* Jump forward and extract the timestamp
        */
        ndx += strlen(EXPIRE_COMMENT_PREFIX);

        /* remember this spot for when we look for the next
         * rule.
        */
        tmp_mark = ndx;

        strlcpy(exp_str, ndx, 11);
        rule_exp = (time_t)atoll(exp_str);

        if(rule_exp <= now)
        {
            /* Backtrack and get the rule number and delete it.
            */
            rn_start = ndx;
            while(--rn_start > cmd_out)
            {
                if(*rn_start == '\n')
                    break;
            }

            if(*rn_start == '\n')
            {
                rn_start++;
            }
            else if(rn_start > cmd_out)
            {
                /* This should not happen. But if it does, complain,
                 * decrement the active rule value, and go on.
                */
                log_msg(LOG_ERR,
                    "Rule parse error while finding rule line start.");

                if (fwc.active_rules > 0)
                    fwc.active_rules--;

                break;
            }

            rn_end = strchr(rn_start, ' ');

            if(rn_end == NULL)
            {
                /* This should not happen. But if it does, complain,
                 * decrement the active rule value, and go on.
                */
                log_msg(LOG_ERR,
                    "Rule parse error while finding rule number.");

                if (fwc.active_rules > 0)
                    fwc.active_rules--;

                break;
            }

            strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1);

            curr_rule = atoi(rule_num_str);

            zero_cmd_buffers();

            /* Move the rule to the expired rules set.
            */
            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_MOVE_RULE_ARGS,
                opts->fw_config->fw_command,
                curr_rule,
                fwc.expire_set_num
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
                    cmd_buf, res, err_buf);

            if(EXTCMD_IS_SUCCESS(res))
            {
                log_msg(LOG_INFO, "Moved rule %s with expire time of %u to set %u.",
                    rule_num_str, rule_exp, fwc.expire_set_num
                );

                if (fwc.active_rules > 0)
                    fwc.active_rules--;

                fwc.rule_map[curr_rule - fwc.start_rule_num] = RULE_EXPIRED;
            }
            else
                log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
        }
        else
        {
            /* Track the minimum future rule expire time.
            */
            if(rule_exp > now)
                min_exp = (min_exp < rule_exp) ? min_exp : rule_exp;
        }

        /* Push our tracking index forward beyond (just processed) _exp_
         * string so we can continue to the next rule in the list.
        */
        ndx = strstr(tmp_mark, EXPIRE_COMMENT_PREFIX);
    }

    /* Set the next pending expire time accordingly. 0 if there are no
     * more rules, or whatever the next expected (min_exp) time will be.
    */
    if(fwc.active_rules < 1)
        fwc.next_expire = 0;
    else if(min_exp)
        fwc.next_expire = min_exp;
}
예제 #15
0
void
fw_initialize(const fko_srv_options_t *opts)
{
    int             res = 0;
    unsigned short  curr_rule;
    char           *ndx;

    /* For now, we just call fw_cleanup to start with clean slate.
    */
    if(strncasecmp(opts->config[CONF_FLUSH_IPFW_AT_INIT], "Y", 1) == 0)
        res = fw_cleanup(opts);

    if(res != 0)
    {
        fprintf(stderr, "Fatal: Errors detected during ipfw rules initialization.\n");
        exit(EXIT_FAILURE);
    }

    /* Allocate our rule_map array for tracking active (and expired) rules.
    */
    fwc.rule_map = calloc(fwc.max_rules, sizeof(char));

    if(fwc.rule_map == NULL)
    {
        fprintf(stderr, "Fatal: Memory allocation error in fw_initialize.\n");
        exit(EXIT_FAILURE);
    }

    /* Create a check-state rule if necessary.
    */
    if(strncasecmp(opts->config[CONF_IPFW_ADD_CHECK_STATE], "Y", 1) == 0)
    {
        zero_cmd_buffers();

        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_ADD_CHECK_STATE_ARGS,
            fwc.fw_command,
            fwc.start_rule_num,
            fwc.active_set_num
        );

        res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

        if (opts->verbose)
            log_msg(LOG_INFO, "fw_initialize() CMD: '%s' (res: %d, err: %s)",
                cmd_buf, res, err_buf);

        if(EXTCMD_IS_SUCCESS(res))
        {
            log_msg(LOG_INFO, "Added check-state rule %u to set %u",
                fwc.start_rule_num,
                fwc.active_set_num
            );

            fwc.rule_map[0] = RULE_ACTIVE;
        }
        else
            log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
    }

    if(fwc.expire_set_num > 0
            && (strncasecmp(opts->config[CONF_FLUSH_IPFW_AT_INIT], "Y", 1) == 0))
    {
        /* Make sure our expire set is disabled.
        */
        zero_cmd_buffers();

        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_DISABLE_SET_ARGS,
            fwc.fw_command,
            fwc.expire_set_num
        );

        res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

        if (opts->verbose)
            log_msg(LOG_INFO, "fw_initialize() CMD: '%s' (res: %d, err: %s)",
                cmd_buf, res, err_buf);

        if(EXTCMD_IS_SUCCESS(res))
            log_msg(LOG_INFO, "Set ipfw expire set %u to disabled.",
                fwc.expire_set_num);
        else
            log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
    }

    /* Now read the expire set in case there are existing
     * rules to track.
    */
    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_LIST_EXP_SET_RULES_ARGS,
        opts->fw_config->fw_command,
        fwc.expire_set_num
    );

    res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);

    if (opts->verbose)
        log_msg(LOG_INFO, "fw_initialize() CMD: '%s' (res: %d)",
            cmd_buf, res);

    if(!EXTCMD_IS_SUCCESS(res))
    {
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
        return;
    }

    if(opts->verbose > 1)
        log_msg(LOG_INFO, "RULES LIST: %s", cmd_out);

    /* Find the first "# DISABLED" string (if any).
    */
    ndx = strstr(cmd_out, "# DISABLED ");

    /* Assume no disabled rules if we did not see the string.
    */
    if(ndx == NULL)
        return;

    /* Otherwise we walk each line to pull the rule number and
     * set the appropriate rule map entries.
    */
    while(ndx != NULL)
    {
        /* Skip over the DISABLED string to the rule num.
        */
        ndx += 11;

        if(isdigit(*ndx))
        {
            curr_rule = atoi(ndx);

            if(curr_rule >= fwc.start_rule_num
              && curr_rule < fwc.start_rule_num + fwc.max_rules)
            {
                fwc.rule_map[curr_rule - fwc.start_rule_num] = RULE_EXPIRED;
                fwc.total_rules++;
            }
        }
        else
            log_msg(LOG_WARNING, "fw_initialize: No rule number found where expected.");

        /* Find the next "# DISABLED" string (if any).
        */
        ndx = strstr(ndx, "# DISABLED ");
    }
}
예제 #16
0
/* Rule Processing - Create an access request...
*/
int
process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat)
{
    unsigned short   rule_num;

    acc_port_list_t *port_list = NULL;
    acc_port_list_t *ple;

    unsigned int    fst_proto;
    unsigned int    fst_port;

    int             res = 0;
    time_t          now;
    unsigned int    exp_ts;

    /* Parse and expand our access message.
    */
    expand_acc_port_list(&port_list, spadat->spa_message_remain);

    /* Start at the top of the proto-port list...
    */
    ple = port_list;

    /* Remember the first proto/port combo in case we need them
     * for NAT access requests.
    */
    fst_proto = ple->proto;
    fst_port  = ple->port;

    /* Set our expire time value.
    */
    time(&now);
    exp_ts = now + spadat->fw_access_timeout;

    /* For straight access requests, we currently support multiple proto/port
     * request.
    */
    if(spadat->message_type == FKO_ACCESS_MSG
      || spadat->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG)
    {
        /* Pull the next available rule number.
        */
        rule_num = get_next_rule_num();

        /* If rule_num comes back as 0, we aready have the maximum number
         * of active rules allowed so we reject and bail here.
        */
        if(rule_num == 0)
        {
            log_msg(LOG_WARNING, "Access request rejected: Maximum allowed number of rules has been reached.");
            return(-1);
        }

        /* Create an access command for each proto/port for the source ip.
        */
        while(ple != NULL)
        {
            zero_cmd_buffers();

            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_ADD_RULE_ARGS,
                fwc.fw_command,
                rule_num,
                fwc.active_set_num,
                ple->proto,
                spadat->use_src_ip,
                ple->port,
                exp_ts
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
                    cmd_buf, res, err_buf);

            if(EXTCMD_IS_SUCCESS(res))
            {
                log_msg(LOG_INFO, "Added Rule %u for %s, %s expires at %u",
                    rule_num,
                    spadat->use_src_ip,
                    spadat->spa_message_remain, exp_ts
                );

                fwc.rule_map[rule_num - fwc.start_rule_num] = RULE_ACTIVE;

                fwc.active_rules++;
                fwc.total_rules++;

                /* Reset the next expected expire time for this chain if it
                 * is warranted.
                */
                if(fwc.next_expire < now || exp_ts < fwc.next_expire)
                    fwc.next_expire = exp_ts;
            }
            else
                log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); 

            ple = ple->next;
        }

    }
    else
    {
        /* No other SPA request modes are supported yet.
        */
        if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG
          || spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
        {
            log_msg(LOG_WARNING, "Local NAT requests are not currently supported.");
        }
        else if(spadat->message_type == FKO_NAT_ACCESS_MSG
          || spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG)
        {
            log_msg(LOG_WARNING, "Forwarding/NAT requests are not currently supported.");
        }

        return(-1);
    }

    return(res);
}
예제 #17
0
/* Iterate over the configure firewall access chains and purge expired
 * firewall rules.
*/
void
check_firewall_rules(const fko_srv_options_t * const opts)
{
    char             exp_str[12]     = {0};
    char             rule_num_str[6] = {0};
    char            *ndx, *rn_start, *rn_end, *tmp_mark;

    int             i, res, rn_offset, rule_num, is_err;
    time_t          now, rule_exp, min_exp = 0;

    struct fw_chain *ch = opts->fw_config->chain;

    time(&now);

    /* Iterate over each chain and look for active rules to delete.
    */
    for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
    {
        /* If there are no active rules or we have not yet
         * reached our expected next expire time, continue.
        */
        if(ch[i].active_rules == 0 || ch[i].next_expire > now)
            continue;

        zero_cmd_buffers();

        rn_offset = 0;

        /* There should be a rule to delete.  Get the current list of
         * rules for this chain and delete the ones that are expired.
        */
        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
            opts->fw_config->fw_command,
            ch[i].table,
            ch[i].to_chain
        );

        res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE,
                WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
        chop_newline(cmd_out);

        log_msg(LOG_DEBUG, "check_firewall_rules() CMD: '%s' (res: %d, cmd_out: %s)",
            cmd_buf, res, cmd_out);

        if(!EXTCMD_IS_SUCCESS(res))
        {
            log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
            continue;
        }

        log_msg(LOG_DEBUG, "RES=%i, CMD_BUF: %s\nRULES LIST: %s", res, cmd_buf, cmd_out);

        ndx = strstr(cmd_out, EXPIRE_COMMENT_PREFIX);
        if(ndx == NULL)
        {
            /* we did not find an expected rule.
            */
            log_msg(LOG_ERR,
                "Did not find expire comment in rules list %i", i);

            if (ch[i].active_rules > 0)
                ch[i].active_rules--;

            continue;
        }

        /* walk the list and process rules as needed.
        */
        while (ndx != NULL) {
            /* Jump forward and extract the timestamp
            */
            ndx += strlen(EXPIRE_COMMENT_PREFIX);

            /* remember this spot for when we look for the next
             * rule.
            */
            tmp_mark = ndx;

            strlcpy(exp_str, ndx, sizeof(exp_str));
            rule_exp = (time_t)atoll(exp_str);

            if(rule_exp <= now)
            {
                /* Backtrack and get the rule number and delete it.
                */
                rn_start = ndx;
                while(--rn_start > cmd_out)
                {
                    if(*rn_start == '\n')
                        break;
                }

                if(*rn_start != '\n')
                {
                    /* This should not happen. But if it does, complain,
                     * decrement the active rule value, and go on.
                    */
                    log_msg(LOG_ERR,
                        "Rule parse error while finding rule line start in chain %i", i);

                    if (ch[i].active_rules > 0)
                        ch[i].active_rules--;

                    break;
                }
                rn_start++;

                rn_end = strchr(rn_start, ' ');
                if(rn_end == NULL)
                {
                    /* This should not happen. But if it does, complain,
                     * decrement the active rule value, and go on.
                    */
                    log_msg(LOG_ERR,
                        "Rule parse error while finding rule number in chain %i", i);

                    if (ch[i].active_rules > 0)
                        ch[i].active_rules--;

                    break;
                }

                strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1);

                rule_num = strtol_wrapper(rule_num_str, rn_offset, RCHK_MAX_IPT_RULE_NUM,
                        NO_EXIT_UPON_ERR, &is_err);
                if(is_err != FKO_SUCCESS)
                {
                    log_msg(LOG_ERR,
                        "Rule parse error while finding rule number in chain %i", i);

                    if (ch[i].active_rules > 0)
                        ch[i].active_rules--;

                    break;
                }

                zero_cmd_buffers();

                snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
                    opts->fw_config->fw_command,
                    ch[i].table,
                    ch[i].to_chain,
                    rule_num - rn_offset
                );

                res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
                        WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
                chop_newline(err_buf);

                log_msg(LOG_DEBUG, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
                    cmd_buf, res, err_buf);

                if(EXTCMD_IS_SUCCESS(res))
                {
                    log_msg(LOG_INFO, "Removed rule %s from %s with expire time of %u",
                        rule_num_str, ch[i].to_chain, rule_exp
                    );

                    rn_offset++;

                    if (ch[i].active_rules > 0)
                        ch[i].active_rules--;
                }
                else
                    log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

            }
            else
            {
                /* Track the minimum future rule expire time.
                */
                if(rule_exp > now)
                    min_exp = (min_exp < rule_exp) ? min_exp : rule_exp;
            }

            /* Push our tracking index forward beyond (just processed) _exp_
             * string so we can continue to the next rule in the list.
            */
            ndx = strstr(tmp_mark, EXPIRE_COMMENT_PREFIX);
        }

        /* Set the next pending expire time accordingly. 0 if there are no
         * more rules, or whatever the next expected (min_exp) time will be.
        */
        if(ch[i].active_rules < 1)
            ch[i].next_expire = 0;
        else if(min_exp)
            ch[i].next_expire = min_exp;
    }
}
예제 #18
0
/* Process the SPA packet data
*/
int
incoming_spa(fko_srv_options_t *opts)
{
    /* Always a good idea to initialize ctx to null if it will be used
     * repeatedly (especially when using fko_new_with_data().
    */
    fko_ctx_t       ctx = NULL;

    char            *spa_ip_demark, *gpg_id;
    time_t          now_ts;
    int             res, status, ts_diff, enc_type;

    spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);

    /* This will hold our pertinent SPA data.
    */
    spa_data_t spadat;

    /* Get the access.conf data for the stanza that matches this incoming
     * source IP address.
    */
    acc_stanza_t   *acc = acc_check_source(opts, spa_pkt->packet_src_ip);

    inet_ntop(AF_INET, &(spa_pkt->packet_src_ip),
        spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip));

    /* At this point, we want to validate and (if needed) preprocess the
     * SPA data and/or to be reasonably sure we have a SPA packet (i.e
     * try to eliminate obvious non-spa packets).
    */
    res = preprocess_spa_data(opts, spadat.pkt_source_ip);
    if(res != FKO_SUCCESS)
        return(SPA_MSG_NOT_SPA_DATA);

    log_msg(LOG_INFO, "SPA Packet from IP: %s received.", spadat.pkt_source_ip);

    if(acc == NULL)
    {
        log_msg(LOG_WARNING,
            "No access data found for source IP: %s", spadat.pkt_source_ip
        );

        return(SPA_MSG_ACCESS_DENIED);
    }

    if(opts->verbose > 1)
        log_msg(LOG_INFO, "SPA Packet: '%s'\n", spa_pkt->packet_data);

    /* Get encryption type and try its decoding routine first (if the key
     * for that type is set)
    */
    enc_type = fko_encryption_type((char *)spa_pkt->packet_data);

    if(enc_type == FKO_ENCRYPTION_RIJNDAEL)
    {
        if(acc->key != NULL)
            res = fko_new_with_data(&ctx, (char *)spa_pkt->packet_data, acc->key);
        else 
        {
            log_msg(LOG_ERR,
                "No KEY for RIJNDAEL encrypted messages");
            return(SPA_MSG_FKO_CTX_ERROR);
        }
    }
    else if(enc_type == FKO_ENCRYPTION_GPG)
    {
        /* For GPG we create the new context without decrypting on the fly
         * so we can set some  GPG parameters first.
        */
        if(acc->gpg_decrypt_pw != NULL)
        {
            res = fko_new_with_data(&ctx, (char *)spa_pkt->packet_data, NULL);
            if(res != FKO_SUCCESS)
            {
                log_msg(LOG_WARNING,
                    "Error creating fko context (before decryption): %s",
                    fko_errstr(res)
                );
                return(SPA_MSG_FKO_CTX_ERROR);
            }

            /* Set whatever GPG parameters we have.
            */
            if(acc->gpg_home_dir != NULL)
                res = fko_set_gpg_home_dir(ctx, acc->gpg_home_dir);
                if(res != FKO_SUCCESS)
                {
                    log_msg(LOG_WARNING,
                        "Error setting GPG keyring path to %s: %s",
                        acc->gpg_home_dir,
                        fko_errstr(res)
                    );
                    return(SPA_MSG_FKO_CTX_ERROR);
                }

            if(acc->gpg_decrypt_id != NULL)
                fko_set_gpg_recipient(ctx, acc->gpg_decrypt_id);

            /* If GPG_REQUIRE_SIG is set for this acc stanza, then set
             * the FKO context accordingly and check the other GPG Sig-
             * related parameters. This also applies when REMOTE_ID is
             * set.
            */
            if(acc->gpg_require_sig)
            {
                fko_set_gpg_signature_verify(ctx, 1);

                /* Set whether or not to ignore signature verification errors.
                */
                fko_set_gpg_ignore_verify_error(ctx, acc->gpg_ignore_sig_error);
            }
            else
            {
                fko_set_gpg_signature_verify(ctx, 0);
                fko_set_gpg_ignore_verify_error(ctx, 1);
            }

            /* Now decrypt the data.
            */
            res = fko_decrypt_spa_data(ctx, acc->gpg_decrypt_pw);
        }
        else
        {
            log_msg(LOG_ERR,
                "No GPG_DECRYPT_PW for GPG encrypted messages");
            return(SPA_MSG_FKO_CTX_ERROR);
        }
    }
    else
    {
        log_msg(LOG_ERR, "Unable to determing encryption type. Got type=%i.",
            enc_type);
        return(SPA_MSG_FKO_CTX_ERROR);
    }

    /* Do we have a valid FKO context?
    */
    if(res != FKO_SUCCESS)
    {
        log_msg(LOG_WARNING, "Error creating fko context: %s",
            fko_errstr(res));

        if(IS_GPG_ERROR(res))
            log_msg(LOG_WARNING, " - GPG ERROR: %s",
                fko_gpg_errstr(ctx));

        goto clean_and_bail;
    }

    /* At this point, we assume the SPA data is valid.  Now we need to see
     * if it meets our access criteria.
    */
    if(opts->verbose > 2)
        log_msg(LOG_INFO, "SPA Decode (res=%i):\n%s", res, dump_ctx(ctx));

    /* First, if this is a GPG message, and GPG_REMOTE_ID list is not empty,
     * then we need to make sure this incoming message is signer ID matches
     * an entry in the list.
    */
    if(enc_type == FKO_ENCRYPTION_GPG && acc->gpg_require_sig)
    {
        res = fko_get_gpg_signature_id(ctx, &gpg_id);
        if(res != FKO_SUCCESS)
        {
            log_msg(LOG_WARNING, "Error pulling the GPG signature ID from the context: %s",
                fko_gpg_errstr(ctx));
            goto clean_and_bail;
        }

        if(opts->verbose)
        log_msg(LOG_INFO, "Incoming SPA data signed by '%s'.", gpg_id);

        if(acc->gpg_remote_id != NULL && !acc_check_gpg_remote_id(acc, gpg_id))
        {
            log_msg(LOG_WARNING,
                "Incoming SPA packet signed by ID: %s, but that ID is not the GPG_REMOTE_ID list.",
                gpg_id);
            goto clean_and_bail;
        }
    }

    /* Check for replays if so configured.
    */
    if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
    {
        res = replay_check(opts, ctx);
        if(res != 0) /* non-zero means we have seen this packet before. */
            goto clean_and_bail;
    }

    /* Populate our spa data struct for future reference.
    */
    res = get_spa_data_fields(ctx, &spadat);

    /* Figure out what our timeout will be. If it is specified in the SPA
     * data, then use that.  If not, try the FW_ACCESS_TIMEOUT from the
     * access.conf file (if there is one).  Otherwise use the default.
    */
    if(spadat.client_timeout > 0)
        spadat.fw_access_timeout = spadat.client_timeout;
    else if(acc->fw_access_timeout > 0)
        spadat.fw_access_timeout = acc->fw_access_timeout;
    else
        spadat.fw_access_timeout = DEF_FW_ACCESS_TIMEOUT;

    if(res != FKO_SUCCESS)
    {
        log_msg(LOG_ERR, "Unexpected error pulling SPA data from the context: %s",
            fko_errstr(res));
        res = SPA_MSG_ERROR;
        goto clean_and_bail;
    }

    /* Check packet age if so configured.
    */
    if(strncasecmp(opts->config[CONF_ENABLE_SPA_PACKET_AGING], "Y", 1) == 0)
    {
        time(&now_ts);

        ts_diff = now_ts - spadat.timestamp;

        if(ts_diff > atoi(opts->config[CONF_MAX_SPA_PACKET_AGE]))
        {
            log_msg(LOG_WARNING, "SPA data is too old (%i seconds).",
                ts_diff);
            res = SPA_MSG_TOO_OLD;
            goto clean_and_bail;
        }
    }

    /* At this point, we have enough to check the embedded (or packet source)
     * IP address against the defined access rights.  We start by splitting
     * the spa msg source IP from the remainder of the message.
    */
    spa_ip_demark = strchr(spadat.spa_message, ',');
    if(spa_ip_demark == NULL)
    {
        log_msg(LOG_WARNING, "Error parsing SPA message string: %s",
            fko_errstr(res));
        res = SPA_MSG_ERROR;
        goto clean_and_bail;
    }

    strlcpy(spadat.spa_message_src_ip, spadat.spa_message, (spa_ip_demark-spadat.spa_message)+1);
    strlcpy(spadat.spa_message_remain, spa_ip_demark+1, 1024);

    /* If use source IP was requested (embedded IP of 0.0.0.0), make sure it
     * is allowed.
    */
    if(strcmp(spadat.spa_message_src_ip, "0.0.0.0") == 0)
    {
        if(acc->require_source_address)
        {
            log_msg(LOG_WARNING,
                "Got 0.0.0.0 when valid source IP was required."
            );
            res = SPA_MSG_ACCESS_DENIED;
            goto clean_and_bail;
        }

        spadat.use_src_ip = spadat.pkt_source_ip;
    }
    else
        spadat.use_src_ip = spadat.spa_message_src_ip;

    /* If REQUIRE_USERNAME is set, make sure the username in this SPA data
     * matches.
    */
    if(acc->require_username != NULL)
    {
        if(strcmp(spadat.username, acc->require_username) != 0)
        {
            log_msg(LOG_WARNING,
                "Username in SPA data (%s) does not match required username: %s",
                spadat.username, acc->require_username
            );
            res = SPA_MSG_ACCESS_DENIED;
            goto clean_and_bail;
        }
    }

    /* Take action based on SPA message type.  */

    /* Command messages.
    */
    if(spadat.message_type == FKO_COMMAND_MSG)
    {
        if(!acc->enable_cmd_exec)
        {
            log_msg(LOG_WARNING,
                "SPA Command message are not allowed in the current configuration."
            );
            res = SPA_MSG_ACCESS_DENIED;
        }
        else
        {
            log_msg(LOG_INFO,
                "Processing SPA Command message: command='%s'.",
                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)
            {
                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, 0, 0);
            }
            else /* Just run it as we are (root that is). */
                res = run_extcmd(spadat.spa_message_remain, NULL, 0, 5);

            /* --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(res);

            if(opts->verbose > 2)
                log_msg(LOG_WARNING,
                    "CMD_EXEC: command returned %i", status);

            if(status != 0)
                res = SPA_MSG_COMMAND_ERROR;
        }

        goto clean_and_bail;
    }

    /* From this point forward, we have some kind of access message. So
     * we first see if access is allowed by checking access against
     * restrict_ports and open_ports.
     *
     *  --DSS TODO: We should add BLACKLIST support here as well.
    */
    if(! acc_check_port_access(acc, spadat.spa_message_remain))
    {
        log_msg(LOG_WARNING,
            "One or more requested protocol/ports was denied per access.conf."
        );

        res = SPA_MSG_ACCESS_DENIED;

        goto clean_and_bail;       
    }

    /* At this point, we can process the SPA request.
    */
    res = process_spa_request(opts, &spadat);

clean_and_bail:
    if(ctx != NULL)
        fko_destroy(ctx);

    return(res);
}
예제 #19
0
/* Quietly flush and delete all fwknop custom chains.
*/
static void
delete_all_chains(const fko_srv_options_t *opts)
{
    int     i, res;
    int     jump_rule_num;

    for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
    {
        if(fwc.chain[i].target[0] == '\0')
            continue;

        /* First look for a jump rule to this chain and remove it if it
         * is there.
        */
        if((jump_rule_num = jump_rule_exists(i)) > 0)
        {
            zero_cmd_buffers();

            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
                fwc.fw_command,
                fwc.chain[i].table,
                fwc.chain[i].from_chain,
                jump_rule_num
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                log_msg(LOG_INFO, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
                    cmd_buf, res, err_buf);

            /* Expect full success on this */
            if(! EXTCMD_IS_SUCCESS(res))
                log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
        }

        zero_cmd_buffers();

        /* Now flush and remove the chain.
        */
        snprintf(cmd_buf, CMD_BUFSIZE-1,
            "(%s " IPT_FLUSH_CHAIN_ARGS "; %s " IPT_DEL_CHAIN_ARGS ")", // > /dev/null 2>&1",
            fwc.fw_command,
            fwc.chain[i].table,
            fwc.chain[i].to_chain,
            fwc.fw_command,
            fwc.chain[i].table,
            fwc.chain[i].to_chain
        );

        res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

        if (opts->verbose)
            log_msg(LOG_INFO, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
                cmd_buf, res, err_buf);

        /* Expect full success on this */
        if(! EXTCMD_IS_SUCCESS(res))
            log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
    }
}
예제 #20
0
/* Rule Processing - Create an access request...
*/
int
process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat)
{
    char             nat_ip[MAX_IPV4_STR_LEN] = {0};
    char             snat_target[SNAT_TARGET_BUFSIZE] = {0};
    char            *ndx;

    unsigned int     nat_port = 0;

    acc_port_list_t *port_list = NULL;
    acc_port_list_t *ple;

    unsigned int    fst_proto;
    unsigned int    fst_port;

    struct fw_chain *in_chain   = &(opts->fw_config->chain[IPT_INPUT_ACCESS]);
    struct fw_chain *out_chain  = &(opts->fw_config->chain[IPT_OUTPUT_ACCESS]);
    struct fw_chain *fwd_chain  = &(opts->fw_config->chain[IPT_FORWARD_ACCESS]);
    struct fw_chain *dnat_chain = &(opts->fw_config->chain[IPT_DNAT_ACCESS]);
    struct fw_chain *snat_chain; /* We assign this later (if we need to). */

    int             res = 0;
    time_t          now;
    unsigned int    exp_ts;

    /* Parse and expand our access message.
    */
    if(expand_acc_port_list(&port_list, spadat->spa_message_remain) != 1)
        return res;

    /* Start at the top of the proto-port list...
    */
    ple = port_list;

    /* Remember the first proto/port combo in case we need them
     * for NAT access requests.
    */
    fst_proto = ple->proto;
    fst_port  = ple->port;

    /* Set our expire time value.
    */
    time(&now);
    exp_ts = now + spadat->fw_access_timeout;

    /* For straight access requests, we currently support multiple proto/port
     * request.
    */
    if((spadat->message_type == FKO_ACCESS_MSG
      || spadat->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG) && !acc->force_nat)
    {

        /* Check to make sure that the jump rules exist for each
         * required chain
        */
        if(jump_rule_exists(IPT_INPUT_ACCESS) == 0)
            add_jump_rule(opts, IPT_INPUT_ACCESS);

        if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
            if(jump_rule_exists(IPT_OUTPUT_ACCESS) == 0)
                add_jump_rule(opts, IPT_OUTPUT_ACCESS);

        /* Create an access command for each proto/port for the source ip.
        */
        while(ple != NULL)
        {
            zero_cmd_buffers();

            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS,
                opts->fw_config->fw_command,
                in_chain->table,
                in_chain->to_chain,
                ple->proto,
                spadat->use_src_ip,
                ple->port,
                exp_ts,
                in_chain->target
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
                    cmd_buf, res, err_buf);

            if(EXTCMD_IS_SUCCESS(res))
            {
                log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u",
                    in_chain->to_chain, spadat->use_src_ip,
                    spadat->spa_message_remain, exp_ts
                );

                in_chain->active_rules++;

                /* Reset the next expected expire time for this chain if it
                * is warranted.
                */
                if(in_chain->next_expire < now || exp_ts < in_chain->next_expire)
                    in_chain->next_expire = exp_ts;
            }
            else
                log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

            /* If we have to make an corresponding OUTPUT rule if out_chain target
            * is not NULL.
            */
            if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
            {
                zero_cmd_buffers();

                snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_OUT_RULE_ARGS,
                    opts->fw_config->fw_command,
                    out_chain->table,
                    out_chain->to_chain,
                    ple->proto,
                    spadat->use_src_ip,
                    ple->port,
                    exp_ts,
                    out_chain->target
                );

                res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

                if (opts->verbose)
                    log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
                        cmd_buf, res, err_buf);

                if(EXTCMD_IS_SUCCESS(res))
                {
                    log_msg(LOG_INFO, "Added OUTPUT Rule to %s for %s, %s expires at %u",
                        out_chain->to_chain, spadat->use_src_ip,
                        spadat->spa_message_remain, exp_ts
                    );

                    out_chain->active_rules++;

                    /* Reset the next expected expire time for this chain if it
                    * is warranted.
                    */
                    if(out_chain->next_expire < now || exp_ts < out_chain->next_expire)
                        out_chain->next_expire = exp_ts;
                }
                else
                    log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); 

            }

            ple = ple->next;
        }
    }
    /* NAT requests... */
    else if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG
      || spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG
      || spadat->message_type == FKO_NAT_ACCESS_MSG
      || spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
      || acc->force_nat)
    {
        /* Parse out the NAT IP and Port components.
        */
        if(acc->force_nat)
        {
            strlcpy(nat_ip, acc->force_nat_ip, MAX_IPV4_STR_LEN);
            nat_port = acc->force_nat_port;
        }
        else
        {
            ndx = strchr(spadat->nat_access, ',');
            if(ndx != NULL)
            {
                strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1);
                nat_port = atoi(ndx+1);
            }
        }

        if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG)
        {
            /* Need to add an ACCEPT rule into the INPUT chain
            */
            zero_cmd_buffers();

            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS,
                opts->fw_config->fw_command,
                in_chain->table,
                in_chain->to_chain,
                fst_proto,
                spadat->use_src_ip,
                nat_port,
                exp_ts,
                in_chain->target
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
                    cmd_buf, res, err_buf);

            if(EXTCMD_IS_SUCCESS(res))
            {
                log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u",
                    in_chain->to_chain, spadat->use_src_ip,
                    spadat->spa_message_remain, exp_ts
                );

                in_chain->active_rules++;

                /* Reset the next expected expire time for this chain if it
                * is warranted.
                */
                if(in_chain->next_expire < now || exp_ts < in_chain->next_expire)
                    in_chain->next_expire = exp_ts;
            }
            else
                log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

        }
        else if(fwd_chain->to_chain != NULL && strlen(fwd_chain->to_chain))
        {
            /* Make our FORWARD and NAT rules, and make sure the
             * required jump rule exists
            */
            if (jump_rule_exists(IPT_FORWARD_ACCESS) == 0)
                add_jump_rule(opts, IPT_FORWARD_ACCESS);

            zero_cmd_buffers();

            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_FWD_RULE_ARGS,
                opts->fw_config->fw_command,
                fwd_chain->table,
                fwd_chain->to_chain,
                fst_proto,
                spadat->use_src_ip,
                nat_ip,
                nat_port,
                exp_ts,
                fwd_chain->target
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
                    cmd_buf, res, err_buf);

            if(EXTCMD_IS_SUCCESS(res))
            {
                log_msg(LOG_INFO, "Added FORWARD Rule to %s for %s, %s expires at %u",
                    fwd_chain->to_chain, spadat->use_src_ip,
                    spadat->spa_message_remain, exp_ts
                );

                fwd_chain->active_rules++;

                /* Reset the next expected expire time for this chain if it
                * is warranted.
                */
                if(fwd_chain->next_expire < now || exp_ts < fwd_chain->next_expire)
                    fwd_chain->next_expire = exp_ts;
            }
            else
                log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); 
        }

        if(dnat_chain->to_chain != NULL && strlen(dnat_chain->to_chain))
        {

            /* Make sure the required jump rule exists
            */
            if (jump_rule_exists(IPT_DNAT_ACCESS) == 0)
                add_jump_rule(opts, IPT_DNAT_ACCESS);

            zero_cmd_buffers();

            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_DNAT_RULE_ARGS,
                opts->fw_config->fw_command,
                dnat_chain->table,
                dnat_chain->to_chain,
                fst_proto,
                spadat->use_src_ip,
                fst_port,
                exp_ts,
                dnat_chain->target,
                nat_ip,
                nat_port
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
                    cmd_buf, res, err_buf);

            if(EXTCMD_IS_SUCCESS(res))
            {
                log_msg(LOG_INFO, "Added DNAT Rule to %s for %s, %s expires at %u",
                    dnat_chain->to_chain, spadat->use_src_ip,
                    spadat->spa_message_remain, exp_ts
                );

                dnat_chain->active_rules++;

                /* Reset the next expected expire time for this chain if it
                * is warranted.
                */
                if(dnat_chain->next_expire < now || exp_ts < dnat_chain->next_expire)
                    dnat_chain->next_expire = exp_ts;
            }
            else
                log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); 
        }

        /* If SNAT (or MASQUERADE) is wanted, then we add those rules here as well.
        */
        if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0)
        {
            zero_cmd_buffers();

            /* Setup some parameter depending on whether we are using SNAT
             * or MASQUERADE.
            */
            if(strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0)
            {
                /* Using static SNAT */
                snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]);
                snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
                    "--to-source %s:%i", opts->config[CONF_SNAT_TRANSLATE_IP],
                    fst_port);
            }
            else
            {
                /* Using MASQUERADE */
                snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]);
                snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
                    "--to-ports %i", fst_port);
            }

            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_SNAT_RULE_ARGS,
                opts->fw_config->fw_command,
                snat_chain->table,
                snat_chain->to_chain,
                fst_proto,
                nat_ip,
                nat_port,
                exp_ts,
                snat_chain->target,
                snat_target
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
                    cmd_buf, res, err_buf);

            if(EXTCMD_IS_SUCCESS(res))
            {
                log_msg(LOG_INFO, "Added Source NAT Rule to %s for %s, %s expires at %u",
                    snat_chain->to_chain, spadat->use_src_ip,
                    spadat->spa_message_remain, exp_ts
                );

                snat_chain->active_rules++;

                /* Reset the next expected expire time for this chain if it
                * is warranted.
                */
            if(snat_chain->next_expire < now || exp_ts < snat_chain->next_expire)
                    snat_chain->next_expire = exp_ts;
            }
            else
                log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
        }
    }

    /* Done with the port list for access rules.
    */
    free_acc_port_list(port_list);

    return(res);
}
예제 #21
0
/* Rule Processing - Create an access request...
*/
int
process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat)
{
    char             new_rule[MAX_PF_NEW_RULE_LEN];
    char             write_cmd[CMD_BUFSIZE];

    FILE            *pfctl_fd = NULL;

    acc_port_list_t *port_list = NULL;
    acc_port_list_t *ple;

    unsigned int    fst_proto;
    unsigned int    fst_port;

    int             res = 0;
    time_t          now;
    unsigned int    exp_ts;

    /* Parse and expand our access message.
    */
    expand_acc_port_list(&port_list, spadat->spa_message_remain);

    /* Start at the top of the proto-port list...
    */
    ple = port_list;

    /* Remember the first proto/port combo in case we need them
     * for NAT access requests.
    */
    fst_proto = ple->proto;
    fst_port  = ple->port;

    /* Set our expire time value.
    */
    time(&now);
    exp_ts = now + spadat->fw_access_timeout;

    /* For straight access requests, we currently support multiple proto/port
     * request.
    */
    if(spadat->message_type == FKO_ACCESS_MSG
      || spadat->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG)
    {
        /* Create an access command for each proto/port for the source ip.
        */
        while(ple != NULL)
        {
            zero_cmd_buffers();

            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " PF_LIST_ANCHOR_RULES_ARGS,
                opts->fw_config->fw_command,
                opts->fw_config->anchor
            );

            /* Cache the current anchor rule set
            */
            res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);

            /* Build the new rule string
            */
            memset(new_rule, 0x0, MAX_PF_NEW_RULE_LEN);
            snprintf(new_rule, MAX_PF_NEW_RULE_LEN-1, PF_ADD_RULE_ARGS "\n",
                ple->proto,
                spadat->use_src_ip,
                ple->port,
                exp_ts
            );

            if (strlen(cmd_out) + strlen(new_rule) < STANDARD_CMD_OUT_BUFSIZE)
            {
                /* We add the rule to the running policy
                */
                strlcat(cmd_out, new_rule, STANDARD_CMD_OUT_BUFSIZE);

                memset(write_cmd, 0x0, CMD_BUFSIZE);

                snprintf(write_cmd, CMD_BUFSIZE-1, "%s " PF_WRITE_ANCHOR_RULES_ARGS,
                    opts->fw_config->fw_command,
                    opts->fw_config->anchor
                );

                if ((pfctl_fd = popen(write_cmd, "w")) == NULL)
                {
                    log_msg(LOG_WARNING, "Could not execute command: %s",
                        write_cmd);
                    return(-1);
                }

                if (fwrite(cmd_out, strlen(cmd_out), 1, pfctl_fd) == 1)
                {
                    log_msg(LOG_INFO, "Added Rule for %s, %s expires at %u",
                        spadat->use_src_ip,
                        spadat->spa_message_remain,
                        exp_ts
                    );

                    fwc.active_rules++;

                    /* Reset the next expected expire time for this chain if it
                     * is warranted.
                    */
                    if(fwc.next_expire < now || exp_ts < fwc.next_expire)
                        fwc.next_expire = exp_ts;
                }
                else
                    log_msg(LOG_WARNING, "Could not write rule to pf anchor");

                pclose(pfctl_fd);
            }
            else
            {
                /* We don't have enough room to add the new firewall rule,
                 * so throw a warning and bail.  Once some of the existing
                 * rules are expired the user will once again be able to gain
                 * access.  Note that we don't expect to really ever hit this
                 * limit because of STANDARD_CMD_OUT_BUFSIZE is quite a number
                 * of anchor rules.
                */
                log_msg(LOG_WARNING, "Max anchor rules reached, try again later.");
                return 0;
            }

            ple = ple->next;
        }

    }
    else
    {
        /* No other SPA request modes are supported yet.
        */
        if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG
          || spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
        {
            log_msg(LOG_WARNING, "Local NAT requests are not currently supported.");
        }
        else if(spadat->message_type == FKO_NAT_ACCESS_MSG
          || spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG)
        {
            log_msg(LOG_WARNING, "Forwarding/NAT requests are not currently supported.");
        }

        return(-1);
    }

    return(res);
}
예제 #22
0
static void
ipt_chk_support(const fko_srv_options_t * const opts)
{
    int               res = 1;
    struct fw_chain  *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]);

    zero_cmd_buffers();

    /* Add a harmless rule to the iptables INPUT chain and see if iptables
     * supports '-C' to check for it.  Set "have_ipt_chk_support" accordingly,
     * delete the rule, and return.
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_CHK_RULE_ARGS,
        opts->fw_config->fw_command,
        in_chain->table,
        in_chain->from_chain,
        1,   /* first rule */
        in_chain->target
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "ipt_chk_support() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    zero_cmd_buffers();

    /* Now see if '-C' works - any output indicates failure
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_VERIFY_CHK_ARGS,
        opts->fw_config->fw_command,
        in_chain->table,
        in_chain->from_chain,
        in_chain->target
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "ipt_chk_support() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    if(EXTCMD_IS_SUCCESS(res) && strlen(err_buf))
    {
        log_msg(LOG_DEBUG, "ipt_chk_support() -C not supported");
        have_ipt_chk_support = 0;
    }
    else
    {
        log_msg(LOG_DEBUG, "ipt_chk_support() -C supported");
        have_ipt_chk_support = 1;
    }

    /* Delete the tmp rule
    */
    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
        opts->fw_config->fw_command,
        in_chain->table,
        in_chain->from_chain,
        1
    );
    run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);

    return;
}
예제 #23
0
static int
comment_match_exists(const fko_srv_options_t * const opts)
{
    int               res = 1;
    char             *ndx = NULL;
    struct fw_chain  *in_chain  = &(opts->fw_config->chain[IPT_INPUT_ACCESS]);

    zero_cmd_buffers();

    /* Add a harmless rule to the iptables INPUT chain that uses the comment
     * match and make sure it exists.  If not, return zero.  Otherwise, delete
     * the rule and return true.
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_COMMENT_ARGS,
        opts->fw_config->fw_command,
        in_chain->table,
        in_chain->from_chain,
        1,   /* first rule */
        in_chain->target
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "comment_match_exists() CMD: '%s' (res: %d, err: %s)",
            cmd_buf, res, err_buf);

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
        opts->fw_config->fw_command,
        in_chain->table,
        in_chain->from_chain
    );

    res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(cmd_out);

    if(!EXTCMD_IS_SUCCESS(res))
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);

    ndx = strstr(cmd_out, TMP_COMMENT);
    if(ndx == NULL)
        res = 0;  /* did not find the tmp comment */
    else
        res = 1;

    if(res == 1)
    {
        /* Delete the tmp comment rule
        */
        zero_cmd_buffers();

        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
            opts->fw_config->fw_command,
            in_chain->table,
            in_chain->from_chain,
            1
        );
        run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
                WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    }

    return res;
}
예제 #24
0
/* Iterate over the configure firewall access chains and purge expired
 * firewall rules.
*/
void
check_firewall_rules(const fko_srv_options_t *opts)
{
    char            exp_str[12];
    char            anchor_rules_copy[STANDARD_CMD_OUT_BUFSIZE];
    char            write_cmd[CMD_BUFSIZE];
    char           *ndx, *tmp_mark, *tmp_ndx, *newline_tmp_ndx;

    time_t          now, rule_exp, min_exp=0;
    int             i=0, res=0, anchor_ndx=0, is_delete=0;

    FILE            *pfctl_fd = NULL;

    /* If we have not yet reached our expected next expire
       time, continue.
    */
    if(fwc.next_expire == 0)
        return;

    time(&now);

    if (fwc.next_expire > now)
        return;

    zero_cmd_buffers();

    /* There should be a rule to delete.  Get the current list of
     * rules and delete the ones that are expired.
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " PF_LIST_ANCHOR_RULES_ARGS,
        opts->fw_config->fw_command,
        opts->fw_config->anchor
    );

    res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);

    if(!EXTCMD_IS_SUCCESS(res))
    {
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
        return;
    }

    /* Find the first _exp_ string (if any).
    */
    ndx = strstr(cmd_out, EXPIRE_COMMENT_PREFIX);

    if(ndx == NULL)
    {
        /* we did not find an expected rule.
        */
        log_msg(LOG_ERR,
            "Did not find expire comment in rules list %i.\n", i);

        return;
    }

    memset(anchor_rules_copy, 0x0, STANDARD_CMD_OUT_BUFSIZE);

    /* Walk the list and process rules as needed.
    */
    while (ndx != NULL)
    {
        /* Jump forward and extract the timestamp
        */
        ndx += strlen(EXPIRE_COMMENT_PREFIX);

        /* remember this spot for when we look for the next
         * rule.
        */
        tmp_mark = ndx;

        strlcpy(exp_str, ndx, 11);
        rule_exp = (time_t)atoll(exp_str);

        if(rule_exp <= now)
        {
            /* We are going to delete this rule, and because we rebuild the
             * PF anchor to include all rules that haven't expired, to delete
             * this rule we just skip to the next one.
            */
            log_msg(LOG_INFO, "Deleting rule with expire time of %u.", rule_exp);

            if (fwc.active_rules > 0)
                fwc.active_rules--;

            is_delete = 1;
        }
        else
        {
            /* The rule has not expired, so copy it into the anchor string that
             * lists current rules and will be used to feed
             * 'pfctl -a <anchor> -f -'.
            */

            /* back up to the previous newline or the beginning of the rules
             * output string.
            */
            tmp_ndx = ndx;
            while(--tmp_ndx > cmd_out)
            {
                if(*tmp_ndx == '\n')
                    break;
            }

            if(*tmp_ndx == '\n')
            {
                tmp_ndx++;
            }

            /* may sure the rule begins with the string "pass", and make sure
             * it ends with a newline.  Bail if either test fails.
            */
            if (strlen(tmp_ndx) <= strlen("pass")
                || strncmp(tmp_ndx, "pass", strlen("pass")) != 0)
            {
                break;
            }

            newline_tmp_ndx = tmp_ndx;
            while (*newline_tmp_ndx != '\n' && *newline_tmp_ndx != '\0')
            {
                newline_tmp_ndx++;
            }

            if (*newline_tmp_ndx != '\n')
                break;

            /* copy the whole rule to the next newline (includes the expiration
               time).
            */
            while (*tmp_ndx != '\n' && *tmp_ndx != '\0'
                && anchor_ndx < STANDARD_CMD_OUT_BUFSIZE)
            {
                anchor_rules_copy[anchor_ndx] = *tmp_ndx;
                tmp_ndx++;
                anchor_ndx++;
            }
            anchor_rules_copy[anchor_ndx] = '\n';
            anchor_ndx++;

            /* Track the minimum future rule expire time.
            */
            if(rule_exp > now)
                min_exp = (min_exp < rule_exp) ? min_exp : rule_exp;
        }

        /* Push our tracking index forward beyond (just processed) _exp_
         * string so we can continue to the next rule in the list.
        */
        ndx = strstr(tmp_mark, EXPIRE_COMMENT_PREFIX);

    }

    if (is_delete)
    {
        /* We re-instantiate the anchor rules with the new rules string that
         * has the rule(s) deleted.  If there isn't at least one "pass" rule,
         * then we just flush the anchor.
        */

        if (strlen(anchor_rules_copy) > strlen("pass")
            && strncmp(anchor_rules_copy, "pass", strlen("pass")) == 0)
        {
            memset(write_cmd, 0x0, CMD_BUFSIZE);

            snprintf(write_cmd, CMD_BUFSIZE-1, "%s " PF_WRITE_ANCHOR_RULES_ARGS,
                opts->fw_config->fw_command,
                opts->fw_config->anchor
            );

            if ((pfctl_fd = popen(write_cmd, "w")) == NULL)
            {
                log_msg(LOG_WARNING, "Could not execute command: %s",
                    write_cmd);
                return;
            }

            if (fwrite(anchor_rules_copy, strlen(anchor_rules_copy), 1, pfctl_fd) != 1)
            {
                log_msg(LOG_WARNING, "Could not write rules to pf anchor");
            }
            pclose(pfctl_fd);
        }
        else
        {
            delete_all_anchor_rules(opts);
        }

    }

    /* Set the next pending expire time accordingly. 0 if there are no
     * more rules, or whatever the next expected (min_exp) time will be.
    */
    if(fwc.active_rules < 1)
        fwc.next_expire = 0;
    else if(min_exp)
        fwc.next_expire = min_exp;

    return;
}
예제 #25
0
/* Print all firewall rules currently instantiated by the running fwknopd
 * daemon to stdout.
*/
int
fw_dump_rules(const fko_srv_options_t * const opts)
{
    int     i, res, got_err = 0;

    struct fw_chain *ch = opts->fw_config->chain;

    if (opts->fw_list_all == 1)
    {
        fprintf(stdout, "Listing all iptables rules in applicable tables...\n");
        fflush(stdout);

        for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
        {

            if(fwc.chain[i].target[0] == '\0')
                continue;

            zero_cmd_buffers();

            /* Create the list command
            */
            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_ALL_RULES_ARGS,
                opts->fw_config->fw_command,
                ch[i].table
            );

            res = run_extcmd(cmd_buf, NULL, 0, NO_STDERR,
                        NO_TIMEOUT, &pid_status, opts);

            log_msg(LOG_DEBUG, "fw_dump_rules() CMD: '%s' (res: %d)",
                cmd_buf, res);

            /* Expect full success on this */
            if(! EXTCMD_IS_SUCCESS(res))
            {
                log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
                got_err++;
            }
        }
    }
    else
    {
        fprintf(stdout, "Listing rules in fwknopd iptables chains...\n");
        fflush(stdout);

        for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
        {

            if(fwc.chain[i].target[0] == '\0')
                continue;

            zero_cmd_buffers();

            /* Create the list command
            */
            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
                opts->fw_config->fw_command,
                ch[i].table,
                ch[i].to_chain
            );

            fprintf(stdout, "\n");
            fflush(stdout);

            res = run_extcmd(cmd_buf, NULL, 0, NO_STDERR,
                        NO_TIMEOUT, &pid_status, opts);

            log_msg(LOG_DEBUG, "fw_dump_rules() CMD: '%s' (res: %d)",
                cmd_buf, res);

            /* Expect full success on this */
            if(! EXTCMD_IS_SUCCESS(res))
            {
                log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
                got_err++;
            }
        }
    }

    return(got_err);
}
예제 #26
0
/* Process command messages
*/
static int
process_cmd_msg(fko_srv_options_t *opts, acc_stanza_t *acc,
        spa_data_t *spadat, const int stanza_num, int *res)
{
    int             pid_status=0;
    char            cmd_buf[MAX_SPA_CMD_LEN] = {0};

    if(!acc->enable_cmd_exec)
    {
        log_msg(LOG_WARNING,
            "[%s] (stanza #%d) SPA Command messages are not allowed in the current configuration.",
            spadat->pkt_source_ip, stanza_num
        );
        return 0;
    }
    else if(opts->test)
    {
        log_msg(LOG_WARNING,
            "[%s] (stanza #%d) --test mode enabled, skipping command execution.",
            spadat->pkt_source_ip, stanza_num
        );
        return 0;
    }
    else
    {
        log_msg(LOG_INFO,
            "[%s] (stanza #%d) Processing SPA Command message: command='%s'.",
            spadat->pkt_source_ip, stanza_num, spadat->spa_message_remain
        );

        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) 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,
                    cmd_buf, NULL, 0, WANT_STDERR, NO_TIMEOUT,
                    &pid_status, opts);
        }
        else /* Just run it as we are (root that is). */
        {
            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
        */
        log_msg(LOG_INFO,
            "[%s] (stanza #%d) CMD_EXEC: command returned %i, pid_status: %d",
            spadat->pkt_source_ip, stanza_num, *res,
            WIFEXITED(pid_status) ? WEXITSTATUS(pid_status) : pid_status);

        if(WIFEXITED(pid_status))
        {
            if(WEXITSTATUS(pid_status) != 0)
                *res = SPA_MSG_COMMAND_ERROR;
        }
        else
            *res = SPA_MSG_COMMAND_ERROR;
    }
    return 1;
}
예제 #27
0
/* Quietly flush and delete all fwknop custom chains.
*/
static void
delete_all_chains(const fko_srv_options_t * const opts)
{
    int     i, res, cmd_ctr = 0;

    for(i=0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
    {
        if(fwc.chain[i].target[0] == '\0')
            continue;

        /* First look for a jump rule to this chain and remove it if it
         * is there.
        */
        cmd_ctr = 0;
        while(cmd_ctr < CMD_LOOP_TRIES && (jump_rule_exists(opts, i) == 1))
        {
            zero_cmd_buffers();

            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_JUMP_RULE_ARGS,
                fwc.fw_command,
                fwc.chain[i].table,
                fwc.chain[i].from_chain,
                fwc.chain[i].to_chain
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
                    WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
            chop_newline(err_buf);

            log_msg(LOG_DEBUG, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
                cmd_buf, res, err_buf);

            /* Expect full success on this */
            if(! EXTCMD_IS_SUCCESS(res))
                log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

            cmd_ctr++;
        }

        zero_cmd_buffers();

        /* Now flush and remove the chain.
        */
        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_FLUSH_CHAIN_ARGS,
            fwc.fw_command,
            fwc.chain[i].table,
            fwc.chain[i].to_chain
        );

        res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
                NO_TIMEOUT, &pid_status, opts);
        chop_newline(err_buf);

        log_msg(LOG_DEBUG, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
            cmd_buf, res, err_buf);

        /* Expect full success on this */
        if(! EXTCMD_IS_SUCCESS(res))
            log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

        zero_cmd_buffers();

        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_CHAIN_ARGS,
            fwc.fw_command,
            fwc.chain[i].table,
            fwc.chain[i].to_chain
        );

        res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
                NO_TIMEOUT, &pid_status, opts);
        chop_newline(err_buf);

        log_msg(LOG_DEBUG, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
            cmd_buf, res, err_buf);

        /* Expect full success on this */
        if(! EXTCMD_IS_SUCCESS(res))
            log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
    }
    return;
}