/** * 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 registration for vars "name=value" parameters * * @param[in] ib Engine * @param[in] module Collection manager's module object (unused) * @param[in] manager The collection manager object to register with (unused) * @param[in] mp Memory pool to use for allocations * @param[in] collection_name Name of the collection * @param[in] uri Full collection URI (unused) * @param[in] uri_scheme URI scheme (unused) * @param[in] uri_data Hierarchical/data part of the URI * @param[in] params List of parameter strings * @param[in] register_data Register callback data (unused) * @param[out] pmanager_inst_data Pointer to manager specific collection data * * @returns Status code: * - IB_OK All OK * - IB_Exxx Other error */ static ib_status_t core_managed_collection_vars_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; ib_list_t *vars_list; ib_list_t *field_list; ib_mpool_t *tmp = ib_engine_pool_temp_get(ib); ib_status_t rc; if (strlen(uri_data) != 0) { return IB_DECLINED; } if (ib_list_elements(params) < 1) { return IB_EINVAL; } /* Create a temporary list */ rc = ib_list_create(&vars_list, tmp); if (rc != IB_OK) { return rc; } /* First pass; walk through all params, look for "a=b" type syntax */ IB_LIST_LOOP_CONST(params, node) { static const int ovecsize = 9; int ovector[ovecsize]; const char *param = (const char *)node->data; core_vars_t *vars; int pcre_rc; pcre_rc = pcre_exec(core_vars_manager.pattern, NULL, param, strlen(param), 0, 0, ovector, ovecsize); if (pcre_rc < 0) { return IB_DECLINED; } vars = ib_mpool_alloc(tmp, sizeof(*vars)); if (vars == NULL) { return IB_EALLOC; } vars->name = ib_mpool_memdup_to_str(tmp, param + ovector[2], ovector[3] - ovector[2]); vars->value = ib_mpool_memdup_to_str(tmp, param + ovector[4], ovector[5] - ovector[4]); if ( (vars->name == NULL) || (vars->value == NULL) ) { return IB_EALLOC; } rc = ib_list_push(vars_list, vars); if (rc != IB_OK) { return rc; } } /* Build the list of fields */ rc = ib_list_create(&field_list, mp); if (rc != IB_OK) { return rc; } /* Now walk though the list, creating a field for each one */ IB_LIST_LOOP_CONST(vars_list, node) { const core_vars_t *vars = (const core_vars_t *)node->data; ib_field_t *field; ib_field_val_union_t fval; rc = ib_field_from_string(mp, IB_FIELD_NAME(vars->name), vars->value, &field, &fval); if (rc != IB_OK) { ib_log_error(ib, "Error creating field (\"%s\", \"%s\"): %s", vars->name, vars->value, ib_status_to_string(rc)); return rc; } rc = ib_list_push(field_list, field); if (rc != IB_OK) { return rc; } if (field->type == IB_FTYPE_NUM) { ib_log_trace(ib, "Created numeric field \"%s\" %"PRId64" in \"%s\"", vars->name, fval.num, collection_name); } else if (field->type == IB_FTYPE_FLOAT) { ib_log_trace(ib, "Created float field \"%s\" %f in \"%s\"", vars->name, (double)fval.fnum, collection_name); } else { ib_log_trace(ib, "Created string field \"%s\" \"%s\" in \"%s\"", vars->name, fval.nulstr, collection_name); } } /* Finally, store the list as the manager specific collection data */ *pmanager_inst_data = field_list; return IB_OK; }