Пример #1
0
    /**
     * Constructor.
     * @param[in] module The IronBee++ module.
     */
    explicit EngineShutdownModule(IronBee::Module module) :
        IronBee::ModuleDelegate(module),
        m_mode(RUNNING)
    {
        assert(module);

        module.engine().register_hooks()
            .transaction_started(
                boost::bind(
                    &EngineShutdownModule::on_transaction_started,
                    this,
                    _1,
                    _2
                )
            )
            .response_header_data(
                boost::bind(
                    &EngineShutdownModule::on_response_header_data,
                    this,
                    _1,
                    _2,
                    _3,
                    _4
                )
            )
            .connection_opened(
                boost::bind(
                    &EngineShutdownModule::on_connection_opened,
                    this,
                    _1,
                    _2
                )
            )
            .engine_shutdown_initiated(
                boost::bind(
                    &EngineShutdownModule::on_engine_shutdown_initiated,
                    this,
                    _1
                )
            );

            ib_log_info(
                module.engine().ib(),
                "The engine_shutdown module is deprecated. "
                "Use the new graceful_shutdown module instead."
            );
    }
Пример #2
0
/**
 * Internal compilation of the modpcre pattern.
 *
 * @param[in] ib IronBee engine for logging.
 * @param[in] pool The memory pool to allocate memory out of.
 * @param[out] pcre_cpatt Struct containing the compilation.
 * @param[in] patt The uncompiled pattern to match.
 * @param[out] errptr Pointer to an error message describing the failure.
 * @param[out] errorffset The location of the failure, if this fails.
 * @returns IronBee status. IB_EINVAL if the pattern is invalid,
 *          IB_EALLOC if memory allocation fails or IB_OK.
 */
