예제 #1
0
/* Given a config parameter name, return its index or -1 if not found.
*/
static int
config_entry_index(const fko_srv_options_t *opts, const char *var)
{
    int i;

    for(i=0; i<NUMBER_OF_CONFIG_ENTRIES; i++)
        if(opts->config[i] != NULL && CONF_VAR_IS(var, config_map[i]))
            return(i);

    return(-1);
}
예제 #2
0
파일: access.c 프로젝트: maxkas/fwknop
/* Read and parse the access file, popluating the access data as we go.
*/
void
parse_access_file(fko_srv_options_t *opts)
{
    FILE           *file_ptr;
    char           *ndx;
    int             got_source = 0;
    unsigned int    num_lines = 0;

    char            access_line_buf[MAX_LINE_LEN] = {0};
    char            var[MAX_LINE_LEN]  = {0};
    char            val[MAX_LINE_LEN]  = {0};

    struct passwd  *pw;
    struct stat     st;

    acc_stanza_t   *curr_acc = NULL;

    /* First see if the access file exists.  If it doesn't, complain
     * and bail.
    */
    if(stat(opts->config[CONF_ACCESS_FILE], &st) != 0)
    {
        fprintf(stderr, "[*] Access file: '%s' was not found.\n",
            opts->config[CONF_ACCESS_FILE]);

        exit(EXIT_FAILURE);
    }

    if ((file_ptr = fopen(opts->config[CONF_ACCESS_FILE], "r")) == NULL)
    {
        fprintf(stderr, "[*] Could not open access file: %s\n",
            opts->config[CONF_ACCESS_FILE]);
        perror(NULL);

        exit(EXIT_FAILURE);
    }

    /* Initialize the access list.
    */
    acc_stanza_init(opts);

    /* Now walk through access file pulling the access entries into the
     * current stanza.
    */
    while ((fgets(access_line_buf, MAX_LINE_LEN, file_ptr)) != NULL)
    {
        num_lines++;
        access_line_buf[MAX_LINE_LEN-1] = '\0';

        /* Get past comments and empty lines (note: we only look at the
         * first character.
        */
        if(IS_EMPTY_LINE(access_line_buf[0]))
            continue;

        if(sscanf(access_line_buf, "%s %[^;\n\r]", var, val) != 2)
        {
            fprintf(stderr,
                "*Invalid access file entry in %s at line %i.\n - '%s'",
                opts->config[CONF_ACCESS_FILE], num_lines, access_line_buf
            );
            continue;
        }

        /* Remove any colon that may be on the end of the var
        */
        if((ndx = strrchr(var, ':')) != NULL)
            *ndx = '\0';

        /*
        */
        if(opts->verbose > 3)
            fprintf(stderr,
                "ACCESS FILE: %s, LINE: %s\tVar: %s, Val: '%s'\n",
                opts->config[CONF_ACCESS_FILE], access_line_buf, var, val
            );

        /* Process the entry.
         *
         * NOTE: If a new access.conf parameter is created.  It also needs
         *       to be accounted for in the following if/if else construct.
        */

        if(CONF_VAR_IS(var, "SOURCE"))
        {
            /* If this is not the first stanza, sanity check the previous
             * stanza for the minimum required data.
            */
            if(curr_acc != NULL) {
                if(!acc_data_is_valid(curr_acc))
                {
                    fprintf(stderr,
                        "[*] Data error in access file: '%s'\n",
                        opts->config[CONF_ACCESS_FILE]);
                    exit(EXIT_FAILURE);
                }
            }

            /* Start new stanza.
            */
            curr_acc = acc_stanza_add(opts);

            add_acc_string(&(curr_acc->source), val);

            got_source++;
        }
        else if (curr_acc == NULL)
        {
            /* The stanza must start with the "SOURCE" variable
            */
            continue;
        }
        else if(CONF_VAR_IS(var, "OPEN_PORTS"))
        {
            add_acc_string(&(curr_acc->open_ports), val);
        }
        else if(CONF_VAR_IS(var, "RESTRICT_PORTS"))
        {
            add_acc_string(&(curr_acc->restrict_ports), val);
        }
        else if(CONF_VAR_IS(var, "KEY"))
        {
            if(strcasecmp(val, "__CHANGEME__") == 0)
            {
                fprintf(stderr,
                    "[*] KEY value is not properly set in stanza source '%s' in access file: '%s'\n",
                    curr_acc->source, opts->config[CONF_ACCESS_FILE]);
                exit(EXIT_FAILURE);
            }
            add_acc_string(&(curr_acc->key), val);
        }
        else if(CONF_VAR_IS(var, "FW_ACCESS_TIMEOUT"))
        {
            add_acc_int(&(curr_acc->fw_access_timeout), val);
        }
        else if(CONF_VAR_IS(var, "ENABLE_CMD_EXEC"))
        {
            add_acc_bool(&(curr_acc->enable_cmd_exec), val);
        }
        else if(CONF_VAR_IS(var, "CMD_EXEC_USER"))
        {
            add_acc_string(&(curr_acc->cmd_exec_user), val);

            errno = 0;
            pw = getpwnam(val);

            if(pw == NULL)
            {
                fprintf(stderr, "Unable to determine UID for CMD_EXEC_USER: %s.\n",
                    errno ? strerror(errno) : "Not a user on this system");
                exit(EXIT_FAILURE); 
            } 

            curr_acc->cmd_exec_uid = pw->pw_uid;
        }
        else if(CONF_VAR_IS(var, "REQUIRE_USERNAME"))
        {
            add_acc_string(&(curr_acc->require_username), val);
        }
        else if(CONF_VAR_IS(var, "REQUIRE_SOURCE_ADDRESS"))
        {
            add_acc_bool(&(curr_acc->require_source_address), val);
        }
        else if(CONF_VAR_IS(var, "GPG_HOME_DIR"))
        {
            if (is_valid_dir(val))
            {
                add_acc_string(&(curr_acc->gpg_home_dir), val);
            }
            else
            {
                fprintf(stderr,
                    "[*] GPG_HOME_DIR directory '%s' stat()/existence problem in stanza source '%s' in access file: '%s'\n",
                    val, curr_acc->source, opts->config[CONF_ACCESS_FILE]);
                exit(EXIT_FAILURE);
            }
        }
        else if(CONF_VAR_IS(var, "GPG_DECRYPT_ID"))
        {
            add_acc_string(&(curr_acc->gpg_decrypt_id), val);
        }
        else if(CONF_VAR_IS(var, "GPG_DECRYPT_PW"))
        {
            if(strcasecmp(val, "__CHANGEME__") == 0)
            {
                fprintf(stderr,
                    "[*] GPG_DECRYPT_PW value is not properly set in stanza source '%s' in access file: '%s'\n",
                    curr_acc->source, opts->config[CONF_ACCESS_FILE]);
                exit(EXIT_FAILURE);
            }
            add_acc_string(&(curr_acc->gpg_decrypt_pw), val);
        }
        else if(CONF_VAR_IS(var, "GPG_REQUIRE_SIG"))
        {
            add_acc_bool(&(curr_acc->gpg_require_sig), val);
        }
        else if(CONF_VAR_IS(var, "GPG_IGNORE_SIG_VERIFY_ERROR"))
        {
            add_acc_bool(&(curr_acc->gpg_ignore_sig_error), val);
        }
        else if(CONF_VAR_IS(var, "GPG_REMOTE_ID"))
        {
            add_acc_string(&(curr_acc->gpg_remote_id), val);
        }
        else 
        {
            fprintf(stderr,
                "*Ignoring unknown access parameter: '%s' in %s\n",
                var, opts->config[CONF_ACCESS_FILE]
            );
        }
    }

    fclose(file_ptr);

    /* Basic check to ensure that we got at least one SOURCE stanza with
     * a valid KEY defined (valid meaning it has a value that is not
     * "__CHANGEME__".
    */
    if (got_source == 0)
    {
        fprintf(stderr,
            "[*] Could not find valid SOURCE stanza in access file: '%s'\n",
            opts->config[CONF_ACCESS_FILE]);
        exit(EXIT_FAILURE);
    }

    /* Sanity check the last stanza
    */
    if(!acc_data_is_valid(curr_acc))
    {
        fprintf(stderr,
            "[*] Data error in access file: '%s'\n",
            opts->config[CONF_ACCESS_FILE]);
        exit(EXIT_FAILURE);
    }

    /* Expand our the expandable fields into their respective data buckets.
    */
    expand_acc_ent_lists(opts);

    /* Make sure default values are set where needed.
     * a default value.
    */
    set_acc_defaults(opts);

    return;
}
예제 #3
0
/* Parse the config file...
*/
static void
parse_config_file(fko_srv_options_t *opts, const char *config_file)
{
    FILE           *cfile_ptr;
    unsigned int    numLines = 0;
    unsigned int    i, good_ent;
    int             cndx;

    char            conf_line_buf[MAX_LINE_LEN] = {0};
    char            var[MAX_LINE_LEN]  = {0};
    char            val[MAX_LINE_LEN]  = {0};
    char            tmp1[MAX_LINE_LEN] = {0};
    char            tmp2[MAX_LINE_LEN] = {0};

    struct stat     st;

    /* Make sure the config file exists.
    */
    if(stat(config_file, &st) != 0)
    {
        log_msg(LOG_ERR, "[*] Config file: '%s' was not found.",
                config_file);
        clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
    }

    if(verify_file_perms_ownership(config_file) != 1)
        clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);

    /* See the comment in the parse_access_file() function regarding security
     * here relative to a TOCTOU bug flagged by Coverity.
    */
    if ((cfile_ptr = fopen(config_file, "r")) == NULL)
    {
        log_msg(LOG_ERR, "[*] Could not open config file: %s",
                config_file);
        perror(NULL);

        clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
    }

    while ((fgets(conf_line_buf, MAX_LINE_LEN, cfile_ptr)) != NULL)
    {
        numLines++;
        conf_line_buf[MAX_LINE_LEN-1] = '\0';

        /* Get past comments and empty lines (note: we only look at the
         * first character.
        */
        if(IS_EMPTY_LINE(conf_line_buf[0]))
            continue;

        if(sscanf(conf_line_buf, "%s %[^;\n\r]", var, val) != 2)
        {
            log_msg(LOG_ERR,
                    "*Invalid config file entry in %s at line %i.\n - '%s'",
                    config_file, numLines, conf_line_buf
                   );
            continue;
        }

        /*
        fprintf(stderr,
            "CONF FILE: %s, LINE: %s\tVar: %s, Val: '%s'\n",
            config_file, conf_line_buf, var, val
        );
        */

        good_ent = 0;
        for(i=0; i<NUMBER_OF_CONFIG_ENTRIES; i++)
        {
            if(CONF_VAR_IS(config_map[i], var))
            {
                /* First check to see if we need to do a varable expansion
                 * on this value.  Note: this only supports one expansion and
                 * only if the value starts with the variable.
                */
                if(*val == '$')
                {
                    if(sscanf((val+1), "%[A-Z_]%s", tmp1, tmp2))
                    {
                        if((cndx = config_entry_index(opts, tmp1)) >= 0)
                        {
                            strlcpy(val, opts->config[cndx], sizeof(val));
                            strlcat(val, tmp2, sizeof(val));
                        }
                    }
                }

                set_config_entry(opts, i, val);
                good_ent++;
                break;
            }
        }

        if(good_ent == 0)
            log_msg(LOG_ERR,
                    "[*] Ignoring unknown configuration parameter: '%s' in %s",
                    var, config_file
                   );
    }

    fclose(cfile_ptr);

    return;
}
예제 #4
0
static int
parse_rc_param(fko_cli_options_t *options, const char *var, char * val)
{
    int     tmpint;

    /* Digest Type */
    if(CONF_VAR_IS(var, "DIGEST_TYPE"))
    {
        tmpint = digest_strtoint(val);
        if(tmpint < 0)
            return(-1);
        else
            options->digest_type = tmpint;
    }
    /* Server protocol */
    else if(CONF_VAR_IS(var, "SPA_SERVER_PROTO"))
    {
        tmpint = proto_strtoint(val);
        if(tmpint < 0)
            return(-1);
        else
            options->spa_proto = tmpint;
    }
    /* Server port */
    else if(CONF_VAR_IS(var, "SPA_SERVER_PORT"))
    {
        tmpint = atoi(val);
        if(tmpint < 0 || tmpint > MAX_PORT)
            return(-1);
        else
            options->spa_dst_port = tmpint;
    }
    /* Source port */
    else if(CONF_VAR_IS(var, "SPA_SOURCE_PORT"))
    {
        tmpint = atoi(val);
        if(tmpint < 0 || tmpint > MAX_PORT)
            return(-1);
        else
            options->spa_src_port = tmpint;
    }
    /* Firewall rule timeout */
    else if(CONF_VAR_IS(var, "FW_TIMEOUT"))
    {
        tmpint = atoi(val);
        if(tmpint < 0)
            return(-1);
        else
            options->fw_timeout = tmpint;
    }
    /* Allow IP */
    else if(CONF_VAR_IS(var, "ALLOW_IP"))
    {
        /* In case this was set previously
        */
        options->resolve_ip_http = 0;

        /* use source, resolve, or an actual IP
        */
        if(strcasecmp(val, "source") == 0)
            strlcpy(options->allow_ip_str, "0.0.0.0", 8);
        else if(strcasecmp(val, "resolve") == 0)
            options->resolve_ip_http = 1;
        else /* Assume IP address */
            strlcpy(options->allow_ip_str, val, MAX_IPV4_STR_LEN);
    }
    /* Time Offset */
    else if(CONF_VAR_IS(var, "TIME_OFFSET"))
    {
        if(val[0] == '-')
        {
            val++;
            options->time_offset_minus = parse_time_offset(val);
        }
        else
            options->time_offset_plus = parse_time_offset(val);
    }
    /* Use GPG ? */
    else if(CONF_VAR_IS(var, "USE_GPG"))
    {
        if(val[0] == 'y' || val[0] == 'Y')
            options->use_gpg = 1;
    }
    /* Use GPG Agent ? */
    else if(CONF_VAR_IS(var, "USE_GPG_AGENT"))
    {
        if(val[0] == 'y' || val[0] == 'Y')
            options->use_gpg_agent = 1;
    }
    /* GPG Recipient */
    else if(CONF_VAR_IS(var, "GPG_RECIPIENT"))
    {
        strlcpy(options->gpg_recipient_key, val, MAX_GPG_KEY_ID);
    }
    /* GPG Signer */
    else if(CONF_VAR_IS(var, "GPG_SIGNER"))
    {
        strlcpy(options->gpg_signer_key, val, MAX_GPG_KEY_ID);
    }
    /* GPG Homedir */
    else if(CONF_VAR_IS(var, "GPG_HOMEDIR"))
    {
        strlcpy(options->gpg_home_dir, val, MAX_PATH_LEN);
    }
    /* Spoof User */
    else if(CONF_VAR_IS(var, "SPOOF_USER"))
    {
        strlcpy(options->spoof_user, val, MAX_USERNAME_LEN);
    }
    /* Spoof Source IP */
    else if(CONF_VAR_IS(var, "SPOOF_SOURCE_IP"))
    {
        strlcpy(options->spoof_ip_src_str, val, MAX_IPV4_STR_LEN);
    }
    /* ACCESS request */
    else if(CONF_VAR_IS(var, "ACCESS"))
    {
        strlcpy(options->access_str, val, MAX_LINE_LEN);
    }
    /* SPA Server (destination) */
    else if(CONF_VAR_IS(var, "SPA_SERVER"))
    {
        strlcpy(options->spa_server_str, val, MAX_SERVER_STR_LEN);
    }
    /* Rand port ? */
    else if(CONF_VAR_IS(var, "RAND_PORT"))
    {
        if(val[0] == 'y' || val[0] == 'Y')
            options->rand_port = 1;
    }
    /* Key file */
    else if(CONF_VAR_IS(var, "KEY_FILE"))
    {
        strlcpy(options->get_key_file, val, MAX_PATH_LEN);
    }
    /* NAT Access Request */
    else if(CONF_VAR_IS(var, "NAT_ACCESS"))
    {
        strlcpy(options->nat_access_str, val, MAX_PATH_LEN);
    }
    /* HTTP User Agent */
    else if(CONF_VAR_IS(var, "HTTP_USER_AGENT"))
    {
        strlcpy(options->http_user_agent, val, HTTP_MAX_USER_AGENT_LEN);
    }
    /* Resolve URL */
    else if(CONF_VAR_IS(var, "RESOLVE_URL"))
    {
        if(options->resolve_url != NULL)
            free(options->resolve_url);
        tmpint = strlen(val)+1;
        options->resolve_url = malloc(tmpint);
        if(options->resolve_url == NULL)
        {
            fprintf(stderr, "Memory allocation error for resolve URL.\n");
            exit(EXIT_FAILURE);
        }
        strlcpy(options->resolve_url, val, tmpint);
    }
    /* NAT Local ? */
    else if(CONF_VAR_IS(var, "NAT_LOCAL"))
    {
        if(val[0] == 'y' || val[0] == 'Y')
            options->nat_local = 1;
    }
    /* NAT rand port ? */
    else if(CONF_VAR_IS(var, "NAT_RAND_PORT"))
    {
        if(val[0] == 'y' || val[0] == 'Y')
            options->nat_rand_port = 1;
    }
    /* NAT port */
    else if(CONF_VAR_IS(var, "NAT_PORT"))
    {
        tmpint = atoi(val);
        if(tmpint < 0 || tmpint > MAX_PORT)
            return(-1);
        else
            options->nat_port = tmpint;
    }

    return(0);
}