/** * 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." ); }
/** * 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); }
/** * 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; }
/** * 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); }
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); }
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); }