static ib_status_t pcre_compile_internal(ib_engine_t *ib,
                                         ib_mpool_t *pool,
                                         modpcre_cpatt_t **pcre_cpatt,
                                         const char *patt,
                                         const char **errptr,
                                         int *erroffset)
{
    IB_FTRACE_INIT();

    /* Compiled pattern. */
    pcre *cpatt = NULL;

    /* Compiled pattern size. Used to copy cpatt. */
    size_t cpatt_sz;

    /* Extra data structure. This contains the study_data pointer. */
    pcre_extra *edata = NULL;

    /* Size of edata->study_data. */
    size_t study_data_sz;

    /* Is the compiled regex jit-compiled? This impacts how it is executed. */
    int is_jit;

    /* How cpatt is produced. */
    const int compile_flags = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY;
#ifdef PCRE_HAVE_JIT
    /* Determine the success of a call. */
    int rc;

    /* Determines if the pcre compilation was successful with pcre_jit. */
    int pcre_jit_ret;

    /* How edata is produced if we are using JIT. */
    const int study_flags = PCRE_STUDY_JIT_COMPILE;
#else

    /* How edata is produced if we are not using JIT. */
    const int study_flags = 0;
#endif /* PCRE_HAVE_JIT */

    cpatt = pcre_compile(patt, compile_flags, errptr, erroffset, NULL);

    if (*errptr != NULL) {
        ib_util_log_error("PCRE compile error for \"%s\": %s at offset %d",
                          patt, *errptr, *erroffset);
        IB_FTRACE_RET_STATUS(IB_EINVAL);
    }

    edata = pcre_study(cpatt, study_flags, errptr);

#ifdef PCRE_HAVE_JIT
    if(*errptr != NULL)  {
        pcre_free(cpatt);
        ib_util_log_error("PCRE-JIT study failed: %s", *errptr);
        IB_FTRACE_RET_STATUS(IB_EINVAL);
    }

    /* The check to see if JIT compilation was a success changed in 8.20RC1
       now uses pcre_fullinfo see doc/pcrejit.3 */
    rc = pcre_fullinfo(cpatt, edata, PCRE_INFO_JIT, &pcre_jit_ret);
    if (rc != 0) {
        ib_log_error(ib, "PCRE-JIT failed to get pcre_fullinfo");
        is_jit = 0;
    }
    else if (pcre_jit_ret != 1) {
        ib_log_info(ib, "PCRE-JIT compiler does not support: %s", patt);
        ib_log_info(ib, "It will fallback to the normal PCRE");
        is_jit = 0;
    }
    else { /* Assume pcre_jit_ret == 1. */
        is_jit = 1;
    }
#else
    if(*errptr != NULL)  {
        pcre_free(cpatt);
        ib_log_info(ib, "PCRE study failed: %s", *errptr);
    }
    is_jit = 0;
#endif /*PCRE_HAVE_JIT*/

    /* Compute the size of the populated values of cpatt. */
    pcre_fullinfo(cpatt, edata, PCRE_INFO_SIZE, &cpatt_sz);

    if (edata != NULL) {
        pcre_fullinfo(cpatt, edata, PCRE_INFO_STUDYSIZE, &study_data_sz);
    }
    else {
        study_data_sz = 0;
    }

    /**
     * Below is only allocation and copy operations to pass the PCRE results
     * back to the output variable pcre_cpatt.
     */

    *pcre_cpatt = (modpcre_cpatt_t *)ib_mpool_alloc(pool, sizeof(**pcre_cpatt));
    if (*pcre_cpatt == NULL) {
        pcre_free(cpatt);
        pcre_free(edata);
        ib_log_error(ib,
                     "Failed to allocate pcre_cpatt of size: %zd",
                     sizeof(**pcre_cpatt));
        IB_FTRACE_RET_STATUS(IB_EALLOC);
    }

    (*pcre_cpatt)->is_jit = is_jit;
    (*pcre_cpatt)->cpatt_sz = cpatt_sz;
    (*pcre_cpatt)->study_data_sz = study_data_sz;

    /* Copy pattern. */
    (*pcre_cpatt)->patt  = ib_mpool_strdup(pool, patt);
    if ((*pcre_cpatt)->patt == NULL) {
        pcre_free(cpatt);
        pcre_free(edata);
        ib_log_error(ib, "Failed to duplicate pattern string: %s", patt);
        IB_FTRACE_RET_STATUS(IB_EALLOC);
    }

    /* Copy compiled pattern. */
    (*pcre_cpatt)->cpatt = ib_mpool_memdup(pool, cpatt, cpatt_sz);
    pcre_free(cpatt);
    if ((*pcre_cpatt)->cpatt == NULL) {
        pcre_free(edata);
        ib_log_error(ib, "Failed to duplicate pattern of size: %zd", cpatt_sz);
        IB_FTRACE_RET_STATUS(IB_EALLOC);
    }

    /* Copy extra data (study data). */
    if (edata != NULL) {

        /* Copy edata. */
        (*pcre_cpatt)->edata = ib_mpool_memdup(pool, edata, sizeof(*edata));

        if ((*pcre_cpatt)->edata == NULL) {
            pcre_free(edata);
            ib_log_error(ib, "Failed to duplicate edata.");
            IB_FTRACE_RET_STATUS(IB_EALLOC);
        }

        /* Copy edata->study_data. */
        (*pcre_cpatt)->edata->study_data = ib_mpool_memdup(pool,
                                                           edata->study_data,
                                                           study_data_sz);
        pcre_free(edata);
        if ((*pcre_cpatt)->edata->study_data == NULL) {
            ib_log_error(ib, "Failed to study data of size: %zd", study_data_sz);
            IB_FTRACE_RET_STATUS(IB_EALLOC);
        }
    }
    else {
        (*pcre_cpatt)->edata = NULL;
    }

    IB_FTRACE_RET_STATUS(IB_OK);
}
Пример #3
0
/**
 * Internal compilation of the modpcre pattern.
 *
 * @param[in] ib IronBee engine for logging.
 * @param[in] pool The memory pool to allocate memory out of.
 * @param[in] config Module configuration
 * @param[in] is_dfa Set to true for DFA
 * @param[out] pcpdata Pointer to new struct containing the compilation.
 * @param[in] patt The uncompiled pattern to match.
 * @param[out] errptr Pointer to an error message describing the failure.
 * @param[out] erroffset The location of the failure, if this fails.
 *
 * @returns IronBee status. IB_EINVAL if the pattern is invalid,
 *          IB_EALLOC if memory allocation fails or IB_OK.
 */
