static void core_gen_tx_numeric_field(ib_tx_t *tx, const char *name, ib_num_t val) { ib_field_t *f; assert(tx != NULL); assert(name != NULL); ib_num_t num = val; ib_status_t rc = ib_field_create(&f, tx->mp, name, strlen(name), IB_FTYPE_NUM, &num); if (rc != IB_OK) { ib_log_warning(tx->ib, "Failed to create \"%s\" field: %s", name, ib_status_to_string(rc)); return; } rc = ib_data_add(tx->data, f); if (rc != IB_OK) { ib_log_warning_tx(tx, "Failed add \"%s\" field to transaction data store: %s", name, ib_status_to_string(rc) ); } }
static void core_gen_tx_bytestr_alias_field(ib_tx_t *tx, const char *name, ib_bytestr_t *val) { ib_field_t *f; assert(tx != NULL); assert(name != NULL); assert(val != NULL); ib_status_t rc = ib_field_create_no_copy(&f, tx->mp, name, strlen(name), IB_FTYPE_BYTESTR, val); if (rc != IB_OK) { ib_log_warning(tx->ib, "Failed to create \"%s\" field: %s", name, ib_status_to_string(rc)); return; } rc = ib_data_add(tx->data, f); if (rc != IB_OK) { ib_log_warning_tx(tx, "Failed add \"%s\" field to transaction data store: %s", name, ib_status_to_string(rc) ); } }
/** * Called to initialize the user agent module (when the module is loaded). * * Registers a handler for the request_header_finished_event event. * * @param[in,out] ib IronBee object * @param[in] m Module object * @param[in] cbdata (unused) * * @returns Status code */ static ib_status_t modua_init(ib_engine_t *ib, ib_module_t *m, void *cbdata) { ib_status_t rc; modua_match_rule_t *failed_rule; unsigned int failed_frule_num; /* Register the user agent callback */ rc = ib_hook_tx_register(ib, request_header_finished_event, modua_user_agent, NULL); if (rc != IB_OK) { ib_log_error(ib, "Hook register returned %s", ib_status_to_string(rc)); } /* Register the remote address callback */ rc = ib_hook_tx_register(ib, request_header_finished_event, modua_remoteip, NULL); if (rc != IB_OK) { ib_log_error(ib, "Hook register returned %s", ib_status_to_string(rc)); } /* Initializations */ rc = modua_ruleset_init(&failed_rule, &failed_frule_num); if (rc != IB_OK) { ib_log_error(ib, "User agent rule initialization failed" " on rule %s field rule #%d: %s", failed_rule->label, failed_frule_num, ib_status_to_string(rc)); } /* Get the rules */ modua_match_ruleset = modua_ruleset_get( ); if (modua_match_ruleset == NULL) { ib_log_error(ib, "Failed to get user agent rule list: %s", ib_status_to_string(rc)); return rc; } ib_log_debug(ib, "Found %d match rules", modua_match_ruleset->num_rules); rc = ib_data_register_indexed(ib_engine_data_config_get(ib), "remote_addr"); if (rc != IB_OK) { ib_log_warning(ib, "User agent failed to register \"remote_addr\" as indexed: %s", ib_status_to_string(rc) ); /* Continue. */ } rc = ib_data_register_indexed(ib_engine_data_config_get(ib), "UA"); if (rc != IB_OK) { ib_log_warning(ib, "User agent failed to register \"UA\" as indexed: %s", ib_status_to_string(rc) ); /* Continue. */ } return IB_OK; }
/* Called when module is loaded. */ static ib_status_t geoip_init(ib_engine_t *ib, ib_module_t *m, void *cbdata) { ib_status_t rc; GeoIP *geoip_db = NULL; module_data_t *mod_data; mod_data = ib_mpool_calloc(ib_engine_pool_main_get(ib), sizeof(*mod_data), 1); if (mod_data == NULL) { return IB_EALLOC; } ib_log_debug(ib, "Initializing default GeoIP database..."); geoip_db = GeoIP_new(GEOIP_MMAP_CACHE); if (geoip_db == NULL) { ib_log_debug(ib, "Failed to initialize GeoIP database."); return IB_EUNKNOWN; } ib_log_debug(ib, "Initializing GeoIP database complete."); ib_log_debug(ib, "Registering handler..."); /* Store off pointer to our module data structure */ mod_data->geoip_db = geoip_db; /* And point the generic module data at it */ m->data = mod_data; rc = ib_hook_tx_register(ib, handle_context_tx_event, geoip_lookup, mod_data); if (rc != IB_OK) { ib_log_debug( ib, "Failed to register tx hook: %s", ib_status_to_string(rc)); return rc; } ib_log_debug(ib, "Done registering handler."); rc = ib_var_source_register( &(mod_data->geoip_source), ib_engine_var_config_get(ib), IB_S2SL("GEOIP"), IB_PHASE_NONE, IB_PHASE_NONE ); if (rc != IB_OK) { ib_log_warning(ib, "GeoIP failed to register \"GEOIP\" var: %s", ib_status_to_string(rc) ); /* Continue */ } if (rc != IB_OK) { ib_log_debug(ib, "Failed to load GeoIP module."); return rc; } geoip_directive_map[0].cbdata_cb = mod_data; ib_log_debug(ib, "GeoIP module loaded."); 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[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; }
/** * Called to initialize the user agent module (when the module is loaded). * * Registers a handler for the request_header_finished_event event. * * @param[in,out] ib IronBee object * @param[in] m Module object * @param[in] cbdata (unused) * * @returns Status code */ static ib_status_t modua_init(ib_engine_t *ib, ib_module_t *m, void *cbdata) { ib_status_t rc; modua_match_rule_t *failed_rule; unsigned int failed_frule_num; /* Register the user agent callback */ rc = ib_hook_tx_register(ib, request_header_finished_event, modua_user_agent, m); if (rc != IB_OK) { ib_log_error(ib, "Hook register returned %s", ib_status_to_string(rc)); } /* Register the remote address callback */ rc = ib_hook_tx_register(ib, request_header_finished_event, modua_remoteip, m); if (rc != IB_OK) { ib_log_error(ib, "Hook register returned %s", ib_status_to_string(rc)); } /* Initializations */ rc = modua_ruleset_init(&failed_rule, &failed_frule_num); if (rc != IB_OK) { ib_log_error(ib, "User agent rule initialization failed" " on rule %s field rule #%d: %s", failed_rule->label, failed_frule_num, ib_status_to_string(rc)); } /* Get the rules */ modua_match_ruleset = modua_ruleset_get( ); if (modua_match_ruleset == NULL) { ib_log_error(ib, "Failed to get user agent rule list: %s", ib_status_to_string(rc)); return rc; } ib_log_debug(ib, "Found %d match rules", modua_match_ruleset->num_rules); rc = ib_var_source_register( NULL, ib_engine_var_config_get(ib), IB_S2SL("remote_addr"), IB_PHASE_NONE, IB_PHASE_NONE ); if (rc != IB_OK && rc != IB_EEXIST) { ib_log_warning(ib, "User agent failed to register \"remote_addr\": %s", ib_status_to_string(rc) ); /* Continue. */ } rc = ib_var_source_register( NULL, ib_engine_var_config_get(ib), IB_S2SL("UA"), IB_PHASE_NONE, IB_PHASE_NONE ); if (rc != IB_OK) { ib_log_warning(ib, "User agent failed to register \"UA\": %s", ib_status_to_string(rc) ); /* Continue. */ } rc = ib_hook_context_register(ib, context_close_event, modua_ctx_close, m); if (rc != IB_OK) { ib_log_error(ib, "Could not register context close hook: %s", ib_status_to_string(rc)); return rc; } return IB_OK; }
/** * Handle managed collection: JSON file persist function * * @param[in] ib Engine * @param[in] tx Transaction to select a context for (or NULL) * @param[in] module Collection manager's module object * @param[in] manager The collection manager object * @param[in] collection_name Name of the collection to populate * @param[in] collection Collection to populate * @param[in] manager_inst_data Manager instance data * @param[in] persist_data Persist callback data * * @returns * - IB_OK on success or when @a collection_data is length 0. * - IB_DECLINED if not configured to persist * - IB_EUNKNOWN for file open/write/close errors * - Errors returned by ib_json_encode() */ static ib_status_t core_managed_collection_jsonfile_persist_fn( const ib_engine_t *ib, const ib_tx_t *tx, const ib_module_t *module, const ib_collection_manager_t *manager, const char *collection_name, const ib_list_t *collection, void *manager_inst_data, void *persist_data) { assert(ib != NULL); assert(tx != NULL); assert(module != NULL); assert(manager != NULL); assert(collection_name != NULL); assert(collection != NULL); assert(manager_inst_data != NULL); const core_json_file_t *json_file = (const core_json_file_t *)manager_inst_data; int fd; ssize_t remain; char *buf; size_t bufsize; uint8_t *bufp; ib_status_t rc; if (! json_file->persist) { return IB_DECLINED; } rc = ib_json_encode(tx->mp, collection, true, &buf, &bufsize); if (rc != IB_OK) { ib_log_warning(ib, "JSON file: failed to encode collection \"%s\": %s", collection_name, strerror(errno)); return IB_EUNKNOWN; } fd = open(json_file->path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { ib_log_warning(ib, "JSON file persist: open(\"%s\") failed: %s", json_file->path, strerror(errno)); return IB_EUNKNOWN; } remain = (ssize_t)bufsize; bufp = (uint8_t *)buf; while(remain > 0) { ssize_t bytes = write(fd, bufp, remain); if (bytes <= 0) { if (errno == EINTR) { continue; } ib_log_warning(ib, "JSON file: write(\"%s\") failed: %s", json_file->path, strerror(errno)); close(fd); return IB_EUNKNOWN; } else { remain -= bytes; bufp += bytes; assert(remain >= 0); } } close(fd); return IB_OK; }
/** * Handle managed collection: JSON file populate function * * @param[in] ib Engine * @param[in] tx Transaction to populate * @param[in] module Collection manager's module object * @param[in] collection_name The name of the collection. * @param[in] collection An ib_list_t of fields copied into @a collection. * @param[in,out] manager_inst_data Collection to populate with fields in @a * collection_data. * @param[in] populate_data Populate callback data * * @returns * - IB_OK on success or when @a collection_data is length 0. * - IB_EUNKNOWN for errors from file I/O * - IB_EALLOC for allocation errors * - Errors from ib_json_decode_ex() */ static ib_status_t core_managed_collection_jsonfile_populate_fn( const ib_engine_t *ib, const ib_tx_t *tx, const ib_module_t *module, const ib_collection_manager_t *manager, const char *collection_name, ib_list_t *collection, void *manager_inst_data, void *populate_data) { assert(ib != NULL); assert(tx != NULL); assert(module != NULL); assert(manager != NULL); assert(collection_name != NULL); assert(collection != NULL); assert(manager_inst_data != NULL); const core_json_file_t *json_file = (const core_json_file_t *)manager_inst_data; int fd; ssize_t filesize; ssize_t remain; uint8_t *buf; uint8_t *bufp; struct stat sbuf; ib_status_t rc; const char *error; /* Get the file's size */ if (stat(json_file->path, &sbuf) < 0) { ib_log_warning(ib, "JSON file: stat(\"%s\") failed: %s", json_file->path, strerror(errno)); return json_file->persist ? IB_OK : IB_DECLINED; } else { filesize = sbuf.st_size; if (filesize == 0) { return IB_OK; } } fd = open(json_file->path, O_RDONLY); if (fd < 0) { ib_log_warning(ib, "JSON file: open(\"%s\") failed: %s", json_file->path, strerror(errno)); return IB_DECLINED; } buf = ib_mpool_alloc(tx->mp, filesize); if (buf == NULL) { return IB_EALLOC; } remain = filesize; bufp = buf; while(remain > 0) { ssize_t bytes = read(fd, bufp, remain); if (bytes < 0) { if (errno == EINTR) { continue; } ib_log_warning(ib, "JSON file: read(\"%s\") failed: %s", json_file->path, strerror(errno)); close(fd); return IB_EUNKNOWN; } else if (bytes == 0) { ib_log_warning(ib, "JSON file: \"%s\": end of file reached", json_file->path); close(fd); return IB_EUNKNOWN; } else { remain -= bytes; bufp += bytes; assert(remain >= 0); } } close(fd); /* Now, decode the JSON buffer */ rc = ib_json_decode_ex(tx->mp, buf, filesize, collection, &error); if (rc != IB_OK) { ib_log_error(ib, "Error decoding JSON buffer for \"%s\": \"%s\"", collection_name, error == NULL ? ib_status_to_string(rc) : error); } else { ib_log_debug(ib, "Populated collection \"%s\" from JSON file \"%s\"", collection_name, json_file->path); } return rc; }
/** * 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; }