static void rspamadm_confighelp_search_word_step (const ucl_object_t *obj, ucl_object_t *res, const gchar *str, gsize len, GString *path) { ucl_object_iter_t it = NULL; const ucl_object_t *cur, *elt; const gchar *dot_pos; while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) { if (cur->keylen > 0) { rspamd_printf_gstring (path, ".%*s", (int) cur->keylen, cur->key); if (rspamd_substring_search_caseless (cur->key, cur->keylen, str, len) != -1) { ucl_object_insert_key (res, ucl_object_ref (cur), path->str, path->len, true); goto fin; } } if (ucl_object_type (cur) == UCL_OBJECT) { elt = ucl_object_lookup (cur, "data"); if (elt != NULL && ucl_object_type (elt) == UCL_STRING) { if (rspamd_substring_search_caseless (elt->value.sv, elt->len, str, len) != -1) { ucl_object_insert_key (res, ucl_object_ref (cur), path->str, path->len, true); goto fin; } } rspamadm_confighelp_search_word_step (cur, res, str, len, path); } fin: /* Remove the last component of the path */ dot_pos = strrchr (path->str, '.'); if (dot_pos) { g_string_erase (path, dot_pos - path->str, path->len - (dot_pos - path->str)); } } }
static gboolean rspamd_symbols_cache_process_settings (struct rspamd_task *task, struct symbols_cache *cache) { const ucl_object_t *wl, *cur, *disabled; struct metric *def; struct rspamd_symbols_group *gr; GHashTableIter gr_it; ucl_object_iter_t it = NULL; gpointer k, v; wl = ucl_object_lookup (task->settings, "whitelist"); if (wl != NULL) { msg_info_task ("<%s> is whitelisted", task->message_id); task->flags |= RSPAMD_TASK_FLAG_SKIP; return TRUE; } disabled = ucl_object_lookup (task->settings, "symbols_disabled"); if (disabled) { it = NULL; while ((cur = ucl_iterate_object (disabled, &it, true)) != NULL) { rspamd_symbols_cache_disable_symbol (task, cache, ucl_object_tostring (cur)); } } /* Disable groups of symbols */ disabled = ucl_object_lookup (task->settings, "groups_disabled"); def = g_hash_table_lookup (task->cfg->metrics, DEFAULT_METRIC); if (def && disabled) { it = NULL; while ((cur = ucl_iterate_object (disabled, &it, true)) != NULL) { if (ucl_object_type (cur) == UCL_STRING) { gr = g_hash_table_lookup (def->groups, ucl_object_tostring (cur)); if (gr) { g_hash_table_iter_init (&gr_it, gr->symbols); while (g_hash_table_iter_next (&gr_it, &k, &v)) { rspamd_symbols_cache_disable_symbol (task, cache, k); } } } } } return FALSE; }
gpointer rspamd_redis_init (struct rspamd_stat_ctx *ctx, struct rspamd_config *cfg, struct rspamd_statfile *st) { struct redis_stat_ctx *backend; struct rspamd_statfile_config *stf = st->stcf; struct rspamd_redis_stat_elt *st_elt; const ucl_object_t *obj; gboolean ret = FALSE; backend = g_slice_alloc0 (sizeof (*backend)); /* First search in backend configuration */ obj = ucl_object_lookup (st->classifier->cfg->opts, "backend"); if (obj != NULL && ucl_object_type (obj) == UCL_OBJECT) { ret = rspamd_redis_try_ucl (backend, obj, cfg, stf->symbol); } /* Now try statfiles config */ if (!ret) { ret = rspamd_redis_try_ucl (backend, stf->opts, cfg, stf->symbol); } /* Now try classifier config */ if (!ret) { ret = rspamd_redis_try_ucl (backend, st->classifier->cfg->opts, cfg, stf->symbol); } if (!ret) { msg_err_config ("cannot init redis backend for %s", stf->symbol); g_slice_free1 (sizeof (*backend), backend); return NULL; } stf->clcf->flags |= RSPAMD_FLAG_CLASSIFIER_INCREMENTING_BACKEND; backend->stcf = stf; st_elt = g_slice_alloc0 (sizeof (*st_elt)); st_elt->ev_base = ctx->ev_base; st_elt->ctx = backend; backend->stat_elt = rspamd_stat_ctx_register_async ( rspamd_redis_async_stat_cb, rspamd_redis_async_stat_fin, st_elt, REDIS_STAT_TIMEOUT); st_elt->async = backend->stat_elt; return (gpointer)backend; }
static gint lua_config_get_all_opt (lua_State * L) { struct rspamd_config *cfg = lua_check_config (L, 1); const gchar *mname; const ucl_object_t *obj, *cur, *cur_elt; ucl_object_iter_t it = NULL; gint i; if (cfg) { mname = luaL_checkstring (L, 2); if (mname) { obj = ucl_obj_get_key (cfg->rcl_obj, mname); /* Flatten object */ if (obj != NULL && (ucl_object_type (obj) == UCL_OBJECT || ucl_object_type (obj) == UCL_ARRAY)) { lua_newtable (L); it = ucl_object_iterate_new (obj); LL_FOREACH (obj, cur) { it = ucl_object_iterate_reset (it, cur); while ((cur_elt = ucl_object_iterate_safe (it, true))) { lua_pushstring (L, ucl_object_key (cur_elt)); ucl_object_push_lua (L, cur_elt, true); lua_settable (L, -3); } } ucl_object_iterate_free (it); return 1; } else if (obj != NULL) {
/* * snprintkeys writes the value contained in obj to dst. */ static int snprintval(char *dst, size_t size, ucl_object_t const *obj) { switch (ucl_object_type(obj)) { case UCL_INT: return snprintf(dst, size, "%" PRId64, ucl_object_toint(obj)); case UCL_FLOAT: case UCL_TIME: return snprintf(dst, size, "%0.10f", ucl_object_todouble(obj)); case UCL_STRING: return snprintf(dst, size, "%s", ucl_object_tostring(obj)); case UCL_BOOLEAN: return snprintf(dst, size, "%s", ucl_object_toboolean(obj) ? "true": "false"); default: *dst = '\0'; return 0; } }
/* * expand extrapolates one or more environment variables from obj. If obj * is of type UCL_OBJECT or UCL_ARRAY then a new variable will be created * will be created containing a list of keys in obj and then expand will be * called recursively for each member. Otherwise a new environment variable * will be created with the value of obj. */ static void expand(size_t keylen, ucl_object_t const *obj) { ucl_object_iter_t it = NULL; ucl_object_t const *o; int i, l; switch (ucl_object_type(obj)) { case UCL_OBJECT: if (snprintkeys(envval, MAX_VALUE_LEN, obj) >= MAX_VALUE_LEN) errx(EX_DATAERR, "value too long \"%s\"", envval); setenv(envkey, envval, 1); while ((o = ucl_iterate_object(obj, &it, true)) != NULL) { l = snprintf(envkey + keylen, MAX_KEY_LEN - keylen, "_%s", ucl_object_key(o)); if (l >= MAX_KEY_LEN - keylen) errx(EX_DATAERR, "key too long \"%s\"", envkey); expand(keylen + l, o); } break; case UCL_ARRAY: if (snprintkeys(envval, MAX_VALUE_LEN, obj) >= MAX_VALUE_LEN) errx(EX_DATAERR, "value too long \"%s\"", envval); setenv(envkey, envval, 1); i = 0; while ((o = ucl_iterate_object(obj, &it, true)) != NULL) { l = snprintf(envkey + keylen, MAX_KEY_LEN - keylen, "_%d", i++); if (l > MAX_KEY_LEN - keylen) errx(EX_DATAERR, "key too long \"%s\"", envkey); expand(keylen + l, o); } break; default: if (snprintval(envval, MAX_VALUE_LEN, obj) >= MAX_VALUE_LEN) errx(EX_DATAERR, "value too long \"%s\"", envval); setenv(envkey, envval, 1); break; } }
/* * print outputs the appropriate data for obj. If obj is a UCL_OBJECT or * UCL_ARRAY a list if keys is printed, otherwise the value is printed. */ static void print(ucl_object_t const *obj) { int n; switch (ucl_object_type(obj)) { case UCL_OBJECT: case UCL_ARRAY: n = snprintkeys(envval, MAX_VALUE_LEN, obj); if (n < 0) errx(EX_SOFTWARE, "error listing keys"); break; default: n = snprintval(envval, MAX_VALUE_LEN, obj); if (n < 0) errx(EX_SOFTWARE, "error formatting value"); break; } if (n >= MAX_VALUE_LEN) errx(EX_DATAERR, "output too long"); if (n > 0 && puts(envval) < 0) err(EX_IOERR, "cannot write value"); }
bool merge_recursive(ucl_object_t *top, ucl_object_t *elt, bool copy) { const ucl_object_t *cur; ucl_object_iter_t it = NULL; ucl_object_t *found = NULL, *cp_obj = NULL; bool success = false; it = ucl_object_iterate_new(elt); while ((cur = ucl_object_iterate_safe(it, false))) { cp_obj = ucl_object_ref(cur); if (debug > 0) { fprintf(stderr, "DEBUG: Looping over (elt)%s, found key: %s\n", ucl_object_key(top), ucl_object_key(cur)); } if (ucl_object_type(cur) == UCL_OBJECT) { found = __DECONST(ucl_object_t *, ucl_object_find_key(top, ucl_object_key(cur))); if (found == NULL) { /* new key not found in old object, insert it */ if (debug > 0) { fprintf(stderr, "DEBUG: unmatched key, inserting: %s into top\n", ucl_object_key(cur)); } success = ucl_object_insert_key_merged(top, cp_obj, ucl_object_key(cp_obj), 0, true); if (success == false) { return false; } continue; } if (debug > 0) { fprintf(stderr, "DEBUG: (obj) Found key %s in (top)%s too, merging...\n", ucl_object_key(found), ucl_object_key(top)); } success = merge_recursive(found, cp_obj, copy); if (success == false) { return false; } } else if (ucl_object_type(cur) == UCL_ARRAY) {
/* * snprintkeys writes the keys contained in obj to dst. */ static int snprintkeys(char *dst, size_t size, ucl_object_t const *obj) { ucl_object_iter_t it = NULL; ucl_object_t const *o; int n = 0; int i = 0; switch (ucl_object_type(obj)) { case UCL_OBJECT: for (i = 0; (o = ucl_iterate_object(obj, &it, true)) != NULL; i++) { int l; l = snprintf(dst + n, (size - n > 0) ? size - n: 0, "%s%s", (i == 0)?"":"\n", ucl_object_key(o)); if (l < 0) return l; n += l; } break; case UCL_ARRAY: { for (i = 0; (o = ucl_iterate_object(obj, &it, true)) != NULL; i++) { int l; l = snprintf(dst + n, (size - n > 0) ? size - n: 0, "%s%d", (i == 0)?"":"\n", i); if (l < 0) return l; n += l; } break; } default: *dst = '\0'; break; } return n; }
gpointer rspamd_stat_cache_redis_init (struct rspamd_stat_ctx *ctx, struct rspamd_config *cfg, struct rspamd_statfile *st, const ucl_object_t *cf) { struct rspamd_redis_cache_ctx *cache_ctx; struct rspamd_statfile_config *stf = st->stcf; const ucl_object_t *obj; gboolean ret = FALSE; cache_ctx = g_slice_alloc0 (sizeof (*cache_ctx)); /* First search in backend configuration */ obj = ucl_object_lookup (st->classifier->cfg->opts, "backend"); if (obj != NULL && ucl_object_type (obj) == UCL_OBJECT) { ret = rspamd_redis_cache_try_ucl (cache_ctx, obj, cfg, stf->symbol); } /* Now try statfiles config */ if (!ret) { ret = rspamd_redis_cache_try_ucl (cache_ctx, stf->opts, cfg, stf->symbol); } /* Now try classifier config */ if (!ret) { ret = rspamd_redis_cache_try_ucl (cache_ctx, st->classifier->cfg->opts, cfg, stf->symbol); } /* Now try global redis settings */ if (!ret) { obj = ucl_object_lookup (cfg->rcl_obj, "redis"); if (obj) { const ucl_object_t *specific_obj; specific_obj = ucl_object_lookup (obj, "statistics"); if (specific_obj) { ret = rspamd_redis_cache_try_ucl (cache_ctx, specific_obj, cfg, stf->symbol); } else { ret = rspamd_redis_cache_try_ucl (cache_ctx, obj, cfg, stf->symbol); } } } if (!ret) { msg_err_config ("cannot init redis cache for %s", stf->symbol); g_slice_free1 (sizeof (*cache_ctx), cache_ctx); return NULL; } cache_ctx->stcf = stf; return (gpointer)cache_ctx; }
static gboolean rspamd_redis_cache_try_ucl (struct rspamd_redis_cache_ctx *cache_ctx, const ucl_object_t *obj, struct rspamd_config *cfg, const gchar *symbol) { const ucl_object_t *elt, *relt; elt = ucl_object_lookup_any (obj, "read_servers", "servers", NULL); if (elt == NULL) { return FALSE; } cache_ctx->read_servers = rspamd_upstreams_create (cfg->ups_ctx); if (!rspamd_upstreams_from_ucl (cache_ctx->read_servers, elt, REDIS_DEFAULT_PORT, NULL)) { msg_err ("statfile %s cannot get read servers configuration", symbol); return FALSE; } relt = elt; elt = ucl_object_lookup (obj, "write_servers"); if (elt == NULL) { /* Use read servers as write ones */ g_assert (relt != NULL); cache_ctx->write_servers = rspamd_upstreams_create (cfg->ups_ctx); if (!rspamd_upstreams_from_ucl (cache_ctx->write_servers, relt, REDIS_DEFAULT_PORT, NULL)) { msg_err ("statfile %s cannot get write servers configuration", symbol); return FALSE; } } else { cache_ctx->write_servers = rspamd_upstreams_create (cfg->ups_ctx); if (!rspamd_upstreams_from_ucl (cache_ctx->write_servers, elt, REDIS_DEFAULT_PORT, NULL)) { msg_err ("statfile %s cannot get write servers configuration", symbol); rspamd_upstreams_destroy (cache_ctx->write_servers); cache_ctx->write_servers = NULL; } } elt = ucl_object_lookup (obj, "timeout"); if (elt) { cache_ctx->timeout = ucl_object_todouble (elt); } else { cache_ctx->timeout = REDIS_DEFAULT_TIMEOUT; } elt = ucl_object_lookup (obj, "password"); if (elt) { cache_ctx->password = ucl_object_tostring (elt); } else { cache_ctx->password = NULL; } elt = ucl_object_lookup_any (obj, "db", "database", "dbname", NULL); if (elt) { cache_ctx->dbname = ucl_object_tostring (elt); } else { cache_ctx->dbname = NULL; } elt = ucl_object_lookup_any (obj, "cache_key", "key", NULL); if (elt == NULL || ucl_object_type (elt) != UCL_STRING) { cache_ctx->redis_object = DEFAULT_REDIS_KEY; } else { cache_ctx->redis_object = ucl_object_tostring (elt); } return TRUE; }
static gboolean rspamd_redis_try_ucl (struct redis_stat_ctx *backend, const ucl_object_t *obj, struct rspamd_config *cfg, const gchar *symbol) { const ucl_object_t *elt, *relt, *users_enabled; const gchar *lua_script; elt = ucl_object_lookup_any (obj, "read_servers", "servers", NULL); if (elt == NULL) { return FALSE; } backend->read_servers = rspamd_upstreams_create (cfg->ups_ctx); if (!rspamd_upstreams_from_ucl (backend->read_servers, elt, REDIS_DEFAULT_PORT, NULL)) { msg_err ("statfile %s cannot get read servers configuration", symbol); return FALSE; } relt = elt; elt = ucl_object_lookup (obj, "write_servers"); if (elt == NULL) { /* Use read servers as write ones */ g_assert (relt != NULL); backend->write_servers = rspamd_upstreams_create (cfg->ups_ctx); if (!rspamd_upstreams_from_ucl (backend->write_servers, relt, REDIS_DEFAULT_PORT, NULL)) { msg_err ("statfile %s cannot get write servers configuration", symbol); return FALSE; } } else { backend->write_servers = rspamd_upstreams_create (cfg->ups_ctx); if (!rspamd_upstreams_from_ucl (backend->write_servers, elt, REDIS_DEFAULT_PORT, NULL)) { msg_err ("statfile %s cannot get write servers configuration", symbol); rspamd_upstreams_destroy (backend->write_servers); backend->write_servers = NULL; } } elt = ucl_object_lookup (obj, "prefix"); if (elt == NULL || ucl_object_type (elt) != UCL_STRING) { /* Default non-users statistics */ backend->redis_object = REDIS_DEFAULT_OBJECT; /* * Make redis backend compatible with sqlite3 backend in users settings */ users_enabled = ucl_object_lookup_any (obj, "per_user", "users_enabled", NULL); if (users_enabled != NULL) { if (ucl_object_type (users_enabled) == UCL_BOOLEAN) { backend->enable_users = ucl_object_toboolean (users_enabled); backend->cbref_user = -1; if (backend->enable_users) { backend->redis_object = REDIS_DEFAULT_USERS_OBJECT; } } else if (ucl_object_type (users_enabled) == UCL_STRING) { lua_script = ucl_object_tostring (users_enabled); if (luaL_dostring (cfg->lua_state, lua_script) != 0) { msg_err_config ("cannot execute lua script for users " "extraction: %s", lua_tostring (cfg->lua_state, -1)); } else { if (lua_type (cfg->lua_state, -1) == LUA_TFUNCTION) { backend->enable_users = TRUE; backend->cbref_user = luaL_ref (cfg->lua_state, LUA_REGISTRYINDEX); } else { msg_err_config ("lua script must return " "function(task) and not %s", lua_typename (cfg->lua_state, lua_type ( cfg->lua_state, -1))); } } } } else { backend->enable_users = FALSE; } } else { /* XXX: sanity check */ backend->redis_object = ucl_object_tostring (elt); } elt = ucl_object_lookup (obj, "timeout"); if (elt) { backend->timeout = ucl_object_todouble (elt); } else { backend->timeout = REDIS_DEFAULT_TIMEOUT; } elt = ucl_object_lookup (obj, "password"); if (elt) { backend->password = ucl_object_tostring (elt); } else { backend->password = NULL; } elt = ucl_object_lookup_any (obj, "db", "database", "dbname", NULL); if (elt) { backend->dbname = ucl_object_tostring (elt); } else { backend->dbname = NULL; } return TRUE; }
gint regexp_module_config (struct rspamd_config *cfg) { struct regexp_module_item *cur_item; const ucl_object_t *sec, *value, *elt; ucl_object_iter_t it = NULL; gint res = TRUE, id; if (!rspamd_config_is_module_enabled (cfg, "regexp")) { return TRUE; } sec = ucl_object_find_key (cfg->rcl_obj, "regexp"); if (sec == NULL) { msg_err_config ("regexp module enabled, but no rules are defined"); return TRUE; } regexp_module_ctx->max_size = 0; while ((value = ucl_iterate_object (sec, &it, true)) != NULL) { if (g_ascii_strncasecmp (ucl_object_key (value), "max_size", sizeof ("max_size") - 1) == 0) { regexp_module_ctx->max_size = ucl_obj_toint (value); rspamd_mime_expression_set_re_limit (regexp_module_ctx->max_size); } else if (g_ascii_strncasecmp (ucl_object_key (value), "max_threads", sizeof ("max_threads") - 1) == 0) { msg_warn_config ("regexp module is now single threaded, max_threads is ignored"); } else if (value->type == UCL_STRING) { cur_item = rspamd_mempool_alloc0 (regexp_module_ctx->regexp_pool, sizeof (struct regexp_module_item)); cur_item->symbol = ucl_object_key (value); if (!read_regexp_expression (regexp_module_ctx->regexp_pool, cur_item, ucl_object_key (value), ucl_obj_tostring (value), cfg)) { res = FALSE; } else { rspamd_symbols_cache_add_symbol (cfg->cache, cur_item->symbol, 0, process_regexp_item, cur_item, SYMBOL_TYPE_NORMAL, -1); } } else if (value->type == UCL_USERDATA) { /* Just a lua function */ cur_item = rspamd_mempool_alloc0 (regexp_module_ctx->regexp_pool, sizeof (struct regexp_module_item)); cur_item->symbol = ucl_object_key (value); cur_item->lua_function = ucl_object_toclosure (value); rspamd_symbols_cache_add_symbol (cfg->cache, cur_item->symbol, 0, process_regexp_item, cur_item, SYMBOL_TYPE_NORMAL, -1); } else if (value->type == UCL_OBJECT) { const gchar *description = NULL, *group = NULL, *metric = DEFAULT_METRIC; gdouble score = 0.0; gboolean one_shot = FALSE, is_lua = FALSE, valid_expression = TRUE; /* We have some lua table, extract its arguments */ elt = ucl_object_find_key (value, "callback"); if (elt == NULL || elt->type != UCL_USERDATA) { /* Try plain regexp expression */ elt = ucl_object_find_any_key (value, "regexp", "re", NULL); if (elt != NULL && ucl_object_type (elt) == UCL_STRING) { cur_item = rspamd_mempool_alloc0 (regexp_module_ctx->regexp_pool, sizeof (struct regexp_module_item)); cur_item->symbol = ucl_object_key (value); if (!read_regexp_expression (regexp_module_ctx->regexp_pool, cur_item, ucl_object_key (value), ucl_obj_tostring (elt), cfg)) { res = FALSE; } else { valid_expression = TRUE; } } else { msg_err_config ( "no callback/expression defined for regexp symbol: " "%s", ucl_object_key (value)); } } else { is_lua = TRUE; cur_item = rspamd_mempool_alloc0 ( regexp_module_ctx->regexp_pool, sizeof (struct regexp_module_item)); cur_item->symbol = ucl_object_key (value); cur_item->lua_function = ucl_object_toclosure (value); } if (cur_item && (is_lua || valid_expression)) { id = rspamd_symbols_cache_add_symbol (cfg->cache, cur_item->symbol, 0, process_regexp_item, cur_item, SYMBOL_TYPE_NORMAL, -1); elt = ucl_object_find_key (value, "condition"); if (elt != NULL && ucl_object_type (elt) == UCL_USERDATA) { struct ucl_lua_funcdata *conddata; conddata = ucl_object_toclosure (elt); rspamd_symbols_cache_add_condition (cfg->cache, id, conddata->L, conddata->idx); } elt = ucl_object_find_key (value, "metric"); if (elt) { metric = ucl_object_tostring (elt); } elt = ucl_object_find_key (value, "description"); if (elt) { description = ucl_object_tostring (elt); } elt = ucl_object_find_key (value, "group"); if (elt) { group = ucl_object_tostring (elt); } elt = ucl_object_find_key (value, "score"); if (elt) { score = ucl_object_todouble (elt); } elt = ucl_object_find_key (value, "one_shot"); if (elt) { one_shot = ucl_object_toboolean (elt); } rspamd_config_add_metric_symbol (cfg, metric, cur_item->symbol, score, description, group, one_shot, FALSE); } } else { msg_warn_config ("unknown type of attribute %s for regexp module", ucl_object_key (value)); } } return res; }
static struct rspamd_osb_tokenizer_config * rspamd_tokenizer_osb_config_from_ucl (rspamd_mempool_t * pool, const ucl_object_t *obj) { const ucl_object_t *elt; struct rspamd_osb_tokenizer_config *cf, *def; guchar *key = NULL; gsize keylen; if (pool != NULL) { cf = rspamd_mempool_alloc0 (pool, sizeof (*cf)); } else { cf = g_malloc0 (sizeof (*cf)); } /* Use default config */ def = rspamd_tokenizer_osb_default_config (); memcpy (cf, def, sizeof (*cf)); elt = ucl_object_lookup (obj, "hash"); if (elt != NULL && ucl_object_type (elt) == UCL_STRING) { if (g_ascii_strncasecmp (ucl_object_tostring (elt), "xxh", 3) == 0) { cf->ht = RSPAMD_OSB_HASH_XXHASH; elt = ucl_object_lookup (obj, "seed"); if (elt != NULL && ucl_object_type (elt) == UCL_INT) { cf->seed = ucl_object_toint (elt); } } else if (g_ascii_strncasecmp (ucl_object_tostring (elt), "sip", 3) == 0) { cf->ht = RSPAMD_OSB_HASH_SIPHASH; elt = ucl_object_lookup (obj, "key"); if (elt != NULL && ucl_object_type (elt) == UCL_STRING) { key = rspamd_decode_base32 (ucl_object_tostring (elt), 0, &keylen); if (keylen < sizeof (rspamd_sipkey_t)) { msg_warn ("siphash key is too short: %z", keylen); g_free (key); } else { memcpy (cf->sk, key, sizeof (cf->sk)); g_free (key); } } else { msg_warn_pool ("siphash cannot be used without key"); } } } else { elt = ucl_object_lookup (obj, "compat"); if (elt != NULL && ucl_object_toboolean (elt)) { cf->ht = RSPAMD_OSB_HASH_COMPAT; } } elt = ucl_object_lookup (obj, "window"); if (elt != NULL && ucl_object_type (elt) == UCL_INT) { cf->window_size = ucl_object_toint (elt); if (cf->window_size > DEFAULT_FEATURE_WINDOW_SIZE * 4) { msg_err_pool ("too large window size: %d", cf->window_size); cf->window_size = DEFAULT_FEATURE_WINDOW_SIZE; } } return cf; }
void json_config_fin_cb (rspamd_mempool_t * pool, struct map_cb_data *data) { struct config_json_buf *jb; ucl_object_t *top; struct ucl_parser *parser; if (data->prev_data) { jb = data->prev_data; /* Clean prev data */ if (jb->buf) { g_free (jb->buf); } g_free (jb); } /* Now parse json */ if (data->cur_data) { jb = data->cur_data; } else { msg_err ("no data read"); return; } if (jb->buf == NULL) { msg_err ("no data read"); return; } /* NULL terminate current buf */ *jb->pos = '\0'; parser = ucl_parser_new (0); if (!ucl_parser_add_chunk (parser, jb->buf, jb->pos - jb->buf)) { msg_err ("cannot load json data: parse error %s", ucl_parser_get_error (parser)); ucl_parser_free (parser); return; } top = ucl_parser_get_object (parser); ucl_parser_free (parser); if (ucl_object_type (top) != UCL_ARRAY) { ucl_object_unref (top); msg_err ("loaded json is not an array"); return; } jb->cfg->current_dynamic_conf = NULL; ucl_object_unref (jb->obj); jb->obj = top; /* * Note about thread safety: we are updating values that are gdoubles so it is not atomic in general case * but on the other hand all that data is used only in the main thread, so why it is *likely* safe * to do this task in this way without explicit lock. */ apply_dynamic_conf (jb->obj, jb->cfg); jb->cfg->current_dynamic_conf = jb->obj; }
static gboolean rspamd_symbols_cache_load_items (struct symbols_cache *cache, const gchar *name) { struct rspamd_symbols_cache_header *hdr; struct stat st; struct ucl_parser *parser; ucl_object_t *top; const ucl_object_t *cur, *elt; ucl_object_iter_t it; struct cache_item *item, *parent; const guchar *p; gint fd; gpointer map; double w; fd = open (name, O_RDONLY); if (fd == -1) { msg_info ("cannot open file %s, error %d, %s", name, errno, strerror (errno)); return FALSE; } if (fstat (fd, &st) == -1) { close (fd); msg_info ("cannot stat file %s, error %d, %s", name, errno, strerror (errno)); return FALSE; } if (st.st_size < (gint)sizeof (*hdr)) { close (fd); errno = EINVAL; msg_info ("cannot use file %s, error %d, %s", name, errno, strerror (errno)); return FALSE; } map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { close (fd); msg_info ("cannot mmap file %s, error %d, %s", name, errno, strerror (errno)); return FALSE; } close (fd); hdr = map; if (memcmp (hdr->magic, rspamd_symbols_cache_magic, sizeof (rspamd_symbols_cache_magic)) != 0) { msg_info ("cannot use file %s, bad magic", name); munmap (map, st.st_size); return FALSE; } parser = ucl_parser_new (0); p = (const guchar *)(hdr + 1); if (!ucl_parser_add_chunk (parser, p, st.st_size - sizeof (*hdr))) { msg_info ("cannot use file %s, cannot parse: %s", name, ucl_parser_get_error (parser)); munmap (map, st.st_size); ucl_parser_free (parser); return FALSE; } top = ucl_parser_get_object (parser); munmap (map, st.st_size); ucl_parser_free (parser); if (top == NULL || ucl_object_type (top) != UCL_OBJECT) { msg_info ("cannot use file %s, bad object", name); ucl_object_unref (top); return FALSE; } it = ucl_object_iterate_new (top); while ((cur = ucl_object_iterate_safe (it, true))) { item = g_hash_table_lookup (cache->items_by_symbol, ucl_object_key (cur)); if (item) { /* Copy saved info */ elt = ucl_object_find_key (cur, "weight"); if (elt) { w = ucl_object_todouble (elt); if (w != 0) { item->weight = w; } } elt = ucl_object_find_key (cur, "time"); if (elt) { item->avg_time = ucl_object_todouble (elt); } elt = ucl_object_find_key (cur, "count"); if (elt) { item->avg_counter = ucl_object_toint (elt); } elt = ucl_object_find_key (cur, "frequency"); if (elt) { item->frequency = ucl_object_toint (elt); } if (item->type == SYMBOL_TYPE_VIRTUAL && item->parent != -1) { g_assert (item->parent < (gint)cache->items_by_id->len); parent = g_ptr_array_index (cache->items_by_id, item->parent); if (parent->weight < item->weight) { parent->weight = item->weight; } /* * We maintain avg_time for virtual symbols equal to the * parent item avg_time */ parent->avg_time = item->avg_time; parent->avg_counter = item->avg_counter; } if (fabs (item->weight) > cache->max_weight) { cache->max_weight = fabs (item->weight); } cache->total_freq += item->frequency; } } ucl_object_iterate_free (it); ucl_object_unref (top); return TRUE; }
struct rspamd_map* rspamd_map_add_from_ucl (struct rspamd_config *cfg, const ucl_object_t *obj, const gchar *description, map_cb_t read_callback, map_fin_cb_t fin_callback, void **user_data) { ucl_object_iter_t it = NULL; const ucl_object_t *cur, *elt; struct rspamd_map *map; struct rspamd_map_backend *bk; g_assert (obj != NULL); if (ucl_object_type (obj) == UCL_STRING) { /* Just a plain string */ return rspamd_map_add (cfg, ucl_object_tostring (obj), NULL, read_callback, fin_callback, user_data); } map = g_slice_alloc0 (sizeof (struct rspamd_map)); map->read_callback = read_callback; map->fin_callback = fin_callback; map->user_data = user_data; map->cfg = cfg; map->id = g_random_int (); map->locked = rspamd_mempool_alloc0_shared (cfg->cfg_pool, sizeof (gint)); map->cache = rspamd_mempool_alloc0_shared (cfg->cfg_pool, sizeof (*map->cache)); map->backends = g_ptr_array_new (); map->poll_timeout = cfg->map_timeout; if (description) { map->description = g_strdup (description); } if (ucl_object_type (obj) == UCL_ARRAY) { /* Add array of maps as multiple backends */ while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) { if (ucl_object_type (cur) == UCL_STRING) { bk = rspamd_map_parse_backend (cfg, ucl_object_tostring (cur)); if (bk != NULL) { g_ptr_array_add (map->backends, bk); if (!map->name) { map->name = g_strdup (ucl_object_tostring (cur)); } } } else { msg_err_config ("bad map element type: %s", ucl_object_type_to_string (ucl_object_type (cur))); } } if (map->backends->len == 0) { msg_err_config ("map has no urls to be loaded"); goto err; } } else if (ucl_object_type (obj) == UCL_OBJECT) { elt = ucl_object_lookup (obj, "name"); if (elt && ucl_object_type (elt) == UCL_STRING) { map->name = g_strdup (ucl_object_tostring (elt)); } elt = ucl_object_lookup (obj, "description"); if (elt && ucl_object_type (elt) == UCL_STRING) { if (map->description) { g_free (map->description); } map->description = g_strdup (ucl_object_tostring (elt)); } elt = ucl_object_lookup_any (obj, "timeout", "poll", "poll_time", "watch_interval", NULL); if (elt) { map->poll_timeout = ucl_object_todouble (elt); } elt = ucl_object_lookup_any (obj, "upstreams", "url", "urls", NULL); if (elt == NULL) { msg_err_config ("map has no urls to be loaded"); goto err; } if (ucl_object_type (obj) == UCL_ARRAY) { /* Add array of maps as multiple backends */ while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) { if (ucl_object_type (cur) == UCL_STRING) { bk = rspamd_map_parse_backend (cfg, ucl_object_tostring (cur)); if (bk != NULL) { g_ptr_array_add (map->backends, bk); if (!map->name) { map->name = g_strdup (ucl_object_tostring (cur)); } } } else { msg_err_config ("bad map element type: %s", ucl_object_type_to_string (ucl_object_type (cur))); goto err; } } if (map->backends->len == 0) { msg_err_config ("map has no urls to be loaded"); goto err; } } else if (ucl_object_type (elt) == UCL_STRING) { bk = rspamd_map_parse_backend (cfg, ucl_object_tostring (elt)); if (bk != NULL) { g_ptr_array_add (map->backends, bk); if (!map->name) { map->name = g_strdup (ucl_object_tostring (cur)); } } } if (map->backends->len == 0) { msg_err_config ("map has no urls to be loaded"); goto err; } } rspamd_map_calculate_hash (map); msg_info_map ("added map from ucl"); cfg->maps = g_list_prepend (cfg->maps, map); return map; err: g_ptr_array_free (map->backends, TRUE); g_free (map->name); g_free (map->description); g_slice_free1 (sizeof (*map), map); return NULL; }
/** * Apply configuration to the specified configuration * @param conf_metrics * @param cfg */ static void apply_dynamic_conf (const ucl_object_t *top, struct rspamd_config *cfg) { gint test_act; const ucl_object_t *cur_elt, *cur_nm, *it_val; ucl_object_iter_t it = NULL; struct metric *real_metric; struct metric_action *cur_action; struct rspamd_symbol_def *s; while ((cur_elt = ucl_iterate_object (top, &it, true))) { if (ucl_object_type (cur_elt) != UCL_OBJECT) { msg_err ("loaded json array element is not an object"); continue; } cur_nm = ucl_object_find_key (cur_elt, "metric"); if (!cur_nm || ucl_object_type (cur_nm) != UCL_STRING) { msg_err ( "loaded json metric object element has no 'metric' attribute"); continue; } real_metric = g_hash_table_lookup (cfg->metrics, ucl_object_tostring (cur_nm)); if (real_metric == NULL) { msg_warn ("cannot find metric %s", ucl_object_tostring (cur_nm)); continue; } cur_nm = ucl_object_find_key (cur_elt, "symbols"); /* Parse symbols */ if (cur_nm && ucl_object_type (cur_nm) == UCL_ARRAY) { ucl_object_iter_t nit = NULL; while ((it_val = ucl_iterate_object (cur_nm, &nit, true))) { if (ucl_object_find_key (it_val, "name") && ucl_object_find_key (it_val, "value")) { const ucl_object_t *n = ucl_object_find_key (it_val, "name"); const ucl_object_t *v = ucl_object_find_key (it_val, "value"); if((s = g_hash_table_lookup (real_metric->symbols, ucl_object_tostring (n))) != NULL) { *s->weight_ptr = ucl_object_todouble (v); } } else { msg_info ( "json symbol object has no mandatory 'name' and 'value' attributes"); } } } else { ucl_object_t *arr; arr = ucl_object_typed_new (UCL_ARRAY); ucl_object_insert_key ((ucl_object_t *)cur_elt, arr, "symbols", sizeof ("symbols") - 1, false); } cur_nm = ucl_object_find_key (cur_elt, "actions"); /* Parse actions */ if (cur_nm && ucl_object_type (cur_nm) == UCL_ARRAY) { ucl_object_iter_t nit = NULL; while ((it_val = ucl_iterate_object (cur_nm, &nit, true))) { if (ucl_object_find_key (it_val, "name") && ucl_object_find_key (it_val, "value")) { if (!rspamd_action_from_str (ucl_object_tostring ( ucl_object_find_key (it_val, "name")), &test_act)) { msg_err ("unknown action: %s", ucl_object_tostring (ucl_object_find_key (it_val, "name"))); continue; } cur_action = &real_metric->actions[test_act]; cur_action->action = test_act; cur_action->score = ucl_object_todouble (ucl_object_find_key (it_val, "value")); } else { msg_info ( "json action object has no mandatory 'name' and 'value' attributes"); } } } else { ucl_object_t *arr; arr = ucl_object_typed_new (UCL_ARRAY); ucl_object_insert_key ((ucl_object_t *)cur_elt, arr, "actions", sizeof ("actions") - 1, false); } } }
static gboolean rspamd_fuzzy_backend_redis_try_ucl (struct rspamd_fuzzy_backend_redis *backend, const ucl_object_t *obj, struct rspamd_config *cfg) { const ucl_object_t *elt, *relt; elt = ucl_object_lookup_any (obj, "read_servers", "servers", NULL); if (elt == NULL) { return FALSE; } backend->read_servers = rspamd_upstreams_create (cfg->ups_ctx); if (!rspamd_upstreams_from_ucl (backend->read_servers, elt, REDIS_DEFAULT_PORT, NULL)) { msg_err_config ("cannot get read servers configuration"); return FALSE; } relt = elt; elt = ucl_object_lookup (obj, "write_servers"); if (elt == NULL) { /* Use read servers as write ones */ g_assert (relt != NULL); backend->write_servers = rspamd_upstreams_create (cfg->ups_ctx); if (!rspamd_upstreams_from_ucl (backend->write_servers, relt, REDIS_DEFAULT_PORT, NULL)) { msg_err_config ("cannot get write servers configuration"); return FALSE; } } else { backend->write_servers = rspamd_upstreams_create (cfg->ups_ctx); if (!rspamd_upstreams_from_ucl (backend->write_servers, elt, REDIS_DEFAULT_PORT, NULL)) { msg_err_config ("cannot get write servers configuration"); rspamd_upstreams_destroy (backend->write_servers); backend->write_servers = NULL; } } elt = ucl_object_lookup (obj, "prefix"); if (elt == NULL || ucl_object_type (elt) != UCL_STRING) { backend->redis_object = REDIS_DEFAULT_OBJECT; } else { backend->redis_object = ucl_object_tostring (elt); } elt = ucl_object_lookup (obj, "timeout"); if (elt) { backend->timeout = ucl_object_todouble (elt); } else { backend->timeout = REDIS_DEFAULT_TIMEOUT; } elt = ucl_object_lookup (obj, "password"); if (elt) { backend->password = ucl_object_tostring (elt); } else { backend->password = NULL; } elt = ucl_object_lookup_any (obj, "db", "database", "dbname", NULL); if (elt) { backend->dbname = ucl_object_tostring (elt); } else { backend->dbname = NULL; } return TRUE; }
int main (int argc, char **argv) { ucl_object_t *obj, *cur, *ar, *ar1, *ref, *test_obj, *comments; ucl_object_iter_t it; const ucl_object_t *found, *it_obj, *test; struct ucl_emitter_functions *fn; FILE *out; unsigned char *emitted; const char *fname_out = NULL; struct ucl_parser *parser; int ret = 0; switch (argc) { case 2: fname_out = argv[1]; break; } if (fname_out != NULL) { out = fopen (fname_out, "w"); if (out == NULL) { exit (-errno); } } else { out = stdout; } obj = ucl_object_typed_new (UCL_OBJECT); /* Keys replacing */ cur = ucl_object_fromstring_common ("value1", 0, UCL_STRING_TRIM); ucl_object_insert_key (obj, cur, "key0", 0, false); cur = ucl_object_fromdouble (0.1); assert (ucl_object_replace_key (obj, cur, "key0", 0, false)); /* Create some strings */ cur = ucl_object_fromstring_common (" test string ", 0, UCL_STRING_TRIM); ucl_object_insert_key (obj, cur, "key1", 0, false); cur = ucl_object_fromstring_common (" test \nstring\n\r\n\b\t\f\\\" ", 0, UCL_STRING_TRIM | UCL_STRING_ESCAPE); ucl_object_insert_key (obj, cur, "key2", 0, false); cur = ucl_object_fromstring_common (" test string \n", 0, 0); ucl_object_insert_key (obj, cur, "key3", 0, false); /* Array of numbers */ ar = ucl_object_typed_new (UCL_ARRAY); cur = ucl_object_fromint (10); ucl_array_append (ar, cur); assert (ucl_array_index_of (ar, cur) == 0); cur = ucl_object_fromdouble (10.1); ucl_array_append (ar, cur); assert (ucl_array_index_of (ar, cur) == 1); cur = ucl_object_fromdouble (9.999); ucl_array_prepend (ar, cur); assert (ucl_array_index_of (ar, cur) == 0); ar1 = ucl_object_copy (ar); cur = ucl_object_fromstring ("abc"); ucl_array_prepend (ar1, cur); cur = ucl_object_fromstring ("cde"); ucl_array_prepend (ar1, cur); cur = ucl_object_fromstring ("аАаБаВ"); /* UTF8 */ ucl_array_prepend (ar1, cur); cur = ucl_object_fromstring ("ааБаВ"); /* UTF8 */ ucl_array_prepend (ar1, cur); /* * This is ususally broken or fragile as utf collate is far from perfect cur = ucl_object_fromstring ("баБаВ"); ucl_array_prepend (ar1, cur); cur = ucl_object_fromstring ("ааБаВ"); // hello to @bapt ucl_array_prepend (ar1, cur); */ cur = ucl_object_fromstring ("№"); /* everybody likes emoji in the code */ ucl_array_prepend (ar1, cur); ucl_object_array_sort (ar1, ucl_object_compare_qsort); /* Removing from an array */ cur = ucl_object_fromdouble (1.0); ucl_array_append (ar, cur); cur = ucl_array_delete (ar, cur); assert (ucl_object_todouble (cur) == 1.0); ucl_object_unref (cur); cur = ucl_object_fromdouble (2.0); ucl_array_append (ar, cur); cur = ucl_array_pop_last (ar); assert (ucl_object_todouble (cur) == 2.0); ucl_object_unref (cur); cur = ucl_object_fromdouble (3.0); ucl_array_prepend (ar, cur); cur = ucl_array_pop_first (ar); assert (ucl_object_todouble (cur) == 3.0); ucl_object_unref (cur); ucl_object_insert_key (obj, ar, "key4", 0, false); cur = ucl_object_frombool (true); /* Ref object to test refcounts */ ref = ucl_object_ref (cur); ucl_object_insert_key (obj, cur, "key4", 0, false); /* Empty strings */ cur = ucl_object_fromstring_common (" ", 0, UCL_STRING_TRIM); ucl_object_insert_key (obj, cur, "key5", 0, false); cur = ucl_object_fromstring_common ("", 0, UCL_STRING_ESCAPE); ucl_object_insert_key (obj, cur, "key6", 0, false); cur = ucl_object_fromstring_common (" \n", 0, UCL_STRING_ESCAPE); ucl_object_insert_key (obj, cur, "key7", 0, false); /* Numbers and booleans */ cur = ucl_object_fromstring_common ("1mb", 0, UCL_STRING_ESCAPE | UCL_STRING_PARSE); ucl_object_insert_key (obj, cur, "key8", 0, false); cur = ucl_object_fromstring_common ("3.14", 0, UCL_STRING_PARSE); ucl_object_insert_key (obj, cur, "key9", 0, false); cur = ucl_object_fromstring_common ("true", 0, UCL_STRING_PARSE); ucl_object_insert_key (obj, cur, "key10", 0, false); cur = ucl_object_fromstring_common (" off ", 0, UCL_STRING_PARSE | UCL_STRING_TRIM); ucl_object_insert_key (obj, cur, "key11", 0, false); cur = ucl_object_fromstring_common ("*****@*****.**", 0, UCL_STRING_PARSE_INT); ucl_object_insert_key (obj, cur, "key12", 0, false); cur = ucl_object_fromstring_common ("#test", 0, UCL_STRING_PARSE_INT); ucl_object_insert_key (obj, cur, "key13", 0, false); cur = ucl_object_frombool (true); ucl_object_insert_key (obj, cur, "k=3", 0, false); ucl_object_insert_key (obj, ar1, "key14", 0, false); cur = ucl_object_new_userdata (ud_dtor, ud_emit, NULL); ucl_object_insert_key (obj, cur, "key15", 0, false); /* More tests for keys */ cur = ucl_object_fromlstring ("test", 3); ucl_object_insert_key (obj, cur, "key16", 0, false); test = ucl_object_lookup_any (obj, "key100", "key200", "key300", "key16", NULL); assert (test == cur); test = ucl_object_lookup_len (obj, "key160", 5); assert (test == cur); cur = ucl_object_pop_key (obj, "key16"); assert (test == cur); test = ucl_object_pop_key (obj, "key16"); assert (test == NULL); test = ucl_object_lookup_len (obj, "key160", 5); assert (test == NULL); /* Objects merging tests */ test_obj = ucl_object_new_full (UCL_OBJECT, 2); ucl_object_insert_key (test_obj, cur, "key16", 0, true); ucl_object_merge (obj, test_obj, true); ucl_object_unref (test_obj); /* Array merging test */ test_obj = ucl_object_new_full (UCL_ARRAY, 3); ucl_array_append (test_obj, ucl_object_fromstring ("test")); ucl_array_merge (test_obj, ar1, false); ucl_object_insert_key (obj, test_obj, "key17", 0, true); /* Object deletion */ cur = ucl_object_fromstring ("test"); ucl_object_insert_key (obj, cur, "key18", 0, true); assert (ucl_object_delete_key (obj, "key18")); assert (!ucl_object_delete_key (obj, "key18")); cur = ucl_object_fromlstring ("test", 4); ucl_object_insert_key (obj, cur, "key18\0\0", 7, true); assert (ucl_object_lookup_len (obj, "key18\0\0", 7) == cur); assert (ucl_object_lookup (obj, "key18") == NULL); assert (ucl_object_lookup_len (obj, "key18\0\1", 7) == NULL); assert (ucl_object_delete_keyl (obj, "key18\0\0", 7)); /* Comments */ comments = ucl_object_typed_new (UCL_OBJECT); found = ucl_object_lookup (obj, "key17"); test = ucl_object_lookup (obj, "key16"); ucl_comments_add (comments, found, "# test comment"); assert (ucl_comments_find (comments, found) != NULL); assert (ucl_comments_find (comments, test) == NULL); ucl_comments_move (comments, found, test); assert (ucl_comments_find (comments, found) == NULL); assert (ucl_comments_find (comments, test) != NULL); /* Array replace */ ar1 = ucl_object_typed_new (UCL_ARRAY); cur = ucl_object_fromstring ("test"); cur = ucl_elt_append (cur, ucl_object_fromstring ("test1")); ucl_array_append (ar1, cur); test = ucl_array_replace_index (ar1, ucl_object_fromstring ("test2"), 0); assert (test == cur); /* Try to find using path */ /* Should exist */ found = ucl_object_lookup_path (obj, "key4.1"); assert (found != NULL && ucl_object_toint (found) == 10); /* . should be ignored */ found = ucl_object_lookup_path (obj, ".key4.1"); assert (found != NULL && ucl_object_toint (found) == 10); /* moar dots... */ found = ucl_object_lookup_path (obj, ".key4........1..."); assert (found != NULL && ucl_object_toint (found) == 10); /* No such index */ found = ucl_object_lookup_path (obj, ".key4.3"); assert (found == NULL); /* No such key */ found = ucl_object_lookup_path (obj, "key9..key1"); assert (found == NULL); /* Test iteration */ it = ucl_object_iterate_new (obj); it_obj = ucl_object_iterate_safe (it, true); /* key0 = 0.1 */ assert (ucl_object_type (it_obj) == UCL_FLOAT); it_obj = ucl_object_iterate_safe (it, true); /* key1 = "" */ assert (ucl_object_type (it_obj) == UCL_STRING); it_obj = ucl_object_iterate_safe (it, true); /* key2 = "" */ assert (ucl_object_type (it_obj) == UCL_STRING); it_obj = ucl_object_iterate_safe (it, true); /* key3 = "" */ assert (ucl_object_type (it_obj) == UCL_STRING); it_obj = ucl_object_iterate_safe (it, true); /* key4 = ([float, int, float], boolean) */ ucl_object_iterate_reset (it, it_obj); it_obj = ucl_object_iterate_safe (it, true); assert (ucl_object_type (it_obj) == UCL_FLOAT); it_obj = ucl_object_iterate_safe (it, true); assert (ucl_object_type (it_obj) == UCL_INT); it_obj = ucl_object_iterate_safe (it, true); assert (ucl_object_type (it_obj) == UCL_FLOAT); it_obj = ucl_object_iterate_safe (it, true); assert (ucl_object_type (it_obj) == UCL_BOOLEAN); ucl_object_iterate_free (it); fn = ucl_object_emit_memory_funcs (&emitted); assert (ucl_object_emit_full (obj, UCL_EMIT_CONFIG, fn, comments)); fprintf (out, "%s\n", emitted); ucl_object_emit_funcs_free (fn); ucl_object_unref (obj); ucl_object_unref (comments); parser = ucl_parser_new (UCL_PARSER_NO_IMPLICIT_ARRAYS); if (ucl_parser_add_chunk_full (parser, emitted, strlen (emitted), 3, UCL_DUPLICATE_ERROR, UCL_PARSE_UCL)) { /* Should fail due to duplicate */ assert (0); } else { assert (ucl_parser_get_error (parser) != NULL); ucl_parser_clear_error (parser); ucl_parser_free (parser); parser = ucl_parser_new (0); ucl_parser_add_chunk_full (parser, emitted, strlen (emitted), 3, UCL_DUPLICATE_MERGE, UCL_PARSE_UCL); } assert (ucl_parser_get_column (parser) == 0); assert (ucl_parser_get_linenum (parser) != 0); ucl_parser_clear_error (parser); assert (ucl_parser_get_error_code (parser) == 0); obj = ucl_parser_get_object (parser); ucl_parser_free (parser); ucl_object_free (obj); if (emitted != NULL) { free (emitted); } fclose (out); /* Ref should still be accessible */ ref->value.iv = 100500; ucl_object_unref (ref); return ret; }
gboolean rspamd_config_is_module_enabled (struct rspamd_config *cfg, const gchar *module_name) { gboolean is_c = FALSE; struct metric *metric; const ucl_object_t *conf, *enabled; GList *cur; struct rspamd_symbols_group *gr; metric = cfg->default_metric; if (g_hash_table_lookup (cfg->c_modules, module_name)) { is_c = TRUE; } if (g_hash_table_lookup (cfg->explicit_modules, module_name) != NULL) { /* Always load module */ return TRUE; } if (is_c) { gboolean found = FALSE; cur = g_list_first (cfg->filters); while (cur) { if (strcmp (cur->data, module_name) == 0) { found = TRUE; break; } cur = g_list_next (cur); } if (!found) { msg_info_config ("internal module %s is disable in `filters` line", module_name); return FALSE; } } conf = ucl_object_find_key (cfg->rcl_obj, module_name); if (conf == NULL) { msg_info_config ("%s module %s is enabled but has not been configured", is_c ? "internal" : "lua", module_name); if (!is_c) { msg_info_config ("%s disabling unconfigured lua module", module_name); return FALSE; } } else { enabled = ucl_object_find_key (conf, "enabled"); if (enabled && ucl_object_type (enabled) == UCL_BOOLEAN) { if (!ucl_object_toboolean (enabled)) { msg_info_config ("%s module %s is disabled in the configuration", is_c ? "internal" : "lua", module_name); return FALSE; } } } /* Now we check symbols group */ gr = g_hash_table_lookup (metric->groups, module_name); if (gr) { if (gr->disabled) { msg_info_config ("%s module %s is disabled in the configuration as " "its group has been disabled", is_c ? "internal" : "lua", module_name); return FALSE; } } return TRUE; }
int merge_mode(char *destination_node, char *data) { ucl_object_t *dst_obj = NULL; ucl_object_t *sub_obj = NULL; ucl_object_t *old_obj = NULL; ucl_object_t *tmp_obj = NULL; int success = 0; char *dst_frag; setparser = ucl_parser_new(UCL_PARSER_KEY_LOWERCASE | UCL_PARSER_NO_IMPLICIT_ARRAYS); /* Lookup the destination to write to */ dst_obj = get_parent(destination_node); sub_obj = get_object(destination_node); if (sub_obj == NULL) { fprintf(stderr, "Failed to find destination node: %s\n", destination_node); return false; } if (include_file != NULL) { /* get UCL to add from file */ set_obj = parse_file(setparser, include_file); } else if (data == NULL || strcmp(data, "-") == 0) { /* get UCL to add from stdin */ set_obj = parse_input(setparser, stdin); } else { /* User provided data inline */ set_obj = parse_string(setparser, data); } if (debug > 0) { char *rt = NULL, *dt = NULL, *st = NULL; rt = objtype_as_string(dst_obj); dt = objtype_as_string(sub_obj); st = objtype_as_string(set_obj); fprintf(stderr, "root type: %s, destination type: %s, new type: %s\n", rt, dt, st); if (rt != NULL) free(rt); if (dt != NULL) free(dt); if (st != NULL) free(st); fprintf(stderr, "Merging key %s to root: %s\n", ucl_object_key(sub_obj), ucl_object_key(dst_obj)); } dst_frag = strrchr(destination_node, input_sepchar); if (dst_frag == NULL) { dst_frag = destination_node; } else { dst_frag++; } /* Add it to the object here */ if (sub_obj == dst_obj && *dst_frag != '\0') { /* Sub-object does not exist, create a new one */ success = ucl_object_insert_key(dst_obj, set_obj, dst_frag, 0, true); } else if (ucl_object_type(sub_obj) == UCL_ARRAY && ucl_object_type(set_obj) == UCL_ARRAY) { if (debug > 0) { fprintf(stderr, "Merging array of size %u with array of size %u\n", sub_obj->len, set_obj->len); } success = ucl_array_merge(sub_obj, set_obj, true); } else if (ucl_object_type(sub_obj) == UCL_ARRAY) { if (debug > 0) { fprintf(stderr, "Appending object to array of size %u\n", sub_obj->len); } success = ucl_array_append(sub_obj, ucl_object_ref(set_obj)); } else if (ucl_object_type(sub_obj) == UCL_OBJECT && ucl_object_type(set_obj) == UCL_OBJECT) { if (debug > 0) { fprintf(stderr, "Merging object %s with object %s\n", ucl_object_key(sub_obj), ucl_object_key(set_obj)); } /* XXX not supported: * success = ucl_object_merge(sub_obj, set_obj, false, true); */ /* Old non-recursive way */ /* success = ucl_object_merge(sub_obj, set_obj, false); */ success = merge_recursive(sub_obj, set_obj, false); } else if (ucl_object_type(sub_obj) != UCL_OBJECT && ucl_object_type(sub_obj) != UCL_ARRAY) { /* Create an explicit array */ if (debug > 0) { fprintf(stderr, "Creating an array and appended the new item\n"); } tmp_obj = ucl_object_typed_new(UCL_ARRAY); /* * Reference and Append the original scalar * The additional reference is required because the old object will be * unreferenced as part of the ucl_object_replace_key operation */ ucl_array_append(tmp_obj, ucl_object_ref(sub_obj)); /* Reference and Append the new scalar (unref in cleanup()) */ ucl_array_append(tmp_obj, ucl_object_ref(set_obj)); /* Replace the old object with the newly created one */ if (ucl_object_type(dst_obj) == UCL_ARRAY) { old_obj = ucl_array_replace_index(dst_obj, tmp_obj, ucl_array_index_of(dst_obj, sub_obj)); success = false; if (old_obj != NULL) { ucl_object_unref(old_obj); success = true; } } else { success = ucl_object_replace_key(dst_obj, tmp_obj, ucl_object_key(sub_obj), 0, true); } } else { if (debug > 0) { fprintf(stderr, "Merging object into key %s\n", ucl_object_key(sub_obj)); } success = ucl_object_insert_key_merged(dst_obj, ucl_object_ref(set_obj), ucl_object_key(sub_obj), 0, true); } return success; }