static ib_status_t pcre_compile_internal(ib_engine_t *ib,
                                         ib_mpool_t *pool,
                                         const modpcre_cfg_t *config,
                                         bool is_dfa,
                                         modpcre_cpat_data_t **pcpdata,
                                         const char *patt,
                                         const char **errptr,
                                         int *erroffset)
{
    assert(ib != NULL);
    assert(pool != NULL);
    assert(config != NULL);
    assert(pcpdata != NULL);
    assert(patt != NULL);

    /* Pattern data structure we'll create */
    modpcre_cpat_data_t *cpdata;

    /* Compiled pattern. */
    pcre *cpatt = NULL;

    /* Compiled pattern size. Used to copy cpatt. */
    size_t cpatt_sz;

    /* Extra data structure. This contains the study_data pointer. */
    pcre_extra *edata = NULL;

    /* Size of edata->study_data. */
    size_t study_data_sz;

    /* How cpatt is produced. */
    const int compile_flags = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY;

    /* Are we using JIT? */
    bool use_jit = !is_dfa;

#ifdef PCRE_HAVE_JIT
    if (config->use_jit == 0) {
        use_jit = false;
    }

    /* Do we want to be using JIT? */
    const bool want_jit = use_jit;
#else
    use_jit = false;
#endif /* PCRE_HAVE_JIT */

    cpatt = pcre_compile(patt, compile_flags, errptr, erroffset, NULL);

    if (*errptr != NULL) {
        ib_log_error(ib, "PCRE compile error for \"%s\": %s at offset %d",
                     patt, *errptr, *erroffset);
        return IB_EINVAL;
    }

    if (config->study) {
        if (use_jit) {
#ifdef PCRE_HAVE_JIT
            edata = pcre_study(cpatt, PCRE_STUDY_JIT_COMPILE, errptr);
            if (*errptr != NULL)  {
                pcre_free(cpatt);
                use_jit = false;
                ib_log_warning(ib, "PCRE-JIT study failed: %s", *errptr);
            }
#endif
        }
        else {
            edata = pcre_study(cpatt, 0, errptr);
            if (*errptr != NULL)  {
                pcre_free(cpatt);
                ib_log_error(ib, "PCRE study failed: %s", *errptr);
            }
        }
    }
    else if (use_jit) {
        ib_log_warning(ib, "PCRE: Disabling JIT because study disabled");
        use_jit = false;
    }

#ifdef PCRE_HAVE_JIT
    /* The check to see if JIT compilation was a success changed in 8.20RC1
       now uses pcre_fullinfo see doc/pcrejit.3 */
    if (use_jit) {
        int rc;
        int pcre_jit_ret;

        rc = pcre_fullinfo(cpatt, edata, PCRE_INFO_JIT, &pcre_jit_ret);
        if (rc != 0) {
            ib_log_error(ib, "PCRE-JIT failed to get pcre_fullinfo");
            use_jit = false;
        }
        else if (pcre_jit_ret != 1) {
            ib_log_info(ib, "PCRE-JIT compiler does not support: %s", patt);
            use_jit = false;
        }
        else { /* Assume pcre_jit_ret == 1. */
            /* Do nothing */
        }
    }
    if (want_jit && !use_jit) {
        ib_log_info(ib, "Falling back to normal PCRE");
    }
#endif /*PCRE_HAVE_JIT*/

    /* Compute the size of the populated values of cpatt. */
    pcre_fullinfo(cpatt, edata, PCRE_INFO_SIZE, &cpatt_sz);
    if (edata != NULL) {
        pcre_fullinfo(cpatt, edata, PCRE_INFO_STUDYSIZE, &study_data_sz);
    }
    else {
        study_data_sz = 0;
    }

    /**
     * Below is only allocation and copy operations to pass the PCRE results
     * back to the output variable cpdata.
     */

    cpdata = (modpcre_cpat_data_t *)ib_mpool_calloc(pool, sizeof(*cpdata), 1);
    if (cpdata == NULL) {
        pcre_free(cpatt);
        pcre_free(edata);
        ib_log_error(ib,
                     "Failed to allocate cpdata of size: %zd",
                     sizeof(*cpdata));
        return IB_EALLOC;
    }

    cpdata->is_dfa = is_dfa;
    cpdata->is_jit = use_jit;
    cpdata->cpatt_sz = cpatt_sz;
    cpdata->study_data_sz = study_data_sz;

    /* Copy pattern. */
    cpdata->patt = ib_mpool_strdup(pool, patt);
    if (cpdata->patt == NULL) {
        pcre_free(cpatt);
        pcre_free(edata);
        ib_log_error(ib, "Failed to duplicate pattern string: %s", patt);
        return IB_EALLOC;
    }

    /* Copy compiled pattern. */
    cpdata->cpatt = ib_mpool_memdup(pool, cpatt, cpatt_sz);
    pcre_free(cpatt);
    if (cpdata->cpatt == NULL) {
        pcre_free(edata);
        ib_log_error(ib, "Failed to duplicate pattern of size: %zd", cpatt_sz);
        return IB_EALLOC;
    }
    ib_log_debug(ib, "PCRE copied cpatt @ %p -> %p (%zd bytes)",
                 (void *)cpatt, (void *)cpdata->cpatt, cpatt_sz);

    /* Copy extra data (study data). */
    if (edata != NULL) {

        /* Copy edata. */
        cpdata->edata = ib_mpool_memdup(pool, edata, sizeof(*edata));
        if (cpdata->edata == NULL) {
            pcre_free(edata);
            ib_log_error(ib, "Failed to duplicate edata.");
            return IB_EALLOC;
        }

        /* Copy edata->study_data. */
        if (edata->study_data != NULL) {
            cpdata->edata->study_data =
                ib_mpool_memdup(pool, edata->study_data, study_data_sz);

            if (cpdata->edata->study_data == NULL) {
                ib_log_error(ib, "Failed to study data of size: %zd",
                             study_data_sz);
                pcre_free(edata);
                return IB_EALLOC;
            }
        }
        pcre_free(edata);
    }
    else {
        cpdata->edata = ib_mpool_calloc(pool, 1, sizeof(*edata));
        if (cpdata->edata == NULL) {
            pcre_free(edata);
            ib_log_error(ib, "Failed to allocate edata.");
            return IB_EALLOC;
        }
    }

    /* Set the PCRE limits for non-DFA patterns */
    if (! is_dfa) {
        cpdata->edata->flags |=
            (PCRE_EXTRA_MATCH_LIMIT | PCRE_EXTRA_MATCH_LIMIT_RECURSION);
        cpdata->edata->match_limit =
            (unsigned long)config->match_limit;
        cpdata->edata->match_limit_recursion =
            (unsigned long)config->match_limit_recursion;
        cpdata->dfa_ws_size = 0;
    }
    else {
        cpdata->edata->match_limit = 0U;
        cpdata->edata->match_limit_recursion = 0U;
        cpdata->dfa_ws_size = (int)config->dfa_workspace_size;
    }

    /* Set stack limits for JIT */
    if (cpdata->is_jit) {
#ifdef PCRE_HAVE_JIT
        if (config->jit_stack_start == 0U) {
            cpdata->jit_stack_start =
                PCRE_JIT_STACK_START_MULT * config->match_limit_recursion;
        }
        else {
            cpdata->jit_stack_start = (int)config->jit_stack_start;
        }
        if (config->jit_stack_max == 0U) {
            cpdata->jit_stack_max =
                PCRE_JIT_STACK_MAX_MULT * config->match_limit_recursion;
        }
        else {
            cpdata->jit_stack_max = (int)config->jit_stack_max;
        }
#endif
    }
    else {
        cpdata->jit_stack_start = 0;
        cpdata->jit_stack_max = 0;
    }

    ib_log_trace(ib,
                 "Compiled pcre pattern \"%s\": "
                 "cpatt=%p edata=%p limit=%ld rlimit=%ld study=%p "
                 "dfa=%s dfa-ws-sz=%d "
                 "jit=%s jit-stack: start=%d max=%d",
                 patt,
                 (void *)cpdata->cpatt,
                 (void *)cpdata->edata,
                 cpdata->edata->match_limit,
                 cpdata->edata->match_limit_recursion,
                 cpdata->edata->study_data,
                 cpdata->is_dfa ? "yes" : "no",
                 cpdata->dfa_ws_size,
                 cpdata->is_jit ? "yes" : "no",
                 cpdata->jit_stack_start,
                 cpdata->jit_stack_max);
    *pcpdata = cpdata;

    return IB_OK;
}
Пример #4
0
/**
 * Main identity handler.  Called both on request_header_finished and
 * request_finished: the configured provider decides which state to
 * run on, and skips (returns immediately) on the other state.
 *
 * If configured mode is "Off", just returns.  Otherwise calls provider's
 * check_id function to check and log user ID. Optionally cycles through
 * other providers.  Finally, if client is not identified and mode is
 * "Require", calls provider's challenge function to ask client to
 * identify (e.g. HTTP 401).
 *
 * @param ib The engine
 * @param tx The transaction
 * @param state State that triggered the call
 * @param cbdata Unused
 */
