ib_status_t DLL_PUBLIC ib_logevent_create(ib_logevent_t **ple, ib_mpool_t *pool, const char *rule_id, ib_logevent_type_t type, ib_logevent_action_t rec_action, ib_logevent_action_t action, uint8_t confidence, uint8_t severity, const char *fmt, ...) { IB_FTRACE_INIT(); /* * Defined so that size_t to int cast is avoided * checking the result of vsnprintf below. * NOTE: This is assumed >3 bytes and should not * be overly large as it is used as the size * of a stack buffer. */ #define IB_LEVENT_MSG_BUF_SIZE 1024 char buf[IB_LEVENT_MSG_BUF_SIZE]; va_list ap; *ple = (ib_logevent_t *)ib_mpool_calloc(pool, 1, sizeof(**ple)); if (*ple == NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } (*ple)->event_id = (uint32_t)ib_clock_get_time(); /* truncated */ (*ple)->mp = pool; (*ple)->rule_id = ib_mpool_strdup(pool, rule_id); (*ple)->type = type; (*ple)->rec_action = rec_action; (*ple)->action = action; (*ple)->confidence = confidence; (*ple)->severity = severity; /* * Generate the message, replacing the last three characters * with "..." if truncation is required. */ va_start(ap, fmt); if (vsnprintf(buf, IB_LEVENT_MSG_BUF_SIZE, fmt, ap) >= IB_LEVENT_MSG_BUF_SIZE) { memcpy(buf + (IB_LEVENT_MSG_BUF_SIZE - 3), "...", 3); } va_end(ap); /* Copy the formatted message. */ (*ple)->msg = ib_mpool_strdup(pool, buf); IB_FTRACE_RET_STATUS(IB_OK); }
ib_status_t ib_tfn_create( const ib_tfn_t **ptfn, ib_mpool_t *mp, const char *name, bool handle_list, ib_tfn_fn_t fn_execute, void *cbdata ) { assert(ptfn != NULL); assert(mp != NULL); assert(name != NULL); assert(fn_execute != NULL); ib_tfn_t *tfn; char *name_copy; name_copy = ib_mpool_strdup(mp, name); if (name_copy == NULL) { return IB_EALLOC; } tfn = (ib_tfn_t *)ib_mpool_alloc(mp, sizeof(*tfn)); if (tfn == NULL) { return IB_EALLOC; } tfn->name = name_copy; tfn->fn_execute = fn_execute; tfn->handle_list = handle_list; tfn->cbdata = cbdata; *ptfn = tfn; return IB_OK; }
/* ASCII lowercase function (string version); See string.h */ ib_status_t ib_strlower(ib_strop_t op, ib_mpool_t *mp, char *str_in, char **str_out, ib_flags_t *result) { IB_FTRACE_INIT(); size_t len; ib_status_t rc = IB_OK; char *out = NULL; assert(mp != NULL); assert(str_in != NULL); assert(str_out != NULL); assert(result != NULL); len = strlen(str_in); switch(op) { case IB_STROP_INPLACE: out = str_in; rc = inplace(IB_STRFLAG_ALIAS, (uint8_t*)str_in, len, result); break; case IB_STROP_COPY: out = ib_mpool_strdup(mp, str_in); if (out == NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } rc = inplace(IB_STRFLAG_NEWBUF, (uint8_t*)out, len, result); break; case IB_STROP_COW: { #if ((__GNUC__==4) && (__GNUC_MINOR__<3)) uint8_t *uint8ptr; rc = copy_on_write(mp, (uint8_t *)str_in, len+1, &uint8ptr, &len, result); out = (char *)uint8ptr; #else rc = copy_on_write(mp, (uint8_t *)str_in, len+1, (uint8_t **)&out, &len, result); #endif break; } default: IB_FTRACE_RET_STATUS(IB_EINVAL); } if (rc == IB_OK) { if (ib_flags_all(*result, IB_STRFLAG_MODIFIED)) { *(out+len) = '\0'; } *str_out = out; } IB_FTRACE_RET_STATUS(rc); }
ib_status_t ib_action_inst_create_ex( ib_engine_t *ib, const char *name, const char *parameters, ib_action_inst_t **act_inst) { assert(ib != NULL); assert(name != NULL); ib_hash_t *action_hash = ib->actions; ib_action_t *action; ib_status_t rc; ib_mpool_t *mpool = ib_engine_pool_main_get(ib); assert(mpool != NULL); rc = ib_hash_get(action_hash, &action, name); if (rc != IB_OK) { /* name is not registered */ return rc; } *act_inst = (ib_action_inst_t *)ib_mpool_alloc(mpool, sizeof(ib_action_inst_t)); if (*act_inst == NULL) { return IB_EALLOC; } (*act_inst)->action = action; (*act_inst)->params = ib_mpool_strdup(mpool, parameters); (*act_inst)->fparam = NULL; if (action->fn_create != NULL) { rc = action->fn_create( ib, parameters, *act_inst, action->cbdata_create ); if (rc != IB_OK) { return rc; } } else { rc = IB_OK; } if ((*act_inst)->fparam == NULL) { rc = ib_field_create(&((*act_inst)->fparam), mpool, IB_FIELD_NAME("param"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in(parameters)); } return rc; }
/// @todo Change this to _ex function with all fields and only use /// the required fields here. ib_status_t ib_logevent_create(ib_logevent_t **ple, ib_mpool_t *pool, const char *rule_id, ib_logevent_type_t type, ib_logevent_activity_t activity, ib_logevent_pri_class_t pri_class, ib_logevent_sec_class_t sec_class, ib_logevent_sys_env_t sys_env, ib_logevent_action_t rec_action, ib_logevent_action_t action, uint8_t confidence, uint8_t severity, const char *fmt, ...) { IB_FTRACE_INIT(ib_logevent_create); char buf[8192]; struct timeval tv; va_list ap; *ple = (ib_logevent_t *)ib_mpool_calloc(pool, 1, sizeof(**ple)); if (*ple == NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } /// @todo Need a true unique id generator gettimeofday(&tv, NULL); (*ple)->event_id = (tv.tv_sec << (32-8)) + tv.tv_usec; /// @todo Generate the remaining portions of the event (*ple)->mp = pool; (*ple)->rule_id = rule_id; (*ple)->type = type; (*ple)->activity = activity; (*ple)->pri_class = pri_class; (*ple)->sec_class = sec_class; (*ple)->sys_env = sys_env; (*ple)->rec_action = rec_action; (*ple)->action = action; (*ple)->confidence = confidence; (*ple)->severity = severity; va_start(ap, fmt); if (vsnprintf(buf, sizeof(buf), fmt, ap) >= (int)sizeof(buf)) { strcpy(buf, "<msg too long>"); } va_end(ap); /* Copy the formatted message. */ (*ple)->msg = ib_mpool_strdup(pool, buf); IB_FTRACE_RET_STATUS(IB_OK); }
static ib_status_t create_fn(ib_engine_t *ib, ib_context_t *ctx, ib_mpool_t *mp, const char *params, ib_action_inst_t *inst, void *cbdata) { if (strcmp(params, "INVALID") == 0) { return IB_EINVAL; } inst->data = ib_mpool_strdup(mp, params); return IB_OK; }
TEST_F(TestIronBeeModuleRulesLua, operator_test) { const ib_operator_t *op; void *instance_data; ib_num_t result; ib_field_t* field1; const char* op_name = "test_module_rules_lua.lua"; const char* rule_name = "luarule001"; char* str1 = (char *)ib_mpool_strdup(ib_engine->mp, "string 1"); ASSERT_TRUE(str1); // Create field 1. ASSERT_EQ(IB_OK, ib_field_create( &field1, ib_engine->mp, IB_FIELD_NAME("field1"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in(str1) ) ); /* Configure the operator. */ configureIronBee(); // Ensure that the operator exists. ASSERT_EQ(IB_OK, ib_operator_lookup(ib_engine, op_name, &op) ); ASSERT_EQ(IB_OK, ib_operator_inst_create(op, ib_context_main(ib_engine), IB_OP_CAPABILITY_NON_STREAM, rule_name, &instance_data)); performTx(); // Attempt to match. ASSERT_EQ(IB_OK, ib_operator_inst_execute(op, instance_data, ib_tx, field1, NULL, &result)); // This time we should succeed. ASSERT_TRUE(result); }
ib_status_t ib_flags_oplist_parse( const ib_strval_t *map, ib_mpool_t *mp, const char *str, const char *sep, ib_list_t *oplist) { if ( (map == NULL) || (str == NULL) || (sep == NULL) || (oplist == NULL) ) { return IB_EINVAL; } char *copy; const char *tmp; /* Make a copy of the string that we can use for strtok */ copy = ib_mpool_strdup(mp, str); if (copy == NULL) { return IB_EALLOC; } /* Clear the list */ ib_list_clear(oplist); /* Walk through the separated list, parser each operator, build the list */ tmp = strtok(copy, sep); do { ib_status_t rc; ib_flags_op_t op; ib_flags_t flags; ib_flags_operation_t *operation; rc = parse_single(map, tmp, &op, &flags); if (rc != IB_OK) { return rc; } operation = ib_mpool_alloc(mp, sizeof(*operation)); if (operation == NULL) { return IB_EALLOC; } operation->op = op; operation->flags = flags; rc = ib_list_push(oplist, operation); if (rc != IB_OK) { return rc; } } while ( (tmp = strtok(NULL, sep)) != NULL); return IB_OK; }
ib_status_t ib_action_register( ib_engine_t *ib, const char *name, ib_flags_t flags, ib_action_create_fn_t fn_create, void *cbdata_create, ib_action_destroy_fn_t fn_destroy, void *cbdata_destroy, ib_action_execute_fn_t fn_execute, void *cbdata_execute ) { IB_FTRACE_INIT(); ib_hash_t *action_hash = ib->actions; ib_mpool_t *pool = ib_engine_pool_main_get(ib); ib_status_t rc; char *name_copy; ib_action_t *act; rc = ib_hash_get(action_hash, &act, name); if (rc == IB_OK) { /* name already is registered */ IB_FTRACE_RET_STATUS(IB_EINVAL); } name_copy = ib_mpool_strdup(pool, name); if (name_copy == NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } act = (ib_action_t *)ib_mpool_alloc(pool, sizeof(*act)); if (act == NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } act->name = name_copy; act->flags = flags; act->fn_create = fn_create; act->cbdata_create = cbdata_create; act->fn_destroy = fn_destroy; act->cbdata_destroy = cbdata_destroy; act->fn_execute = fn_execute; act->cbdata_execute = cbdata_execute; rc = ib_hash_set(action_hash, name_copy, act); IB_FTRACE_RET_STATUS(rc); }
ib_status_t ib_action_register( ib_engine_t *ib, const char *name, ib_action_create_fn_t fn_create, void *cbdata_create, ib_action_destroy_fn_t fn_destroy, void *cbdata_destroy, ib_action_execute_fn_t fn_execute, void *cbdata_execute ) { ib_hash_t *action_hash = ib->actions; ib_mpool_t *pool = ib_engine_pool_main_get(ib); ib_status_t rc; char *name_copy; ib_action_t *act; rc = ib_hash_get(action_hash, &act, name); if (rc == IB_OK) { /* name already is registered */ return IB_EINVAL; } name_copy = ib_mpool_strdup(pool, name); if (name_copy == NULL) { return IB_EALLOC; } act = (ib_action_t *)ib_mpool_alloc(pool, sizeof(*act)); if (act == NULL) { return IB_EALLOC; } act->name = name_copy; act->fn_create = fn_create; act->cbdata_create = cbdata_create; act->fn_destroy = fn_destroy; act->cbdata_destroy = cbdata_destroy; act->fn_execute = fn_execute; act->cbdata_execute = cbdata_execute; rc = ib_hash_set(action_hash, name_copy, act); return rc; }
ib_status_t ib_flags_strtok( const ib_strval_t *map, ib_mpool_t *mp, const char *str, const char *sep, ib_flags_t *pflags, ib_flags_t *pmask) { if ( (map == NULL) || (mp == NULL) || (str == NULL) || (sep == NULL) || (pflags == NULL) || (pmask == NULL) ) { return IB_EINVAL; } int n = 0; ib_flags_t flags = 0; ib_flags_t mask = 0; char *copy; const char *tmp; /* Make a copy of the string that we can use for strtok */ copy = ib_mpool_strdup(mp, str); if (copy == NULL) { return IB_EALLOC; } /* Walk through the separated list */ tmp = strtok(copy, sep); do { ib_status_t rc; rc = ib_flags_string(map, tmp, n++, &flags, &mask); if (rc != IB_OK) { return rc; } } while ( (tmp = strtok(NULL, sep)) != NULL); /* Done */ *pflags = flags; *pmask = mask; return IB_OK; }
ib_status_t test_create_fn(ib_engine_t *ib, ib_context_t *ctx, const ib_rule_t *rule, ib_mpool_t *pool, const char *data, ib_operator_inst_t *op_inst) { char *str; if (strcmp(data, "INVALID") == 0) { return IB_EINVAL; } str = ib_mpool_strdup(pool, data); if (str == NULL) { return IB_EALLOC; } op_inst->data = str; return IB_OK; }
ib_status_t test_create_fn( ib_context_t *ctx, const char *parameters, void **instance_data, void *cbdata ) { assert(ctx != NULL); char *str; ib_mpool_t *pool = ib_context_get_mpool(ctx); if (strcmp(parameters, "INVALID") == 0) { return IB_EINVAL; } str = ib_mpool_strdup(pool, parameters); if (str == NULL) { return IB_EALLOC; } *instance_data = str; return IB_OK; }
ib_status_t ib_tfn_register(ib_engine_t *ib, const char *name, ib_tfn_fn_t fn_execute, ib_flags_t flags, void *fndata) { assert(ib != NULL); assert(name != NULL); assert(fn_execute != NULL); ib_hash_t *tfn_hash = ib->tfns; ib_status_t rc; ib_tfn_t *tfn; char *name_copy; name_copy = ib_mpool_strdup(ib->mp, name); if (name_copy == NULL) { return IB_EALLOC; } tfn = (ib_tfn_t *)ib_mpool_alloc(ib->mp, sizeof(*tfn)); if (tfn == NULL) { return IB_EALLOC; } tfn->name = name_copy; tfn->fn_execute = fn_execute; tfn->tfn_flags = flags; tfn->fndata = fndata; rc = ib_hash_set(tfn_hash, name_copy, tfn); if (rc != IB_OK) { return rc; } return 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[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 dfa pattern. * * The major difference in this compilation from that of a normal pcre pattern * is that it does not use PCRE_JIT because it is intended for use * on streaming data. Streaming data is delivered in chunks * and partial matches are found. Doing partial matches and resumes * disable JIT optimizations and some a few other normal optimizations. * * @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 dfa_compile_internal(ib_mpool_t *pool, dfa_rule_data_t **dfa_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; /* How cpatt is produced. */ const int compile_flags = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; /* How edata is produced if we are not using JIT. */ const int study_flags = 0; 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); if(*errptr != NULL) { pcre_free(cpatt); ib_util_log_error("PCRE study failed: %s", *errptr); } /* 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 dfa_cpatt. */ *dfa_cpatt = (dfa_rule_data_t *)ib_mpool_alloc(pool, sizeof(**dfa_cpatt)); if (*dfa_cpatt == NULL) { pcre_free(cpatt); pcre_free(edata); IB_FTRACE_RET_STATUS(IB_EALLOC); } (*dfa_cpatt)->cpatt_sz = cpatt_sz; (*dfa_cpatt)->study_data_sz = study_data_sz; /* Copy pattern. */ (*dfa_cpatt)->patt = ib_mpool_strdup(pool, patt); if ((*dfa_cpatt)->patt == NULL) { pcre_free(cpatt); pcre_free(edata); IB_FTRACE_RET_STATUS(IB_EALLOC); } /* Copy compiled pattern. */ (*dfa_cpatt)->cpatt = ib_mpool_memdup(pool, cpatt, cpatt_sz); pcre_free(cpatt); if ((*dfa_cpatt)->cpatt == NULL) { pcre_free(edata); IB_FTRACE_RET_STATUS(IB_EALLOC); } /* Copy extra data (study data). */ if (edata != NULL) { /* Copy edata. */ (*dfa_cpatt)->edata = ib_mpool_memdup(pool, edata, sizeof(*edata)); if ((*dfa_cpatt)->edata == NULL) { pcre_free(edata); IB_FTRACE_RET_STATUS(IB_EALLOC); } /* Copy edata->study_data. */ (*dfa_cpatt)->edata->study_data = ib_mpool_memdup(pool, edata->study_data, study_data_sz); pcre_free(edata); if ((*dfa_cpatt)->edata->study_data == NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } } else { (*dfa_cpatt)->edata = NULL; } IB_FTRACE_RET_STATUS(IB_OK); }
/** * Parse the user agent header, splitting into component fields. * * Attempt to tokenize the user agent string passed in, storing the * result in the DPI associated with the transaction. * * @param[in] ib IronBee object * @param[in,out] tx Transaction object * @param[in] bs Byte string containing the agent string * * @returns Status code */ static ib_status_t modua_agent_fields(ib_engine_t *ib, ib_tx_t *tx, const ib_bytestr_t *bs) { const modua_match_rule_t *rule = NULL; ib_field_t *agent_list = NULL; char *product = NULL; char *platform = NULL; char *extra = NULL; char *agent; char *buf; size_t len; ib_status_t rc; /* Get the length of the byte string */ len = ib_bytestr_length(bs); /* Allocate memory for a copy of the string to split up below. */ buf = (char *)ib_mpool_calloc(tx->mp, 1, len+1); if (buf == NULL) { ib_log_error_tx(tx, "Failed to allocate %zd bytes for agent string", len+1); return IB_EALLOC; } /* Copy the string out */ memcpy(buf, ib_bytestr_const_ptr(bs), len); buf[len] = '\0'; ib_log_debug_tx(tx, "Found user agent: '%s'", buf); /* Copy the agent string */ agent = (char *)ib_mpool_strdup(tx->mp, buf); if (agent == NULL) { ib_log_error_tx(tx, "Failed to allocate copy of agent string"); return IB_EALLOC; } /* Parse the user agent string */ rc = modua_parse_uastring(buf, &product, &platform, &extra); if (rc != IB_OK) { ib_log_debug_tx(tx, "Failed to parse User Agent string '%s'", agent); return IB_OK; } /* Categorize the parsed string */ rule = modua_match_cat_rules(product, platform, extra); if (rule == NULL) { ib_log_debug_tx(tx, "No rule matched" ); } else { ib_log_debug_tx(tx, "Matched to rule #%d / category '%s'", rule->rule_num, rule->category ); } /* Build a new list. */ rc = ib_data_add_list(tx->data, "UA", &agent_list); if (rc != IB_OK) { ib_log_alert_tx(tx, "Unable to add UserAgent list to DPI."); return rc; } /* Store Agent */ rc = modua_store_field(ib, tx->mp, agent_list, "agent", agent); if (rc != IB_OK) { return rc; } /* Store product */ rc = modua_store_field(ib, tx->mp, agent_list, "PRODUCT", product); if (rc != IB_OK) { return rc; } /* Store Platform */ rc = modua_store_field(ib, tx->mp, agent_list, "OS", platform); if (rc != IB_OK) { return rc; } /* Store Extra */ rc = modua_store_field(ib, tx->mp, agent_list, "extra", extra); if (rc != IB_OK) { return rc; } /* Store Extra */ if (rule != NULL) { rc = modua_store_field(ib, tx->mp, agent_list, "category", rule->category); } else { rc = modua_store_field(ib, tx->mp, agent_list, "category", NULL ); } if (rc != IB_OK) { return rc; } /* Done */ return IB_OK; }
ib_status_t ib_logformat_set(ib_logformat_t *lf, char *format) { IB_FTRACE_INIT(ib_logformat_set); ib_mpool_t *mp = lf->mp; char literal[IB_LOGFORMAT_MAXLINELEN + 1]; int literal_tot = 0; uint8_t status = 0; int i = 0; int j = 0; int l = 0; memset(lf, 0, sizeof(ib_logformat_t) + 1); lf->mp = mp; literal[0] = '\0'; /* Store the original format (right now its just for debugging purposses) */ lf->orig_format = ib_mpool_strdup(lf->mp, format); if (lf->orig_format == NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } for (; lf->orig_format[i] != '\0' && lf->field_cnt < IB_LOGFORMAT_MAXFIELDS && j < IB_LOGFORMAT_MAXLINELEN; i++) { if (i == 0 && lf->orig_format[i] != '%') { lf->literal_starts = 1; } switch (status) { case IB_LOGFORMAT_ST_PR: /* Which field? */ switch (lf->orig_format[i]) { case IB_LOG_FIELD_REMOTE_ADDR: lf->fields[lf->field_cnt++] = IB_LOG_FIELD_REMOTE_ADDR; break; case IB_LOG_FIELD_LOCAL_ADDR: lf->fields[lf->field_cnt++] = IB_LOG_FIELD_LOCAL_ADDR; break; case IB_LOG_FIELD_HOSTNAME: lf->fields[lf->field_cnt++] = IB_LOG_FIELD_HOSTNAME; break; case IB_LOG_FIELD_SITE_ID: lf->fields[lf->field_cnt++] = IB_LOG_FIELD_SITE_ID; break; case IB_LOG_FIELD_SENSOR_ID: lf->fields[lf->field_cnt++] = IB_LOG_FIELD_SENSOR_ID; break; case IB_LOG_FIELD_TRANSACTION_ID: lf->fields[lf->field_cnt++] = IB_LOG_FIELD_TRANSACTION_ID; break; case IB_LOG_FIELD_TIMESTAMP: lf->fields[lf->field_cnt++] = IB_LOG_FIELD_TIMESTAMP; break; case IB_LOG_FIELD_LOG_FILE: lf->fields[lf->field_cnt++] = IB_LOG_FIELD_LOG_FILE; break; case '%': if (i == 1) { lf->literal_starts = 1; } /* just allow it */ literal[j++] = '%'; break; default: /* Not understood - ignore it */ break; } if (literal[0] != '\0') { literal_tot += j; if (literal_tot > IB_LOGFORMAT_MAXLINELEN) { /* Too long */ IB_FTRACE_RET_STATUS(IB_EINVAL); } /* Add string end for later usage with *printf() functions*/ literal[j] = '\0'; lf->literals[l] = ib_mpool_strdup(lf->mp, literal); if (lf->literals[l] == NULL) { /* Uops.. */ IB_FTRACE_RET_STATUS(IB_EINVAL); } else { lf->literals_len[l] = j; ++l; } literal[0] = '\0'; j = 0; } status = IB_LOGFORMAT_ST_NONE; break; case IB_LOGFORMAT_ST_BS: /* Avoid '\b', '\n' */ switch (lf->orig_format[i]) { case 't': literal[j++] = '\t'; break; case 'n': case 'b': /* Just add a space */ /// @todo more to add? literal[j++] = ' '; break; default: /* Just use the character directly */ literal[j++] = lf->orig_format[i]; } status = IB_LOGFORMAT_ST_NONE; break; case IB_LOGFORMAT_ST_NONE: default: switch (lf->orig_format[i]) { /** @todo Do we need to check certain escape chars? * Will we allow for example '\n' in the log index file? */ case '\\': status = IB_LOGFORMAT_ST_BS; break; case '%': status = IB_LOGFORMAT_ST_PR; break; default: /* literal string */ literal[j++] = lf->orig_format[i]; } } } if (lf->orig_format[i] != '\0' || status == IB_LOGFORMAT_ST_PR) { IB_FTRACE_RET_STATUS(IB_EINVAL); } lf->fields[lf->field_cnt + 1] = '\0'; /* Write the last parsed literal and the length */ if (literal[0] != '\0') { literal_tot += j; if (literal_tot > IB_LOGFORMAT_MAXLINELEN) { /* Too long */ IB_FTRACE_RET_STATUS(IB_EINVAL); } literal[j] = '\0'; lf->literals_len[l] = j; lf->literals[l++] = ib_mpool_strdup(lf->mp, literal); } lf->literal_cnt = l; IB_FTRACE_RET_STATUS(IB_OK); }
TEST_F(TestIBUtilField, AliasConvert) { char *str; ib_field_t *f1; ib_field_t *f2; ib_status_t rc; ib_num_t num; ib_float_t flt; /* * Convert numeric string to number */ /* Copy a number into the string */ str = ib_mpool_strdup(MemPool(), "1"); ASSERT_TRUE(str != NULL); /* Create the aliased field */ rc = ib_field_create_alias(&f1, MemPool(), "one", 3, IB_FTYPE_NULSTR, ib_ftype_nulstr_mutable_out(&str)); ASSERT_EQ(IB_OK, rc); /* Attempt a numeric conversion. */ rc = ib_field_convert(MemPool(), IB_FTYPE_NUM, f1, &f2); ASSERT_EQ(IB_OK, rc); /* Pull out param value for check. */ rc = ib_field_value(f2, ib_ftype_num_out(&num)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(1, num); /* * Convert floating-point string to float */ /* Copy a number into the string */ str = ib_mpool_strdup(MemPool(), "1.1"); ASSERT_TRUE(str != NULL); /* Create the aliased field */ rc = ib_field_create_alias(&f1, MemPool(), "one", 3, IB_FTYPE_NULSTR, ib_ftype_nulstr_mutable_out(&str)); ASSERT_EQ(IB_OK, rc); /* Attempt a numeric conversion. */ rc = ib_field_convert(MemPool(), IB_FTYPE_FLOAT, f1, &f2); ASSERT_EQ(IB_OK, rc); /* Pull out param value for check. */ rc = ib_field_value(f2, ib_ftype_float_out(&flt)); ASSERT_EQ(IB_OK, rc); ASSERT_FLOAT_EQ(1.1, flt); /* * Convert non-numeric string to number */ /* Copy a number into the string */ str = ib_mpool_strdup(MemPool(), "x1"); ASSERT_TRUE(str != NULL); /* Create the aliased field */ rc = ib_field_create_alias(&f1, MemPool(), "one", 3, IB_FTYPE_NULSTR, ib_ftype_nulstr_mutable_out(&str)); ASSERT_EQ(IB_OK, rc); /* Attempt a numeric conversion. */ rc = ib_field_convert(MemPool(), IB_FTYPE_NUM, f1, &f2); ASSERT_EQ(IB_EINVAL, rc); /* * Convert floating-point string to number */ /* Copy a number into the string */ str = ib_mpool_strdup(MemPool(), "1.1"); ASSERT_TRUE(str != NULL); /* Create the aliased field */ rc = ib_field_create_alias(&f1, MemPool(), "one", 3, IB_FTYPE_NULSTR, ib_ftype_nulstr_mutable_out(&str)); ASSERT_EQ(IB_OK, rc); /* Attempt a numeric conversion. */ rc = ib_field_convert(MemPool(), IB_FTYPE_NUM, f1, &f2); ASSERT_EQ(IB_EINVAL, rc); /* * Convert non-numeric string to float */ /* Copy a number into the string */ str = ib_mpool_strdup(MemPool(), "1.1"); ASSERT_TRUE(str != NULL); /* Create the aliased field */ rc = ib_field_create_alias(&f1, MemPool(), "one", 3, IB_FTYPE_NULSTR, ib_ftype_nulstr_mutable_out(&str)); ASSERT_EQ(IB_OK, rc); /* Attempt a numeric conversion. */ rc = ib_field_convert(MemPool(), IB_FTYPE_FLOAT, f1, &f2); ASSERT_EQ(IB_OK, rc); /* Pull out param value for check. */ rc = ib_field_value(f2, ib_ftype_float_out(&flt)); ASSERT_EQ(IB_OK, rc); ASSERT_FLOAT_EQ(1.1, flt); }
ib_status_t ib_field_setv_ex( ib_field_t *f, void *in_pval, const void *arg, size_t alen ) { ib_status_t rc; if (ib_field_is_dynamic(f)) { if (f->val->fn_set == NULL) { return IB_EINVAL; } return f->val->fn_set(f, arg, alen, in_pval, f->val->cbdata_set); } /* No dynamic setter */ if (arg != NULL) { return IB_EINVAL; } /* What and how it is stored depends on the field type. */ switch (f->type) { case IB_FTYPE_BYTESTR: { const ib_bytestr_t *bs = (const ib_bytestr_t *)in_pval; if (bs != NULL) { rc = ib_bytestr_dup((ib_bytestr_t **)f->val->pval, f->mp, bs); if (rc != IB_OK) { goto failed; } } break; } case IB_FTYPE_LIST: { /// @todo Fix const once lists are const aware/copying. ib_list_t *l = (ib_list_t *)in_pval; if (l != NULL) { /// @todo Should do shallow copy *(ib_list_t **)f->val->pval = l; } else { rc = ib_list_create((ib_list_t **)f->val->pval, f->mp); if (rc != IB_OK) { goto failed; } } break; } case IB_FTYPE_SBUFFER: { /// @todo Fix once stream is const aware/copying ib_stream_t *s = (ib_stream_t *)in_pval; if (s != NULL) { /// @todo Should do shallow copy *(ib_stream_t **)f->val->pval = s; } else { rc = ib_stream_create((ib_stream_t **)f->val->pval, f->mp); if (rc != IB_OK) { goto failed; } } break; } case IB_FTYPE_NULSTR: { const char *s = (const char *)in_pval; if (s != NULL) { *(char **)(f->val->pval) = ib_mpool_strdup(f->mp, s); if (*(void **)(f->val->pval) == NULL) { rc = IB_EALLOC; goto failed; } } break; } case IB_FTYPE_NUM: { ib_num_t n = (in_pval != NULL) ? *(ib_num_t *)in_pval : 0; *(ib_num_t *)(f->val->pval) = n; break; } case IB_FTYPE_FLOAT: { ib_float_t fl = (in_pval != NULL) ? *(ib_float_t *)in_pval : 0; *(ib_float_t *)(f->val->pval) = fl; break; } case IB_FTYPE_GENERIC: default: { void *p = in_pval; *(void **)(f->val->pval) = p; break; } } ib_field_util_log_debug("FIELD_SETV", f); return IB_OK; failed: return rc; }
/** * 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; }
/** * Handle managed collection: register for JSON file * * Examines the incoming parameters; if if it looks like a JSON file, * take it; otherwise do nothing (decline) * * @param[in] ib Engine * @param[in] module Collection manager's module object * @param[in] mp Memory pool to use for allocations * @param[in] collection_name Name of the collection * @param[in] uri Full collection URI * @param[in] uri_scheme URI scheme (unused) * @param[in] uri_data Hierarchical/data part of the URI (typically a path) * @param[in] params List of parameter strings * @param[in] register_data Selection callback data * @param[out] pmanager_inst_data Pointer to manager specific data * * @returns Status code: * - IB_DECLINED Parameters not recognized * - IB_OK All OK, parameters recognized * - IB_Exxx Other error */ static ib_status_t core_managed_collection_jsonfile_register_fn( const ib_engine_t *ib, const ib_module_t *module, const ib_collection_manager_t *manager, ib_mpool_t *mp, const char *collection_name, const char *uri, const char *uri_scheme, const char *uri_data, const ib_list_t *params, void *register_data, void **pmanager_inst_data) { assert(ib != NULL); assert(module != NULL); assert(mp != NULL); assert(collection_name != NULL); assert(params != NULL); assert(pmanager_inst_data != NULL); const ib_list_node_t *node; const char *path; const char *param; const char *path_start = uri_data; bool persist = false; core_json_file_t *json_file; /* Get the first element in the list */ if (ib_list_elements(params) > 1) { return IB_EINVAL; } /* Look at the first param (if it exists) */ node = ib_list_first_const(params); if (node != NULL) { param = (const char *)node->data; if (strcasecmp(param, "persist") == 0) { persist = true; } else { ib_log_warning(ib, "JSON file: \"%s\"; unknown parameter \"%s\"", uri, param); return IB_EINVAL; } } /* Try to stat the file */ if (!persist) { struct stat sbuf; if (stat(path_start, &sbuf) < 0) { ib_log_warning(ib, "JSON file: Declining \"%s\"; " "stat(\"%s\") failed: %s", uri, path_start, strerror(errno)); return IB_DECLINED; } if (! S_ISREG(sbuf.st_mode)) { ib_log_warning(ib, "JSON file: Declining \"%s\"; \"%s\" is not a file", uri, path_start); return IB_DECLINED; } } /* Happy now, copy the file name, be done */ path = ib_mpool_strdup(mp, path_start); if (path == NULL) { return IB_EALLOC; } json_file = ib_mpool_alloc(mp, sizeof(*json_file)); if (json_file == NULL) { return IB_EALLOC; } json_file->path = path; json_file->persist = persist; /* Store the file object as the manager specific collection data */ *pmanager_inst_data = json_file; return 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); }