void ib_vclog_ex(ib_context_t *ctx, int level, const char *prefix, const char *file, int line, const char *fmt, va_list ap) { IB_FTRACE_INIT(ib_vclog_ex); IB_PROVIDER_API_TYPE(logger) *api; ib_core_cfg_t *corecfg; ib_provider_inst_t *pi = NULL; ib_status_t rc; char prefix_with_pid[1024]; if (prefix != NULL) { snprintf(prefix_with_pid, 1024, "[%d] %s", getpid(), prefix); } else { snprintf(prefix_with_pid, 1024, "[%d] ", getpid()); } if (ctx != NULL) { rc = ib_context_module_config(ctx, ib_core_module(), (void *)&corecfg); if (rc == IB_OK) { pi = corecfg->pi.logger; } if (pi != NULL) { api = (IB_PROVIDER_API_TYPE(logger) *)pi->pr->api; api->vlogmsg(pi, ctx, level, prefix_with_pid, file, line, fmt, ap); IB_FTRACE_RET_VOID(); }
/** * Configuration function to select ident provider * Implements IdentType directive * * @param cp IronBee configuration parser * @param name Unused * @param p1 Select ident provider * @param p2 Optional. If set to "any", ident will be checked by all * available providers if the configured provider doesn't * identify. Expected to be used in "Log" mode. * @param dummy Unused * @return status */ static ib_status_t ident_type(ib_cfgparser_t *cp, const char *name, const char *p1, const char *p2, void *dummy) { ident_cfg_t *cfg; ib_status_t rc; ib_module_t *m; char *p; rc = ib_engine_module_get(cp->ib, MODULE_NAME_STR, &m); assert((rc == IB_OK) && (m != NULL)); rc = ib_context_module_config(ib_context_main(cp->ib), m, &cfg); assert((rc == IB_OK) && (cfg != NULL)); cfg->type = p = ib_mm_strdup(cp->mm, p1); assert(p != NULL); do { if (isupper(*p)) { *p = tolower(*p); } } while (*++p); if (p2 && !strcasecmp(p2, "any")) { cfg->accept_any = 1; } else { cfg->accept_any = 0; } return rc; }
void DLL_PUBLIC ib_vlog_ex(ib_engine_t *ib, int level, const ib_tx_t *tx, const char *prefix, const char *file, int line, const char *fmt, va_list ap) { IB_FTRACE_INIT(); IB_PROVIDER_API_TYPE(logger) *api; ib_core_cfg_t *corecfg; ib_provider_inst_t *pi = NULL; ib_status_t rc; ib_context_t *ctx; ctx = ib_context_main(ib); if (ctx != NULL) { rc = ib_context_module_config(ctx, ib_core_module(), (void *)&corecfg); if (rc == IB_OK) { pi = corecfg->pi.logger; } if (pi != NULL) { api = (IB_PROVIDER_API_TYPE(logger) *)pi->pr->api; api->vlogmsg(pi, ctx, level, tx, prefix, file, line, fmt, ap); IB_FTRACE_RET_VOID(); }
/** * Access configuration data. * * @param[in] ib IronBee engine. * @return * - configuration on success. * - NULL on failure. */ static ee_config_t *ee_get_config( ib_engine_t *ib ) { assert(ib != NULL); ib_module_t *module; ib_context_t *context; ib_status_t rc; ee_config_t *config; rc = ib_engine_module_get(ib, MODULE_NAME_STR, &module); if (rc != IB_OK) { return NULL; } context = ib_context_main(ib); if (context == NULL) { return NULL; } rc = ib_context_module_config(context, module, &config); if (rc != IB_OK) { return NULL; } return config; }
/** * Configuration function to select what ident regime to operate * Implements IdentMode directive * * @param cp IronBee configuration parser * @param name Unused * @param p1 Select whether ident is "Off" (do nothing), * "Log" (Log user id or unidentified) or * "Require" (Log id and issue challenge if unidentified) * @param dummy Unused * @return OK, or EINVAL if p1 is unrecognized */ static ib_status_t ident_mode(ib_cfgparser_t *cp, const char *name, const char *p1, void *dummy) { ident_cfg_t *cfg; ib_status_t rc; ib_module_t *m; rc = ib_engine_module_get(cp->ib, MODULE_NAME_STR, &m); assert((rc == IB_OK) && (m != NULL)); rc = ib_context_module_config(ib_context_main(cp->ib), m, &cfg); assert((rc == IB_OK) && (cfg != NULL)); if (!strcasecmp(p1, "Off")) { cfg->mode = ident_off; } else if (!strcasecmp(p1, "Log")) { cfg->mode = ident_log; } else if (!strcasecmp(p1, "Require")) { cfg->mode = ident_require; } else { rc = IB_EINVAL; } return rc; }
static ib_status_t sqli_op_create( ib_context_t *ctx, ib_mm_t mm, const char *parameters, void *instance_data, void *cbdata ) { ib_engine_t *ib = ib_context_get_engine(ctx); ib_status_t rc; ib_module_t *m = (ib_module_t *)cbdata; const char *set_name; size_t set_name_len; const sqli_module_config_t *cfg = NULL; const sqli_fingerprint_set_t *ps = NULL; if (parameters == NULL) { ib_log_error(ib, "Missing parameter for operator sqli"); return IB_EINVAL; } set_name = parameters; set_name_len = strlen(parameters); if (set_name[0] == '\'') { ++set_name; --set_name_len; } if (set_name[set_name_len-1] == '\'') { --set_name_len; } if (strncmp("default", set_name, set_name_len) == 0) { *(const sqli_fingerprint_set_t **)instance_data = NULL; return IB_OK; } rc = ib_context_module_config(ctx, m, &cfg); assert(rc == IB_OK); if (cfg->fingerprint_sets == NULL) { rc = IB_ENOENT; } else { rc = ib_hash_get_ex(cfg->fingerprint_sets, &ps, set_name, set_name_len); } if (rc == IB_ENOENT) { ib_log_error(ib, "No such fingerprint set: %s", parameters); return IB_EINVAL; } assert(rc == IB_OK); assert(ps != NULL); *(const sqli_fingerprint_set_t **)instance_data = ps; return IB_OK; }
ib_provider_inst_t *ib_log_provider_get_instance(ib_context_t *ctx) { IB_FTRACE_INIT(); ib_core_cfg_t *corecfg; ib_status_t rc; rc = ib_context_module_config(ctx, ib_core_module(), (void *)&corecfg); if (rc != IB_OK) { IB_FTRACE_RET_PTR(ib_provider_inst_t, NULL); } IB_FTRACE_RET_PTR(ib_provider_inst_t, corecfg->pi.logger); }
/** * Handle on/off directives. * * @param[in] cp Config parser * @param[in] name Directive name * @param[in] onoff on/off flag * @param[in] cbdata Callback data (ignored) * * @returns Status code */ static ib_status_t handle_directive_onoff(ib_cfgparser_t *cp, const char *name, int onoff, void *cbdata) { assert(cp != NULL); assert(name != NULL); assert(cp->ib != NULL); ib_engine_t *ib = cp->ib; ib_status_t rc; ib_module_t *module = NULL; modpcre_cfg_t *config = NULL; ib_context_t *ctx = cp->cur_ctx ? cp->cur_ctx : ib_context_main(ib); const char *pname; /* Get my module object */ rc = ib_engine_module_get(cp->ib, MODULE_NAME_STR, &module); if (rc != IB_OK) { ib_cfg_log_error(cp, "Failed to get %s module object: %s", MODULE_NAME_STR, ib_status_to_string(rc)); return rc; } /* Get my module configuration */ rc = ib_context_module_config(ctx, module, (void *)&config); if (rc != IB_OK) { ib_cfg_log_error(cp, "Failed to get %s module configuration: %s", MODULE_NAME_STR, ib_status_to_string(rc)); return rc; } if (strcasecmp("PcreStudy", name) == 0) { pname = MODULE_NAME_STR ".study"; } else if (strcasecmp("PcreUseJit", name) == 0) { pname = MODULE_NAME_STR ".use_jit"; } else { ib_cfg_log_error(cp, "Unhandled directive \"%s\"", name); return IB_EINVAL; } rc = ib_context_set_num(ctx, pname, onoff); if (rc != IB_OK) { ib_cfg_log_error(cp, "Failed to set \"%s\" to %s for \"%s\": %s", pname, onoff ? "true" : "false", name, ib_status_to_string(rc)); } return IB_OK; }
ib_status_t ib_parser_provider_set_instance(ib_context_t *ctx, ib_provider_inst_t *pi) { IB_FTRACE_INIT(); ib_core_cfg_t *corecfg; ib_status_t rc; rc = ib_context_module_config(ctx, ib_core_module(), (void *)&corecfg); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } corecfg->pi.parser = pi; IB_FTRACE_RET_STATUS(rc); }
void ib_log_provider_set_instance(ib_context_t *ctx, ib_provider_inst_t *pi) { IB_FTRACE_INIT(); ib_core_cfg_t *corecfg; ib_status_t rc; rc = ib_context_module_config(ctx, ib_core_module(), (void *)&corecfg); if (rc != IB_OK) { /// @todo This func should return ib_status_t now IB_FTRACE_RET_VOID(); } corecfg->pi.logger = pi; IB_FTRACE_RET_VOID(); }
/** * @internal * * "Sniffs" the output (response) data from the connection stream. */ static int ironbee_output_filter (ap_filter_t *f, apr_bucket_brigade *bb) { apr_bucket *b; #if 0 conn_rec *c = f->c; ironbee_conn_context *ctx = f->ctx; ib_conn_t *iconn = ctx->iconn; ib_core_cfg_t *corecfg; int buffering = 0; /* Configure. */ ib_context_module_config(iconn->ctx, ib_core_module(), (void *)&corecfg); if (corecfg != NULL) { buffering = (int)corecfg->buffer_res; } #endif for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) { #if 0 /// @todo Should this be done? Maybe only for proxy? if (APR_BUCKET_IS_EOS(b)) { /// @todo Do we need to do this? Maybe only for proxy. apr_bucket *flush = apr_bucket_flush_create(f->c->bucket_alloc); APR_BUCKET_INSERT_BEFORE(b, flush); } if (buffering) { /// @todo setaside into our own pool to destroy later??? apr_bucket_setaside(b, c->pool); process_bucket(f, b); APR_BUCKET_REMOVE(b); } else { #endif process_bucket(f, b); #if 0 } #endif } return ap_pass_brigade(f->next, bb); }
/** * Function exported to enable a module to register an ident provider * * @param engine Engine to register with * @param name Provider name (referenced in IdentType directive) * @param provider The identity provider * @return status */ ib_status_t ib_ident_provider_register(ib_engine_t *engine, const char *name, ib_ident_provider_t *provider) { ident_cfg_t *cfg; ib_status_t rc; ib_module_t *m; rc = ib_engine_module_get(engine, MODULE_NAME_STR, &m); assert((rc == IB_OK) && (m != NULL)); rc = ib_context_module_config(ib_context_main(engine), m, &cfg); assert((rc == IB_OK) && (cfg != NULL)); if (cfg->providers == NULL) { rc = ib_hash_create(&cfg->providers, ib_engine_mm_main_get(engine)); assert((rc == IB_OK) && (cfg->providers != NULL)); } return ib_hash_set(cfg->providers, name, provider); }
ib_status_t core_audit_open(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 rc; /* Non const struct we will build and then assign to * corecfg->auditlog_index_hp. */ ib_logformat_t *auditlog_index_hp; assert(NULL != lpi); assert(NULL != log); assert(NULL != log->ctx); assert(NULL != log->ctx->auditlog); rc = ib_context_module_config(log->ctx, ib_core_module(), (void *)&corecfg); if (rc != IB_OK) { ib_log_error(log->ib, "Could not fetch core configuration: %s", ib_status_to_string(rc) ); IB_FTRACE_RET_STATUS(rc); } assert(NULL != corecfg); /* Copy the FILE* into the core_audit_cfg_t. */ if (log->ctx->auditlog->index_fp != NULL) { cfg->index_fp = log->ctx->auditlog->index_fp; } /* If we have a file name but no file pointer, assign cfg->index_fp. */ else if ((log->ctx->auditlog->index != NULL) && (cfg->index_fp == NULL)) { /** * Open the audit log index file. If the file name starts with * a | a pipe is opened to a subprocess, etc... */ rc = core_audit_open_auditindexfile(lpi, log, cfg, corecfg); if (rc != IB_OK) { ib_log_error(log->ib, "Could not open auditlog index."); IB_FTRACE_RET_STATUS(rc); } } /* Open audit file that contains the record identified by the line * written in index_fp. */ if (cfg->fp == NULL) { rc = core_audit_open_auditfile(lpi, log, cfg, corecfg); if (rc!=IB_OK) { ib_log_error(log->ib, "Failed to open audit log file."); IB_FTRACE_RET_STATUS(rc); } } /* Set the Audit Log index format */ if (corecfg->auditlog_index_hp == NULL) { rc = ib_logformat_create(log->ib->mp, &auditlog_index_hp); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } if (corecfg->auditlog_index_fmt != NULL) { rc = ib_logformat_set(auditlog_index_hp, corecfg->auditlog_index_fmt); } else { rc = ib_logformat_set(auditlog_index_hp, IB_LOGFORMAT_DEFAULT); } if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } /* Commit built struct. */ corecfg->auditlog_index_hp = auditlog_index_hp; } IB_FTRACE_RET_STATUS(IB_OK); }
/** * @internal * * "Sniffs" the input (request) data from the connection stream and tries * to determine who closed a connection and why. */ static int ironbee_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { conn_rec *c = f->c; ironbee_conn_context *ctx = f->ctx; ib_conn_t *iconn = ctx->iconn; ib_core_cfg_t *corecfg; ib_stream_t *istream; apr_bucket *b; apr_status_t rc; int buffering = 0; /* Any mode not handled just gets passed through. */ if ((mode != AP_MODE_GETLINE) && (mode != AP_MODE_READBYTES)) { return ap_get_brigade(f->next, bb, mode, block, readbytes); } /* Configure. */ ib_context_module_config(iconn->ctx, ib_core_module(), (void *)&corecfg); if (corecfg != NULL) { buffering = (int)corecfg->buffer_req; } /* When buffering, data is removed from the brigade and handed * to IronBee. The filter must not return an empty brigade in this * case and keeps reading until there is processed data that comes * back from IronBee. */ do { ib_tx_t *itx = iconn->tx; /* If there is any processed data, then send it now. */ if (buffering && (itx != NULL)) { ib_sdata_t *sdata; /* Take any data from the drain (processed data) and * inject it back into the filter brigade. */ ib_fctl_drain(itx->fctl, &istream); if ((istream != NULL) && (istream->nelts > 0)) { int done = 0; while (!done) { apr_bucket *ibucket = NULL; /// @todo Handle multi-bucket lines if (mode == AP_MODE_GETLINE) { done = 1; } ib_stream_pull(istream, &sdata); if (sdata == NULL) { /* No more data left. */ break; } switch (sdata->type) { case IB_STREAM_DATA: #ifdef IB_DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": DATA[%d]: %.*s", (int)sdata->dlen, (int)sdata->dlen, (char *)sdata->data); #endif /// @todo Is this creating a copy? Just need a reference. ibucket = apr_bucket_heap_create(sdata->data, sdata->dlen, NULL, bb->bucket_alloc); break; case IB_STREAM_FLUSH: #ifdef IB_DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": FLUSH"); #endif ibucket = apr_bucket_flush_create(bb->bucket_alloc); break; case IB_STREAM_EOH: #ifdef IB_DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": EOH"); #endif /// @todo Do something here??? break; case IB_STREAM_EOB: #ifdef IB_DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": EOB"); #endif /// @todo Do something here??? break; case IB_STREAM_EOS: #ifdef IB_DEBUG ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": EOS"); #endif ibucket = apr_bucket_eos_create(bb->bucket_alloc); break; default: ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": UNKNOWN stream data type %d", sdata->type); } if (ibucket != NULL) { APR_BRIGADE_INSERT_TAIL(bb, ibucket); } } /* Need to send any processed data to avoid deadlock. */ if (!APR_BRIGADE_EMPTY(bb)) { return APR_SUCCESS; } } } /* Fetch data from the next filter. */ if (buffering) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "FETCH BRIGADE (buffering)"); /* Normally Apache will request the headers line-by-line, but * IronBee does not require this. So, here the request is * fetched with READBYTES and IronBee will then break * it back up into lines when it is injected back into * the brigade after the data is processed. */ rc = ap_get_brigade(f->next, bb, AP_MODE_READBYTES, block, HUGE_STRING_LEN); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "FETCH BRIGADE (non-buffering)"); rc = ap_get_brigade(f->next, bb, mode, block, readbytes); } /* Check for any timeouts/disconnects/errors. */ if (APR_STATUS_IS_TIMEUP(rc)) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": %s server closed connection (%d)", f->frec->name, rc); ap_remove_input_filter(f); return rc; } else if (APR_STATUS_IS_EOF(rc) || apr_get_os_error() == ECONNRESET) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": %s client closed connection (%d)", f->frec->name, rc); ap_remove_input_filter(f); return rc; } else if (rc != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, IB_PRODUCT_NAME ": %s returned %d (0x%08x) - %s", f->frec->name, rc, rc, strerror(apr_get_os_error())); return rc; } /* Process data. */ for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) { if (buffering) { /// @todo setaside into our own pool to destroy later??? apr_bucket_setaside(b, c->pool); process_bucket(f, b); APR_BUCKET_REMOVE(b); } else { process_bucket(f, b); } } } while (buffering); return APR_SUCCESS; }
/** * Create the PCRE operator. * * @param[in] ctx Current context. * @param[in] parameters Unparsed string with the parameters to * initialize the operator instance. * @param[out] instance_data Instance data. * @param[in] cbdata Callback data. * * @returns IB_OK on success or IB_EALLOC on any other type of error. */ static ib_status_t dfa_operator_create( ib_context_t *ctx, const char *parameters, void *instance_data, void *cbdata ) { assert(ctx != NULL); assert(parameters != NULL); assert(instance_data != NULL); ib_engine_t *ib = ib_context_get_engine(ctx); ib_mpool_t *pool = ib_context_get_mpool(ctx); assert(ib != NULL); assert(pool != NULL); modpcre_cpat_data_t *cpdata; modpcre_operator_data_t *operator_data; ib_module_t *module; modpcre_cfg_t *config; ib_status_t rc; const char *errptr; int erroffset; /* Get my module object */ rc = ib_engine_module_get(ib, MODULE_NAME_STR, &module); if (rc != IB_OK) { ib_log_error(ib, "Failed to get pcre module object: %s", ib_status_to_string(rc)); return rc; } /* Get the context configuration */ rc = ib_context_module_config(ctx, module, &config); if (rc != IB_OK) { ib_log_error(ib, "Failed to get pcre module configuration: %s", ib_status_to_string(rc)); return rc; } rc = pcre_compile_internal(ib, pool, config, true, &cpdata, parameters, &errptr, &erroffset); if (rc != IB_OK) { ib_log_error(ib, "Failed to parse DFA operator pattern \"%s\":%s", parameters, ib_status_to_string(rc)); return rc; } /* Allocate a rule data object, populate it */ operator_data = ib_mpool_alloc(pool, sizeof(*operator_data)); if (operator_data == NULL) { return IB_EALLOC; } operator_data->cpdata = cpdata; rc = dfa_id_set(pool, operator_data); if (rc != IB_OK) { ib_log_error(ib, "Error creating ID for DFA: %s", ib_status_to_string(rc)); return rc; } ib_log_debug(ib, "Compiled DFA id=\"%s\" operator pattern \"%s\" @ %p", operator_data->id, parameters, (void *)cpdata->cpatt); *(modpcre_operator_data_t **)instance_data = operator_data; return IB_OK; }
/** * Create the PCRE operator. * * @param[in] ctx Current context. * @param[in] parameters Unparsed string with the parameters to * initialize the operator instance. * @param[out] instance_data Instance data. * @param[in] cbdata Callback data. * * @returns IB_OK on success or IB_EALLOC on any other type of error. */ static ib_status_t pcre_operator_create( ib_context_t *ctx, const char *parameters, void *instance_data, void *cbdata ) { assert(ctx != NULL); assert(parameters != NULL); assert(instance_data != NULL); ib_engine_t *ib = ib_context_get_engine(ctx); ib_mpool_t *pool = ib_context_get_mpool(ctx); assert(ib != NULL); assert(pool != NULL); modpcre_cpat_data_t *cpdata = NULL; modpcre_operator_data_t *operator_data = NULL; ib_module_t *module; modpcre_cfg_t *config; ib_status_t rc; const char *errptr; int erroffset; if (parameters == NULL) { ib_log_error(ib, "No pattern for operator"); return IB_EINVAL; } /* Get my module object */ rc = ib_engine_module_get(ib, MODULE_NAME_STR, &module); if (rc != IB_OK) { ib_log_error(ib, "Failed to get pcre module object: %s", ib_status_to_string(rc)); return rc; } /* Get the context configuration */ rc = ib_context_module_config(ctx, module, &config); if (rc != IB_OK) { ib_log_error(ib, "Failed to get pcre module configuration: %s", ib_status_to_string(rc)); return rc; } /* Compile the pattern. Note that the rule data is an alias for * the compiled pattern type */ rc = pcre_compile_internal(ib, pool, config, false, &cpdata, parameters, &errptr, &erroffset); if (rc != IB_OK) { return rc; } /* Allocate a rule data object, populate it */ operator_data = ib_mpool_alloc(pool, sizeof(*operator_data)); if (operator_data == NULL) { return IB_EALLOC; } operator_data->cpdata = cpdata; operator_data->id = NULL; /* Not needed for rx rules */ /* Rule data is an alias for the compiled pattern data */ *(modpcre_operator_data_t **)instance_data = operator_data; return rc; }
/** * Handle single parameter directives. * * @param cp Config parser * @param name Directive name * @param p1 First parameter * @param cbdata Callback data (from directive registration) * * @returns Status code */ static ib_status_t handle_directive_param(ib_cfgparser_t *cp, const char *name, const char *p1, void *cbdata) { assert(cp != NULL); assert(name != NULL); assert(p1 != NULL); assert(cp->ib != NULL); ib_engine_t *ib = cp->ib; ib_status_t rc; ib_module_t *module = NULL; modpcre_cfg_t *config = NULL; ib_context_t *ctx = cp->cur_ctx ? cp->cur_ctx : ib_context_main(ib); const char *pname; ib_num_t value; /* Get my module object */ rc = ib_engine_module_get(cp->ib, MODULE_NAME_STR, &module); if (rc != IB_OK) { ib_cfg_log_error(cp, "Failed to get %s module object: %s", MODULE_NAME_STR, ib_status_to_string(rc)); return rc; } /* Get my module configuration */ rc = ib_context_module_config(ctx, module, (void *)&config); if (rc != IB_OK) { ib_cfg_log_error(cp, "Failed to get %s module configuration: %s", MODULE_NAME_STR, ib_status_to_string(rc)); return rc; } /* p1 should be a number */ rc = ib_string_to_num(p1, 0, &value); if (rc != IB_OK) { ib_cfg_log_error(cp, "Failed to convert \"%s\" to a number for \"%s\": %s", p1, name, ib_status_to_string(rc)); return rc; } if (strcasecmp("PcreMatchLimit", name) == 0) { pname = "pcre.match_limit"; } else if (strcasecmp("PcreMatchLimitRecursion", name) == 0) { pname = "pcre.match_limit_recursion"; } else if (strcasecmp("PcreJitStackStart", name) == 0) { pname = "pcre.jit_stack_start"; } else if (strcasecmp("PcreJitStackMax", name) == 0) { pname = "pcre.jit_stack_max"; } else if (strcasecmp("PcreDfaWorkspaceSize", name) == 0) { pname = "pcre.dfa_workspace_size"; } else { ib_cfg_log_error(cp, "Unhandled directive \"%s\"", name); return IB_EINVAL; } rc = ib_context_set_num(ctx, pname, value); if (rc != IB_OK) { ib_cfg_log_error(cp, "Failed to set \"%s\" to %ld for \"%s\": %s", pname, (long int)value, name, ib_status_to_string(rc)); } return IB_OK; }
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); }
static ib_status_t sqli_dir_fingerprint_set( ib_cfgparser_t *cp, const char *directive_name, const char *set_name, const char *set_path, void *cbdata ) { assert(cp != NULL); assert(directive_name != NULL); assert(set_name != NULL); assert(set_path != NULL); ib_status_t rc; ib_context_t *ctx = NULL; ib_module_t *m = NULL; sqli_module_config_t *cfg = NULL; sqli_fingerprint_set_t *ps = NULL; ib_mm_t mm; char *abs_set_path = NULL; rc = ib_cfgparser_context_current(cp, &ctx); assert(rc == IB_OK); assert(ctx != NULL); if (ctx != ib_context_main(cp->ib)) { ib_cfg_log_error(cp, "%s: Only valid at main context.", directive_name ); return IB_EINVAL; } if (strcmp("default", set_name) == 0) { ib_cfg_log_error(cp, "%s: default is a reserved set name.", directive_name ); return IB_EINVAL; } mm = ib_engine_mm_main_get(cp->ib); rc = ib_engine_module_get( ib_context_get_engine(ctx), MODULE_NAME_STR, &m ); assert(rc == IB_OK); rc = ib_context_module_config(ctx, m, &cfg); assert(rc == IB_OK); if (cfg->fingerprint_sets == NULL) { rc = ib_hash_create(&cfg->fingerprint_sets, mm); assert(rc == IB_OK); } assert(cfg->fingerprint_sets != NULL); rc = ib_hash_get(cfg->fingerprint_sets, NULL, set_name); if (rc == IB_OK) { ib_cfg_log_error(cp, "%s: Duplicate fingerprint set definition: %s", directive_name, set_name ); return IB_EINVAL; } assert(rc == IB_ENOENT); abs_set_path = ib_util_relative_file( ib_engine_mm_config_get(cp->ib), ib_cfgparser_curr_file(cp), set_path ); if (abs_set_path == NULL) { return IB_EALLOC; } rc = sqli_create_fingerprint_set_from_file(&ps, abs_set_path, mm); if (rc != IB_OK) { ib_cfg_log_error(cp, "%s: Failure to load fingerprint set from file: %s", directive_name, abs_set_path ); return IB_EINVAL; } assert(ps != NULL); rc = ib_hash_set(cfg->fingerprint_sets, ib_mm_strdup(mm, set_name), ps); assert(rc == IB_OK); return IB_OK; }
/** * Handle request_header events for user agent extraction. * * Extract the "request_headers" field (a list) from the transactions's * data provider instance, then loop through the list, looking for the * "User-Agent" field. If found, the value is parsed and used to update the * connection object fields. * * @param[in] ib IronBee object * @param[in,out] tx Transaction. * @param[in] event Event type * @param[in] data Callback data (module) * * @returns Status code */ static ib_status_t modua_user_agent(ib_engine_t *ib, ib_tx_t *tx, ib_state_event_type_t event, void *data) { assert(ib != NULL); assert(tx != NULL); assert(tx->var_store != NULL); assert(event == request_header_finished_event); assert(data != NULL); const ib_module_t *m = (const ib_module_t *)data; const ib_field_t *req_agent = NULL; ib_status_t rc = IB_OK; const ib_list_t *bs_list; const ib_bytestr_t *bs; const modua_config_t *cfg; rc = ib_context_module_config(ib_context_main(ib), m, &cfg); if (rc != IB_OK) { ib_log_error_tx(tx, "Can't fetch configuration: %s", ib_status_to_string(rc)); return rc; } /* Extract the User-Agent header field */ rc = ib_var_target_get_const( cfg->user_agent, &bs_list, tx->mp, tx->var_store ); if (rc == IB_ENOENT || ib_list_elements(bs_list) == 0) { ib_log_debug_tx(tx, "request_header_finished_event: No user agent"); return IB_OK; } if (rc != IB_OK) { ib_log_error_tx(tx, "Cannot retrieve request_headers:User-Agent: %d", rc); return rc; } if (IB_LIST_ELEMENTS(bs_list) == 0) { ib_log_debug_tx(tx, "request_header_finished_event: No user agent"); return IB_OK; } req_agent = (ib_field_t *)IB_LIST_NODE_DATA(IB_LIST_LAST(bs_list)); /* Found it: copy the data into a newly allocated string buffer */ rc = ib_field_value_type(req_agent, ib_ftype_bytestr_out(&bs), IB_FTYPE_BYTESTR); if (rc != IB_OK) { ib_log_error_tx(tx, "Request user agent is not a BYTESTR: %s", ib_status_to_string(rc)); return rc; } /* Finally, split it up & store the components */ rc = modua_agent_fields(ib, tx, bs); return rc; }
/** * Handle request_header events for remote IP extraction. * * Extract the "request_headers" field (a list) from the transactions's * data provider instance, then loop through the list, looking for the * "X-Forwarded-For" field. If found, the first value in the (comma * separated) list replaces the local ip address string in the connection * object. * * @param[in] ib IronBee object * @param[in,out] tx Transaction object * @param[in] event Event type * @param[in] cbdata Callback data (module) * * @returns Status code */ static ib_status_t modua_remoteip(ib_engine_t *ib, ib_tx_t *tx, ib_state_event_type_t event, void *cbdata) { assert(ib != NULL); assert(tx != NULL); assert(tx->var_store != NULL); assert(event == request_header_finished_event); const ib_module_t *m = (const ib_module_t *)cbdata; ib_field_t *field = NULL; ib_status_t rc = IB_OK; const ib_bytestr_t *bs; const uint8_t *data; size_t len; char *buf; uint8_t *comma; const ib_list_t *list; const ib_list_node_t *node; const ib_field_t *forwarded; uint8_t *stripped; size_t num; ib_flags_t flags; const modua_config_t *cfg; rc = ib_context_module_config(ib_context_main(ib), m, &cfg); if (rc != IB_OK) { ib_log_error_tx(tx, "Can't fetch configuration: %s", ib_status_to_string(rc)); return rc; } ib_log_debug3_tx(tx, "Checking for alternate remote address"); /* Extract the X-Forwarded-For header field */ rc = ib_var_target_get_const( cfg->forwarded_for, &list, tx->mp, tx->var_store ); if (rc == IB_ENOENT || ib_list_elements(list) == 0) { ib_log_debug_tx(tx, "No X-Forwarded-For"); return IB_OK; } if (rc != IB_OK) { ib_log_error_tx(tx, "Cannot retrieve request_headers:User-Agent: %d", rc); return rc; } num = ib_list_elements(list); if (num == 0) { ib_log_debug_tx(tx, "No X-Forwarded-For header found"); return rc; } else if (num != 1) { ib_log_debug_tx(tx, "%zd X-Forwarded-For headers found: ignoring", num); return rc; } node = ib_list_last_const(list); if ( (node == NULL) || (node->data == NULL) ) { ib_log_notice_tx(tx, "Invalid X-Forwarded-For header found"); return rc; } forwarded = (const ib_field_t *)node->data; /* Found it: copy the data into a newly allocated string buffer */ rc = ib_field_value_type(forwarded, ib_ftype_bytestr_out(&bs), IB_FTYPE_BYTESTR); if (rc != IB_OK) { ib_log_notice_tx(tx, "Invalid X-Forwarded-For header value"); return rc; } if (bs == NULL) { ib_log_notice_tx(tx, "X-Forwarded-For header not a bytestr"); return IB_EINVAL; } len = ib_bytestr_length(bs); data = ib_bytestr_const_ptr(bs); /* Search for a comma in the buffer */ comma = memchr(data, ',', len); if (comma != NULL) { len = comma - data; } /* Trim whitespace */ stripped = (uint8_t *)data; rc = ib_strtrim_lr_ex(IB_STROP_INPLACE, tx->mp, stripped, len, &stripped, &len, &flags); if (rc != IB_OK) { return rc; } /* Verify that it looks like a valid IP v4/6 address */ rc = ib_ip_validate_ex((const char *)stripped, len); if (rc != IB_OK) { ib_log_error_tx(tx, "X-Forwarded-For \"%.*s\" is not a valid IP address", (int)len, stripped ); return IB_OK; } /* Allocate memory for copy of stripped string */ buf = (char *)ib_mpool_alloc(tx->mp, len+1); if (buf == NULL) { ib_log_error_tx(tx, "Failed to allocate %zd bytes for remote address", len+1); return IB_EALLOC; } /* Copy the string out */ memcpy(buf, stripped, len); buf[len] = '\0'; ib_log_debug_tx(tx, "Remote address changed to \"%s\"", buf); /* This will lose the pointer to the original address * buffer, but it should be cleaned up with the rest * of the memory pool. */ tx->er_ipstr = buf; /* Update the remote address field in the tx collection */ rc = ib_field_create_bytestr_alias( &field, tx->mp, "", 0, (uint8_t *)buf, len ); if (rc != IB_OK) { ib_log_error_tx(tx, "Failed to create field for remote_addr: %s", ib_status_to_string(rc)); return rc; } rc = ib_var_source_set(cfg->remote_addr, tx->var_store, field); if (rc != IB_OK) { ib_log_error_tx(tx, "Failed to set remote address var: %s", ib_status_to_string(rc)); return rc; } 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); }
/** * Called at context close. Initialized user-agent target. * * @param[in] ib Engine * @param[in] ctx Context * @param[in] event Event triggering the callback * @param[in] cbdata Callback data (module). * * @returns Status code */ static ib_status_t modua_ctx_close( ib_engine_t *ib, ib_context_t *ctx, ib_state_event_type_t event, void *cbdata ) { ib_module_t *m = (ib_module_t *)cbdata; if (ib_context_type(ctx) == IB_CTYPE_MAIN) { modua_config_t *cfg; ib_var_target_t *target; ib_status_t rc; rc = ib_context_module_config(ctx, m, &cfg); if (rc != IB_OK) { ib_log_error(ib, "Can't fetch configuration: %s", ib_status_to_string(rc)); return rc; } rc = ib_var_target_acquire_from_string( &target, ib_engine_pool_main_get(ib), ib_engine_var_config_get(ib), IB_S2SL("request_headers:User-Agent"), NULL, NULL ); if (rc != IB_OK) { ib_log_error(ib, "Error acquiring target for User-Agent header: %s", ib_status_to_string(rc)); return rc; } cfg->user_agent = target; rc = ib_var_target_acquire_from_string( &target, ib_engine_pool_main_get(ib), ib_engine_var_config_get(ib), IB_S2SL("request_headers:X-Forwarded-For"), NULL, NULL ); if (rc != IB_OK) { ib_log_error(ib, "Error acquiring target for X-Forwarded-For header: %s", ib_status_to_string(rc)); return rc; } cfg->forwarded_for = target; rc = ib_var_source_acquire( &(cfg->remote_addr), ib_engine_pool_main_get(ib), ib_engine_var_config_get(ib), IB_S2SL("remote_addr") ); if (rc != IB_OK) { ib_log_error(ib, "Error acquiring source for remote_addr" " header: %s", ib_status_to_string(rc)); return rc; } } return IB_OK; }
ib_status_t core_audit_get_index_line(ib_provider_inst_t *lpi, ib_auditlog_t *log, char *line, int *line_size) { IB_FTRACE_INIT(); core_audit_cfg_t *cfg = (core_audit_cfg_t *)log->cfg_data; ib_core_cfg_t *corecfg; ib_tx_t *tx = log->tx; ib_conn_t *conn = tx->conn; ib_site_t *site = ib_context_site_get(log->ctx); const ib_logformat_t *lf; ib_status_t rc; char *ptr = line; char *tstamp = NULL; uint8_t which; int i = 0; int l = 0; int used = 0; const char *aux = NULL; /* Retrieve corecfg to get the AuditLogIndexFormat */ rc = ib_context_module_config(log->ctx, ib_core_module(), (void *)&corecfg); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } lf = corecfg->auditlog_index_hp; which = lf->literal_starts ? 1 : 0; for (; (i < lf->field_cnt || l < lf->literal_cnt) && used < IB_LOGFORMAT_MAXLINELEN;) { if (which++ % 2 == 0) { int aux_i = 0; switch (lf->fields[i]) { case IB_LOG_FIELD_REMOTE_ADDR: aux = tx->er_ipstr; break; case IB_LOG_FIELD_LOCAL_ADDR: aux = conn->local_ipstr; break; case IB_LOG_FIELD_HOSTNAME: aux = tx->hostname; break; case IB_LOG_FIELD_SITE_ID: if (site == NULL) { aux = (char *)"-"; } else { aux = site->id_str; } break; case IB_LOG_FIELD_SENSOR_ID: aux = log->ib->sensor_id_str; break; case IB_LOG_FIELD_TRANSACTION_ID: aux = tx->id; break; case IB_LOG_FIELD_TIMESTAMP: /* Prepare timestamp (only if needed) */ tstamp = (char *)ib_mpool_alloc(log->mp, 30); if (tstamp == NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } ib_clock_timestamp(tstamp, &tx->tv_created); aux = tstamp; break; case IB_LOG_FIELD_LOG_FILE: aux = cfg->fn; break; default: ptr[used++] = '\n'; /* Not understood */ IB_FTRACE_RET_STATUS(IB_EINVAL); break; } for (; aux != NULL && aux[aux_i] != '\0';) { if (used < IB_LOGFORMAT_MAXLINELEN) { ptr[used++] = aux[aux_i++]; } else { ptr[used++] = '\n'; IB_FTRACE_RET_STATUS(IB_ETRUNC); } } ++i; } else { /* Use literals */ if (used + lf->literals_len[l] < IB_LOGFORMAT_MAXLINELEN) { memcpy(&ptr[used], lf->literals[l], lf->literals_len[l]); used += lf->literals_len[l]; ++l; } else { /* Truncated.. */ ptr[used++] = '\n'; IB_FTRACE_RET_STATUS(IB_ETRUNC); } } } ptr[used++] = '\n'; *line_size = used; IB_FTRACE_RET_STATUS(IB_OK); }
/** * @internal * Handle a PocSig directive. * * @param cp Config parser * @param name Directive name * @param args List of directive arguments * @param cbdata Callback data (from directive registration) * * @returns Status code */ static ib_status_t pocsig_dir_signature(ib_cfgparser_t *cp, const char *name, ib_list_t *args, void *cbdata) { IB_FTRACE_INIT(pocsig_dir_signature); ib_engine_t *ib = cp->ib; ib_context_t *ctx = cp->cur_ctx ? cp->cur_ctx : ib_context_main(ib); ib_list_t *list; const char *target; const char *op; const char *action; pocsig_cfg_t *cfg; pocsig_phase_t phase; pocsig_sig_t *sig; const char *errptr; int erroff; ib_status_t rc; /* Get the pocsig configuration for this context. */ rc = ib_context_module_config(ctx, IB_MODULE_STRUCT_PTR, (void *)&cfg); if (rc != IB_OK) { ib_log_error(ib, 1, "Failed to fetch %s config: %d", MODULE_NAME_STR, rc); } /* Setup the PCRE matcher. */ if (cfg->pcre == NULL) { rc = ib_matcher_create(ib, ib_engine_pool_config_get(ib), "pcre", &cfg->pcre); if (rc != IB_OK) { ib_log_error(ib, 2, "Could not create a PCRE matcher: %d", rc); IB_FTRACE_RET_STATUS(rc); } } /* Determine phase and initialize the phase list if required. */ if (strcasecmp("PocSigPreTx", name) == 0) { phase = POCSIG_PRE; if (cfg->phase[phase] == NULL) { rc = ib_list_create(cfg->phase + POCSIG_PRE, ib_engine_pool_config_get(ib)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } } } else if (strcasecmp("PocSigReqHead", name) == 0) { phase = POCSIG_REQHEAD; if (cfg->phase[phase] == NULL) { ib_log_debug(ib, 4, "Creating list for phase=%d", phase); rc = ib_list_create(&list, ib_engine_pool_config_get(ib)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } ib_log_debug(ib, 4, "List for phase=%d list=%p", phase, list); cfg->phase[phase] = list; } } else if (strcasecmp("PocSigReq", name) == 0) { phase = POCSIG_REQ; if (cfg->phase[phase] == NULL) { rc = ib_list_create(&cfg->phase[phase], ib_engine_pool_config_get(ib)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } } } else if (strcasecmp("PocSigResHead", name) == 0) { phase = POCSIG_RESHEAD; if (cfg->phase[phase] == NULL) { rc = ib_list_create(&cfg->phase[phase], ib_engine_pool_config_get(ib)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } } } else if (strcasecmp("PocSigRes", name) == 0) { phase = POCSIG_RES; if (cfg->phase[POCSIG_RES] == NULL) { rc = ib_list_create(&cfg->phase[POCSIG_RES], ib_engine_pool_config_get(ib)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } } } else if (strcasecmp("PocSigPostTx", name) == 0) { phase = POCSIG_POST; if (cfg->phase[phase] == NULL) { rc = ib_list_create(&cfg->phase[phase], ib_engine_pool_config_get(ib)); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } } } else { ib_log_error(ib, 2, "Invalid signature: %s", name); IB_FTRACE_RET_STATUS(IB_EINVAL); } /* Target */ rc = ib_list_shift(args, &target); if (rc != IB_OK) { ib_log_error(ib, 1, "No PocSig target"); IB_FTRACE_RET_STATUS(IB_EINVAL); } /* Operator */ rc = ib_list_shift(args, &op); if (rc != IB_OK) { ib_log_error(ib, 1, "No PocSig operator"); IB_FTRACE_RET_STATUS(IB_EINVAL); } /* Action */ rc = ib_list_shift(args, &action); if (rc != IB_OK) { ib_log_debug(ib, 4, "No PocSig action"); action = ""; } /* Signature */ sig = (pocsig_sig_t *)ib_mpool_alloc(ib_engine_pool_config_get(ib), sizeof(*sig)); if (sig == NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } sig->target = ib_mpool_strdup(ib_engine_pool_config_get(ib), target); sig->patt = ib_mpool_strdup(ib_engine_pool_config_get(ib), op); sig->emsg = ib_mpool_strdup(ib_engine_pool_config_get(ib), action); /* Compile the PCRE patt. */ if (cfg->pcre == NULL) { ib_log_error(ib, 2, "No PCRE matcher available (load the pcre module?)"); IB_FTRACE_RET_STATUS(IB_EINVAL); } sig->cpatt = ib_matcher_compile(cfg->pcre, sig->patt, &errptr, &erroff); if (sig->cpatt == NULL) { ib_log_error(ib, 2, "Error at offset=%d of PCRE patt=\"%s\": %s", erroff, sig->patt, errptr); IB_FTRACE_RET_STATUS(IB_EINVAL); } ib_log_debug(ib, 4, "POCSIG: \"%s\" \"%s\" \"%s\" phase=%d ctx=%p", target, op, action, phase, ctx); /* Add the signature to the phase list. */ rc = ib_list_push(cfg->phase[phase], sig); if (rc != IB_OK) { ib_log_error(ib, 1, "Failed to add signature"); IB_FTRACE_RET_STATUS(rc); } IB_FTRACE_RET_STATUS(IB_OK); }
/** * @internal * Handle signature execution. * * @param ib Engine * @param tx Transaction * @param cbdata Phase passed as pointer value * * @return Status code */ static ib_status_t pocsig_handle_sigs(ib_engine_t *ib, ib_tx_t *tx, void *cbdata) { IB_FTRACE_INIT(pocsig_handle_post); pocsig_cfg_t *cfg; pocsig_phase_t phase = (pocsig_phase_t)(uintptr_t)cbdata; ib_list_t *sigs; ib_list_node_t *node; int dbglvl; ib_status_t rc; /* Get the pocsig configuration for this context. */ rc = ib_context_module_config(tx->ctx, IB_MODULE_STRUCT_PTR, (void *)&cfg); if (rc != IB_OK) { ib_log_error(ib, 1, "Failed to fetch %s config: %d", MODULE_NAME_STR, rc); } /* If tracing is enabled, lower the log level. */ dbglvl = cfg->trace ? 4 : 9; /* Get the list of sigs for this phase. */ sigs = cfg->phase[phase]; if (sigs == NULL) { ib_log_debug(ib, dbglvl, "No signatures for phase=%d ctx=%p", phase, tx->ctx); IB_FTRACE_RET_STATUS(IB_OK); } ib_log_debug(ib, dbglvl, "Executing %d signatures for phase=%d ctx=%p", ib_list_elements(sigs), phase, tx->ctx); /* Run all the sigs for this phase. */ IB_LIST_LOOP(sigs, node) { pocsig_sig_t *s = (pocsig_sig_t *)ib_list_node_data(node); ib_field_t *f; /* Fetch the field. */ rc = ib_data_get(tx->dpi, s->target, &f); if (rc != IB_OK) { ib_log_error(ib, 4, "PocSig: No field named \"%s\"", s->target); continue; } /* Perform the match. */ ib_log_debug(ib, dbglvl, "PocSig: Matching \"%s\" against field \"%s\"", s->patt, s->target); rc = ib_matcher_match_field(cfg->pcre, s->cpatt, 0, f, NULL); if (rc == IB_OK) { ib_logevent_t *e; ib_log_debug(ib, dbglvl, "PocSig MATCH: %s at %s", s->patt, s->target); /* Create the event. */ rc = ib_logevent_create( &e, tx->mp, "-", IB_LEVENT_TYPE_ALERT, IB_LEVENT_ACT_UNKNOWN, IB_LEVENT_PCLASS_UNKNOWN, IB_LEVENT_SCLASS_UNKNOWN, 90, 80, IB_LEVENT_SYS_UNKNOWN, IB_LEVENT_ACTION_IGNORE, IB_LEVENT_ACTION_IGNORE, s->emsg ); if (rc != IB_OK) { ib_log_error(ib, 3, "PocSig: Error generating event: %d", rc); continue; } /* Log the event. */ ib_clog_event(tx->ctx, e); } else { ib_log_debug(ib, dbglvl, "PocSig NOMATCH"); } }