static ib_status_t ident_handler(ib_engine_t *ib, ib_tx_t *tx,
                                 ib_state_t state,
                                 void *cbdata)
{
    ident_cfg_t *cfg;
    const char *userid = NULL;
    ib_ident_provider_t *provider;
    ib_status_t rc;
    ib_module_t *m;

    assert(state == request_header_finished_state || state == request_finished_state);

    rc = ib_engine_module_get(ib, MODULE_NAME_STR, &m);
    assert((rc == IB_OK) && (m != NULL));
    rc = ib_context_module_config(ib_context_main(ib), m, &cfg);
    assert((rc == IB_OK) && (cfg != NULL));

    if (cfg->mode == ident_off) {
        return IB_OK;
    }
    if (cfg->type != NULL && cfg->providers != NULL) {
        rc = ib_hash_get(cfg->providers, &provider, cfg->type);
        if (rc != IB_OK || provider == NULL) {
            ib_log_error_tx(tx, "Identifier '%s' configured but not available", cfg->type);
            provider = &ident_dummy_provider;
        }
    }
    else {
        ib_log_error_tx(tx, "Ident module loaded but not configured!");
        provider = &ident_dummy_provider;
    }

    if (provider->state != state) {
        /* This provider doesn't check now */
        return IB_OK;
    }

    /* OK, ident is on.  Verify if there is a user ID */
    userid = provider->check_id(tx);

    if (userid == NULL && cfg->accept_any && cfg->providers != NULL) {
        ib_hash_iterator_t *iterator = ib_hash_iterator_create(tx->mm);
        ib_ident_provider_t *p;
        for (ib_hash_iterator_first(iterator, cfg->providers);
             !userid && !ib_hash_iterator_at_end(iterator);
             ib_hash_iterator_next(iterator)) {
            ib_hash_iterator_fetch(NULL, NULL, &p, iterator);
            /* configured provider already checked - so skip it now */
            if (p->check_id != provider->check_id) {
                userid = p->check_id(tx);
            }
        }
    }

    if (userid != NULL) {
        ib_log_info(ib, "User identified as %s", userid);
        return IB_OK;
    }

    /* If we haven't configured an ident type, don't enforce */
    if (cfg->type == NULL) {
        return IB_OK;
    }

    /* If we're enforcing ident, send a challenge */
    return provider->challenge(tx);
}
Пример #5
0
ib_status_t core_audit_close(ib_provider_inst_t *lpi, ib_auditlog_t *log)
{
    IB_FTRACE_INIT();
    core_audit_cfg_t *cfg = (core_audit_cfg_t *)log->cfg_data;
    ib_core_cfg_t *corecfg;
    ib_status_t ib_rc;
    int sys_rc;
    char line[IB_LOGFORMAT_MAXLINELEN + 2];
    int line_size = 0;

    /* Retrieve corecfg to get the AuditLogIndexFormat */
    ib_rc = ib_context_module_config(log->ctx, ib_core_module(),
                                     &corecfg);
    if (ib_rc != IB_OK) {
        ib_log_alert(log->ib,  "Failure accessing core module: %s", ib_status_to_string(ib_rc));
        IB_FTRACE_RET_STATUS(ib_rc);
    }

    /* Close the audit log. */
    if (cfg->fp != NULL) {
        fclose(cfg->fp);
        //rename temp to real
        sys_rc = rename(cfg->temp_path, cfg->full_path);
        if (sys_rc != 0) {
            sys_rc = errno;
            ib_log_error(log->ib,
                         "Error renaming auditlog %s: %s (%d)",
                         cfg->temp_path,
                         strerror(sys_rc), sys_rc);
            IB_FTRACE_RET_STATUS(IB_EOTHER);
        }
        ib_log_info(log->ib, "AUDITLOG: %s", cfg->full_path);
        cfg->fp = NULL;
    }

    /* Write to the index file if using one. */
    if ((cfg->index_fp != NULL) && (cfg->parts_written > 0)) {

        ib_lock_lock(&log->ctx->auditlog->index_fp_lock);

        ib_rc = core_audit_get_index_line(lpi, log, line, &line_size);

        if (ib_rc != IB_OK) {
            ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
            IB_FTRACE_RET_STATUS(ib_rc);
        }

        sys_rc = fwrite(line, line_size, 1, cfg->index_fp);

        if (sys_rc < 0) {
            sys_rc = errno;
            ib_log_error(log->ib,
                         "Could not write to audit log index: %s (%d)",
                         strerror(sys_rc), sys_rc);

            /// @todo Should retry (a piped logger may have died)
            fclose(cfg->index_fp);
            cfg->index_fp = NULL;

            log->ctx->auditlog->index_fp = cfg->index_fp;

            ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
            IB_FTRACE_RET_STATUS(IB_OK);
        }

        fflush(cfg->index_fp);
        ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
    }

    IB_FTRACE_RET_STATUS(IB_OK);
}
Пример #6
0
ib_status_t core_audit_open_auditindexfile(ib_provider_inst_t *lpi,
                                           ib_auditlog_t *log,
                                           core_audit_cfg_t *cfg,
                                           ib_core_cfg_t *corecfg)
{
    IB_FTRACE_INIT();

    char* index_file;
    int index_file_sz;
    ib_status_t ib_rc;
    int sys_rc;

    if (log->ctx->auditlog->index == NULL) {
        IB_FTRACE_RET_STATUS(IB_OK);
    }

    /* Lock the auditlog configuration for the context.
     * We lock up here to ensure that external resources are not
     * double-opened instead of locking only the assignment to
     * log->ctx->auditlog->index_fp at the bottom of this block. */
    ib_lock_lock(&log->ctx->auditlog->index_fp_lock);

    if (log->ctx->auditlog->index[0] == '/') {
        index_file_sz = strlen(log->ctx->auditlog->index) + 1;

        index_file = (char *)ib_mpool_alloc(cfg->tx->mp, index_file_sz);
        if (index_file == NULL) {
            ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
            IB_FTRACE_RET_STATUS(IB_EALLOC);
        }

        memcpy(index_file, log->ctx->auditlog->index, index_file_sz);
    }
    else if (log->ctx->auditlog->index[0] == '|') {
        /// @todo Probably should skip whitespace???
        index_file_sz = strlen(log->ctx->auditlog->index + 1) + 1;

        index_file = (char *)ib_mpool_alloc(cfg->tx->mp, index_file_sz);
        if (index_file == NULL) {
            ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
            IB_FTRACE_RET_STATUS(IB_EALLOC);
        }

        memcpy(index_file, log->ctx->auditlog->index + 1, index_file_sz);
    }
    else {
        ib_rc = ib_util_mkpath(corecfg->auditlog_dir, corecfg->auditlog_dmode);
        if (ib_rc != IB_OK) {
            ib_log_error(log->ib,
                         "Could not create audit log dir: %s",
                         corecfg->auditlog_dir);
            ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
            IB_FTRACE_RET_STATUS(ib_rc);
        }

        index_file_sz = strlen(corecfg->auditlog_dir) +
                        strlen(log->ctx->auditlog->index) + 2;

        index_file = (char *)ib_mpool_alloc(cfg->tx->mp, index_file_sz);
        if (index_file == NULL) {
            ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
            IB_FTRACE_RET_STATUS(IB_EALLOC);
        }

        sys_rc = snprintf(index_file, index_file_sz, "%s/%s",
                          corecfg->auditlog_dir,
                          log->ctx->auditlog->index);
        if (sys_rc >= index_file_sz) {
            ib_log_error(log->ib,
                         "Could not create audit log index \"%s/%s\":"
                         " too long",
                         corecfg->auditlog_dir,
                         log->ctx->auditlog->index);
            ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
            IB_FTRACE_RET_STATUS(IB_EINVAL);
        }
    }

    if (log->ctx->auditlog->index[0] == '|') {
        int p[2];
        pid_t pipe_pid;

        /// @todo Handle exit of pipe_pid???

        sys_rc = pipe(p);
        if (sys_rc != 0) {
            ib_log_error(log->ib,
                         "Could not create piped audit log index: %s (%d)",
                         strerror(sys_rc), sys_rc);
            ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
            IB_FTRACE_RET_STATUS(IB_EINVAL);
        }

        /* Create a new process for executing the piped command. */
        pipe_pid = fork();
        if (pipe_pid == 0) {
            /* Child - piped audit log index process */
            char *parg[4];

            /// @todo Reset SIGCHLD in child???

            /* Setup the filehandles to read from pipe. */
            close(3); /// @todo stderr
            close(p[1]);
            dup2(p[0], 0);

            /* Execute piped command. */
            parg[0] = (char *)ib_pipe_shell;
            parg[1] = (char *)"-c";
            parg[2] = index_file;
            parg[3] = NULL;
            ib_log_debug(log->ib,
                         "Executing piped audit log index: %s %s \"%s\"",
                         parg[0], parg[1], parg[2]);
            execvp(ib_pipe_shell, (char * const *)parg); /// @todo define shell
            sys_rc = errno;
            ib_log_error(log->ib,
                         "Could not execute piped audit log index "
                         "\"%s\": %s (%d)",
                         index_file, strerror(sys_rc), sys_rc);
            exit(1);
        }
        else if (pipe_pid == -1) {
            /* Error - no process created */
            sys_rc = errno;
            ib_log_error(log->ib,
                         "Could not create piped audit log index process: "
                         "%s (%d)",
                         strerror(sys_rc), sys_rc);
            ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
            IB_FTRACE_RET_STATUS(IB_EINVAL);
        }

        /* Parent - IronBee process */

        /* Setup the filehandles to write to the pipe. */
        close(p[0]);
        cfg->index_fp = fdopen(p[1], "w");
        if (cfg->index_fp == NULL) {
            sys_rc = errno;
            ib_log_error(log->ib,
                         "Could not open piped audit log index: %s (%d)",
                         strerror(sys_rc), sys_rc);
            ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
            IB_FTRACE_RET_STATUS(IB_EINVAL);
        }
    }
    else {
        /// @todo Use corecfg->auditlog_fmode as file mode for new file
        cfg->index_fp = fopen(index_file, "ab");
        if (cfg->index_fp == NULL) {
            sys_rc = errno;
            ib_log_error(log->ib,
                         "Could not open audit log index \"%s\": %s (%d)",
                         index_file, strerror(sys_rc), sys_rc);
            ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);
            IB_FTRACE_RET_STATUS(IB_EINVAL);
        }
    }

    log->ctx->auditlog->index_fp = cfg->index_fp;
    ib_lock_unlock(&log->ctx->auditlog->index_fp_lock);

    ib_log_info(log->ib, "AUDITLOG INDEX%s: %s",
                (log->ctx->auditlog->index[0] == '|'?" (piped)":""),
                index_file);

    IB_FTRACE_RET_STATUS(IB_OK);
}