gint lua_config_radix_from_config (lua_State *L) { struct rspamd_config *cfg = lua_check_config (L, 1); const gchar *mname, *optname; const ucl_object_t *obj; struct rspamd_lua_map *map, **pmap; if (!cfg) { return luaL_error (L, "invalid arguments"); } mname = luaL_checkstring (L, 2); optname = luaL_checkstring (L, 3); if (mname && optname) { obj = rspamd_config_get_module_opt (cfg, mname, optname); if (obj) { map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); map->data.radix = radix_create_compressed (); map->type = RSPAMD_LUA_MAP_RADIX; map->data.radix = radix_create_compressed (); map->flags |= RSPAMD_LUA_MAP_FLAG_EMBEDDED; radix_add_generic_iplist (ucl_obj_tostring (obj), &map->data.radix, TRUE); pmap = lua_newuserdata (L, sizeof (void *)); *pmap = map; rspamd_lua_setclass (L, "rspamd{map}", -1); } else { msg_warn_config ("Couldnt find config option [%s][%s]", mname, optname); lua_pushnil (L); } } else { return luaL_error (L, "invalid arguments"); } return 1; }
gint chartable_module_config (struct rspamd_config *cfg) { const ucl_object_t *value; gint res = TRUE; if (!rspamd_config_is_module_enabled (cfg, "chartable")) { return TRUE; } if ((value = rspamd_config_get_module_opt (cfg, "chartable", "symbol")) != NULL) { chartable_module_ctx->symbol = ucl_obj_tostring (value); } else { chartable_module_ctx->symbol = DEFAULT_SYMBOL; } if ((value = rspamd_config_get_module_opt (cfg, "chartable", "threshold")) != NULL) { if (!ucl_obj_todouble_safe (value, &chartable_module_ctx->threshold)) { msg_warn_config ("invalid numeric value"); chartable_module_ctx->threshold = DEFAULT_THRESHOLD; } } else { chartable_module_ctx->threshold = DEFAULT_THRESHOLD; } rspamd_symbols_cache_add_symbol (cfg->cache, chartable_module_ctx->symbol, 0, chartable_symbol_callback, NULL, SYMBOL_TYPE_NORMAL, -1); msg_info_config ("init internal chartable module"); return res; }
gint dkim_module_config (struct rspamd_config *cfg) { const ucl_object_t *value; gint res = TRUE, cb_id = -1, check_id = -1; guint cache_size; gboolean got_trusted = FALSE; if (!rspamd_config_is_module_enabled (cfg, "dkim")) { return TRUE; } dkim_module_ctx->whitelist_ip = radix_create_compressed (); if ((value = rspamd_config_get_module_opt (cfg, "dkim", "symbol_reject")) != NULL) { dkim_module_ctx->symbol_reject = ucl_obj_tostring (value); } else { dkim_module_ctx->symbol_reject = DEFAULT_SYMBOL_REJECT; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "symbol_tempfail")) != NULL) { dkim_module_ctx->symbol_tempfail = ucl_obj_tostring (value); } else { dkim_module_ctx->symbol_tempfail = DEFAULT_SYMBOL_TEMPFAIL; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "symbol_allow")) != NULL) { dkim_module_ctx->symbol_allow = ucl_obj_tostring (value); } else { dkim_module_ctx->symbol_allow = DEFAULT_SYMBOL_ALLOW; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "symbol_na")) != NULL) { dkim_module_ctx->symbol_na = ucl_obj_tostring (value); } else { dkim_module_ctx->symbol_na = DEFAULT_SYMBOL_NA; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "dkim_cache_size")) != NULL) { cache_size = ucl_obj_toint (value); } else { cache_size = DEFAULT_CACHE_SIZE; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "time_jitter")) != NULL) { dkim_module_ctx->time_jitter = ucl_obj_todouble (value); } else { dkim_module_ctx->time_jitter = DEFAULT_TIME_JITTER; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "max_sigs")) != NULL) { dkim_module_ctx->max_sigs = ucl_object_toint (value); } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "whitelist")) != NULL) { rspamd_config_radix_from_ucl (cfg, value, "DKIM whitelist", &dkim_module_ctx->whitelist_ip, NULL); } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "domains")) != NULL) { if (!rspamd_map_add_from_ucl (cfg, value, "DKIM domains", rspamd_kv_list_read, rspamd_kv_list_fin, (void **)&dkim_module_ctx->dkim_domains)) { msg_warn_config ("cannot load dkim domains list from %s", ucl_obj_tostring (value)); } else { got_trusted = TRUE; } } if (!got_trusted && (value = rspamd_config_get_module_opt (cfg, "dkim", "trusted_domains")) != NULL) { if (!rspamd_map_add_from_ucl (cfg, value, "DKIM domains", rspamd_kv_list_read, rspamd_kv_list_fin, (void **)&dkim_module_ctx->dkim_domains)) { msg_warn_config ("cannot load dkim domains list from %s", ucl_obj_tostring (value)); } else { got_trusted = TRUE; } } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "strict_multiplier")) != NULL) { dkim_module_ctx->strict_multiplier = ucl_obj_toint (value); } else { dkim_module_ctx->strict_multiplier = 1; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "trusted_only")) != NULL) { dkim_module_ctx->trusted_only = ucl_obj_toboolean (value); } else { dkim_module_ctx->trusted_only = FALSE; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "skip_multi")) != NULL) { dkim_module_ctx->skip_multi = ucl_obj_toboolean (value); } else { dkim_module_ctx->skip_multi = FALSE; } if (dkim_module_ctx->trusted_only && !got_trusted) { msg_err_config ( "trusted_only option is set and no trusted domains are defined; disabling dkim module completely as it is useless in this case"); } else { cb_id = rspamd_symbols_cache_add_symbol (cfg->cache, dkim_module_ctx->symbol_reject, 0, dkim_symbol_callback, NULL, SYMBOL_TYPE_NORMAL|SYMBOL_TYPE_FINE, -1); rspamd_symbols_cache_add_symbol (cfg->cache, dkim_module_ctx->symbol_na, 0, NULL, NULL, SYMBOL_TYPE_VIRTUAL|SYMBOL_TYPE_FINE, cb_id); rspamd_symbols_cache_add_symbol (cfg->cache, dkim_module_ctx->symbol_tempfail, 0, NULL, NULL, SYMBOL_TYPE_VIRTUAL|SYMBOL_TYPE_FINE, cb_id); rspamd_symbols_cache_add_symbol (cfg->cache, dkim_module_ctx->symbol_allow, 0, NULL, NULL, SYMBOL_TYPE_VIRTUAL|SYMBOL_TYPE_FINE, cb_id); dkim_module_ctx->dkim_hash = rspamd_lru_hash_new ( cache_size, g_free, /* Keys are just C-strings */ dkim_module_key_dtor); msg_info_config ("init internal dkim module"); #ifndef HAVE_OPENSSL msg_warn_config ( "openssl is not found so dkim rsa check is disabled, only check body hash, it is NOT safe to trust these results"); #endif } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "sign_condition")) != NULL) { const gchar *lua_script; lua_script = ucl_object_tostring (value); if (lua_script) { if (luaL_dostring (cfg->lua_state, lua_script) != 0) { msg_err_config ("cannot execute lua script for fuzzy " "learn condition: %s", lua_tostring (cfg->lua_state, -1)); } else { if (lua_type (cfg->lua_state, -1) == LUA_TFUNCTION) { dkim_module_ctx->sign_condition_ref = luaL_ref (cfg->lua_state, LUA_REGISTRYINDEX); dkim_module_ctx->dkim_sign_hash = rspamd_lru_hash_new ( 128, g_free, /* Keys are just C-strings */ (GDestroyNotify)rspamd_dkim_sign_key_unref); check_id = rspamd_symbols_cache_add_symbol (cfg->cache, "DKIM_SIGN", 0, dkim_sign_callback, NULL, SYMBOL_TYPE_CALLBACK|SYMBOL_TYPE_FINE, -1); msg_info_config ("init condition script for DKIM signing"); /* * Allow dkim signing to be executed only after dkim check */ if (cb_id > 0) { rspamd_symbols_cache_add_delayed_dependency (cfg->cache, "DKIM_SIGN", dkim_module_ctx->symbol_reject); } rspamd_config_add_metric_symbol (cfg, DEFAULT_METRIC, "DKIM_SIGN", 0.0, "DKIM signature fake symbol", "dkim", RSPAMD_SYMBOL_FLAG_IGNORE, 1); } else { msg_err_config ("lua script must return " "function(task) and not %s", lua_typename (cfg->lua_state, lua_type (cfg->lua_state, -1))); } } } } return res; }
gint dkim_module_config (struct rspamd_config *cfg) { const ucl_object_t *value; gint res = TRUE, cb_id; guint cache_size, cache_expire; gboolean got_trusted = FALSE; if (!rspamd_config_is_module_enabled (cfg, "dkim")) { return TRUE; } dkim_module_ctx->whitelist_ip = radix_create_compressed (); if ((value = rspamd_config_get_module_opt (cfg, "dkim", "symbol_reject")) != NULL) { dkim_module_ctx->symbol_reject = ucl_obj_tostring (value); } else { dkim_module_ctx->symbol_reject = DEFAULT_SYMBOL_REJECT; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "symbol_tempfail")) != NULL) { dkim_module_ctx->symbol_tempfail = ucl_obj_tostring (value); } else { dkim_module_ctx->symbol_tempfail = DEFAULT_SYMBOL_TEMPFAIL; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "symbol_allow")) != NULL) { dkim_module_ctx->symbol_allow = ucl_obj_tostring (value); } else { dkim_module_ctx->symbol_allow = DEFAULT_SYMBOL_ALLOW; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "dkim_cache_size")) != NULL) { cache_size = ucl_obj_toint (value); } else { cache_size = DEFAULT_CACHE_SIZE; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "dkim_cache_expire")) != NULL) { cache_expire = ucl_obj_todouble (value); } else { cache_expire = DEFAULT_CACHE_MAXAGE; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "time_jitter")) != NULL) { dkim_module_ctx->time_jitter = ucl_obj_todouble (value); } else { dkim_module_ctx->time_jitter = DEFAULT_TIME_JITTER; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "whitelist")) != NULL) { if (!rspamd_map_add (cfg, ucl_obj_tostring (value), "DKIM whitelist", rspamd_radix_read, rspamd_radix_fin, (void **)&dkim_module_ctx->whitelist_ip)) { radix_add_generic_iplist (ucl_obj_tostring (value), &dkim_module_ctx->whitelist_ip); } } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "domains")) != NULL) { if (!rspamd_map_add (cfg, ucl_obj_tostring (value), "DKIM domains", rspamd_kv_list_read, rspamd_kv_list_fin, (void **)&dkim_module_ctx->dkim_domains)) { msg_warn ("cannot load dkim domains list from %s", ucl_obj_tostring (value)); } else { got_trusted = TRUE; } } if (!got_trusted && (value = rspamd_config_get_module_opt (cfg, "dkim", "trusted_domains")) != NULL) { if (!rspamd_map_add (cfg, ucl_obj_tostring (value), "DKIM domains", rspamd_kv_list_read, rspamd_kv_list_fin, (void **)&dkim_module_ctx->dkim_domains)) { msg_warn ("cannot load dkim domains list from %s", ucl_obj_tostring (value)); } else { got_trusted = TRUE; } } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "strict_multiplier")) != NULL) { dkim_module_ctx->strict_multiplier = ucl_obj_toint (value); } else { dkim_module_ctx->strict_multiplier = 1; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "trusted_only")) != NULL) { dkim_module_ctx->trusted_only = ucl_obj_toboolean (value); } else { dkim_module_ctx->trusted_only = FALSE; } if ((value = rspamd_config_get_module_opt (cfg, "dkim", "skip_multi")) != NULL) { dkim_module_ctx->skip_multi = ucl_obj_toboolean (value); } else { dkim_module_ctx->skip_multi = FALSE; } if (dkim_module_ctx->trusted_only && !got_trusted) { msg_err ( "trusted_only option is set and no trusted domains are defined; disabling dkim module completely as it is useless in this case"); } else { cb_id = rspamd_symbols_cache_add_symbol_normal (cfg->cache, dkim_module_ctx->symbol_reject, 1, dkim_symbol_callback, NULL); rspamd_symbols_cache_add_symbol_virtual (cfg->cache, dkim_module_ctx->symbol_tempfail, 1, cb_id); rspamd_symbols_cache_add_symbol_virtual (cfg->cache, dkim_module_ctx->symbol_allow, 1, cb_id); dkim_module_ctx->dkim_hash = rspamd_lru_hash_new ( cache_size, cache_expire, g_free, (GDestroyNotify)rspamd_dkim_key_free); #ifndef HAVE_OPENSSL msg_warn ( "openssl is not found so dkim rsa check is disabled, only check body hash, it is NOT safe to trust these results"); #endif } return res; }
gint fuzzy_check_module_config (struct rspamd_config *cfg) { const ucl_object_t *value, *cur; gint res = TRUE, cb_id; if (!rspamd_config_is_module_enabled (cfg, "fuzzy_check")) { return TRUE; } if ((value = rspamd_config_get_module_opt (cfg, "fuzzy_check", "symbol")) != NULL) { fuzzy_module_ctx->default_symbol = ucl_obj_tostring (value); } else { fuzzy_module_ctx->default_symbol = DEFAULT_SYMBOL; } if ((value = rspamd_config_get_module_opt (cfg, "fuzzy_check", "min_length")) != NULL) { fuzzy_module_ctx->min_hash_len = ucl_obj_toint (value); } else { fuzzy_module_ctx->min_hash_len = 0; } if ((value = rspamd_config_get_module_opt (cfg, "fuzzy_check", "min_bytes")) != NULL) { fuzzy_module_ctx->min_bytes = ucl_obj_toint (value); } else { fuzzy_module_ctx->min_bytes = 0; } if ((value = rspamd_config_get_module_opt (cfg, "fuzzy_check", "min_height")) != NULL) { fuzzy_module_ctx->min_height = ucl_obj_toint (value); } else { fuzzy_module_ctx->min_height = 0; } if ((value = rspamd_config_get_module_opt (cfg, "fuzzy_check", "min_width")) != NULL) { fuzzy_module_ctx->min_width = ucl_obj_toint (value); } else { fuzzy_module_ctx->min_width = 0; } if ((value = rspamd_config_get_module_opt (cfg, "fuzzy_check", "timeout")) != NULL) { fuzzy_module_ctx->io_timeout = ucl_obj_todouble (value) * 1000; } else { fuzzy_module_ctx->io_timeout = DEFAULT_IO_TIMEOUT; } if ((value = rspamd_config_get_module_opt (cfg, "fuzzy_check", "retransmits")) != NULL) { fuzzy_module_ctx->retransmits = ucl_obj_toint (value); } else { fuzzy_module_ctx->retransmits = DEFAULT_RETRANSMITS; } if ((value = rspamd_config_get_module_opt (cfg, "fuzzy_check", "whitelist")) != NULL) { fuzzy_module_ctx->whitelist = radix_create_compressed (); if (!rspamd_map_add (cfg, ucl_obj_tostring (value), "Fuzzy whitelist", rspamd_radix_read, rspamd_radix_fin, (void **)&fuzzy_module_ctx->whitelist)) { radix_add_generic_iplist (ucl_obj_tostring (value), &fuzzy_module_ctx->whitelist); } } else { fuzzy_module_ctx->whitelist = NULL; } if ((value = rspamd_config_get_module_opt (cfg, "fuzzy_check", "rule")) != NULL) { cb_id = rspamd_symbols_cache_add_symbol (cfg->cache, "FUZZY_CALLBACK", 0, fuzzy_symbol_callback, NULL, SYMBOL_TYPE_CALLBACK|SYMBOL_TYPE_FINE, -1); LL_FOREACH (value, cur) { fuzzy_parse_rule (cfg, cur, cb_id); }
static gint fuzzy_parse_rule (struct rspamd_config *cfg, const ucl_object_t *obj, gint cb_id) { const ucl_object_t *value, *cur; struct fuzzy_rule *rule; ucl_object_iter_t it = NULL; const char *k = NULL; if (obj->type != UCL_OBJECT) { msg_err_config ("invalid rule definition"); return -1; } rule = fuzzy_rule_new (fuzzy_module_ctx->default_symbol, fuzzy_module_ctx->fuzzy_pool); if ((value = ucl_object_find_key (obj, "mime_types")) != NULL) { it = NULL; while ((cur = ucl_iterate_object (value, &it, value->type == UCL_ARRAY)) != NULL) { rule->mime_types = g_list_concat (rule->mime_types, parse_mime_types (ucl_obj_tostring (cur))); } } if (rule->mime_types != NULL) { rspamd_mempool_add_destructor (fuzzy_module_ctx->fuzzy_pool, (rspamd_mempool_destruct_t)g_list_free, rule->mime_types); } if ((value = ucl_object_find_key (obj, "max_score")) != NULL) { rule->max_score = ucl_obj_todouble (value); } if ((value = ucl_object_find_key (obj, "symbol")) != NULL) { rule->symbol = ucl_obj_tostring (value); } if ((value = ucl_object_find_key (obj, "read_only")) != NULL) { rule->read_only = ucl_obj_toboolean (value); } if ((value = ucl_object_find_key (obj, "skip_unknown")) != NULL) { rule->skip_unknown = ucl_obj_toboolean (value); } if ((value = ucl_object_find_key (obj, "servers")) != NULL) { rule->servers = rspamd_upstreams_create (); rspamd_mempool_add_destructor (fuzzy_module_ctx->fuzzy_pool, (rspamd_mempool_destruct_t)rspamd_upstreams_destroy, rule->servers); rspamd_upstreams_from_ucl (rule->servers, value, DEFAULT_PORT, NULL); } if ((value = ucl_object_find_key (obj, "fuzzy_map")) != NULL) { it = NULL; while ((cur = ucl_iterate_object (value, &it, true)) != NULL) { parse_flags (rule, cfg, cur, cb_id); } } if ((value = ucl_object_find_key (obj, "encryption_key")) != NULL) { /* Create key from user's input */ k = ucl_object_tostring (value); if (k == NULL || (rule->peer_key = rspamd_http_connection_make_peer_key (k)) == NULL) { msg_err_config ("bad encryption key value: %s", k); return -1; } rule->local_key = rspamd_http_connection_gen_key (); } if ((value = ucl_object_find_key (obj, "fuzzy_key")) != NULL) { /* Create key from user's input */ k = ucl_object_tostring (value); } /* Setup keys */ if (k == NULL) { /* Use some default key for all ops */ k = "rspamd"; } rule->hash_key = g_string_sized_new (BLAKE2B_KEYBYTES); blake2 (rule->hash_key->str, k, NULL, BLAKE2B_KEYBYTES, strlen (k), 0); rule->hash_key->len = BLAKE2B_KEYBYTES; if ((value = ucl_object_find_key (obj, "fuzzy_shingles_key")) != NULL) { k = ucl_object_tostring (value); } if (k == NULL) { k = "rspamd"; } rule->shingles_key = g_string_sized_new (16); blake2 (rule->shingles_key->str, k, NULL, 16, strlen (k), 0); rule->shingles_key->len = 16; if (rspamd_upstreams_count (rule->servers) == 0) { msg_err_config ("no servers defined for fuzzy rule with symbol: %s", rule->symbol); return -1; } else { fuzzy_module_ctx->fuzzy_rules = g_list_prepend ( fuzzy_module_ctx->fuzzy_rules, rule); if (rule->symbol != fuzzy_module_ctx->default_symbol) { rspamd_symbols_cache_add_symbol (cfg->cache, rule->symbol, 0, NULL, NULL, SYMBOL_TYPE_VIRTUAL|SYMBOL_TYPE_FINE, cb_id); } } rspamd_mempool_add_destructor (fuzzy_module_ctx->fuzzy_pool, fuzzy_free_rule, rule); return 0; }
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; }