diff options
author | Vsevolod Stakhov <vsevolod@rspamd.com> | 2023-08-17 12:44:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-17 12:44:51 +0100 |
commit | dbaf8c69895ec2a90a20dbf41b4fa474ac12910b (patch) | |
tree | b9ff352e71a6a46914859063e00999793c6ba7f6 /src | |
parent | e74199003982c88aea6367922042a7291bbe1bde (diff) | |
parent | 87c6b54923fb5bc8105d5adecf33b5f7fa926d65 (diff) | |
download | rspamd-dbaf8c69895ec2a90a20dbf41b4fa474ac12910b.tar.gz rspamd-dbaf8c69895ec2a90a20dbf41b4fa474ac12910b.zip |
Merge pull request #4573 from rspamd/cfg_utils_rework
[Project] Rewrite configuration utils in C++
Diffstat (limited to 'src')
39 files changed, 1856 insertions, 2046 deletions
diff --git a/src/controller.c b/src/controller.c index a6d8a7ca9..13e6794af 100644 --- a/src/controller.c +++ b/src/controller.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -870,6 +870,20 @@ rspamd_controller_handle_symbols(struct rspamd_http_connection_entry *conn_ent, return 0; } +static void +rspamd_controller_actions_cb(struct rspamd_action *act, void *cbd) +{ + ucl_object_t *top = (ucl_object_t *) cbd; + ucl_object_t *obj = ucl_object_typed_new(UCL_OBJECT); + ucl_object_insert_key(obj, + ucl_object_fromstring(act->name), + "action", 0, false); + ucl_object_insert_key(obj, + ucl_object_fromdouble(act->threshold), + "value", 0, false); + ucl_array_append(top, obj); +} + /* * Actions command handler: * request: /actions @@ -884,8 +898,7 @@ rspamd_controller_handle_actions(struct rspamd_http_connection_entry *conn_ent, struct rspamd_http_message *msg) { struct rspamd_controller_session *session = conn_ent->ud; - struct rspamd_action *act, *tmp; - ucl_object_t *obj, *top; + ucl_object_t *top; if (!rspamd_controller_check_password(conn_ent, session, msg, FALSE)) { return 0; @@ -893,18 +906,7 @@ rspamd_controller_handle_actions(struct rspamd_http_connection_entry *conn_ent, top = ucl_object_typed_new(UCL_ARRAY); - HASH_ITER(hh, session->cfg->actions, act, tmp) - { - obj = ucl_object_typed_new(UCL_OBJECT); - ucl_object_insert_key(obj, - ucl_object_fromstring(act->name), - "action", 0, false); - ucl_object_insert_key(obj, - ucl_object_fromdouble(act->threshold), - "value", 0, false); - ucl_array_append(top, obj); - } - + rspamd_config_actions_foreach(session->cfg, rspamd_controller_actions_cb, top); rspamd_controller_send_ucl(conn_ent, top); ucl_object_unref(top); @@ -2086,7 +2088,6 @@ rspamd_controller_handle_learn_common( task); task->fin_arg = conn_ent; task->http_conn = rspamd_http_connection_ref(conn_ent->conn); - ; task->sock = -1; session->task = task; @@ -2301,8 +2302,10 @@ rspamd_controller_handle_saveactions( score = ucl_object_todouble(cur); } - if ((isnan(session->cfg->actions[act].threshold) != isnan(score)) || - (session->cfg->actions[act].threshold != score)) { + struct rspamd_action *cfg_action = rspamd_config_get_action_by_type(ctx->cfg, act); + + if (cfg_action && ((isnan(cfg_action->threshold) != isnan(score)) || + (cfg_action->threshold != score))) { add_dynamic_action(ctx->cfg, DEFAULT_METRIC, act, score); added++; } diff --git a/src/fuzzy_storage.c b/src/fuzzy_storage.c index 0110ed8c2..21c5c271e 100644 --- a/src/fuzzy_storage.c +++ b/src/fuzzy_storage.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -61,7 +61,7 @@ worker_t fuzzy_worker = { "fuzzy", /* Name */ init_fuzzy, /* Init function */ start_fuzzy, /* Start function */ - RSPAMD_WORKER_HAS_SOCKET, + RSPAMD_WORKER_HAS_SOCKET | RSPAMD_WORKER_NO_STRICT_CONFIG, RSPAMD_WORKER_SOCKET_UDP, /* UDP socket */ RSPAMD_WORKER_VER /* Version info */ }; diff --git a/src/libmime/lang_detection.c b/src/libmime/lang_detection.c index 52221cd32..aa5447c8b 100644 --- a/src/libmime/lang_detection.c +++ b/src/libmime/lang_detection.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2017 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -800,7 +800,7 @@ rspamd_language_detector_init(struct rspamd_config *cfg) ucl_object_t *stop_words; bool prefer_fasttext = true; - section = ucl_object_lookup(cfg->rcl_obj, "lang_detection"); + section = ucl_object_lookup(cfg->cfg_ucl_obj, "lang_detection"); if (section != NULL) { elt = ucl_object_lookup(section, "languages"); diff --git a/src/libmime/lang_detection_fasttext.cxx b/src/libmime/lang_detection_fasttext.cxx index f06e8ccb6..a1490fc11 100644 --- a/src/libmime/lang_detection_fasttext.cxx +++ b/src/libmime/lang_detection_fasttext.cxx @@ -1,11 +1,11 @@ -/*- +/* * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -45,7 +45,7 @@ private: public: explicit fasttext_langdet(struct rspamd_config *cfg) { - const auto *ucl_obj = cfg->rcl_obj; + const auto *ucl_obj = cfg->cfg_ucl_obj; const auto *opts_section = ucl_object_find_key(ucl_obj, "lang_detection"); if (opts_section) { diff --git a/src/libmime/scan_result.c b/src/libmime/scan_result.c index a32c91280..080fc0d51 100644 --- a/src/libmime/scan_result.c +++ b/src/libmime/scan_result.c @@ -56,12 +56,25 @@ rspamd_scan_result_dtor(gpointer d) kh_destroy(rspamd_symbols_group_hash, r->sym_groups); } +static void +rspamd_metric_actions_foreach_cb(int i, struct rspamd_action *act, void *cbd) +{ + struct rspamd_scan_result *metric_res = (struct rspamd_scan_result *) cbd; + metric_res->actions_config[i].flags = RSPAMD_ACTION_RESULT_DEFAULT; + if (!(act->flags & RSPAMD_ACTION_NO_THRESHOLD)) { + metric_res->actions_config[i].cur_limit = act->threshold; + } + else { + metric_res->actions_config[i].flags |= RSPAMD_ACTION_RESULT_NO_THRESHOLD; + } + metric_res->actions_config[i].action = act; +} + struct rspamd_scan_result * rspamd_create_metric_result(struct rspamd_task *task, const gchar *name, gint lua_sym_cbref) { struct rspamd_scan_result *metric_res; - guint i; metric_res = rspamd_mempool_alloc0(task->task_pool, sizeof(struct rspamd_scan_result)); @@ -89,27 +102,11 @@ rspamd_create_metric_result(struct rspamd_task *task, } if (task->cfg) { - struct rspamd_action *act, *tmp; - + size_t nact = rspamd_config_actions_size(task->cfg); metric_res->actions_config = rspamd_mempool_alloc0(task->task_pool, - sizeof(struct rspamd_action_config) * HASH_COUNT(task->cfg->actions)); - i = 0; - - HASH_ITER(hh, task->cfg->actions, act, tmp) - { - metric_res->actions_config[i].flags = RSPAMD_ACTION_RESULT_DEFAULT; - if (!(act->flags & RSPAMD_ACTION_NO_THRESHOLD)) { - metric_res->actions_config[i].cur_limit = act->threshold; - } - else { - metric_res->actions_config[i].flags |= RSPAMD_ACTION_RESULT_NO_THRESHOLD; - } - metric_res->actions_config[i].action = act; - - i++; - } - - metric_res->nactions = i; + sizeof(struct rspamd_action_config) * nact); + rspamd_config_actions_foreach_enumerate(task->cfg, rspamd_metric_actions_foreach_cb, metric_res); + metric_res->nactions = nact; } rspamd_mempool_add_destructor(task->task_pool, diff --git a/src/libserver/CMakeLists.txt b/src/libserver/CMakeLists.txt index c4940f917..56cc2444d 100644 --- a/src/libserver/CMakeLists.txt +++ b/src/libserver/CMakeLists.txt @@ -1,49 +1,49 @@ # Librspamdserver ADD_SUBDIRECTORY(css) SET(LIBRSPAMDSERVERSRC - ${CMAKE_CURRENT_SOURCE_DIR}/cfg_utils.c - ${CMAKE_CURRENT_SOURCE_DIR}/cfg_rcl.c - ${CMAKE_CURRENT_SOURCE_DIR}/composites/composites.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/composites/composites_manager.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/dkim.c - ${CMAKE_CURRENT_SOURCE_DIR}/dns.c - ${CMAKE_CURRENT_SOURCE_DIR}/dynamic_cfg.c - ${CMAKE_CURRENT_SOURCE_DIR}/async_session.c - ${CMAKE_CURRENT_SOURCE_DIR}/fuzzy_backend/fuzzy_backend.c - ${CMAKE_CURRENT_SOURCE_DIR}/fuzzy_backend/fuzzy_backend_sqlite.c - ${CMAKE_CURRENT_SOURCE_DIR}/fuzzy_backend/fuzzy_backend_redis.c - ${CMAKE_CURRENT_SOURCE_DIR}/milter.c - ${CMAKE_CURRENT_SOURCE_DIR}/monitored.c - ${CMAKE_CURRENT_SOURCE_DIR}/protocol.c - ${CMAKE_CURRENT_SOURCE_DIR}/re_cache.c - ${CMAKE_CURRENT_SOURCE_DIR}/redis_pool.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/roll_history.c - ${CMAKE_CURRENT_SOURCE_DIR}/spf.c - ${CMAKE_CURRENT_SOURCE_DIR}/ssl_util.c - ${CMAKE_CURRENT_SOURCE_DIR}/symcache/symcache_impl.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/symcache/symcache_item.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/symcache/symcache_runtime.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/symcache/symcache_c.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/task.c - ${CMAKE_CURRENT_SOURCE_DIR}/url.c - ${CMAKE_CURRENT_SOURCE_DIR}/worker_util.c - ${CMAKE_CURRENT_SOURCE_DIR}/logger/logger.c - ${CMAKE_CURRENT_SOURCE_DIR}/logger/logger_file.c - ${CMAKE_CURRENT_SOURCE_DIR}/logger/logger_syslog.c - ${CMAKE_CURRENT_SOURCE_DIR}/logger/logger_console.c - ${CMAKE_CURRENT_SOURCE_DIR}/http/http_util.c - ${CMAKE_CURRENT_SOURCE_DIR}/http/http_message.c - ${CMAKE_CURRENT_SOURCE_DIR}/http/http_connection.c - ${CMAKE_CURRENT_SOURCE_DIR}/http/http_router.c - ${CMAKE_CURRENT_SOURCE_DIR}/http/http_context.c - ${CMAKE_CURRENT_SOURCE_DIR}/maps/map.c - ${CMAKE_CURRENT_SOURCE_DIR}/maps/map_helpers.c - ${CMAKE_CURRENT_SOURCE_DIR}/html/html_entities.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/html/html_url.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/html/html.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/html/html_tests.cxx - ${CMAKE_CURRENT_SOURCE_DIR}/hyperscan_tools.cxx - ${LIBCSSSRC}) + ${CMAKE_CURRENT_SOURCE_DIR}/cfg_utils.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/cfg_rcl.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/composites/composites.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/composites/composites_manager.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/dkim.c + ${CMAKE_CURRENT_SOURCE_DIR}/dns.c + ${CMAKE_CURRENT_SOURCE_DIR}/dynamic_cfg.c + ${CMAKE_CURRENT_SOURCE_DIR}/async_session.c + ${CMAKE_CURRENT_SOURCE_DIR}/fuzzy_backend/fuzzy_backend.c + ${CMAKE_CURRENT_SOURCE_DIR}/fuzzy_backend/fuzzy_backend_sqlite.c + ${CMAKE_CURRENT_SOURCE_DIR}/fuzzy_backend/fuzzy_backend_redis.c + ${CMAKE_CURRENT_SOURCE_DIR}/milter.c + ${CMAKE_CURRENT_SOURCE_DIR}/monitored.c + ${CMAKE_CURRENT_SOURCE_DIR}/protocol.c + ${CMAKE_CURRENT_SOURCE_DIR}/re_cache.c + ${CMAKE_CURRENT_SOURCE_DIR}/redis_pool.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/roll_history.c + ${CMAKE_CURRENT_SOURCE_DIR}/spf.c + ${CMAKE_CURRENT_SOURCE_DIR}/ssl_util.c + ${CMAKE_CURRENT_SOURCE_DIR}/symcache/symcache_impl.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/symcache/symcache_item.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/symcache/symcache_runtime.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/symcache/symcache_c.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/task.c + ${CMAKE_CURRENT_SOURCE_DIR}/url.c + ${CMAKE_CURRENT_SOURCE_DIR}/worker_util.c + ${CMAKE_CURRENT_SOURCE_DIR}/logger/logger.c + ${CMAKE_CURRENT_SOURCE_DIR}/logger/logger_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/logger/logger_syslog.c + ${CMAKE_CURRENT_SOURCE_DIR}/logger/logger_console.c + ${CMAKE_CURRENT_SOURCE_DIR}/http/http_util.c + ${CMAKE_CURRENT_SOURCE_DIR}/http/http_message.c + ${CMAKE_CURRENT_SOURCE_DIR}/http/http_connection.c + ${CMAKE_CURRENT_SOURCE_DIR}/http/http_router.c + ${CMAKE_CURRENT_SOURCE_DIR}/http/http_context.c + ${CMAKE_CURRENT_SOURCE_DIR}/maps/map.c + ${CMAKE_CURRENT_SOURCE_DIR}/maps/map_helpers.c + ${CMAKE_CURRENT_SOURCE_DIR}/html/html_entities.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/html/html_url.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/html/html.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/html/html_tests.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/hyperscan_tools.cxx + ${LIBCSSSRC}) # Librspamd-server SET(RSPAMD_SERVER ${LIBRSPAMDSERVERSRC} PARENT_SCOPE) diff --git a/src/libserver/cfg_file.h b/src/libserver/cfg_file.h index 9b09608f2..3f876ab23 100644 --- a/src/libserver/cfg_file.h +++ b/src/libserver/cfg_file.h @@ -1,11 +1,11 @@ -/*- - * Copyright 2016-2017 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -50,16 +50,6 @@ struct rspamd_cryptobox_pubkey; struct rspamd_dns_resolver; /** - * Types of rspamd bind lines - */ -enum rspamd_cred_type { - CRED_NORMAL, - CRED_CONTROL, - CRED_LMTP, - CRED_DELIVERY -}; - -/** * Logging type */ enum rspamd_log_type { @@ -94,17 +84,6 @@ struct script_module { gchar *digest; }; -/** - * Type of lua variable - */ -enum lua_var_type { - LUA_VAR_NUM, - LUA_VAR_BOOLEAN, - LUA_VAR_STRING, - LUA_VAR_FUNCTION, - LUA_VAR_UNKNOWN -}; - enum rspamd_symbol_group_flags { RSPAMD_SYMBOL_GROUP_NORMAL = 0u, RSPAMD_SYMBOL_GROUP_DISABLED = (1u << 0u), @@ -229,7 +208,7 @@ struct rspamd_worker_conf { guint64 rlimit_maxcore; /**< maximum core file size */ GHashTable *params; /**< params for worker */ GQueue *active_workers; /**< linked list of spawned workers */ - gpointer *ctx; /**< worker's context */ + gpointer ctx; /**< worker's context */ ucl_object_t *options; /**< other worker's options */ struct rspamd_worker_lua_script *scripts; /**< registered lua scripts */ gboolean enabled; @@ -324,6 +303,7 @@ struct rspamd_config_post_init_script { }; struct rspamd_lang_detector; +struct rspamd_rcl_sections_map; enum rspamd_config_settings_policy { RSPAMD_SETTINGS_POLICY_DEFAULT = 0, @@ -356,12 +336,12 @@ struct rspamd_config { #ifdef WITH_GPERF_TOOLS gchar *profile_path; #endif - gdouble unknown_weight; /**< weight of unknown symbols */ - gdouble grow_factor; /**< grow factor for metric */ - GHashTable *symbols; /**< weights of symbols in metric */ - const gchar *subject; /**< subject rewrite string */ - GHashTable *groups; /**< groups of symbols */ - struct rspamd_action *actions; /**< all actions of the metric */ + gdouble unknown_weight; /**< weight of unknown symbols */ + gdouble grow_factor; /**< grow factor for metric */ + GHashTable *symbols; /**< weights of symbols in metric */ + const gchar *subject; /**< subject rewrite string */ + GHashTable *groups; /**< groups of symbols */ + void *actions; /**< all actions of the metric (opaque type) */ gboolean one_shot_mode; /**< rules add only one symbol */ gboolean check_text_attachements; /**< check text attachements as text */ @@ -412,21 +392,21 @@ struct rspamd_config { GList *script_modules; /**< linked list of script modules to load */ GHashTable *explicit_modules; /**< modules that should be always loaded */ - GList *filters; /**< linked list of all filters */ - GList *workers; /**< linked list of all workers params */ - GHashTable *wrk_parsers; /**< hash for worker config parsers, indexed by worker quarks */ - ucl_object_t *rcl_obj; /**< rcl object */ - ucl_object_t *config_comments; /**< comments saved from the config */ - ucl_object_t *doc_strings; /**< documentation strings for config options */ - GPtrArray *c_modules; /**< list of C modules */ - void *composites_manager; /**< hash of composite symbols indexed by its name */ - GList *classifiers; /**< list of all classifiers defined */ - GList *statfiles; /**< list of all statfiles in config file order */ - GHashTable *classifiers_symbols; /**< hashtable indexed by symbol name of classifiers */ - GHashTable *cfg_params; /**< all cfg params indexed by its name in this structure */ - gchar *dynamic_conf; /**< path to dynamic configuration */ - ucl_object_t *current_dynamic_conf; /**< currently loaded dynamic configuration */ - gint clock_res; /**< resolution of clock used */ + GList *filters; /**< linked list of all filters */ + GList *workers; /**< linked list of all workers params */ + struct rspamd_rcl_sections_map *rcl_top_section; /**< top section for RCL config */ + ucl_object_t *cfg_ucl_obj; /**< ucl object */ + ucl_object_t *config_comments; /**< comments saved from the config */ + ucl_object_t *doc_strings; /**< documentation strings for config options */ + GPtrArray *c_modules; /**< list of C modules */ + void *composites_manager; /**< hash of composite symbols indexed by its name */ + GList *classifiers; /**< list of all classifiers defined */ + GList *statfiles; /**< list of all statfiles in config file order */ + GHashTable *classifiers_symbols; /**< hashtable indexed by symbol name of classifiers */ + GHashTable *cfg_params; /**< all cfg params indexed by its name in this structure */ + gchar *dynamic_conf; /**< path to dynamic configuration */ + ucl_object_t *current_dynamic_conf; /**< currently loaded dynamic configuration */ + gint clock_res; /**< resolution of clock used */ GList *maps; /**< maps active */ gdouble map_timeout; /**< maps watch timeout */ @@ -487,7 +467,7 @@ struct rspamd_config { struct rspamd_external_libs_ctx *libs_ctx; /**< context for external libraries */ struct rspamd_monitored_ctx *monitored_ctx; /**< context for monitored resources */ - struct rspamd_redis_pool *redis_pool; /**< redis connection pool */ + void *redis_pool; /**< redis connection pool */ struct rspamd_re_cache *re_cache; /**< static regexp cache */ @@ -730,7 +710,7 @@ gboolean rspamd_config_is_enabled_from_ucl(rspamd_mempool_t *pool, /* * Get action from a string */ -gboolean rspamd_action_from_str(const gchar *data, gint *result); +gboolean rspamd_action_from_str(const gchar *data, enum rspamd_action_type *result); /* * Return textual representation of action enumeration @@ -739,11 +719,6 @@ const gchar *rspamd_action_to_str(enum rspamd_action_type action); const gchar *rspamd_action_to_str_alt(enum rspamd_action_type action); -/* - * Resort all actions (needed to operate with thresholds) - */ -void rspamd_actions_sort(struct rspamd_config *cfg); - /** * Parse radix tree or radix map from ucl object * @param cfg configuration object @@ -811,6 +786,32 @@ struct rspamd_action *rspamd_config_get_action(struct rspamd_config *cfg, struct rspamd_action *rspamd_config_get_action_by_type(struct rspamd_config *cfg, enum rspamd_action_type type); +/** + * Iterate over all actions + * @param cfg + * @param func + * @param data + */ +void rspamd_config_actions_foreach(struct rspamd_config *cfg, + void (*func)(struct rspamd_action *act, void *d), + void *data); +/** + * Iterate over all actions with index + * @param cfg + * @param func + * @param data + */ +void rspamd_config_actions_foreach_enumerate(struct rspamd_config *cfg, + void (*func)(int idx, struct rspamd_action *act, void *d), + void *data); + +/** + * Returns number of actions defined in the config + * @param cfg + * @return + */ +gsize rspamd_config_actions_size(struct rspamd_config *cfg); + int rspamd_config_ev_backend_get(struct rspamd_config *cfg); const gchar *rspamd_config_ev_backend_to_string(int ev_backend, gboolean *effective); @@ -855,9 +856,9 @@ gboolean rspamd_config_libs(struct rspamd_external_libs_ctx *ctx, cfg->cfg_pool->tag.tagname, cfg->checksum, \ RSPAMD_LOG_FUNC, \ __VA_ARGS__) -#define msg_err_config_forced(...) rspamd_default_log_function(G_LOG_LEVEL_CRITICAL | RSPAMD_LOG_FORCED, \ - cfg->cfg_pool->tag.tagname, cfg->checksum, \ - RSPAMD_LOG_FUNC, \ +#define msg_err_config_forced(...) rspamd_default_log_function((gint) G_LOG_LEVEL_CRITICAL | (gint) RSPAMD_LOG_FORCED, \ + cfg->cfg_pool->tag.tagname, cfg->checksum, \ + RSPAMD_LOG_FUNC, \ __VA_ARGS__) #define msg_warn_config(...) rspamd_default_log_function(G_LOG_LEVEL_WARNING, \ cfg->cfg_pool->tag.tagname, cfg->checksum, \ diff --git a/src/libserver/cfg_file_private.h b/src/libserver/cfg_file_private.h index d221e8427..8c9fc6539 100644 --- a/src/libserver/cfg_file_private.h +++ b/src/libserver/cfg_file_private.h @@ -1,11 +1,11 @@ -/*- - * Copyright 2019 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,9 +18,6 @@ #define RSPAMD_CFG_FILE_PRIVATE_H #include "cfg_file.h" -#include "../../contrib/mumhash/mum.h" -#define HASH_CASELESS -#include "uthash_strcase.h" #ifdef __cplusplus extern "C" { @@ -31,12 +28,10 @@ extern "C" { */ struct rspamd_action { enum rspamd_action_type action_type; - enum rspamd_action_flags flags; + int flags; /* enum rspamd_action_flags */ guint priority; - gint lua_handler_ref; /* If special handling is needed */ gdouble threshold; gchar *name; - struct UT_hash_handle hh; /* Index by name */ }; #ifdef __cplusplus diff --git a/src/libserver/cfg_rcl.c b/src/libserver/cfg_rcl.cxx index 8267a4bc8..134cdec98 100644 --- a/src/libserver/cfg_rcl.c +++ b/src/libserver/cfg_rcl.cxx @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +#include "lua/lua_common.h" #include "cfg_rcl.h" #include "rspamd.h" #include "cfg_file_private.h" #include "utlist.h" #include "cfg_file.h" -#include "lua/lua_common.h" #include "expression.h" #include "src/libserver/composites/composites.h" #include "libserver/worker_util.h" @@ -28,59 +29,85 @@ #include "libmime/email_addr.h" #include "libmime/lang_detection.h" +#include <string> +#include <filesystem> +#include <memory> +#include "contrib/ankerl/unordered_dense.h" +#include "fmt/core.h" +#include "libutil/cxx/util.hxx" +#include "libutil/cxx/file_util.hxx" +#include "frozen/unordered_set.h" +#include "frozen/string.h" + #ifdef HAVE_SYSLOG_H #include <syslog.h> #endif -#include <math.h> +#include <cmath> struct rspamd_rcl_default_handler_data { struct rspamd_rcl_struct_parser pd; - gchar *key; + std::string key; rspamd_rcl_default_handler_t handler; - UT_hash_handle hh; }; -struct rspamd_rcl_section { - const gchar *name; /**< name of section */ - const gchar *key_attr; - const gchar *default_key; - rspamd_rcl_handler_t handler; /**< handler of section attributes */ - enum ucl_type type; /**< type of attribute */ - gboolean required; /**< whether this param is required */ - gboolean strict_type; /**< whether we need strict type */ - UT_hash_handle hh; /** hash handle */ - struct rspamd_rcl_section *subsections; /**< hash table of subsections */ - struct rspamd_rcl_default_handler_data *default_parser; /**< generic parsing fields */ - rspamd_rcl_section_fin_t fin; /** called at the end of section parsing */ - gpointer fin_ud; - ucl_object_t *doc_ref; /**< reference to the section's documentation */ -}; +struct rspamd_rcl_sections_map; -struct rspamd_worker_param_key { - const gchar *name; - gpointer ptr; +struct rspamd_rcl_section { + struct rspamd_rcl_sections_map *top{}; + std::string name; /**< name of section */ + std::optional<std::string> key_attr; + std::optional<std::string> default_key; + rspamd_rcl_handler_t handler{}; /**< handler of section attributes */ + enum ucl_type type; /**< type of attribute */ + bool required{}; /**< whether this param is required */ + bool strict_type{}; /**< whether we need strict type */ + mutable bool processed{}; /**< whether this section was processed */ + ankerl::unordered_dense::map<std::string, std::shared_ptr<struct rspamd_rcl_section>> subsections; + ankerl::unordered_dense::map<std::string, struct rspamd_rcl_default_handler_data> default_parser; /**< generic parsing fields */ + rspamd_rcl_section_fin_t fin{}; /** called at the end of section parsing */ + gpointer fin_ud{}; + ucl_object_t *doc_ref{}; /**< reference to the section's documentation */ }; struct rspamd_worker_param_parser { rspamd_rcl_default_handler_t handler; /**< handler function */ struct rspamd_rcl_struct_parser parser; /**< parser attributes */ - - struct rspamd_worker_param_key key; }; struct rspamd_worker_cfg_parser { - GHashTable *parsers; /**< parsers hash */ + struct pair_hash { + using is_avalanching = void; + template<class T1, class T2> + std::size_t operator()(const std::pair<T1, T2> &pair) const + { + return ankerl::unordered_dense::hash<T1>()(pair.first) ^ ankerl::unordered_dense::hash<T2>()(pair.second); + } + }; + ankerl::unordered_dense::map<std::pair<std::string, gpointer>, + rspamd_worker_param_parser, pair_hash> + parsers; /**< parsers hash */ gint type; /**< workers quark */ - gboolean (*def_obj_parser)(ucl_object_t *obj, gpointer ud); /**< - default object parser */ + gboolean (*def_obj_parser)(ucl_object_t *obj, gpointer ud); /**< default object parser */ gpointer def_ud; }; -static gboolean rspamd_rcl_process_section(struct rspamd_config *cfg, - struct rspamd_rcl_section *sec, - gpointer ptr, const ucl_object_t *obj, rspamd_mempool_t *pool, - GError **err); +struct rspamd_rcl_sections_map { + ankerl::unordered_dense::map<std::string, std::shared_ptr<struct rspamd_rcl_section>> sections; + std::vector<std::shared_ptr<struct rspamd_rcl_section>> sections_order; + ankerl::unordered_dense::map<int, struct rspamd_worker_cfg_parser> workers_parser; + ankerl::unordered_dense::set<std::string> lua_modules_seen; +}; + +static bool rspamd_rcl_process_section(struct rspamd_config *cfg, + const struct rspamd_rcl_section &sec, + gpointer ptr, const ucl_object_t *obj, rspamd_mempool_t *pool, + GError **err); +static bool +rspamd_rcl_section_parse_defaults(struct rspamd_config *cfg, + const struct rspamd_rcl_section §ion, + rspamd_mempool_t *pool, const ucl_object_t *obj, gpointer ptr, + GError **err); /* * Common section handlers @@ -91,15 +118,15 @@ rspamd_rcl_logging_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, GError **err) { const ucl_object_t *val; - const gchar *facility = NULL, *log_type = NULL, *log_level = NULL; - struct rspamd_config *cfg = ud; + const gchar *facility = nullptr, *log_type = nullptr, *log_level = nullptr; + auto *cfg = (struct rspamd_config *) ud; val = ucl_object_lookup(obj, "type"); - if (val != NULL && ucl_object_tostring_safe(val, &log_type)) { + if (val != nullptr && ucl_object_tostring_safe(val, &log_type)) { if (g_ascii_strcasecmp(log_type, "file") == 0) { /* Need to get filename */ val = ucl_object_lookup(obj, "filename"); - if (val == NULL || val->type != UCL_STRING) { + if (val == nullptr || val->type != UCL_STRING) { g_set_error(err, CFG_RCL_ERROR, ENOENT, @@ -116,7 +143,7 @@ rspamd_rcl_logging_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, cfg->log_facility = LOG_DAEMON; cfg->log_type = RSPAMD_LOG_SYSLOG; val = ucl_object_lookup(obj, "facility"); - if (val != NULL && ucl_object_tostring_safe(val, &facility)) { + if (val != nullptr && ucl_object_tostring_safe(val, &facility)) { if (g_ascii_strcasecmp(facility, "LOG_AUTH") == 0 || g_ascii_strcasecmp(facility, "auth") == 0) { cfg->log_facility = LOG_AUTH; @@ -202,7 +229,7 @@ rspamd_rcl_logging_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, /* Handle log level */ val = ucl_object_lookup(obj, "level"); - if (val != NULL && ucl_object_tostring_safe(val, &log_level)) { + if (val != nullptr && ucl_object_tostring_safe(val, &log_level)) { if (g_ascii_strcasecmp(log_level, "error") == 0) { cfg->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL; } @@ -234,17 +261,17 @@ rspamd_rcl_logging_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } /* Handle flags */ - val = ucl_object_lookup_any(obj, "color", "log_color", NULL); + val = ucl_object_lookup_any(obj, "color", "log_color", nullptr); if (val && ucl_object_toboolean(val)) { cfg->log_flags |= RSPAMD_LOG_FLAG_COLOR; } - val = ucl_object_lookup_any(obj, "severity", "log_severity", NULL); + val = ucl_object_lookup_any(obj, "severity", "log_severity", nullptr); if (val && ucl_object_toboolean(val)) { cfg->log_flags |= RSPAMD_LOG_FLAG_SEVERITY; } - val = ucl_object_lookup_any(obj, "systemd", "log_systemd", NULL); + val = ucl_object_lookup_any(obj, "systemd", "log_systemd", nullptr); if (val && ucl_object_toboolean(val)) { cfg->log_flags |= RSPAMD_LOG_FLAG_SYSTEMD; } @@ -254,13 +281,13 @@ rspamd_rcl_logging_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, cfg->log_flags |= RSPAMD_LOG_FLAG_RE_CACHE; } - val = ucl_object_lookup_any(obj, "usec", "log_usec", NULL); + val = ucl_object_lookup_any(obj, "usec", "log_usec", nullptr); if (val && ucl_object_toboolean(val)) { cfg->log_flags |= RSPAMD_LOG_FLAG_USEC; } - return rspamd_rcl_section_parse_defaults(cfg, section, cfg->cfg_pool, obj, - cfg, err); + return rspamd_rcl_section_parse_defaults(cfg, *section, cfg->cfg_pool, obj, + (void *) cfg, err); } static gboolean @@ -269,40 +296,39 @@ rspamd_rcl_options_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, struct rspamd_rcl_section *section, GError **err) { const ucl_object_t *dns, *upstream, *neighbours; - struct rspamd_config *cfg = ud; - struct rspamd_rcl_section *dns_section, *upstream_section, *neighbours_section; + auto *cfg = (struct rspamd_config *) ud; - HASH_FIND_STR(section->subsections, "dns", dns_section); + auto maybe_subsection = rspamd::find_map(section->subsections, "dns"); dns = ucl_object_lookup(obj, "dns"); - if (dns_section != NULL && dns != NULL) { + if (maybe_subsection && dns != nullptr) { if (!rspamd_rcl_section_parse_defaults(cfg, - dns_section, cfg->cfg_pool, dns, + *maybe_subsection.value().get(), cfg->cfg_pool, dns, cfg, err)) { return FALSE; } } - HASH_FIND_STR(section->subsections, "upstream", upstream_section); + maybe_subsection = rspamd::find_map(section->subsections, "upstream"); - upstream = ucl_object_lookup_any(obj, "upstream", "upstreams", NULL); - if (upstream_section != NULL && upstream != NULL) { + upstream = ucl_object_lookup_any(obj, "upstream", "upstreams", nullptr); + if (maybe_subsection && upstream != nullptr) { if (!rspamd_rcl_section_parse_defaults(cfg, - upstream_section, cfg->cfg_pool, + *maybe_subsection.value().get(), cfg->cfg_pool, upstream, cfg, err)) { return FALSE; } } - HASH_FIND_STR(section->subsections, "neighbours", neighbours_section); + maybe_subsection = rspamd::find_map(section->subsections, "neighbours"); neighbours = ucl_object_lookup(obj, "neighbours"); - if (neighbours_section != NULL && neighbours != NULL) { + if (maybe_subsection && neighbours != nullptr) { const ucl_object_t *cur; LL_FOREACH(neighbours, cur) { - if (!rspamd_rcl_process_section(cfg, neighbours_section, cfg, cur, + if (!rspamd_rcl_process_section(cfg, *maybe_subsection.value().get(), cfg, cur, pool, err)) { return FALSE; } @@ -310,7 +336,7 @@ rspamd_rcl_options_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } if (rspamd_rcl_section_parse_defaults(cfg, - section, cfg->cfg_pool, obj, + *section, cfg->cfg_pool, obj, cfg, err)) { /* We need to init this early */ rspamd_multipattern_library_init(cfg->hs_cache_dir); @@ -331,27 +357,23 @@ rspamd_rcl_group_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, const gchar *key, gpointer ud, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_config *cfg = ud; - struct rspamd_symbols_group *gr; - const ucl_object_t *val, *elt; - struct rspamd_rcl_section *subsection; - struct rspamd_rcl_symbol_data sd; - const gchar *description = NULL; + auto *cfg = static_cast<rspamd_config *>(ud); + const gchar *description = nullptr; - g_assert(key != NULL); + g_assert(key != nullptr); - gr = g_hash_table_lookup(cfg->groups, key); + auto *gr = static_cast<rspamd_symbols_group *>(g_hash_table_lookup(cfg->groups, key)); - if (gr == NULL) { + if (gr == nullptr) { gr = rspamd_config_new_group(cfg, key); } - if (!rspamd_rcl_section_parse_defaults(cfg, section, pool, obj, + if (!rspamd_rcl_section_parse_defaults(cfg, *section, pool, obj, gr, err)) { return FALSE; } - if ((elt = ucl_object_lookup(obj, "one_shot")) != NULL) { + if (const auto *elt = ucl_object_lookup(obj, "one_shot"); elt != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, CFG_RCL_ERROR, @@ -366,7 +388,7 @@ rspamd_rcl_group_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } } - if ((elt = ucl_object_lookup(obj, "disabled")) != NULL) { + if (const auto *elt = ucl_object_lookup(obj, "disabled"); elt != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, CFG_RCL_ERROR, @@ -381,7 +403,7 @@ rspamd_rcl_group_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } } - if ((elt = ucl_object_lookup(obj, "enabled")) != NULL) { + if (const auto *elt = ucl_object_lookup(obj, "enabled"); elt != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, CFG_RCL_ERROR, @@ -396,7 +418,7 @@ rspamd_rcl_group_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } } - if ((elt = ucl_object_lookup(obj, "public")) != NULL) { + if (const auto *elt = ucl_object_lookup(obj, "public"); elt != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, CFG_RCL_ERROR, @@ -411,7 +433,7 @@ rspamd_rcl_group_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } } - if ((elt = ucl_object_lookup(obj, "private")) != NULL) { + if (const auto *elt = ucl_object_lookup(obj, "private"); elt != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, CFG_RCL_ERROR, @@ -426,23 +448,25 @@ rspamd_rcl_group_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } } - elt = ucl_object_lookup(obj, "description"); - if (elt) { + + if (const auto *elt = ucl_object_lookup(obj, "description"); elt != nullptr) { description = ucl_object_tostring(elt); gr->description = rspamd_mempool_strdup(cfg->cfg_pool, description); } - sd.gr = gr; - sd.cfg = cfg; + struct rspamd_rcl_symbol_data sd = { + .gr = gr, + .cfg = cfg, + }; /* Handle symbols */ - val = ucl_object_lookup(obj, "symbols"); - if (val != NULL && ucl_object_type(val) == UCL_OBJECT) { - HASH_FIND_STR(section->subsections, "symbols", subsection); - g_assert(subsection != NULL); - if (!rspamd_rcl_process_section(cfg, subsection, &sd, val, + if (const auto *val = ucl_object_lookup(obj, "symbols"); val != nullptr && ucl_object_type(val) == UCL_OBJECT) { + auto subsection = rspamd::find_map(section->subsections, "symbols"); + + g_assert(subsection.has_value()); + if (!rspamd_rcl_process_section(cfg, *subsection.value().get(), &sd, val, pool, err)) { return FALSE; @@ -457,18 +481,18 @@ rspamd_rcl_symbol_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, const gchar *key, gpointer ud, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_symbol_data *sd = ud; + auto *sd = static_cast<rspamd_rcl_symbol_data *>(ud); struct rspamd_config *cfg; const ucl_object_t *elt; - const gchar *description = NULL; + const gchar *description = nullptr; gdouble score = NAN; guint priority = 1, flags = 0; gint nshots = 0; - g_assert(key != NULL); + g_assert(key != nullptr); cfg = sd->cfg; - if ((elt = ucl_object_lookup(obj, "one_shot")) != NULL) { + if ((elt = ucl_object_lookup(obj, "one_shot")) != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, CFG_RCL_ERROR, @@ -483,7 +507,7 @@ rspamd_rcl_symbol_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } } - if ((elt = ucl_object_lookup(obj, "any_shot")) != NULL) { + if ((elt = ucl_object_lookup(obj, "any_shot")) != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, CFG_RCL_ERROR, @@ -498,7 +522,7 @@ rspamd_rcl_symbol_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } } - if ((elt = ucl_object_lookup(obj, "one_param")) != NULL) { + if ((elt = ucl_object_lookup(obj, "one_param")) != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, CFG_RCL_ERROR, @@ -514,7 +538,7 @@ rspamd_rcl_symbol_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } } - if ((elt = ucl_object_lookup(obj, "ignore")) != NULL) { + if ((elt = ucl_object_lookup(obj, "ignore")) != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, CFG_RCL_ERROR, @@ -530,7 +554,7 @@ rspamd_rcl_symbol_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } } - if ((elt = ucl_object_lookup(obj, "enabled")) != NULL) { + if ((elt = ucl_object_lookup(obj, "enabled")) != nullptr) { if (ucl_object_type(elt) != UCL_BOOLEAN) { g_set_error(err, CFG_RCL_ERROR, @@ -546,7 +570,7 @@ rspamd_rcl_symbol_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } } - if ((elt = ucl_object_lookup(obj, "nshots")) != NULL) { + if ((elt = ucl_object_lookup(obj, "nshots")) != nullptr) { if (ucl_object_type(elt) != UCL_FLOAT && ucl_object_type(elt) != UCL_INT) { g_set_error(err, CFG_RCL_ERROR, @@ -560,7 +584,7 @@ rspamd_rcl_symbol_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, nshots = ucl_object_toint(elt); } - elt = ucl_object_lookup_any(obj, "score", "weight", NULL); + elt = ucl_object_lookup_any(obj, "score", "weight", nullptr); if (elt) { if (ucl_object_type(elt) != UCL_FLOAT && ucl_object_type(elt) != UCL_INT) { g_set_error(err, @@ -604,7 +628,7 @@ rspamd_rcl_symbol_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } else { rspamd_config_add_symbol(cfg, key, score, - description, NULL, flags, priority, nshots); + description, nullptr, flags, priority, nshots); } elt = ucl_object_lookup(obj, "groups"); @@ -615,7 +639,7 @@ rspamd_rcl_symbol_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, gr_it = ucl_object_iterate_new(elt); - while ((cur_gr = ucl_object_iterate_safe(gr_it, true)) != NULL) { + while ((cur_gr = ucl_object_iterate_safe(gr_it, true)) != nullptr) { rspamd_config_add_symbol_group(cfg, key, ucl_object_tostring(cur_gr)); } @@ -631,13 +655,13 @@ rspamd_rcl_actions_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, const gchar *key, gpointer ud, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_config *cfg = ud; + auto *cfg = static_cast<rspamd_config *>(ud); const ucl_object_t *cur; ucl_object_iter_t it; it = ucl_object_iterate_new(obj); - while ((cur = ucl_object_iterate_safe(it, true)) != NULL) { + while ((cur = ucl_object_iterate_safe(it, true)) != nullptr) { gint type = ucl_object_type(cur); if (type == UCL_NULL) { @@ -646,13 +670,12 @@ rspamd_rcl_actions_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } else if (type == UCL_OBJECT || type == UCL_FLOAT || type == UCL_INT) { /* Exceptions */ - struct rspamd_rcl_default_handler_data *sec_cur, *sec_tmp; - gboolean default_elt = FALSE; + auto default_elt = false; - HASH_ITER(hh, section->default_parser, sec_cur, sec_tmp) - { - if (strcmp(ucl_object_key(cur), sec_cur->key) == 0) { - default_elt = TRUE; + for (const auto &[name, def_elt]: section->default_parser) { + if (def_elt.key == ucl_object_key(cur)) { + default_elt = true; + break; } } @@ -678,60 +701,60 @@ rspamd_rcl_actions_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, ucl_object_iterate_free(it); - return rspamd_rcl_section_parse_defaults(cfg, section, pool, obj, cfg, err); + return rspamd_rcl_section_parse_defaults(cfg, *section, pool, obj, cfg, err); } - +constexpr const auto known_worker_attributes = frozen::make_unordered_set<frozen::string>({ + "bind_socket", + "listen", + "bind", + "count", + "max_files", + "max_core", + "enabled", +}); static gboolean rspamd_rcl_worker_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, const gchar *key, gpointer ud, struct rspamd_rcl_section *section, GError **err) { - const ucl_object_t *val, *cur, *cur_obj; - ucl_object_t *robj; - ucl_object_iter_t it = NULL; - const gchar *worker_type, *worker_bind; - struct rspamd_config *cfg = ud; - GQuark qtype; - struct rspamd_worker_conf *wrk; - struct rspamd_worker_cfg_parser *wparser; - struct rspamd_worker_param_parser *whandler; - struct rspamd_worker_param_key srch; - - g_assert(key != NULL); - worker_type = key; - - qtype = g_quark_try_string(worker_type); - if (qtype != 0) { - wrk = rspamd_config_new_worker(cfg, NULL); - wrk->options = ucl_object_copy(obj); - wrk->worker = rspamd_get_worker_by_type(cfg, qtype); - - if (wrk->worker == NULL) { - g_set_error(err, - CFG_RCL_ERROR, - EINVAL, - "unknown worker type: %s", - worker_type); - return FALSE; - } + auto *cfg = static_cast<rspamd_config *>(ud); - wrk->type = qtype; + g_assert(key != nullptr); + const auto *worker_type = key; - if (wrk->worker->worker_init_func) { - wrk->ctx = wrk->worker->worker_init_func(cfg); - } - } - else { + auto qtype = g_quark_try_string(worker_type); + if (qtype == 0) { msg_err_config("unknown worker type: %s", worker_type); - return TRUE; + return FALSE; } - val = ucl_object_lookup_any(obj, "bind_socket", "listen", "bind", NULL); + auto *wrk = rspamd_config_new_worker(cfg, nullptr); + wrk->options = ucl_object_copy(obj); + wrk->worker = rspamd_get_worker_by_type(cfg, qtype); + + if (wrk->worker == nullptr) { + g_set_error(err, + CFG_RCL_ERROR, + EINVAL, + "unknown worker type: %s", + worker_type); + return FALSE; + } + + wrk->type = qtype; + + if (wrk->worker->worker_init_func) { + wrk->ctx = wrk->worker->worker_init_func(cfg); + } + + const auto *val = ucl_object_lookup_any(obj, "bind_socket", "listen", "bind", nullptr); /* This name is more logical */ - if (val != NULL) { - it = ucl_object_iterate_new(val); + if (val != nullptr) { + auto it = ucl_object_iterate_new(val); + const ucl_object_t *cur; + const char *worker_bind = nullptr; - while ((cur = ucl_object_iterate_safe(it, true)) != NULL) { + while ((cur = ucl_object_iterate_safe(it, true)) != nullptr) { if (!ucl_object_tostring_safe(cur, &worker_bind)) { continue; } @@ -749,49 +772,56 @@ rspamd_rcl_worker_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, ucl_object_iterate_free(it); } - if (!rspamd_rcl_section_parse_defaults(cfg, section, cfg->cfg_pool, obj, + if (!rspamd_rcl_section_parse_defaults(cfg, *section, cfg->cfg_pool, obj, wrk, err)) { return FALSE; } /* Parse other attributes */ - wparser = g_hash_table_lookup(cfg->wrk_parsers, &qtype); + auto maybe_wparser = rspamd::find_map(section->top->workers_parser, wrk->type); - if (wparser != NULL && obj->type == UCL_OBJECT) { - it = ucl_object_iterate_new(obj); + if (maybe_wparser && obj->type == UCL_OBJECT) { + auto &wparser = maybe_wparser.value().get(); + auto it = ucl_object_iterate_new(obj); + const ucl_object_t *cur; - while ((cur = ucl_object_iterate_full(it, UCL_ITERATE_EXPLICIT)) != NULL) { - srch.name = ucl_object_key(cur); - srch.ptr = wrk->ctx; /* XXX: is it valid? Update! no, it is not valid, omfg... */ - whandler = g_hash_table_lookup(wparser->parsers, &srch); + while ((cur = ucl_object_iterate_full(it, UCL_ITERATE_EXPLICIT)) != nullptr) { + auto srch = std::make_pair(ucl_object_key(cur), (gpointer) wrk->ctx); + auto maybe_specific = rspamd::find_map(wparser.parsers, srch); - if (whandler != NULL) { + if (maybe_specific) { + auto &whandler = maybe_specific.value().get(); + const ucl_object_t *cur_obj; LL_FOREACH(cur, cur_obj) { - if (!whandler->handler(cfg->cfg_pool, - cur_obj, - &whandler->parser, - section, - err)) { + if (!whandler.handler(cfg->cfg_pool, + cur_obj, + (void *) &whandler.parser, + section, + err)) { ucl_object_iterate_free(it); return FALSE; } - if (!(whandler->parser.flags & RSPAMD_CL_FLAG_MULTIPLE)) { + if (!(whandler.parser.flags & RSPAMD_CL_FLAG_MULTIPLE)) { break; } } } + else if (!(wrk->worker->flags & RSPAMD_WORKER_NO_STRICT_CONFIG) && + known_worker_attributes.find(std::string_view{ucl_object_key(cur)}) == known_worker_attributes.end()) { + msg_warn_config("unknown worker attribute: %s; worker type: %s", ucl_object_key(cur), worker_type); + } } ucl_object_iterate_free(it); - if (wparser->def_obj_parser != NULL) { - robj = ucl_object_ref(obj); + if (wparser.def_obj_parser != nullptr) { + auto *robj = ucl_object_ref(obj); - if (!wparser->def_obj_parser(robj, wparser->def_ud)) { + if (!wparser.def_obj_parser(robj, wparser.def_ud)) { ucl_object_unref(robj); return FALSE; @@ -811,38 +841,35 @@ rspamd_rcl_lua_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, const gchar *key, gpointer ud, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_config *cfg = ud; - const gchar *lua_src = rspamd_mempool_strdup(pool, - ucl_object_tostring(obj)); - gchar *cur_dir, *lua_dir, *lua_file; - lua_State *L = cfg->lua_state; - gint err_idx; - - lua_dir = g_path_get_dirname(lua_src); - lua_file = g_path_get_basename(lua_src); - - if (lua_dir && lua_file) { - cur_dir = g_malloc(PATH_MAX); - if (getcwd(cur_dir, PATH_MAX) != NULL && chdir(lua_dir) != -1) { + namespace fs = std::filesystem; + auto *cfg = static_cast<rspamd_config *>(ud); + auto lua_src = fs::path{ucl_object_tostring(obj)}; + auto *L = RSPAMD_LUA_CFG_STATE(cfg); + std::error_code ec1; + + auto lua_dir = fs::weakly_canonical(lua_src.parent_path(), ec1); + auto lua_file = lua_src.filename(); + + if (!ec1 && !lua_dir.empty() && !lua_file.empty()) { + auto cur_dir = fs::current_path(ec1); + if (!ec1 && !cur_dir.empty() && ::chdir(lua_dir.c_str()) != -1) { /* Push traceback function */ lua_pushcfunction(L, &rspamd_lua_traceback); - err_idx = lua_gettop(L); + auto err_idx = lua_gettop(L); /* Load file */ - if (luaL_loadfile(L, lua_file) != 0) { + if (luaL_loadfile(L, lua_file.c_str()) != 0) { g_set_error(err, CFG_RCL_ERROR, EINVAL, "cannot load lua file %s: %s", - lua_src, + lua_src.c_str(), lua_tostring(L, -1)); - if (chdir(cur_dir) == -1) { - msg_err_config("cannot chdir to %s: %s", cur_dir, + if (::chdir(cur_dir.c_str()) == -1) { + msg_err_config("cannot chdir to %s: %s", cur_dir.c_str(), strerror(errno)); } - g_free(cur_dir); - g_free(lua_dir); - g_free(lua_file); + return FALSE; } @@ -852,19 +879,15 @@ rspamd_rcl_lua_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, CFG_RCL_ERROR, EINVAL, "cannot init lua file %s: %s", - lua_src, + lua_src.c_str(), lua_tostring(L, -1)); lua_settop(L, 0); - if (chdir(cur_dir) == -1) { - msg_err_config("cannot chdir to %s: %s", cur_dir, + if (::chdir(cur_dir.c_str()) == -1) { + msg_err_config("cannot chdir to %s: %s", cur_dir.c_str(), strerror(errno)); } - g_free(cur_dir); - g_free(lua_file); - g_free(lua_dir); - return FALSE; } @@ -872,27 +895,21 @@ rspamd_rcl_lua_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } else { g_set_error(err, CFG_RCL_ERROR, ENOENT, "cannot chdir to %s: %s", - lua_dir, strerror(errno)); - if (chdir(cur_dir) == -1) { - msg_err_config("cannot chdir to %s: %s", cur_dir, strerror(errno)); + lua_dir.c_str(), strerror(errno)); + if (::chdir(cur_dir.c_str()) == -1) { + msg_err_config("cannot chdir back to %s: %s", cur_dir.c_str(), strerror(errno)); } - g_free(cur_dir); - g_free(lua_dir); - g_free(lua_file); + return FALSE; } - if (chdir(cur_dir) == -1) { - msg_err_config("cannot chdir to %s: %s", cur_dir, strerror(errno)); + if (::chdir(cur_dir.c_str()) == -1) { + msg_err_config("cannot chdir back to %s: %s", cur_dir.c_str(), strerror(errno)); } - g_free(cur_dir); - g_free(lua_dir); - g_free(lua_file); } else { - g_free(lua_dir); - g_free(lua_file); + g_set_error(err, CFG_RCL_ERROR, ENOENT, "cannot find to %s: %s", - lua_src, strerror(errno)); + lua_src.c_str(), strerror(errno)); return FALSE; } @@ -900,114 +917,35 @@ rspamd_rcl_lua_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, } gboolean -rspamd_rcl_add_lua_plugins_path(struct rspamd_config *cfg, +rspamd_rcl_add_lua_plugins_path(struct rspamd_rcl_sections_map *sections, + struct rspamd_config *cfg, const gchar *path, gboolean main_path, - GHashTable *modules_seen, GError **err) { - struct stat st; - struct script_module *cur_mod, *seen_mod; - GPtrArray *paths; - gchar *fname, *ext_pos; - guint i; + namespace fs = std::filesystem; + auto dir = fs::path{path}; + std::error_code ec; - if (stat(path, &st) == -1) { + auto add_single_file = [&](const fs::path &fpath) -> bool { + auto fname = fpath.filename(); + auto modname = fname.string(); - if (errno != ENOENT || main_path) { - g_set_error(err, - CFG_RCL_ERROR, - errno, - "cannot stat path %s, %s", - path, - strerror(errno)); - return FALSE; + if (fname.has_extension()) { + modname = modname.substr(0, modname.size() - fname.extension().native().size()); } - else { - msg_debug_config("optional plugins path %s is absent, skip it", path); + auto *cur_mod = rspamd_mempool_alloc_type(cfg->cfg_pool, + struct script_module); + cur_mod->path = rspamd_mempool_strdup(cfg->cfg_pool, fpath.c_str()); + cur_mod->name = rspamd_mempool_strdup(cfg->cfg_pool, modname.c_str()); - return TRUE; + if (sections->lua_modules_seen.contains(modname)) { + msg_info_config("already seen module %s, skip %s", + cur_mod->name, cur_mod->path); + return false; } - } - - /* Handle directory */ - if (S_ISDIR(st.st_mode)) { - paths = rspamd_glob_path(path, "*.lua", TRUE, err); - if (!paths) { - return FALSE; - } - - PTR_ARRAY_FOREACH(paths, i, fname) - { - cur_mod = - rspamd_mempool_alloc(cfg->cfg_pool, - sizeof(struct script_module)); - cur_mod->path = rspamd_mempool_strdup(cfg->cfg_pool, fname); - cur_mod->name = g_path_get_basename(cur_mod->path); - rspamd_mempool_add_destructor(cfg->cfg_pool, g_free, - cur_mod->name); - ext_pos = strstr(cur_mod->name, ".lua"); - - if (ext_pos != NULL) { - *ext_pos = '\0'; - } - - if (modules_seen) { - seen_mod = g_hash_table_lookup(modules_seen, cur_mod->name); - - if (seen_mod != NULL) { - msg_info_config("already seen module %s at %s, skip %s", - cur_mod->name, seen_mod->path, cur_mod->path); - continue; - } - } - - if (cfg->script_modules == NULL) { - cfg->script_modules = g_list_append(cfg->script_modules, - cur_mod); - rspamd_mempool_add_destructor(cfg->cfg_pool, - (rspamd_mempool_destruct_t) g_list_free, - cfg->script_modules); - } - else { - cfg->script_modules = g_list_append(cfg->script_modules, - cur_mod); - } - - if (modules_seen) { - g_hash_table_insert(modules_seen, cur_mod->name, cur_mod); - } - } - - g_ptr_array_free(paths, TRUE); - } - else { - /* Handle single file */ - cur_mod = - rspamd_mempool_alloc(cfg->cfg_pool, sizeof(struct script_module)); - cur_mod->path = rspamd_mempool_strdup(cfg->cfg_pool, path); - cur_mod->name = g_path_get_basename(cur_mod->path); - rspamd_mempool_add_destructor(cfg->cfg_pool, g_free, - cur_mod->name); - ext_pos = strstr(cur_mod->name, ".lua"); - - if (ext_pos != NULL) { - *ext_pos = '\0'; - } - - if (modules_seen) { - seen_mod = g_hash_table_lookup(modules_seen, cur_mod->name); - - if (seen_mod != NULL) { - msg_info_config("already seen module %s at %s, skip %s", - cur_mod->name, seen_mod->path, cur_mod->path); - - return TRUE; - } - } - - if (cfg->script_modules == NULL) { + if (cfg->script_modules == nullptr) { cfg->script_modules = g_list_append(cfg->script_modules, cur_mod); rspamd_mempool_add_destructor(cfg->cfg_pool, @@ -1019,8 +957,36 @@ rspamd_rcl_add_lua_plugins_path(struct rspamd_config *cfg, cur_mod); } - if (modules_seen) { - g_hash_table_insert(modules_seen, cur_mod->name, cur_mod); + sections->lua_modules_seen.insert(fname.string()); + + return true; + }; + + if (fs::is_regular_file(dir, ec) && dir.has_extension() && dir.extension() == ".lua") { + add_single_file(dir); + } + else if (!fs::is_directory(dir, ec)) { + if (!fs::exists(dir) && !main_path) { + msg_debug_config("optional plugins path %s is absent, skip it", path); + + return TRUE; + } + + g_set_error(err, + CFG_RCL_ERROR, + errno, + "invalid lua path spec %s, %s", + path, + ec.message().c_str()); + return FALSE; + } + else { + /* Handle directory */ + for (const auto &p: fs::recursive_directory_iterator(dir, ec)) { + auto fpath = p.path().string(); + if (p.is_regular_file() && fpath.ends_with(".lua")) { + add_single_file(p.path()); + } } } @@ -1032,26 +998,22 @@ rspamd_rcl_modules_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, const gchar *key, gpointer ud, struct rspamd_rcl_section *section, GError **err) { - const ucl_object_t *val, *cur; - struct rspamd_config *cfg = ud; - const gchar *data; + auto *cfg = static_cast<rspamd_config *>(ud); + const char *data; if (obj->type == UCL_OBJECT) { - GHashTable *mods_seen = g_hash_table_new(rspamd_strcase_hash, - rspamd_strcase_equal); - val = ucl_object_lookup(obj, "path"); + const auto *val = ucl_object_lookup(obj, "path"); if (val) { + const auto *cur = val; LL_FOREACH(val, cur) { if (ucl_object_tostring_safe(cur, &data)) { - if (!rspamd_rcl_add_lua_plugins_path(cfg, - rspamd_mempool_strdup(cfg->cfg_pool, data), + if (!rspamd_rcl_add_lua_plugins_path(section->top, + cfg, + data, TRUE, - mods_seen, err)) { - g_hash_table_unref(mods_seen); - return FALSE; } } @@ -1062,7 +1024,6 @@ rspamd_rcl_modules_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, CFG_RCL_ERROR, EINVAL, "path attribute is missing"); - g_hash_table_unref(mods_seen); return FALSE; } @@ -1070,15 +1031,15 @@ rspamd_rcl_modules_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, val = ucl_object_lookup(obj, "fallback_path"); if (val) { + const auto *cur = val; LL_FOREACH(val, cur) { if (ucl_object_tostring_safe(cur, &data)) { - if (!rspamd_rcl_add_lua_plugins_path(cfg, - rspamd_mempool_strdup(cfg->cfg_pool, data), + if (!rspamd_rcl_add_lua_plugins_path(section->top, + cfg, + data, FALSE, - mods_seen, err)) { - g_hash_table_unref(mods_seen); return FALSE; } @@ -1089,27 +1050,24 @@ rspamd_rcl_modules_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, val = ucl_object_lookup(obj, "try_path"); if (val) { + const auto *cur = val; LL_FOREACH(val, cur) { if (ucl_object_tostring_safe(cur, &data)) { - if (!rspamd_rcl_add_lua_plugins_path(cfg, - rspamd_mempool_strdup(cfg->cfg_pool, data), + if (!rspamd_rcl_add_lua_plugins_path(section->top, + cfg, + data, FALSE, - mods_seen, err)) { - g_hash_table_unref(mods_seen); return FALSE; } } } } - - g_hash_table_unref(mods_seen); } else if (ucl_object_tostring_safe(obj, &data)) { - if (!rspamd_rcl_add_lua_plugins_path(cfg, - rspamd_mempool_strdup(cfg->cfg_pool, data), TRUE, NULL, err)) { + if (!rspamd_rcl_add_lua_plugins_path(section->top, cfg, data, TRUE, err)) { return FALSE; } } @@ -1134,36 +1092,33 @@ rspamd_rcl_statfile_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, const gchar *key, gpointer ud, struct rspamd_rcl_section *section, GError **err) { - struct statfile_parser_data *stud = ud; - struct rspamd_classifier_config *ccf; - struct rspamd_config *cfg; - const ucl_object_t *val; - struct rspamd_statfile_config *st; + auto *stud = (struct statfile_parser_data *) ud; GList *labels; - g_assert(key != NULL); + g_assert(key != nullptr); - cfg = stud->cfg; - ccf = stud->ccf; + auto *cfg = stud->cfg; + auto *ccf = stud->ccf; - st = rspamd_config_new_statfile(cfg, NULL); + auto *st = rspamd_config_new_statfile(cfg, nullptr); st->symbol = rspamd_mempool_strdup(cfg->cfg_pool, key); - if (rspamd_rcl_section_parse_defaults(cfg, section, pool, obj, st, err)) { + if (rspamd_rcl_section_parse_defaults(cfg, *section, pool, obj, st, err)) { ccf->statfiles = rspamd_mempool_glist_prepend(pool, ccf->statfiles, st); - if (st->label != NULL) { - labels = g_hash_table_lookup(ccf->labels, st->label); - if (labels != NULL) { + if (st->label != nullptr) { + labels = (GList *) g_hash_table_lookup(ccf->labels, st->label); + if (labels != nullptr) { + /* Must use append to preserve the head stored in the hash table */ labels = g_list_append(labels, st); } else { g_hash_table_insert(ccf->labels, st->label, - g_list_prepend(NULL, st)); + g_list_prepend(nullptr, st)); } } - if (st->symbol != NULL) { + if (st->symbol != nullptr) { g_hash_table_insert(cfg->classifiers_symbols, st->symbol, st); } else { @@ -1177,8 +1132,8 @@ rspamd_rcl_statfile_handler(rspamd_mempool_t *pool, const ucl_object_t *obj, st->opts = (ucl_object_t *) obj; st->clcf = ccf; - val = ucl_object_lookup(obj, "spam"); - if (val == NULL) { + const auto *val = ucl_object_lookup(obj, "spam"); + if (val == nullptr) { msg_info_config( "statfile %s has no explicit 'spam' setting, trying to guess by symbol", st->symbol); @@ -1216,47 +1171,41 @@ rspamd_rcl_classifier_handler(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - const ucl_object_t *val, *cur; - ucl_object_iter_t it = NULL; - struct rspamd_config *cfg = ud; - struct statfile_parser_data stud; - const gchar *st_key; - struct rspamd_classifier_config *ccf; - gboolean res = TRUE; - struct rspamd_rcl_section *stat_section; - struct rspamd_tokenizer_config *tkcf = NULL; - lua_State *L = cfg->lua_state; + auto *cfg = static_cast<rspamd_config *>(ud); - g_assert(key != NULL); - ccf = rspamd_config_new_classifier(cfg, NULL); + g_assert(key != nullptr); + auto *ccf = rspamd_config_new_classifier(cfg, nullptr); + auto *tkcf = (rspamd_tokenizer_config *) nullptr; ccf->classifier = rspamd_mempool_strdup(cfg->cfg_pool, key); - if (rspamd_rcl_section_parse_defaults(cfg, section, cfg->cfg_pool, obj, + if (rspamd_rcl_section_parse_defaults(cfg, *section, cfg->cfg_pool, obj, ccf, err)) { - HASH_FIND_STR(section->subsections, "statfile", stat_section); + auto stat_section = rspamd::find_map(section->subsections, "statfile"); - if (ccf->classifier == NULL) { - ccf->classifier = "bayes"; + if (ccf->classifier == nullptr) { + ccf->classifier = rspamd_mempool_strdup(cfg->cfg_pool, "bayes"); } - if (ccf->name == NULL) { + if (ccf->name == nullptr) { ccf->name = ccf->classifier; } - it = ucl_object_iterate_new(obj); + auto it = ucl_object_iterate_new(obj); + const auto *val = obj; + auto res = TRUE; - while ((val = ucl_object_iterate_safe(it, true)) != NULL && res) { - st_key = ucl_object_key(val); + while ((val = ucl_object_iterate_safe(it, true)) != nullptr && res) { + const auto *st_key = ucl_object_key(val); - if (st_key != NULL) { + if (st_key != nullptr) { if (g_ascii_strcasecmp(st_key, "statfile") == 0) { + const auto *cur = val; LL_FOREACH(val, cur) { - stud.cfg = cfg; - stud.ccf = ccf; - res = rspamd_rcl_process_section(cfg, stat_section, &stud, + struct statfile_parser_data stud = {.cfg = cfg, .ccf = ccf}; + res = rspamd_rcl_process_section(cfg, *stat_section.value().get(), &stud, cur, cfg->cfg_pool, err); if (!res) { @@ -1267,20 +1216,20 @@ rspamd_rcl_classifier_handler(rspamd_mempool_t *pool, } } else if (g_ascii_strcasecmp(st_key, "tokenizer") == 0) { - tkcf = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*tkcf)); + tkcf = rspamd_mempool_alloc0_type(cfg->cfg_pool, rspamd_tokenizer_config); if (ucl_object_type(val) == UCL_STRING) { tkcf->name = ucl_object_tostring(val); } else if (ucl_object_type(val) == UCL_OBJECT) { - cur = ucl_object_lookup(val, "name"); - if (cur != NULL) { + const auto *cur = ucl_object_lookup(val, "name"); + if (cur != nullptr) { tkcf->name = ucl_object_tostring(cur); tkcf->opts = val; } else { cur = ucl_object_lookup(val, "type"); - if (cur != NULL) { + if (cur != nullptr) { tkcf->name = ucl_object_tostring(cur); tkcf->opts = val; } @@ -1296,17 +1245,18 @@ rspamd_rcl_classifier_handler(rspamd_mempool_t *pool, msg_err_config("fatal configuration error, cannot parse statfile definition"); } - if (tkcf == NULL) { - tkcf = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*tkcf)); - tkcf->name = NULL; + if (tkcf == nullptr) { + tkcf = rspamd_mempool_alloc0_type(cfg->cfg_pool, rspamd_tokenizer_config); + tkcf->name = nullptr; } ccf->tokenizer = tkcf; /* Handle lua conditions */ - val = ucl_object_lookup_any(obj, "learn_condition", NULL); + const auto *val = ucl_object_lookup_any(obj, "learn_condition", nullptr); if (val) { + const auto *cur = val; LL_FOREACH(val, cur) { if (ucl_object_type(cur) == UCL_STRING) { @@ -1315,14 +1265,14 @@ rspamd_rcl_classifier_handler(rspamd_mempool_t *pool, gint ref_idx; lua_script = ucl_object_tolstring(cur, &slen); - ref_idx = rspamd_lua_function_ref_from_str(L, + ref_idx = rspamd_lua_function_ref_from_str(RSPAMD_LUA_CFG_STATE(cfg), lua_script, slen, "learn_condition", err); if (ref_idx == LUA_NOREF) { return FALSE; } - rspamd_lua_add_ref_dtor(L, cfg->cfg_pool, ref_idx); + rspamd_lua_add_ref_dtor(RSPAMD_LUA_CFG_STATE(cfg), cfg->cfg_pool, ref_idx); ccf->learn_conditions = rspamd_mempool_glist_append( cfg->cfg_pool, ccf->learn_conditions, @@ -1331,9 +1281,10 @@ rspamd_rcl_classifier_handler(rspamd_mempool_t *pool, } } - val = ucl_object_lookup_any(obj, "classify_condition", NULL); + val = ucl_object_lookup_any(obj, "classify_condition", nullptr); if (val) { + const auto *cur = val; LL_FOREACH(val, cur) { if (ucl_object_type(cur) == UCL_STRING) { @@ -1342,14 +1293,14 @@ rspamd_rcl_classifier_handler(rspamd_mempool_t *pool, gint ref_idx; lua_script = ucl_object_tolstring(cur, &slen); - ref_idx = rspamd_lua_function_ref_from_str(L, + ref_idx = rspamd_lua_function_ref_from_str(RSPAMD_LUA_CFG_STATE(cfg), lua_script, slen, "classify_condition", err); if (ref_idx == LUA_NOREF) { return FALSE; } - rspamd_lua_add_ref_dtor(L, cfg->cfg_pool, ref_idx); + rspamd_lua_add_ref_dtor(RSPAMD_LUA_CFG_STATE(cfg), cfg->cfg_pool, ref_idx); ccf->classify_conditions = rspamd_mempool_glist_append( cfg->cfg_pool, ccf->classify_conditions, @@ -1361,7 +1312,7 @@ rspamd_rcl_classifier_handler(rspamd_mempool_t *pool, ccf->opts = (ucl_object_t *) obj; cfg->classifiers = g_list_prepend(cfg->classifiers, ccf); - return res; + return TRUE; } static gboolean @@ -1372,27 +1323,27 @@ rspamd_rcl_composite_handler(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_config *cfg = ud; + auto *cfg = static_cast<rspamd_config *>(ud); void *composite; const gchar *composite_name; - g_assert(key != NULL); + g_assert(key != nullptr); composite_name = key; - const ucl_object_t *val = ucl_object_lookup(obj, "enabled"); - if (val != NULL && !ucl_object_toboolean(val)) { + const auto *val = ucl_object_lookup(obj, "enabled"); + if (val != nullptr && !ucl_object_toboolean(val)) { msg_info_config("composite %s is disabled", composite_name); return TRUE; } if ((composite = rspamd_composites_manager_add_from_ucl(cfg->composites_manager, - composite_name, obj)) != NULL) { + composite_name, obj)) != nullptr) { rspamd_symcache_add_symbol(cfg->cache, composite_name, 0, - NULL, composite, SYMBOL_TYPE_COMPOSITE, -1); + nullptr, composite, SYMBOL_TYPE_COMPOSITE, -1); } - return composite != NULL; + return composite != nullptr; } static gboolean @@ -1403,11 +1354,10 @@ rspamd_rcl_composites_handler(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - ucl_object_iter_t it = NULL; - const ucl_object_t *cur; - gboolean success = TRUE; + auto success = TRUE; - it = ucl_object_iterate_new(obj); + auto it = ucl_object_iterate_new(obj); + const auto *cur = obj; while ((cur = ucl_object_iterate_safe(it, true))) { success = rspamd_rcl_composite_handler(pool, cur, @@ -1430,14 +1380,11 @@ rspamd_rcl_neighbours_handler(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_config *cfg = ud; - const ucl_object_t *hostval, *pathval; - ucl_object_t *neigh; - gboolean has_port = FALSE, has_proto = FALSE; - GString *urlstr; + auto *cfg = static_cast<rspamd_config *>(ud); + auto has_port = FALSE, has_proto = FALSE; const gchar *p; - if (key == NULL) { + if (key == nullptr) { g_set_error(err, CFG_RCL_ERROR, EINVAL, @@ -1445,9 +1392,9 @@ rspamd_rcl_neighbours_handler(rspamd_mempool_t *pool, return FALSE; } - hostval = ucl_object_lookup(obj, "host"); + const auto *hostval = ucl_object_lookup(obj, "host"); - if (hostval == NULL || ucl_object_type(hostval) != UCL_STRING) { + if (hostval == nullptr || ucl_object_type(hostval) != UCL_STRING) { g_set_error(err, CFG_RCL_ERROR, EINVAL, @@ -1455,44 +1402,43 @@ rspamd_rcl_neighbours_handler(rspamd_mempool_t *pool, return FALSE; } - neigh = ucl_object_typed_new(UCL_OBJECT); + auto *neigh = ucl_object_typed_new(UCL_OBJECT); ucl_object_insert_key(neigh, ucl_object_copy(hostval), "host", 0, false); - if ((p = strrchr(ucl_object_tostring(hostval), ':')) != NULL) { + if ((p = strrchr(ucl_object_tostring(hostval), ':')) != nullptr) { if (g_ascii_isdigit(p[1])) { has_port = TRUE; } } - if (strstr(ucl_object_tostring(hostval), "://") != NULL) { + if (strstr(ucl_object_tostring(hostval), "://") != nullptr) { has_proto = TRUE; } /* Now make url */ - urlstr = g_string_sized_new(63); - pathval = ucl_object_lookup(obj, "path"); + auto urlstr = std::string{}; + const auto *pathval = ucl_object_lookup(obj, "path"); if (!has_proto) { - g_string_append_len(urlstr, "http://", sizeof("http://") - 1); + urlstr += "http://"; } - g_string_append(urlstr, ucl_object_tostring(hostval)); + urlstr += ucl_object_tostring(hostval); if (!has_port) { - g_string_append(urlstr, ":11334"); + urlstr += ":11334"; } - if (pathval == NULL) { - g_string_append(urlstr, "/"); + if (pathval == nullptr) { + urlstr += "/"; } else { - g_string_append(urlstr, ucl_object_tostring(pathval)); + urlstr += ucl_object_tostring(pathval); } ucl_object_insert_key(neigh, - ucl_object_fromlstring(urlstr->str, urlstr->len), + ucl_object_fromlstring(urlstr.data(), urlstr.size()), "url", 0, false); - g_string_free(urlstr, TRUE); ucl_object_insert_key(cfg->neighbours, neigh, key, 0, true); return TRUE; @@ -1500,67 +1446,92 @@ rspamd_rcl_neighbours_handler(rspamd_mempool_t *pool, struct rspamd_rcl_section * -rspamd_rcl_add_section(struct rspamd_rcl_section **top, +rspamd_rcl_add_section(struct rspamd_rcl_sections_map **top, + struct rspamd_rcl_section *parent_section, const gchar *name, const gchar *key_attr, rspamd_rcl_handler_t handler, enum ucl_type type, gboolean required, gboolean strict_type) { - struct rspamd_rcl_section *new; - ucl_object_t *parent_doc; - - new = g_malloc0(sizeof(struct rspamd_rcl_section)); - new->name = name; - new->key_attr = key_attr; - new->handler = handler; - new->type = type; - new->strict_type = strict_type; - - if (*top == NULL) { - parent_doc = NULL; - new->doc_ref = NULL; - } - else { - parent_doc = (*top)->doc_ref; - new->doc_ref = ucl_object_ref(rspamd_rcl_add_doc_obj(parent_doc, - NULL, - name, - type, - NULL, - 0, - NULL, - 0)); - } - - HASH_ADD_KEYPTR(hh, *top, new->name, strlen(new->name), new); - return new; + return rspamd_rcl_add_section_doc(top, parent_section, name, key_attr, handler, + type, required, strict_type, nullptr, nullptr); } struct rspamd_rcl_section * -rspamd_rcl_add_section_doc(struct rspamd_rcl_section **top, +rspamd_rcl_add_section_doc(struct rspamd_rcl_sections_map **top, + struct rspamd_rcl_section *parent_section, const gchar *name, const gchar *key_attr, rspamd_rcl_handler_t handler, enum ucl_type type, gboolean required, gboolean strict_type, ucl_object_t *doc_target, const gchar *doc_string) { - struct rspamd_rcl_section *new_section; - - new_section = g_malloc0(sizeof(struct rspamd_rcl_section)); - new_section->name = name; - new_section->key_attr = key_attr; - new_section->handler = handler; - new_section->type = type; - new_section->strict_type = strict_type; - - new_section->doc_ref = ucl_object_ref(rspamd_rcl_add_doc_obj(doc_target, - doc_string, - name, - type, - NULL, - 0, - NULL, - 0)); - - HASH_ADD_KEYPTR(hh, *top, new_section->name, strlen(new_section->name), new_section); - return new_section; + if (top == nullptr) { + g_error("invalid arguments to rspamd_rcl_add_section"); + return nullptr; + } + if (*top == nullptr) { + *top = new rspamd_rcl_sections_map; + } + + auto fill_section = [&](struct rspamd_rcl_section *section) { + section->name = name; + if (key_attr) { + section->key_attr = std::string{key_attr}; + } + section->handler = handler; + section->type = type; + section->strict_type = strict_type; + + if (doc_target == nullptr) { + if (parent_section && parent_section->doc_ref) { + section->doc_ref = ucl_object_ref(rspamd_rcl_add_doc_obj(parent_section->doc_ref, + doc_string, + name, + type, + nullptr, + 0, + nullptr, + 0)); + } + else { + section->doc_ref = nullptr; + } + } + else { + section->doc_ref = ucl_object_ref(rspamd_rcl_add_doc_obj(doc_target, + doc_string, + name, + type, + nullptr, + 0, + nullptr, + 0)); + } + section->top = *top; + }; + + /* Select the appropriate container and insert section inside it */ + if (parent_section) { + auto it = parent_section->subsections.insert(std::make_pair(std::string{name}, + std::make_shared<rspamd_rcl_section>())); + if (!it.second) { + g_error("invalid arguments to rspamd_rcl_add_section"); + return nullptr; + } + + fill_section(it.first->second.get()); + return it.first->second.get(); + } + else { + auto it = (*top)->sections.insert(std::make_pair(std::string{name}, + std::make_shared<rspamd_rcl_section>())); + if (!it.second) { + g_error("invalid arguments to rspamd_rcl_add_section"); + return nullptr; + } + + (*top)->sections_order.push_back(it.first->second); + fill_section(it.first->second.get()); + return it.first->second.get(); + } } struct rspamd_rcl_default_handler_data * @@ -1571,34 +1542,32 @@ rspamd_rcl_add_default_handler(struct rspamd_rcl_section *section, gint flags, const gchar *doc_string) { - struct rspamd_rcl_default_handler_data *nhandler; + auto it = section->default_parser.emplace(std::make_pair(std::string{name}, rspamd_rcl_default_handler_data{})); - nhandler = g_malloc0(sizeof(struct rspamd_rcl_default_handler_data)); - nhandler->key = g_strdup(name); - nhandler->handler = handler; - nhandler->pd.offset = offset; - nhandler->pd.flags = flags; + auto &nhandler = it.first->second; + nhandler.key = name; + nhandler.handler = handler; + nhandler.pd.offset = offset; + nhandler.pd.flags = flags; - if (section->doc_ref != NULL) { + if (section->doc_ref != nullptr) { rspamd_rcl_add_doc_obj(section->doc_ref, doc_string, name, UCL_NULL, handler, flags, - NULL, + nullptr, 0); } - HASH_ADD_KEYPTR(hh, section->default_parser, nhandler->key, strlen(nhandler->key), nhandler); - return nhandler; + return &nhandler; } -struct rspamd_rcl_section * +struct rspamd_rcl_sections_map * rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) { - struct rspamd_rcl_section *new = NULL, *sub, *ssub; - + auto *top = new rspamd_rcl_sections_map; /* * Important notice: * the order of parsing is equal to order of this initialization, therefore @@ -1609,14 +1578,14 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) * Logging section */ if (!(skip_sections && g_hash_table_lookup(skip_sections, "logging"))) { - sub = rspamd_rcl_add_section_doc(&new, - "logging", NULL, - rspamd_rcl_logging_handler, - UCL_OBJECT, - FALSE, - TRUE, - cfg->doc_strings, - "Configure rspamd logging"); + auto *sub = rspamd_rcl_add_section_doc(&top, nullptr, + "logging", nullptr, + rspamd_rcl_logging_handler, + UCL_OBJECT, + FALSE, + TRUE, + cfg->doc_strings, + "Configure rspamd logging"); /* Default handlers */ rspamd_rcl_add_default_handler(sub, "log_buffer", @@ -1675,59 +1644,59 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) "Enable colored output (for console logging)", "log_color", UCL_BOOLEAN, - NULL, + nullptr, 0, - NULL, + nullptr, 0); rspamd_rcl_add_doc_by_path(cfg, "logging", "Enable severity logging output (e.g. [error] or [warning])", "log_severity", UCL_BOOLEAN, - NULL, + nullptr, 0, - NULL, + nullptr, 0); rspamd_rcl_add_doc_by_path(cfg, "logging", "Enable systemd compatible logging", "systemd", UCL_BOOLEAN, - NULL, + nullptr, 0, - NULL, + nullptr, 0); rspamd_rcl_add_doc_by_path(cfg, "logging", "Write statistics of regexp processing to log (useful for hyperscan)", "log_re_cache", UCL_BOOLEAN, - NULL, + nullptr, 0, - NULL, + nullptr, 0); rspamd_rcl_add_doc_by_path(cfg, "logging", "Use microseconds resolution for timestamps", "log_usec", UCL_BOOLEAN, - NULL, + nullptr, 0, - NULL, + nullptr, 0); } if (!(skip_sections && g_hash_table_lookup(skip_sections, "options"))) { /** * Options section */ - sub = rspamd_rcl_add_section_doc(&new, - "options", NULL, - rspamd_rcl_options_handler, - UCL_OBJECT, - FALSE, - TRUE, - cfg->doc_strings, - "Global rspamd options"); + auto *sub = rspamd_rcl_add_section_doc(&top, nullptr, + "options", nullptr, + rspamd_rcl_options_handler, + UCL_OBJECT, + FALSE, + TRUE, + cfg->doc_strings, + "Global rspamd options"); rspamd_rcl_add_default_handler(sub, "cache_file", rspamd_rcl_parse_struct_string, @@ -1740,6 +1709,7 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) G_STRUCT_OFFSET(struct rspamd_config, cache_reload_time), RSPAMD_CL_FLAG_TIME_FLOAT, "How often cache reload should be performed"); + /* Old DNS configuration */ rspamd_rcl_add_default_handler(sub, "dns_nameserver", @@ -2034,7 +2004,7 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) rspamd_rcl_parse_struct_string, G_STRUCT_OFFSET(struct rspamd_config, ssl_ciphers), 0, - "List of ssl ciphers (e.g. HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4)"); + "List of ssl ciphers (e.g. HIGH:!anullptr:!kRSA:!PSK:!SRP:!MD5:!RC4)"); rspamd_rcl_add_default_handler(sub, "max_message", rspamd_rcl_parse_struct_integer, @@ -2176,17 +2146,17 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) "Events backend to use: kqueue, epoll, select, poll or auto (default: auto)"); /* Neighbours configuration */ - rspamd_rcl_add_section_doc(&sub->subsections, "neighbours", "name", + rspamd_rcl_add_section_doc(&top, sub, "neighbours", "name", rspamd_rcl_neighbours_handler, UCL_OBJECT, FALSE, TRUE, cfg->doc_strings, "List of members of Rspamd cluster"); /* New DNS configuration */ - ssub = rspamd_rcl_add_section_doc(&sub->subsections, "dns", NULL, NULL, - UCL_OBJECT, FALSE, TRUE, - cfg->doc_strings, - "Options for DNS resolver"); + auto *ssub = rspamd_rcl_add_section_doc(&top, sub, "dns", nullptr, nullptr, + UCL_OBJECT, FALSE, TRUE, + cfg->doc_strings, + "Options for DNS resolver"); rspamd_rcl_add_default_handler(ssub, "nameserver", rspamd_rcl_parse_struct_ucl, @@ -2232,7 +2202,7 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) /* New upstreams configuration */ - ssub = rspamd_rcl_add_section_doc(&sub->subsections, "upstream", NULL, NULL, + ssub = rspamd_rcl_add_section_doc(&top, sub, "upstream", nullptr, nullptr, UCL_OBJECT, FALSE, TRUE, cfg->doc_strings, "Upstreams configuration parameters"); @@ -2266,14 +2236,14 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) /** * Symbols and actions sections */ - sub = rspamd_rcl_add_section_doc(&new, - "actions", NULL, - rspamd_rcl_actions_handler, - UCL_OBJECT, - FALSE, - TRUE, - cfg->doc_strings, - "Actions configuration"); + auto *sub = rspamd_rcl_add_section_doc(&top, nullptr, + "actions", nullptr, + rspamd_rcl_actions_handler, + UCL_OBJECT, + FALSE, + TRUE, + cfg->doc_strings, + "Actions configuration"); rspamd_rcl_add_default_handler(sub, "unknown_weight", rspamd_rcl_parse_struct_double, @@ -2297,19 +2267,19 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) } if (!(skip_sections && g_hash_table_lookup(skip_sections, "group"))) { - sub = rspamd_rcl_add_section_doc(&new, - "group", "name", - rspamd_rcl_group_handler, - UCL_OBJECT, - FALSE, - TRUE, - cfg->doc_strings, - "Symbol groups configuration"); - ssub = rspamd_rcl_add_section_doc(&sub->subsections, "symbols", "name", - rspamd_rcl_symbol_handler, - UCL_OBJECT, FALSE, TRUE, - cfg->doc_strings, - "Symbols configuration"); + auto *sub = rspamd_rcl_add_section_doc(&top, nullptr, + "group", "name", + rspamd_rcl_group_handler, + UCL_OBJECT, + FALSE, + TRUE, + cfg->doc_strings, + "Symbol groups configuration"); + rspamd_rcl_add_section_doc(&top, sub, "symbols", "name", + rspamd_rcl_symbol_handler, + UCL_OBJECT, FALSE, TRUE, + cfg->doc_strings, + "Symbols configuration"); /* Group part */ rspamd_rcl_add_default_handler(sub, @@ -2324,14 +2294,13 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) /** * Worker section */ - sub = rspamd_rcl_add_section_doc(&new, - "worker", "type", - rspamd_rcl_worker_handler, - UCL_OBJECT, - FALSE, - TRUE, - cfg->doc_strings, - "Workers common options"); + auto *sub = rspamd_rcl_add_section_doc(&top, nullptr, "worker", "type", + rspamd_rcl_worker_handler, + UCL_OBJECT, + FALSE, + TRUE, + cfg->doc_strings, + "Workers common options"); rspamd_rcl_add_default_handler(sub, "count", rspamd_rcl_parse_struct_integer, @@ -2362,28 +2331,28 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) /** * Modules handler */ - sub = rspamd_rcl_add_section_doc(&new, - "modules", NULL, - rspamd_rcl_modules_handler, - UCL_OBJECT, - FALSE, - FALSE, - cfg->doc_strings, - "Lua plugins to load"); + rspamd_rcl_add_section_doc(&top, nullptr, + "modules", nullptr, + rspamd_rcl_modules_handler, + UCL_OBJECT, + FALSE, + FALSE, + cfg->doc_strings, + "Lua plugins to load"); } if (!(skip_sections && g_hash_table_lookup(skip_sections, "classifier"))) { /** * Classifiers handler */ - sub = rspamd_rcl_add_section_doc(&new, - "classifier", "type", - rspamd_rcl_classifier_handler, - UCL_OBJECT, - FALSE, - TRUE, - cfg->doc_strings, - "CLassifier options"); + auto *sub = rspamd_rcl_add_section_doc(&top, nullptr, + "classifier", "type", + rspamd_rcl_classifier_handler, + UCL_OBJECT, + FALSE, + TRUE, + cfg->doc_strings, + "CLassifier options"); /* Default classifier is 'bayes' for now */ sub->default_key = "bayes"; @@ -2433,14 +2402,14 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) /* * Statfile defaults */ - ssub = rspamd_rcl_add_section_doc(&sub->subsections, - "statfile", "symbol", - rspamd_rcl_statfile_handler, - UCL_OBJECT, - TRUE, - TRUE, - sub->doc_ref, - "Statfiles options"); + auto *ssub = rspamd_rcl_add_section_doc(&top, sub, + "statfile", "symbol", + rspamd_rcl_statfile_handler, + UCL_OBJECT, + TRUE, + TRUE, + sub->doc_ref, + "Statfiles options"); rspamd_rcl_add_default_handler(ssub, "label", rspamd_rcl_parse_struct_string, @@ -2459,95 +2428,68 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) /** * Composites handlers */ - sub = rspamd_rcl_add_section_doc(&new, - "composite", "name", - rspamd_rcl_composite_handler, - UCL_OBJECT, - FALSE, - TRUE, - cfg->doc_strings, - "Rspamd composite symbols"); - sub = rspamd_rcl_add_section_doc(&new, - "composites", NULL, - rspamd_rcl_composites_handler, - UCL_OBJECT, - FALSE, - TRUE, - cfg->doc_strings, - "Rspamd composite symbols"); + rspamd_rcl_add_section_doc(&top, nullptr, + "composite", "name", + rspamd_rcl_composite_handler, + UCL_OBJECT, + FALSE, + TRUE, + cfg->doc_strings, + "Rspamd composite symbols"); + rspamd_rcl_add_section_doc(&top, nullptr, + "composites", nullptr, + rspamd_rcl_composites_handler, + UCL_OBJECT, + FALSE, + TRUE, + cfg->doc_strings, + "Rspamd composite symbols"); } if (!(skip_sections && g_hash_table_lookup(skip_sections, "lua"))) { /** * Lua handler */ - sub = rspamd_rcl_add_section_doc(&new, - "lua", NULL, - rspamd_rcl_lua_handler, - UCL_STRING, - FALSE, - TRUE, - cfg->doc_strings, - "Lua files to load"); - } - - return new; -} - -struct rspamd_rcl_section * -rspamd_rcl_config_get_section(struct rspamd_rcl_section *top, - const char *path) -{ - struct rspamd_rcl_section *cur, *found = NULL; - char **path_components; - gint ncomponents, i; - - - if (path == NULL) { - return top; + rspamd_rcl_add_section_doc(&top, nullptr, + "lua", nullptr, + rspamd_rcl_lua_handler, + UCL_STRING, + FALSE, + TRUE, + cfg->doc_strings, + "Lua files to load"); } - path_components = g_strsplit_set(path, "/", -1); - ncomponents = g_strv_length(path_components); - - cur = top; - for (i = 0; i < ncomponents; i++) { - if (cur == NULL) { - g_strfreev(path_components); - return NULL; - } - HASH_FIND_STR(cur, path_components[i], found); - if (found == NULL) { - g_strfreev(path_components); - return NULL; - } - cur = found; - } + cfg->rcl_top_section = top; - g_strfreev(path_components); - return found; + return top; } -static gboolean +static bool rspamd_rcl_process_section(struct rspamd_config *cfg, - struct rspamd_rcl_section *sec, + const struct rspamd_rcl_section &sec, gpointer ptr, const ucl_object_t *obj, rspamd_mempool_t *pool, GError **err) { ucl_object_iter_t it; const ucl_object_t *cur; - gboolean is_nested = TRUE; - const gchar *key = NULL; + auto is_nested = true; + const gchar *key = nullptr; + + if (sec.processed) { + /* Section has been already processed */ + return TRUE; + } - g_assert(obj != NULL); - g_assert(sec->handler != NULL); + g_assert(obj != nullptr); + g_assert(sec.handler != nullptr); - if (sec->key_attr != NULL) { + if (sec.key_attr) { it = ucl_object_iterate_new(obj); - while ((cur = ucl_object_iterate_full(it, UCL_ITERATE_EXPLICIT)) != NULL) { + while ((cur = ucl_object_iterate_full(it, UCL_ITERATE_EXPLICIT)) != nullptr) { if (ucl_object_type(cur) != UCL_OBJECT) { - is_nested = FALSE; + is_nested = false; break; } } @@ -2555,54 +2497,54 @@ rspamd_rcl_process_section(struct rspamd_config *cfg, ucl_object_iterate_free(it); } else { - is_nested = FALSE; + is_nested = false; } if (is_nested) { /* Just reiterate on all subobjects */ it = ucl_object_iterate_new(obj); - while ((cur = ucl_object_iterate_full(it, UCL_ITERATE_EXPLICIT)) != NULL) { - if (!sec->handler(pool, cur, ucl_object_key(cur), ptr, sec, err)) { + while ((cur = ucl_object_iterate_full(it, UCL_ITERATE_EXPLICIT)) != nullptr) { + if (!sec.handler(pool, cur, ucl_object_key(cur), ptr, const_cast<rspamd_rcl_section *>(&sec), err)) { ucl_object_iterate_free(it); - return FALSE; + return false; } } ucl_object_iterate_free(it); - return TRUE; + return true; } else { - if (sec->key_attr != NULL) { + if (sec.key_attr) { /* First of all search for required attribute and use it as a key */ - cur = ucl_object_lookup(obj, sec->key_attr); + cur = ucl_object_lookup(obj, sec.key_attr.value().c_str()); - if (cur == NULL) { - if (sec->default_key == NULL) { + if (cur == nullptr) { + if (!sec.default_key) { g_set_error(err, CFG_RCL_ERROR, EINVAL, "required attribute " "'%s' is missing for section '%s', current key: %s", - sec->key_attr, - sec->name, - ucl_object_emit(obj, UCL_EMIT_CONFIG)); + sec.key_attr.value().c_str(), + sec.name.c_str(), + ucl_object_key(obj)); - return FALSE; + return false; } else { msg_info("using default key '%s' for mandatory field '%s' " "for section '%s'", - sec->default_key, sec->key_attr, - sec->name); - key = sec->default_key; + sec.default_key.value().c_str(), sec.key_attr.value().c_str(), + sec.name.c_str()); + key = sec.default_key.value().c_str(); } } else if (ucl_object_type(cur) != UCL_STRING) { g_set_error(err, CFG_RCL_ERROR, EINVAL, "required attribute %s" " is not a string for section %s", - sec->key_attr, sec->name); + sec.key_attr.value().c_str(), sec.name.c_str()); - return FALSE; + return false; } else { key = ucl_object_tostring(cur); @@ -2610,18 +2552,15 @@ rspamd_rcl_process_section(struct rspamd_config *cfg, } } - return sec->handler(pool, obj, key, ptr, sec, err); + return sec.handler(pool, obj, key, ptr, const_cast<rspamd_rcl_section *>(&sec), err); } gboolean -rspamd_rcl_parse(struct rspamd_rcl_section *top, +rspamd_rcl_parse(struct rspamd_rcl_sections_map *top, struct rspamd_config *cfg, gpointer ptr, rspamd_mempool_t *pool, const ucl_object_t *obj, GError **err) { - const ucl_object_t *found, *cur_obj; - struct rspamd_rcl_section *cur, *tmp, *found_sec; - if (obj->type != UCL_OBJECT) { g_set_error(err, CFG_RCL_ERROR, @@ -2631,24 +2570,22 @@ rspamd_rcl_parse(struct rspamd_rcl_section *top, } /* Iterate over known sections and ignore unknown ones */ - HASH_ITER(hh, top, cur, tmp) - { - if (strcmp(cur->name, "*") == 0) { + for (const auto &sec_ptr: top->sections_order) { + if (sec_ptr->name == "*") { /* Default section handler */ + const auto *cur_obj = obj; LL_FOREACH(obj, cur_obj) { - HASH_FIND_STR(top, ucl_object_key(cur_obj), found_sec); - - if (found_sec == NULL) { - if (cur->handler != NULL) { - if (!rspamd_rcl_process_section(cfg, cur, ptr, cur_obj, + if (!top->sections.contains(ucl_object_key(cur_obj))) { + if (sec_ptr->handler != nullptr) { + if (!rspamd_rcl_process_section(cfg, *sec_ptr, ptr, cur_obj, pool, err)) { return FALSE; } } else { rspamd_rcl_section_parse_defaults(cfg, - cur, + *sec_ptr, pool, cur_obj, ptr, @@ -2658,34 +2595,35 @@ rspamd_rcl_parse(struct rspamd_rcl_section *top, } } else { - found = ucl_object_lookup(obj, cur->name); - if (found == NULL) { - if (cur->required) { + const auto *found = ucl_object_lookup(obj, sec_ptr->name.c_str()); + if (found == nullptr) { + if (sec_ptr->required) { g_set_error(err, CFG_RCL_ERROR, ENOENT, - "required section %s is missing", cur->name); + "required section %s is missing", sec_ptr->name.c_str()); return FALSE; } } else { /* Check type */ - if (cur->strict_type) { - if (cur->type != found->type) { + if (sec_ptr->strict_type) { + if (sec_ptr->type != found->type) { g_set_error(err, CFG_RCL_ERROR, EINVAL, - "object in section %s has invalid type", cur->name); + "object in section %s has invalid type", sec_ptr->name.c_str()); return FALSE; } } + const auto *cur_obj = found; LL_FOREACH(found, cur_obj) { - if (cur->handler != NULL) { - if (!rspamd_rcl_process_section(cfg, cur, ptr, cur_obj, + if (sec_ptr->handler != nullptr) { + if (!rspamd_rcl_process_section(cfg, *sec_ptr, ptr, cur_obj, pool, err)) { return FALSE; } } else { - rspamd_rcl_section_parse_defaults(cfg, cur, + rspamd_rcl_section_parse_defaults(cfg, *sec_ptr, pool, cur_obj, ptr, @@ -2694,22 +2632,20 @@ rspamd_rcl_parse(struct rspamd_rcl_section *top, } } } - if (cur->fin) { - cur->fin(pool, cur->fin_ud); + if (sec_ptr->fin) { + sec_ptr->fin(pool, sec_ptr->fin_ud); } } return TRUE; } -gboolean +static bool rspamd_rcl_section_parse_defaults(struct rspamd_config *cfg, - struct rspamd_rcl_section *section, + const struct rspamd_rcl_section §ion, rspamd_mempool_t *pool, const ucl_object_t *obj, gpointer ptr, GError **err) { - const ucl_object_t *found, *cur_obj; - struct rspamd_rcl_default_handler_data *cur, *tmp; if (obj->type != UCL_OBJECT) { g_set_error(err, @@ -2717,24 +2653,25 @@ rspamd_rcl_section_parse_defaults(struct rspamd_config *cfg, EINVAL, "default configuration must be an object for section %s " "(actual type is %s)", - section->name, ucl_object_type_to_string(obj->type)); + section.name.c_str(), ucl_object_type_to_string(ucl_object_type(obj))); return FALSE; } - HASH_ITER(hh, section->default_parser, cur, tmp) - { - found = ucl_object_lookup(obj, cur->key); - if (found != NULL) { - cur->pd.user_struct = ptr; - cur->pd.cfg = cfg; + for (const auto &cur: section.default_parser) { + const auto *found = ucl_object_lookup(obj, cur.first.c_str()); + if (found != nullptr) { + auto new_pd = cur.second.pd; + new_pd.user_struct = ptr; + new_pd.cfg = cfg; + const auto *cur_obj = found; LL_FOREACH(found, cur_obj) { - if (!cur->handler(pool, cur_obj, &cur->pd, section, err)) { + if (!cur.second.handler(pool, cur_obj, &new_pd, const_cast<rspamd_rcl_section *>(§ion), err)) { return FALSE; } - if (!(cur->pd.flags & RSPAMD_CL_FLAG_MULTIPLE)) { + if (!(new_pd.flags & RSPAMD_CL_FLAG_MULTIPLE)) { break; } } @@ -2751,32 +2688,31 @@ rspamd_rcl_parse_struct_string(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_struct_parser *pd = ud; - gchar **target; + auto *pd = (struct rspamd_rcl_struct_parser *) ud; const gsize num_str_len = 32; - target = (gchar **) (((gchar *) pd->user_struct) + pd->offset); + auto target = (gchar **) (((gchar *) pd->user_struct) + pd->offset); switch (obj->type) { case UCL_STRING: *target = rspamd_mempool_strdup(pool, ucl_copy_value_trash(obj)); break; case UCL_INT: - *target = rspamd_mempool_alloc(pool, num_str_len); + *target = (gchar *) rspamd_mempool_alloc(pool, num_str_len); rspamd_snprintf(*target, num_str_len, "%L", obj->value.iv); break; case UCL_FLOAT: - *target = rspamd_mempool_alloc(pool, num_str_len); + *target = (gchar *) rspamd_mempool_alloc(pool, num_str_len); rspamd_snprintf(*target, num_str_len, "%f", obj->value.dv); break; case UCL_BOOLEAN: - *target = rspamd_mempool_alloc(pool, num_str_len); + *target = (gchar *) rspamd_mempool_alloc(pool, num_str_len); rspamd_snprintf(*target, num_str_len, "%s", ((gboolean) obj->value.iv) ? "true" : "false"); break; case UCL_NULL: /* String is enforced to be null */ - *target = NULL; + *target = nullptr; break; default: g_set_error(err, @@ -2798,7 +2734,7 @@ rspamd_rcl_parse_struct_integer(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_struct_parser *pd = ud; + auto *pd = (struct rspamd_rcl_struct_parser *) ud; union { gint *ip; gint32 *i32p; @@ -2898,7 +2834,7 @@ rspamd_rcl_parse_struct_double(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_struct_parser *pd = ud; + auto *pd = (struct rspamd_rcl_struct_parser *) ud; gdouble *target; target = (gdouble *) (((gchar *) pd->user_struct) + pd->offset); @@ -2923,7 +2859,7 @@ rspamd_rcl_parse_struct_time(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_struct_parser *pd = ud; + auto *pd = (struct rspamd_rcl_struct_parser *) ud; union { gint *psec; guint32 *pu32; @@ -2987,7 +2923,7 @@ rspamd_rcl_parse_struct_keypair(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_struct_parser *pd = ud; + auto *pd = (struct rspamd_rcl_struct_parser *) ud; struct rspamd_cryptobox_keypair **target, *kp; target = (struct rspamd_cryptobox_keypair **) (((gchar *) pd->user_struct) + @@ -2995,18 +2931,18 @@ rspamd_rcl_parse_struct_keypair(rspamd_mempool_t *pool, if (obj->type == UCL_OBJECT) { kp = rspamd_keypair_from_ucl(obj); - if (kp != NULL) { + if (kp != nullptr) { rspamd_mempool_add_destructor(pool, (rspamd_mempool_destruct_t) rspamd_keypair_unref, kp); *target = kp; } else { - gchar *dump = ucl_object_emit(obj, UCL_EMIT_JSON_COMPACT); + gchar *dump = (char *) ucl_object_emit(obj, UCL_EMIT_JSON_COMPACT); g_set_error(err, CFG_RCL_ERROR, EINVAL, "cannot load the keypair specified: %s; section: %s; value: %s", - ucl_object_key(obj), section->name, dump); + ucl_object_key(obj), section->name.c_str(), dump); free(dump); return FALSE; @@ -3031,12 +2967,12 @@ rspamd_rcl_parse_struct_pubkey(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_struct_parser *pd = ud; + auto *pd = (struct rspamd_rcl_struct_parser *) ud; struct rspamd_cryptobox_pubkey **target, *pk; gsize len; const gchar *str; - gint keypair_type = RSPAMD_KEYPAIR_KEX, - keypair_mode = RSPAMD_CRYPTOBOX_MODE_25519; + rspamd_cryptobox_keypair_type keypair_type = RSPAMD_KEYPAIR_KEX; + rspamd_cryptobox_mode keypair_mode = RSPAMD_CRYPTOBOX_MODE_25519; if (pd->flags & RSPAMD_CL_FLAG_SIGNKEY) { keypair_type = RSPAMD_KEYPAIR_SIGN; @@ -3052,7 +2988,7 @@ rspamd_rcl_parse_struct_pubkey(rspamd_mempool_t *pool, pk = rspamd_pubkey_from_base32(str, len, keypair_type, keypair_mode); - if (pk != NULL) { + if (pk != nullptr) { *target = pk; } else { @@ -3081,7 +3017,7 @@ rspamd_rcl_parse_struct_pubkey(rspamd_mempool_t *pool, static void rspamd_rcl_insert_string_list_item(gpointer *target, rspamd_mempool_t *pool, - const gchar *src, gboolean is_hash) + std::string_view elt, gboolean is_hash) { union { GHashTable *hv; @@ -3093,17 +3029,17 @@ rspamd_rcl_insert_string_list_item(gpointer *target, rspamd_mempool_t *pool, d.p = *target; if (is_hash) { - if (d.hv == NULL) { + if (d.hv == nullptr) { d.hv = g_hash_table_new(rspamd_str_hash, rspamd_str_equal); rspamd_mempool_add_destructor(pool, (rspamd_mempool_destruct_t) g_hash_table_unref, d.hv); } - val = rspamd_mempool_strdup(pool, src); + val = rspamd_mempool_strdup_len(pool, elt.data(), elt.size()); g_hash_table_insert(d.hv, val, val); } else { - val = rspamd_mempool_strdup(pool, src); + val = rspamd_mempool_strdup_len(pool, elt.data(), elt.size()); d.lv = g_list_prepend(d.lv, val); } @@ -3117,51 +3053,50 @@ rspamd_rcl_parse_struct_string_list(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_struct_parser *pd = ud; - gpointer *target; - gchar *val, **strvec, **cvec; - const ucl_object_t *cur; - const gsize num_str_len = 32; - ucl_object_iter_t iter = NULL; - gboolean is_hash, need_destructor = TRUE; + auto *pd = (struct rspamd_rcl_struct_parser *) ud; + constexpr const auto num_str_len = 32; + auto need_destructor = true; - is_hash = pd->flags & RSPAMD_CL_FLAG_STRING_LIST_HASH; - target = (gpointer *) (((gchar *) pd->user_struct) + pd->offset); + auto is_hash = pd->flags & RSPAMD_CL_FLAG_STRING_LIST_HASH; + auto *target = (gpointer *) (((gchar *) pd->user_struct) + pd->offset); - if (!is_hash && *target != NULL) { + if (!is_hash && *target != nullptr) { need_destructor = FALSE; } - iter = ucl_object_iterate_new(obj); + auto iter = ucl_object_iterate_new(obj); + const auto *cur = obj; - while ((cur = ucl_object_iterate_safe(iter, true)) != NULL) { + while ((cur = ucl_object_iterate_safe(iter, true)) != nullptr) { switch (cur->type) { - case UCL_STRING: - strvec = g_strsplit_set(ucl_object_tostring(cur), ",", -1); - cvec = strvec; - - while (*cvec) { - rspamd_rcl_insert_string_list_item(target, pool, *cvec, is_hash); - cvec++; - } + case UCL_STRING: { + rspamd::string_foreach_delim(ucl_object_tostring(cur), ", ", [&](const auto &elt) { + rspamd_rcl_insert_string_list_item(target, pool, elt, is_hash); + }); - g_strfreev(strvec); /* Go to the next object */ continue; - case UCL_INT: - val = rspamd_mempool_alloc(pool, num_str_len); + } + case UCL_INT: { + auto *val = (gchar *) rspamd_mempool_alloc(pool, num_str_len); rspamd_snprintf(val, num_str_len, "%L", cur->value.iv); + rspamd_rcl_insert_string_list_item(target, pool, val, is_hash); break; - case UCL_FLOAT: - val = rspamd_mempool_alloc(pool, num_str_len); + } + case UCL_FLOAT: { + auto *val = (gchar *) rspamd_mempool_alloc(pool, num_str_len); rspamd_snprintf(val, num_str_len, "%f", cur->value.dv); + rspamd_rcl_insert_string_list_item(target, pool, val, is_hash); break; - case UCL_BOOLEAN: - val = rspamd_mempool_alloc(pool, num_str_len); + } + case UCL_BOOLEAN: { + auto *val = (gchar *) rspamd_mempool_alloc(pool, num_str_len); rspamd_snprintf(val, num_str_len, "%s", ((gboolean) cur->value.iv) ? "true" : "false"); + rspamd_rcl_insert_string_list_item(target, pool, val, is_hash); break; + } default: g_set_error(err, CFG_RCL_ERROR, @@ -3173,15 +3108,13 @@ rspamd_rcl_parse_struct_string_list(rspamd_mempool_t *pool, return FALSE; } - - rspamd_rcl_insert_string_list_item(target, pool, val, is_hash); } ucl_object_iterate_free(iter); #if 0 /* WTF: why don't we allow empty list here?? */ - if (*target == NULL) { + if (*target == nullptr) { g_set_error (err, CFG_RCL_ERROR, EINVAL, @@ -3193,8 +3126,8 @@ rspamd_rcl_parse_struct_string_list(rspamd_mempool_t *pool, } #endif - if (!is_hash && *target != NULL) { - *target = g_list_reverse(*target); + if (!is_hash && *target != nullptr) { + *target = g_list_reverse(*(GList **) target); if (need_destructor) { rspamd_mempool_add_destructor(pool, @@ -3213,7 +3146,7 @@ rspamd_rcl_parse_struct_ucl(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_struct_parser *pd = ud; + auto *pd = (struct rspamd_rcl_struct_parser *) ud; const ucl_object_t **target; target = (const ucl_object_t **) (((gchar *) pd->user_struct) + pd->offset); @@ -3231,7 +3164,7 @@ rspamd_rcl_parse_struct_boolean(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_struct_parser *pd = ud; + auto *pd = (struct rspamd_rcl_struct_parser *) ud; gboolean *target; target = (gboolean *) (((gchar *) pd->user_struct) + pd->offset); @@ -3266,7 +3199,7 @@ rspamd_rcl_parse_struct_addr(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_struct_parser *pd = ud; + auto *pd = (struct rspamd_rcl_struct_parser *) ud; rspamd_inet_addr_t **target; const gchar *val; gsize size; @@ -3305,8 +3238,8 @@ rspamd_rcl_parse_struct_mime_addr(rspamd_mempool_t *pool, struct rspamd_rcl_section *section, GError **err) { - struct rspamd_rcl_struct_parser *pd = ud; - GPtrArray **target, *tmp_addr = NULL; + auto *pd = (struct rspamd_rcl_struct_parser *) ud; + GPtrArray **target, *tmp_addr = nullptr; const gchar *val; ucl_object_iter_t it; const ucl_object_t *cur; @@ -3314,7 +3247,7 @@ rspamd_rcl_parse_struct_mime_addr(rspamd_mempool_t *pool, target = (GPtrArray **) (((gchar *) pd->user_struct) + pd->offset); it = ucl_object_iterate_new(obj); - while ((cur = ucl_object_iterate_safe(it, true)) != NULL) { + while ((cur = ucl_object_iterate_safe(it, true)) != nullptr) { if (ucl_object_type(cur) == UCL_STRING) { val = ucl_object_tostring(obj); tmp_addr = rspamd_email_address_from_mime(pool, val, @@ -3338,31 +3271,6 @@ rspamd_rcl_parse_struct_mime_addr(rspamd_mempool_t *pool, return TRUE; } -static guint -rspamd_worker_param_key_hash(gconstpointer p) -{ - const struct rspamd_worker_param_key *k = p; - rspamd_cryptobox_fast_hash_state_t st; - - rspamd_cryptobox_fast_hash_init(&st, rspamd_hash_seed()); - rspamd_cryptobox_fast_hash_update(&st, k->name, strlen(k->name)); - rspamd_cryptobox_fast_hash_update(&st, &k->ptr, sizeof(gpointer)); - - return rspamd_cryptobox_fast_hash_final(&st); -} - -static gboolean -rspamd_worker_param_key_equal(gconstpointer p1, gconstpointer p2) -{ - const struct rspamd_worker_param_key *k1 = p1, *k2 = p2; - - if (k1->ptr == k2->ptr) { - return strcmp(k1->name, k2->name) == 0; - } - - return FALSE; -} - void rspamd_rcl_register_worker_option(struct rspamd_config *cfg, GQuark type, const gchar *name, @@ -3372,26 +3280,11 @@ void rspamd_rcl_register_worker_option(struct rspamd_config *cfg, gint flags, const gchar *doc_string) { - struct rspamd_worker_param_parser *nhandler; - struct rspamd_worker_cfg_parser *nparser; - struct rspamd_worker_param_key srch; - const ucl_object_t *doc_workers, *doc_target; - ucl_object_t *doc_obj; + auto parser_it = cfg->rcl_top_section->workers_parser.try_emplace(type, rspamd_worker_cfg_parser{}); + auto &parser = parser_it.first->second; + auto handler_it = parser.parsers.try_emplace(std::make_pair(std::string{name}, target), rspamd_worker_param_parser{}); - nparser = g_hash_table_lookup(cfg->wrk_parsers, &type); - - if (nparser == NULL) { - rspamd_rcl_register_worker_parser(cfg, type, NULL, NULL); - nparser = g_hash_table_lookup(cfg->wrk_parsers, &type); - - g_assert(nparser != NULL); - } - - srch.name = name; - srch.ptr = target; - - nhandler = g_hash_table_lookup(nparser->parsers, &srch); - if (nhandler != NULL) { + if (!handler_it.second) { msg_warn_config( "handler for parameter %s is already registered for worker type %s", name, @@ -3399,30 +3292,24 @@ void rspamd_rcl_register_worker_option(struct rspamd_config *cfg, return; } - nhandler = - rspamd_mempool_alloc0(cfg->cfg_pool, - sizeof(struct rspamd_worker_param_parser)); - nhandler->key.name = name; - nhandler->key.ptr = target; - nhandler->parser.flags = flags; - nhandler->parser.offset = offset; - nhandler->parser.user_struct = target; - nhandler->handler = handler; - - g_hash_table_insert(nparser->parsers, &nhandler->key, nhandler); + auto &nhandler = handler_it.first->second; + nhandler.parser.flags = flags; + nhandler.parser.offset = offset; + nhandler.parser.user_struct = target; + nhandler.handler = handler; - doc_workers = ucl_object_lookup(cfg->doc_strings, "workers"); + const auto *doc_workers = ucl_object_lookup(cfg->doc_strings, "workers"); - if (doc_workers == NULL) { - doc_obj = ucl_object_typed_new(UCL_OBJECT); + if (doc_workers == nullptr) { + auto *doc_obj = ucl_object_typed_new(UCL_OBJECT); ucl_object_insert_key(cfg->doc_strings, doc_obj, "workers", 0, false); doc_workers = doc_obj; } - doc_target = ucl_object_lookup(doc_workers, g_quark_to_string(type)); + const auto *doc_target = ucl_object_lookup(doc_workers, g_quark_to_string(type)); - if (doc_target == NULL) { - doc_obj = ucl_object_typed_new(UCL_OBJECT); + if (doc_target == nullptr) { + auto *doc_obj = ucl_object_typed_new(UCL_OBJECT); ucl_object_insert_key((ucl_object_t *) doc_workers, doc_obj, g_quark_to_string(type), 0, true); doc_target = doc_obj; @@ -3434,41 +3321,15 @@ void rspamd_rcl_register_worker_option(struct rspamd_config *cfg, UCL_NULL, handler, flags, - NULL, + nullptr, 0); } - -void rspamd_rcl_register_worker_parser(struct rspamd_config *cfg, gint type, - gboolean (*func)(ucl_object_t *, gpointer), gpointer ud) -{ - struct rspamd_worker_cfg_parser *nparser; - - nparser = g_hash_table_lookup(cfg->wrk_parsers, &type); - - if (nparser == NULL) { - /* Allocate new parser for this worker */ - nparser = - rspamd_mempool_alloc0(cfg->cfg_pool, - sizeof(struct rspamd_worker_cfg_parser)); - nparser->type = type; - nparser->parsers = g_hash_table_new(rspamd_worker_param_key_hash, - rspamd_worker_param_key_equal); - rspamd_mempool_add_destructor(cfg->cfg_pool, - (rspamd_mempool_destruct_t) g_hash_table_unref, nparser->parsers); - - g_hash_table_insert(cfg->wrk_parsers, &nparser->type, nparser); - } - - nparser->def_obj_parser = func; - nparser->def_ud = ud; -} - /* Checksum functions */ static int rspamd_rcl_emitter_append_c(unsigned char c, size_t nchars, void *ud) { - rspamd_cryptobox_hash_state_t *hs = ud; + auto *hs = (rspamd_cryptobox_hash_state_t *) ud; guint64 d[2]; d[0] = nchars; @@ -3482,7 +3343,7 @@ rspamd_rcl_emitter_append_c(unsigned char c, size_t nchars, void *ud) static int rspamd_rcl_emitter_append_len(unsigned const char *str, size_t len, void *ud) { - rspamd_cryptobox_hash_state_t *hs = ud; + auto *hs = (rspamd_cryptobox_hash_state_t *) ud; rspamd_cryptobox_hash_update(hs, str, len); @@ -3491,7 +3352,7 @@ rspamd_rcl_emitter_append_len(unsigned const char *str, size_t len, void *ud) static int rspamd_rcl_emitter_append_int(int64_t elt, void *ud) { - rspamd_cryptobox_hash_state_t *hs = ud; + auto *hs = (rspamd_cryptobox_hash_state_t *) ud; rspamd_cryptobox_hash_update(hs, (const guchar *) &elt, sizeof(elt)); @@ -3501,36 +3362,16 @@ rspamd_rcl_emitter_append_int(int64_t elt, void *ud) static int rspamd_rcl_emitter_append_double(double elt, void *ud) { - rspamd_cryptobox_hash_state_t *hs = ud; + auto *hs = (rspamd_cryptobox_hash_state_t *) ud; rspamd_cryptobox_hash_update(hs, (const guchar *) &elt, sizeof(elt)); return 0; } -void rspamd_rcl_section_free(gpointer p) +void rspamd_rcl_sections_free(struct rspamd_rcl_sections_map *sections) { - struct rspamd_rcl_section *top = p, *cur, *tmp; - struct rspamd_rcl_default_handler_data *dh, *dhtmp; - - HASH_ITER(hh, top, cur, tmp) - { - HASH_DEL(top, cur); - - if (cur->subsections) { - rspamd_rcl_section_free(cur->subsections); - } - - HASH_ITER(hh, cur->default_parser, dh, dhtmp) - { - HASH_DEL(cur->default_parser, dh); - g_free(dh->key); - g_free(dh); - } - - ucl_object_unref(cur->doc_ref); - g_free(cur); - } + delete sections; } /** @@ -3554,12 +3395,12 @@ void rspamd_rcl_section_free(gpointer p) */ void rspamd_rcl_maybe_apply_lua_transform(struct rspamd_config *cfg) { - lua_State *L = cfg->lua_state; + auto *L = RSPAMD_LUA_CFG_STATE(cfg); gint err_idx, ret; gchar str[PATH_MAX]; static const char *transform_script = "lua_cfg_transform"; - g_assert(L != NULL); + g_assert(L != nullptr); rspamd_snprintf(str, sizeof(str), "return require \"%s\"", transform_script); @@ -3589,7 +3430,7 @@ void rspamd_rcl_maybe_apply_lua_transform(struct rspamd_config *cfg) lua_pushvalue(L, -2); /* Push the existing config */ - ucl_object_push_lua(L, cfg->rcl_obj, true); + ucl_object_push_lua(L, cfg->cfg_ucl_obj, true); if ((ret = lua_pcall(L, 1, 2, err_idx)) != 0) { msg_err("call to rspamadm lua script failed (%d): %s", ret, @@ -3600,10 +3441,10 @@ void rspamd_rcl_maybe_apply_lua_transform(struct rspamd_config *cfg) } if (lua_toboolean(L, -2) && lua_type(L, -1) == LUA_TTABLE) { - ucl_object_t *old_cfg = cfg->rcl_obj; + ucl_object_t *old_cfg = cfg->cfg_ucl_obj; msg_info_config("configuration has been transformed in Lua"); - cfg->rcl_obj = ucl_object_lua_import(L, -1); + cfg->cfg_ucl_obj = ucl_object_lua_import(L, -1); ucl_object_unref(old_cfg); } @@ -3617,8 +3458,8 @@ rspamd_rcl_decrypt_handler(struct ucl_parser *parser, unsigned char **destination, size_t *dest_len, void *user_data) { - GError *err = NULL; - struct rspamd_cryptobox_keypair *kp = (struct rspamd_cryptobox_keypair *) user_data; + GError *err = nullptr; + auto *kp = (struct rspamd_cryptobox_keypair *) user_data; if (!rspamd_keypair_decrypt(kp, source, source_len, destination, dest_len, &err)) { @@ -3637,12 +3478,11 @@ rspamd_rcl_jinja_handler(struct ucl_parser *parser, unsigned char **destination, size_t *dest_len, void *user_data) { - struct rspamd_config *cfg = (struct rspamd_config *) user_data; - lua_State *L = cfg->lua_state; - gint err_idx; + auto *cfg = (struct rspamd_config *) user_data; + auto *L = RSPAMD_LUA_CFG_STATE(cfg); lua_pushcfunction(L, &rspamd_lua_traceback); - err_idx = lua_gettop(L); + auto err_idx = lua_gettop(L); /* Obtain function */ if (!rspamd_lua_require_function(L, "lua_util", "jinja_template")) { @@ -3652,7 +3492,7 @@ rspamd_rcl_jinja_handler(struct ucl_parser *parser, return false; } - lua_pushlstring(L, source, source_len); + lua_pushlstring(L, (const char *) source, source_len); lua_getglobal(L, "rspamd_env"); lua_pushboolean(L, false); @@ -3669,7 +3509,7 @@ rspamd_rcl_jinja_handler(struct ucl_parser *parser, gsize nsize; ndata = lua_tolstring(L, -1, &nsize); - *destination = UCL_ALLOC(nsize); + *destination = (unsigned char *) UCL_ALLOC(nsize); memcpy(*destination, ndata, nsize); *dest_len = nsize; } @@ -3699,14 +3539,14 @@ void rspamd_config_calculate_cksum(struct rspamd_config *cfg) struct ucl_emitter_functions f; /* Calculate checksum */ - rspamd_cryptobox_hash_init(&hs, NULL, 0); + rspamd_cryptobox_hash_init(&hs, nullptr, 0); f.ucl_emitter_append_character = rspamd_rcl_emitter_append_c; f.ucl_emitter_append_double = rspamd_rcl_emitter_append_double; f.ucl_emitter_append_int = rspamd_rcl_emitter_append_int; f.ucl_emitter_append_len = rspamd_rcl_emitter_append_len; - f.ucl_emitter_free_func = NULL; + f.ucl_emitter_free_func = nullptr; f.ud = &hs; - ucl_object_emit_full(cfg->rcl_obj, UCL_EMIT_MSGPACK, + ucl_object_emit_full(cfg->cfg_ucl_obj, UCL_EMIT_MSGPACK, &f, cfg->config_comments); rspamd_cryptobox_hash_final(&hs, cksumbuf); cfg->checksum = rspamd_encode_base32(cksumbuf, sizeof(cksumbuf), RSPAMD_BASE32_DEFAULT); @@ -3724,55 +3564,30 @@ rspamd_config_parse_ucl(struct rspamd_config *cfg, gboolean skip_jinja, GError **err) { - struct stat st; - gint fd; - struct ucl_parser *parser; - gchar keypair_path[PATH_MAX]; - struct rspamd_cryptobox_keypair *decrypt_keypair = NULL; - gchar *data; - - if ((fd = open(filename, O_RDONLY)) == -1) { - g_set_error(err, cfg_rcl_error_quark(), errno, - "cannot open %s: %s", filename, strerror(errno)); - return FALSE; - } - if (fstat(fd, &st) == -1) { - g_set_error(err, cfg_rcl_error_quark(), errno, - "cannot stat %s: %s", filename, strerror(errno)); - close(fd); + struct rspamd_cryptobox_keypair *decrypt_keypair = nullptr; + auto cfg_file_maybe = rspamd::util::raii_mmaped_file::mmap_shared(filename, O_RDONLY, PROT_READ, 0); - return FALSE; - } - /* Now mmap this file to simplify reading process */ - if ((data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + if (!cfg_file_maybe) { g_set_error(err, cfg_rcl_error_quark(), errno, - "cannot mmap %s: %s", filename, strerror(errno)); - close(fd); - + "cannot open %s: %*s", filename, (int) cfg_file_maybe.error().error_message.size(), + cfg_file_maybe.error().error_message.data()); return FALSE; } - close(fd); + auto &cfg_file = cfg_file_maybe.value(); /* Try to load keyfile if available */ - rspamd_snprintf(keypair_path, sizeof(keypair_path), "%s.key", - filename); - if ((fd = open(keypair_path, O_RDONLY)) != -1) { - struct ucl_parser *kp_parser; - - kp_parser = ucl_parser_new(0); - - if (ucl_parser_add_fd(kp_parser, fd)) { - ucl_object_t *kp_obj; - - kp_obj = ucl_parser_get_object(kp_parser); + rspamd::util::raii_file::open(fmt::format("{}.key", filename), O_RDONLY).map([&](const auto &keyfile) { + auto *kp_parser = ucl_parser_new(0); + if (ucl_parser_add_fd(kp_parser, keyfile.get_fd())) { + auto *kp_obj = ucl_parser_get_object(kp_parser); - g_assert(kp_obj != NULL); + g_assert(kp_obj != nullptr); decrypt_keypair = rspamd_keypair_from_ucl(kp_obj); - if (decrypt_keypair == NULL) { - msg_err_config_forced("cannot load keypair from %s: invalid keypair", - keypair_path); + if (decrypt_keypair == nullptr) { + msg_err_config_forced("cannot load keypair from %s.key: invalid keypair", + filename); } else { /* Add decryption support to UCL */ @@ -3784,62 +3599,52 @@ rspamd_config_parse_ucl(struct rspamd_config *cfg, ucl_object_unref(kp_obj); } else { - msg_err_config_forced("cannot load keypair from %s: %s", - keypair_path, ucl_parser_get_error(kp_parser)); + msg_err_config_forced("cannot load keypair from %s.key: %s", + filename, ucl_parser_get_error(kp_parser)); } - ucl_parser_free(kp_parser); - close(fd); - } + }); - parser = ucl_parser_new(UCL_PARSER_SAVE_COMMENTS); - rspamd_ucl_add_conf_variables(parser, vars); - rspamd_ucl_add_conf_macros(parser, cfg); - ucl_parser_set_filevars(parser, filename, true); + auto parser = std::shared_ptr<ucl_parser>(ucl_parser_new(UCL_PARSER_SAVE_COMMENTS), ucl_parser_free); + rspamd_ucl_add_conf_variables(parser.get(), vars); + rspamd_ucl_add_conf_macros(parser.get(), cfg); + ucl_parser_set_filevars(parser.get(), filename, true); if (inc_trace) { - ucl_parser_set_include_tracer(parser, inc_trace, trace_data); + ucl_parser_set_include_tracer(parser.get(), inc_trace, trace_data); } if (decrypt_keypair) { - struct ucl_parser_special_handler *decrypt_handler; - - decrypt_handler = rspamd_mempool_alloc0(cfg->cfg_pool, - sizeof(*decrypt_handler)); + auto *decrypt_handler = rspamd_mempool_alloc0_type(cfg->cfg_pool, + struct ucl_parser_special_handler); decrypt_handler->user_data = decrypt_keypair; decrypt_handler->magic = encrypted_magic; decrypt_handler->magic_len = sizeof(encrypted_magic); decrypt_handler->handler = rspamd_rcl_decrypt_handler; decrypt_handler->free_function = rspamd_rcl_decrypt_free; - ucl_parser_add_special_handler(parser, decrypt_handler); + ucl_parser_add_special_handler(parser.get(), decrypt_handler); } if (!skip_jinja) { - struct ucl_parser_special_handler *jinja_handler; - - jinja_handler = rspamd_mempool_alloc0(cfg->cfg_pool, - sizeof(*jinja_handler)); + auto *jinja_handler = rspamd_mempool_alloc0_type(cfg->cfg_pool, + struct ucl_parser_special_handler); jinja_handler->user_data = cfg; jinja_handler->flags = UCL_SPECIAL_HANDLER_PREPROCESS_ALL; jinja_handler->handler = rspamd_rcl_jinja_handler; - ucl_parser_add_special_handler(parser, jinja_handler); + ucl_parser_add_special_handler(parser.get(), jinja_handler); } - if (!ucl_parser_add_chunk(parser, data, st.st_size)) { + if (!ucl_parser_add_chunk(parser.get(), (unsigned char *) cfg_file.get_map(), cfg_file.get_size())) { g_set_error(err, cfg_rcl_error_quark(), errno, - "ucl parser error: %s", ucl_parser_get_error(parser)); - ucl_parser_free(parser); - munmap(data, st.st_size); + "ucl parser error: %s", ucl_parser_get_error(parser.get())); return FALSE; } - munmap(data, st.st_size); - cfg->rcl_obj = ucl_parser_get_object(parser); - cfg->config_comments = ucl_object_ref(ucl_parser_get_comments(parser)); - ucl_parser_free(parser); + cfg->cfg_ucl_obj = ucl_parser_get_object(parser.get()); + cfg->config_comments = ucl_object_ref(ucl_parser_get_comments(parser.get())); return TRUE; } @@ -3853,45 +3658,45 @@ rspamd_config_read(struct rspamd_config *cfg, gboolean skip_jinja, gchar **lua_env) { - GError *err = NULL; - struct rspamd_rcl_section *top, *logger_section; - const ucl_object_t *logger_obj; + GError *err = nullptr; - rspamd_lua_set_path(cfg->lua_state, NULL, vars); + rspamd_lua_set_path(RSPAMD_LUA_CFG_STATE(cfg), nullptr, vars); - if (!rspamd_lua_set_env(cfg->lua_state, vars, lua_env, &err)) { + if (!rspamd_lua_set_env(RSPAMD_LUA_CFG_STATE(cfg), vars, lua_env, &err)) { msg_err_config_forced("failed to set up environment: %e", err); g_error_free(err); return FALSE; } - if (!rspamd_config_parse_ucl(cfg, filename, vars, NULL, NULL, skip_jinja, &err)) { + if (!rspamd_config_parse_ucl(cfg, filename, vars, nullptr, nullptr, skip_jinja, &err)) { msg_err_config_forced("failed to load config: %e", err); g_error_free(err); return FALSE; } - top = rspamd_rcl_config_init(cfg, NULL); + auto *top = rspamd_rcl_config_init(cfg, nullptr); + cfg->rcl_top_section = top; /* Add new paths if defined in options */ - rspamd_lua_set_path(cfg->lua_state, cfg->rcl_obj, vars); - rspamd_lua_set_globals(cfg, cfg->lua_state); - rspamd_mempool_add_destructor(cfg->cfg_pool, rspamd_rcl_section_free, top); - err = NULL; + rspamd_lua_set_path(RSPAMD_LUA_CFG_STATE(cfg), cfg->cfg_ucl_obj, vars); + rspamd_lua_set_globals(cfg, RSPAMD_LUA_CFG_STATE(cfg)); + rspamd_mempool_add_destructor(cfg->cfg_pool, (rspamd_mempool_destruct_t) rspamd_rcl_sections_free, top); + err = nullptr; - if (logger_fin != NULL) { - HASH_FIND_STR(top, "logging", logger_section); + /* Pre-init logging if possible */ + if (logger_fin != nullptr) { + auto logging_section_maybe = rspamd::find_map(top->sections, "logging"); - if (logger_section != NULL) { - logger_obj = ucl_object_lookup_any(cfg->rcl_obj, "logging", - "logger", NULL); + if (logging_section_maybe) { + const auto *logger_obj = ucl_object_lookup_any(cfg->cfg_ucl_obj, "logging", + "logger", nullptr); - if (logger_obj == NULL) { + if (logger_obj == nullptr) { logger_fin(cfg->cfg_pool, logger_ud); } else { - if (!rspamd_rcl_process_section(cfg, logger_section, cfg, + if (!rspamd_rcl_process_section(cfg, *logging_section_maybe.value().get().get(), cfg, logger_obj, cfg->cfg_pool, &err)) { msg_err_config_forced("cannot init logger: %e", err); g_error_free(err); @@ -3903,38 +3708,32 @@ rspamd_config_read(struct rspamd_config *cfg, } /* Init lua logging */ - lua_State *L = cfg->lua_state; - gint err_idx; - struct rspamd_config **pcfg; - - lua_pushcfunction(L, &rspamd_lua_traceback); - err_idx = lua_gettop(L); + lua_pushcfunction(RSPAMD_LUA_CFG_STATE(cfg), &rspamd_lua_traceback); + auto err_idx = lua_gettop(RSPAMD_LUA_CFG_STATE(cfg)); /* Obtain function */ - if (!rspamd_lua_require_function(L, "lua_util", + if (!rspamd_lua_require_function(RSPAMD_LUA_CFG_STATE(cfg), "lua_util", "init_debug_logging")) { msg_err_config("cannot require lua_util.init_debug_logging"); - lua_settop(L, err_idx - 1); + lua_settop(RSPAMD_LUA_CFG_STATE(cfg), err_idx - 1); return FALSE; } - pcfg = lua_newuserdata(L, sizeof(*pcfg)); - *pcfg = cfg; - rspamd_lua_setclass(L, "rspamd{config}", -1); + void *pcfg = lua_newuserdata(RSPAMD_LUA_CFG_STATE(cfg), sizeof(void *)); + memcpy(pcfg, &cfg, sizeof(void *)); + rspamd_lua_setclass(RSPAMD_LUA_CFG_STATE(cfg), "rspamd{config}", -1); - if (lua_pcall(L, 1, 0, err_idx) != 0) { + if (lua_pcall(RSPAMD_LUA_CFG_STATE(cfg), 1, 0, err_idx) != 0) { msg_err_config("cannot call lua init_debug_logging script: %s", - lua_tostring(L, -1)); - lua_settop(L, err_idx - 1); + lua_tostring(RSPAMD_LUA_CFG_STATE(cfg), -1)); + lua_settop(RSPAMD_LUA_CFG_STATE(cfg), err_idx - 1); return FALSE; } - lua_settop(L, err_idx - 1); + lua_settop(RSPAMD_LUA_CFG_STATE(cfg), err_idx - 1); } - - HASH_DEL(top, logger_section); } } @@ -3942,7 +3741,7 @@ rspamd_config_read(struct rspamd_config *cfg, rspamd_rcl_maybe_apply_lua_transform(cfg); rspamd_config_calculate_cksum(cfg); - if (!rspamd_rcl_parse(top, cfg, cfg, cfg->cfg_pool, cfg->rcl_obj, &err)) { + if (!rspamd_rcl_parse(top, cfg, cfg, cfg->cfg_pool, cfg->cfg_ucl_obj, &err)) { msg_err_config("rcl parse error: %e", err); if (err) { @@ -3965,16 +3764,8 @@ rspamd_rcl_doc_obj_from_handler(ucl_object_t *doc_obj, rspamd_rcl_default_handler_t handler, gint flags) { - gboolean has_example = FALSE, has_type = FALSE; - const gchar *type = NULL; - - if (ucl_object_lookup(doc_obj, "example") != NULL) { - has_example = TRUE; - } - - if (ucl_object_lookup(doc_obj, "type") != NULL) { - has_type = TRUE; - } + auto has_example = ucl_object_lookup(doc_obj, "example") != nullptr; + auto has_type = ucl_object_lookup(doc_obj, "type") != nullptr; if (handler == rspamd_rcl_parse_struct_string) { if (!has_type) { @@ -3983,7 +3774,7 @@ rspamd_rcl_doc_obj_from_handler(ucl_object_t *doc_obj, } } else if (handler == rspamd_rcl_parse_struct_integer) { - type = "int"; + auto *type = "int"; if (flags & RSPAMD_CL_FLAG_INT_16) { type = "int16"; @@ -4013,7 +3804,7 @@ rspamd_rcl_doc_obj_from_handler(ucl_object_t *doc_obj, } } else if (handler == rspamd_rcl_parse_struct_time) { - type = "time"; + auto *type = "time"; if (!has_type) { ucl_object_insert_key(doc_obj, ucl_object_fromstring(type), @@ -4029,7 +3820,7 @@ rspamd_rcl_doc_obj_from_handler(ucl_object_t *doc_obj, ucl_object_insert_key(doc_obj, ucl_object_fromstring_common("param = \"str1, str2, str3\" OR " "param = [\"str1\", \"str2\", \"str3\"]", - 0, 0), + 0, static_cast<ucl_string_flags>(0)), "example", 0, false); @@ -4095,8 +3886,8 @@ rspamd_rcl_add_doc_obj(ucl_object_t *doc_target, { ucl_object_t *doc_obj; - if (doc_target == NULL || doc_name == NULL) { - return NULL; + if (doc_target == nullptr || doc_name == nullptr) { + return nullptr; } doc_obj = ucl_object_typed_new(UCL_OBJECT); @@ -4104,7 +3895,7 @@ rspamd_rcl_add_doc_obj(ucl_object_t *doc_target, /* Insert doc string itself */ if (doc_string) { ucl_object_insert_key(doc_obj, - ucl_object_fromstring_common(doc_string, 0, 0), + ucl_object_fromstring_common(doc_string, 0, static_cast<ucl_string_flags>(0)), "data", 0, false); } else { @@ -4126,7 +3917,7 @@ rspamd_rcl_add_doc_obj(ucl_object_t *doc_target, if (default_value) { ucl_object_insert_key(doc_obj, - ucl_object_fromstring_common(default_value, 0, 0), + ucl_object_fromstring_common(default_value, 0, static_cast<ucl_string_flags>(0)), "default", 0, false); } @@ -4146,11 +3937,9 @@ rspamd_rcl_add_doc_by_path(struct rspamd_config *cfg, const char *default_value, gboolean required) { - const ucl_object_t *found, *cur; - ucl_object_t *obj; - gchar **path_components, **comp; + const auto *cur = cfg->doc_strings; - if (doc_path == NULL) { + if (doc_path == nullptr) { /* Assume top object */ return rspamd_rcl_add_doc_obj(cfg->doc_strings, doc_string, @@ -4162,9 +3951,9 @@ rspamd_rcl_add_doc_by_path(struct rspamd_config *cfg, required); } else { - found = ucl_object_lookup_path(cfg->doc_strings, doc_path); + const auto *found = ucl_object_lookup_path(cfg->doc_strings, doc_path); - if (found != NULL) { + if (found != nullptr) { return rspamd_rcl_add_doc_obj((ucl_object_t *) found, doc_string, doc_name, @@ -4176,35 +3965,25 @@ rspamd_rcl_add_doc_by_path(struct rspamd_config *cfg, } /* Otherwise we need to insert all components of the path */ - path_components = g_strsplit_set(doc_path, ".", -1); - cur = cfg->doc_strings; - - for (comp = path_components; *comp != NULL; comp++) { + rspamd::string_foreach_delim(doc_path, ".", [&](const std::string_view &elt) { if (ucl_object_type(cur) != UCL_OBJECT) { - msg_err_config("Bad path while lookup for '%s' at %s", - doc_path, *comp); - g_strfreev(path_components); - - return NULL; + msg_err_config("Bad path while lookup for '%s' at %*s", + doc_path, (int) elt.size(), elt.data()); } - - found = ucl_object_lookup(cur, *comp); - - if (found == NULL) { - obj = ucl_object_typed_new(UCL_OBJECT); + const auto *found = ucl_object_lookup_len(cur, elt.data(), elt.size()); + if (found == nullptr) { + auto *obj = ucl_object_typed_new(UCL_OBJECT); ucl_object_insert_key((ucl_object_t *) cur, obj, - *comp, - 0, + elt.data(), + elt.size(), true); cur = obj; } else { cur = found; } - } - - g_strfreev(path_components); + }); } return rspamd_rcl_add_doc_obj(ucl_object_ref(cur), @@ -4222,18 +4001,18 @@ rspamd_rcl_add_doc_from_comments(struct rspamd_config *cfg, ucl_object_t *top_doc, const ucl_object_t *obj, const ucl_object_t *comments, gboolean is_top) { - ucl_object_iter_t it = NULL; + ucl_object_iter_t it = nullptr; const ucl_object_t *cur, *cmt; ucl_object_t *cur_doc; if (ucl_object_type(obj) == UCL_OBJECT) { - while ((cur = ucl_object_iterate(obj, &it, true)) != NULL) { - cur_doc = NULL; + while ((cur = ucl_object_iterate(obj, &it, true)) != nullptr) { + cur_doc = nullptr; - if ((cmt = ucl_comments_find(comments, cur)) != NULL) { + if ((cmt = ucl_comments_find(comments, cur)) != nullptr) { cur_doc = rspamd_rcl_add_doc_obj(top_doc, ucl_object_tostring(cmt), ucl_object_key(cur), - ucl_object_type(cur), NULL, 0, NULL, FALSE); + ucl_object_type(cur), nullptr, 0, nullptr, FALSE); } if (ucl_object_type(cur) == UCL_OBJECT) { @@ -4251,10 +4030,10 @@ rspamd_rcl_add_doc_from_comments(struct rspamd_config *cfg, } } else if (!is_top) { - if ((cmt = ucl_comments_find(comments, obj)) != NULL) { + if ((cmt = ucl_comments_find(comments, obj)) != nullptr) { rspamd_rcl_add_doc_obj(top_doc, ucl_object_tostring(cmt), ucl_object_key(obj), - ucl_object_type(obj), NULL, 0, NULL, FALSE); + ucl_object_type(obj), nullptr, 0, nullptr, FALSE); } } } @@ -4266,28 +4045,23 @@ rspamd_rcl_add_doc_by_example(struct rspamd_config *cfg, const gchar *doc_name, const gchar *example_data, gsize example_len) { - struct ucl_parser *parser; - ucl_object_t *top, *top_doc; - const ucl_object_t *comments; - - parser = ucl_parser_new(UCL_PARSER_NO_FILEVARS | UCL_PARSER_SAVE_COMMENTS); + auto parser = std::shared_ptr<ucl_parser>(ucl_parser_new(UCL_PARSER_NO_FILEVARS | UCL_PARSER_SAVE_COMMENTS), ucl_parser_free); - if (!ucl_parser_add_chunk(parser, example_data, example_len)) { + if (!ucl_parser_add_chunk(parser.get(), reinterpret_cast<const unsigned char *>(example_data), example_len)) { msg_err_config("cannot parse example: %s", - ucl_parser_get_error(parser)); - ucl_parser_free(parser); + ucl_parser_get_error(parser.get())); - return NULL; + return nullptr; } - top = ucl_parser_get_object(parser); - comments = ucl_parser_get_comments(parser); + auto *top = ucl_parser_get_object(parser.get()); + const auto *comments = ucl_parser_get_comments(parser.get()); /* Add top object */ - top_doc = rspamd_rcl_add_doc_by_path(cfg, root_path, doc_string, - doc_name, ucl_object_type(top), NULL, 0, NULL, FALSE); + auto *top_doc = rspamd_rcl_add_doc_by_path(cfg, root_path, doc_string, + doc_name, ucl_object_type(top), nullptr, 0, nullptr, FALSE); ucl_object_insert_key(top_doc, - ucl_object_fromstring_common(example_data, example_len, 0), + ucl_object_fromstring_common(example_data, example_len, static_cast<ucl_string_flags>(0)), "example", 0, false); rspamd_rcl_add_doc_from_comments(cfg, top_doc, top, comments, TRUE); diff --git a/src/libserver/cfg_rcl.h b/src/libserver/cfg_rcl.h index 6bbeda0e6..766c55e83 100644 --- a/src/libserver/cfg_rcl.h +++ b/src/libserver/cfg_rcl.h @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -33,6 +33,7 @@ extern "C" { #endif struct rspamd_rcl_section; +struct rspamd_rcl_sections_map; struct rspamd_config; struct rspamd_rcl_default_handler_data; @@ -59,7 +60,7 @@ struct rspamd_rcl_struct_parser { struct rspamd_config *cfg; gpointer user_struct; goffset offset; - enum rspamd_rcl_flag flags; + int flags; /* enum rspamd_rcl_flag */ }; @@ -120,13 +121,18 @@ struct rspamd_rcl_default_handler_data *rspamd_rcl_add_default_handler( * @return newly created structure */ struct rspamd_rcl_section *rspamd_rcl_add_section( - struct rspamd_rcl_section **top, - const gchar *name, const gchar *key_attr, + struct rspamd_rcl_sections_map **top, + struct rspamd_rcl_section *parent_section, + const gchar *name, + const gchar *key_attr, rspamd_rcl_handler_t handler, - enum ucl_type type, gboolean required, gboolean strict_type); + enum ucl_type type, + gboolean required, + gboolean strict_type); struct rspamd_rcl_section *rspamd_rcl_add_section_doc( - struct rspamd_rcl_section **top, + struct rspamd_rcl_sections_map **top, + struct rspamd_rcl_section *parent_section, const gchar *name, const gchar *key_attr, rspamd_rcl_handler_t handler, enum ucl_type type, gboolean required, @@ -138,18 +144,8 @@ struct rspamd_rcl_section *rspamd_rcl_add_section_doc( * Init common sections known to rspamd * @return top section */ -struct rspamd_rcl_section *rspamd_rcl_config_init(struct rspamd_config *cfg, - GHashTable *skip_sections); - -/** - * Get a section specified by path, it understand paths separated by '/' character - * @param top top section - * @param path '/' divided path - * @return - */ -struct rspamd_rcl_section *rspamd_rcl_config_get_section( - struct rspamd_rcl_section *top, - const char *path); +struct rspamd_rcl_sections_map *rspamd_rcl_config_init(struct rspamd_config *cfg, + GHashTable *skip_sections); /** * Parse configuration @@ -161,25 +157,11 @@ struct rspamd_rcl_section *rspamd_rcl_config_get_section( * @param err error pointer * @return */ -gboolean rspamd_rcl_parse(struct rspamd_rcl_section *top, +gboolean rspamd_rcl_parse(struct rspamd_rcl_sections_map *top, struct rspamd_config *cfg, gpointer ptr, rspamd_mempool_t *pool, const ucl_object_t *obj, GError **err); - -/** - * Parse default structure for a section - * @param section section - * @param cfg config file - * @param obj object to parse - * @param ptr ptr to pass - * @param err error ptr - * @return TRUE if the object has been parsed - */ -gboolean rspamd_rcl_section_parse_defaults(struct rspamd_config *cfg, - struct rspamd_rcl_section *section, - rspamd_mempool_t *pool, const ucl_object_t *obj, gpointer ptr, - GError **err); /** * Here is a section of common handlers that accepts rcl_struct_parser * which itself contains a struct pointer and the offset of a member in a @@ -376,16 +358,6 @@ void rspamd_rcl_register_worker_option(struct rspamd_config *cfg, const gchar *doc_string); /** - * Register a default parser for a worker - * @param cfg config structure - * @param type type of worker (GQuark) - * @param func handler function - * @param ud userdata for handler function - */ -void rspamd_rcl_register_worker_parser(struct rspamd_config *cfg, gint type, - gboolean (*func)(ucl_object_t *, gpointer), gpointer ud); - -/** * Adds new documentation object to the configuration * @param doc_target target object where to insert documentation (top object is used if this is NULL) * @param doc_object documentation object to insert @@ -448,10 +420,10 @@ ucl_object_t *rspamd_rcl_add_doc_by_example(struct rspamd_config *cfg, * @param err * @return */ -gboolean rspamd_rcl_add_lua_plugins_path(struct rspamd_config *cfg, +gboolean rspamd_rcl_add_lua_plugins_path(struct rspamd_rcl_sections_map *sections, + struct rspamd_config *cfg, const gchar *path, gboolean main_path, - GHashTable *modules_seen, GError **err); @@ -475,7 +447,7 @@ gboolean rspamd_rcl_add_lua_plugins_path(struct rspamd_config *cfg, * @param cfg */ void rspamd_rcl_maybe_apply_lua_transform(struct rspamd_config *cfg); -void rspamd_rcl_section_free(gpointer p); +void rspamd_rcl_sections_free(struct rspamd_rcl_sections_map *sections); void rspamd_config_calculate_cksum(struct rspamd_config *cfg); diff --git a/src/libserver/cfg_utils.c b/src/libserver/cfg_utils.cxx index cdb1518a8..5c5a8a24b 100644 --- a/src/libserver/cfg_utils.c +++ b/src/libserver/cfg_utils.cxx @@ -15,12 +15,13 @@ */ #include "config.h" +#include "lua/lua_common.h" +#include "lua/lua_thread_pool.h" + #include "cfg_file.h" #include "rspamd.h" #include "cfg_file_private.h" -#include "scan_result.h" -#include "lua/lua_common.h" -#include "lua/lua_thread_pool.h" + #include "maps/map.h" #include "maps/map_helpers.h" #include "maps/map_private.h" @@ -61,6 +62,15 @@ #include "blas-config.h" +#include <string> +#include <string_view> +#include <vector> +#include "fmt/core.h" +#include "cxx/util.hxx" +#include "frozen/unordered_map.h" +#include "frozen/string.h" +#include "contrib/ankerl/unordered_dense.h" + #define DEFAULT_SCORE 10.0 #define DEFAULT_RLIMIT_NOFILE 2048 @@ -84,7 +94,12 @@ struct rspamd_ucl_map_cbdata { struct rspamd_config *cfg; - GString *buf; + std::string buf; + + explicit rspamd_ucl_map_cbdata(struct rspamd_config *cfg) + : cfg(cfg) + { + } }; static gchar *rspamd_ucl_read_cb(gchar *chunk, gint len, @@ -99,6 +114,51 @@ RSPAMD_CONSTRUCTOR(rspamd_config_log_init) rspamd_config_log_id = rspamd_logger_add_debug_module("config"); } +struct rspamd_actions_list { + using action_ptr = std::shared_ptr<rspamd_action>; + std::vector<action_ptr> actions; + ankerl::unordered_dense::map<std::string_view, action_ptr> actions_by_name; + + explicit rspamd_actions_list() + { + actions.reserve(METRIC_ACTION_MAX + 2); + actions_by_name.reserve(METRIC_ACTION_MAX + 2); + } + + void add_action(action_ptr action) + { + actions.push_back(action); + actions_by_name[action->name] = action; + sort(); + } + + void sort() + { + std::sort(actions.begin(), actions.end(), [](const action_ptr &a1, const action_ptr &a2) -> bool { + if (!isnan(a1->threshold) && !isnan(a2->threshold)) { + return a1->threshold < a2->threshold; + } + + if (isnan(a1->threshold) && isnan(a2->threshold)) { + return false; + } + else if (isnan(a1->threshold)) { + return true; + } + + return false; + }); + } + + void clear() + { + actions.clear(); + actions_by_name.clear(); + } +}; + +#define RSPAMD_CFG_ACTIONS(cfg) (reinterpret_cast<rspamd_actions_list *>((cfg)->actions)) + gboolean rspamd_parse_bind_line(struct rspamd_config *cfg, struct rspamd_worker_conf *cf, @@ -108,25 +168,29 @@ rspamd_parse_bind_line(struct rspamd_config *cfg, const gchar *fdname; gboolean ret = TRUE; - if (str == NULL) { + if (str == nullptr) { return FALSE; } - cnf = g_malloc0(sizeof(struct rspamd_worker_bind_conf)); + cnf = rspamd_mempool_alloc0_type(cfg->cfg_pool, struct rspamd_worker_bind_conf); cnf->cnt = 1024; - cnf->bind_line = g_strdup(str); + cnf->bind_line = rspamd_mempool_strdup(cfg->cfg_pool, str); + + auto bind_line = std::string_view{cnf->bind_line}; - if (g_ascii_strncasecmp(str, "systemd:", sizeof("systemd:") - 1) == 0) { + if (bind_line.starts_with("systemd:")) { /* The actual socket will be passed by systemd environment */ fdname = str + sizeof("systemd:") - 1; cnf->is_systemd = TRUE; - cnf->addrs = g_ptr_array_new_full(1, g_free); + cnf->addrs = g_ptr_array_new_full(1, nullptr); + rspamd_mempool_add_destructor(cfg->cfg_pool, + rspamd_ptr_array_free_hard, cnf->addrs); if (fdname[0]) { - g_ptr_array_add(cnf->addrs, g_strdup(fdname)); + g_ptr_array_add(cnf->addrs, rspamd_mempool_strdup(cfg->cfg_pool, fdname)); cnf->cnt = cnf->addrs->len; - cnf->name = g_strdup(str); + cnf->name = rspamd_mempool_strdup(cfg->cfg_pool, str); LL_PREPEND(cf->bind_conf, cnf); } else { @@ -136,7 +200,7 @@ rspamd_parse_bind_line(struct rspamd_config *cfg, } else { if (rspamd_parse_host_port_priority(str, &cnf->addrs, - NULL, &cnf->name, DEFAULT_BIND_PORT, TRUE, NULL) == RSPAMD_PARSE_ADDR_FAIL) { + nullptr, &cnf->name, DEFAULT_BIND_PORT, TRUE, cfg->cfg_pool) == RSPAMD_PARSE_ADDR_FAIL) { msg_err_config("cannot parse bind line: %s", str); ret = FALSE; } @@ -146,15 +210,6 @@ rspamd_parse_bind_line(struct rspamd_config *cfg, } } - if (!ret) { - if (cnf->addrs) { - g_ptr_array_free(cnf->addrs, TRUE); - } - - g_free(cnf->name); - g_free(cnf); - } - return ret; } @@ -174,15 +229,16 @@ rspamd_config_new(enum rspamd_config_init_flags flags) cfg->dns_io_per_server = 16; cfg->unknown_weight = NAN; + cfg->actions = (void *) new rspamd_actions_list(); + /* Add all internal actions to keep compatibility */ for (int i = METRIC_ACTION_REJECT; i < METRIC_ACTION_MAX; i++) { - struct rspamd_action *action; - action = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*action)); + auto &&action = std::make_shared<rspamd_action>(); action->threshold = NAN; action->name = rspamd_mempool_strdup(cfg->cfg_pool, - rspamd_action_to_str(i)); - action->action_type = i; + rspamd_action_to_str(static_cast<rspamd_action_type>(i))); + action->action_type = static_cast<rspamd_action_type>(i); if (i == METRIC_ACTION_SOFT_REJECT) { action->flags |= RSPAMD_ACTION_NO_THRESHOLD | RSPAMD_ACTION_HAM; @@ -194,8 +250,7 @@ rspamd_config_new(enum rspamd_config_init_flags flags) action->flags |= RSPAMD_ACTION_HAM; } - HASH_ADD_KEYPTR(hh, cfg->actions, - action->name, strlen(action->name), action); + RSPAMD_CFG_ACTIONS(cfg)->add_action(std::move(action)); } /* Disable timeout */ @@ -209,7 +264,6 @@ rspamd_config_new(enum rspamd_config_init_flags flags) cfg->cfg_params = g_hash_table_new(rspamd_str_hash, rspamd_str_equal); cfg->debug_modules = g_hash_table_new(rspamd_str_hash, rspamd_str_equal); cfg->explicit_modules = g_hash_table_new(rspamd_str_hash, rspamd_str_equal); - cfg->wrk_parsers = g_hash_table_new(g_int_hash, g_int_equal); cfg->trusted_keys = g_hash_table_new(rspamd_str_hash, rspamd_str_equal); @@ -233,11 +287,12 @@ rspamd_config_new(enum rspamd_config_init_flags flags) cfg->max_opts_len = 4096; /* Default log line */ - cfg->log_format_str = "id: <$mid>,$if_qid{ qid: <$>,}$if_ip{ ip: $,}" - "$if_user{ user: $,}$if_smtp_from{ from: <$>,} (default: $is_spam " - "($action): [$scores] [$symbols_scores_params]), len: $len, time: $time_real, " - "dns req: $dns_req, digest: <$digest>" - "$if_smtp_rcpts{ rcpts: <$>, }$if_mime_rcpt{ mime_rcpt: <$>, }"; + cfg->log_format_str = rspamd_mempool_strdup(cfg->cfg_pool, + "id: <$mid>,$if_qid{ qid: <$>,}$if_ip{ ip: $,}" + "$if_user{ user: $,}$if_smtp_from{ from: <$>,} (default: $is_spam " + "($action): [$scores] [$symbols_scores_params]), len: $len, time: $time_real, " + "dns req: $dns_req, digest: <$digest>" + "$if_smtp_rcpts{ rcpts: <$>, }$if_mime_rcpt{ mime_rcpt: <$>, }"); /* Allow non-mime input by default */ cfg->allow_raw_input = TRUE; /* Default maximum words processed */ @@ -252,12 +307,12 @@ rspamd_config_new(enum rspamd_config_init_flags flags) cfg->full_gc_iters = DEFAULT_GC_MAXITERS; /* Default hyperscan cache */ - cfg->hs_cache_dir = RSPAMD_DBDIR "/"; + cfg->hs_cache_dir = rspamd_mempool_strdup(cfg->cfg_pool, RSPAMD_DBDIR "/"); if (!(flags & RSPAMD_CONFIG_INIT_SKIP_LUA)) { - cfg->lua_state = rspamd_lua_init(flags & RSPAMD_CONFIG_INIT_WIPE_LUA_MEM); + cfg->lua_state = (void *) rspamd_lua_init(flags & RSPAMD_CONFIG_INIT_WIPE_LUA_MEM); cfg->own_lua_state = TRUE; - cfg->lua_thread_pool = lua_thread_pool_new(cfg->lua_state); + cfg->lua_thread_pool = (void *) lua_thread_pool_new(RSPAMD_LUA_CFG_STATE(cfg)); } cfg->cache = rspamd_symcache_new(cfg); @@ -269,7 +324,7 @@ rspamd_config_new(enum rspamd_config_init_flags flags) */ cfg->enable_shutdown_workaround = TRUE; - cfg->ssl_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"; + cfg->ssl_ciphers = rspamd_mempool_strdup(cfg->cfg_pool, "HIGH:!anullptr:!kRSA:!PSK:!SRP:!MD5:!RC4"); cfg->max_message = DEFAULT_MAX_MESSAGE; cfg->max_pic_size = DEFAULT_MAX_PIC; cfg->images_cache_size = 256; @@ -295,27 +350,27 @@ void rspamd_config_free(struct rspamd_config *cfg) struct rspamd_config_settings_elt *set, *stmp; struct rspamd_worker_log_pipe *lp, *ltmp; - rspamd_lua_run_config_unload(cfg->lua_state, cfg); + rspamd_lua_run_config_unload(RSPAMD_LUA_CFG_STATE(cfg), cfg); /* Scripts part */ DL_FOREACH_SAFE(cfg->on_term_scripts, sc, sctmp) { - luaL_unref(cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref); + luaL_unref(RSPAMD_LUA_CFG_STATE(cfg), LUA_REGISTRYINDEX, sc->cbref); } DL_FOREACH_SAFE(cfg->on_load_scripts, sc, sctmp) { - luaL_unref(cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref); + luaL_unref(RSPAMD_LUA_CFG_STATE(cfg), LUA_REGISTRYINDEX, sc->cbref); } DL_FOREACH_SAFE(cfg->post_init_scripts, sc, sctmp) { - luaL_unref(cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref); + luaL_unref(RSPAMD_LUA_CFG_STATE(cfg), LUA_REGISTRYINDEX, sc->cbref); } DL_FOREACH_SAFE(cfg->config_unload_scripts, sc, sctmp) { - luaL_unref(cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref); + luaL_unref(RSPAMD_LUA_CFG_STATE(cfg), LUA_REGISTRYINDEX, sc->cbref); } DL_FOREACH_SAFE(cfg->setting_ids, set, stmp) @@ -329,7 +384,7 @@ void rspamd_config_free(struct rspamd_config *cfg) g_list_free(cfg->classifiers); g_list_free(cfg->workers); rspamd_symcache_destroy(cfg->cache); - ucl_object_unref(cfg->rcl_obj); + ucl_object_unref(cfg->cfg_ucl_obj); ucl_object_unref(cfg->config_comments); ucl_object_unref(cfg->doc_strings); ucl_object_unref(cfg->neighbours); @@ -338,7 +393,6 @@ void rspamd_config_free(struct rspamd_config *cfg) g_hash_table_unref(cfg->classifiers_symbols); g_hash_table_unref(cfg->debug_modules); g_hash_table_unref(cfg->explicit_modules); - g_hash_table_unref(cfg->wrk_parsers); g_hash_table_unref(cfg->trusted_keys); rspamd_re_cache_unref(cfg->re_cache); @@ -348,9 +402,9 @@ void rspamd_config_free(struct rspamd_config *cfg) rspamd_monitored_ctx_destroy(cfg->monitored_ctx); } - if (cfg->lua_state && cfg->own_lua_state) { - lua_thread_pool_free(cfg->lua_thread_pool); - rspamd_lua_close(cfg->lua_state); + if (RSPAMD_LUA_CFG_STATE(cfg) && cfg->own_lua_state) { + lua_thread_pool_free((struct lua_thread_pool *) cfg->lua_thread_pool); + rspamd_lua_close(RSPAMD_LUA_CFG_STATE(cfg)); } if (cfg->redis_pool) { @@ -358,7 +412,7 @@ void rspamd_config_free(struct rspamd_config *cfg) } rspamd_upstreams_library_unref(cfg->ups_ctx); - HASH_CLEAR(hh, cfg->actions); + delete RSPAMD_CFG_ACTIONS(cfg); rspamd_mempool_destructors_enforce(cfg->cfg_pool); @@ -382,10 +436,10 @@ rspamd_config_get_module_opt(struct rspamd_config *cfg, const gchar *module_name, const gchar *opt_name) { - const ucl_object_t *res = NULL, *sec; + const ucl_object_t *res = nullptr, *sec; - sec = ucl_obj_get_key(cfg->rcl_obj, module_name); - if (sec != NULL) { + sec = ucl_obj_get_key(cfg->cfg_ucl_obj, module_name); + if (sec != nullptr) { res = ucl_obj_get_key(sec, opt_name); } @@ -445,173 +499,123 @@ gint rspamd_config_parse_flag(const gchar *str, guint len) return -1; } +// A mapping between names and log format types + flags +constexpr const auto config_vars = frozen::make_unordered_map<frozen::string, std::pair<rspamd_log_format_type, int>>({ + {"mid", {RSPAMD_LOG_MID, 0}}, + {"qid", {RSPAMD_LOG_QID, 0}}, + {"user", {RSPAMD_LOG_USER, 0}}, + {"ip", {RSPAMD_LOG_IP, 0}}, + {"len", {RSPAMD_LOG_LEN, 0}}, + {"dns_req", {RSPAMD_LOG_DNS_REQ, 0}}, + {"smtp_from", {RSPAMD_LOG_SMTP_FROM, 0}}, + {"mime_from", {RSPAMD_LOG_MIME_FROM, 0}}, + {"smtp_rcpt", {RSPAMD_LOG_SMTP_RCPT, 0}}, + {"mime_rcpt", {RSPAMD_LOG_MIME_RCPT, 0}}, + {"smtp_rcpts", {RSPAMD_LOG_SMTP_RCPTS, 0}}, + {"mime_rcpts", {RSPAMD_LOG_MIME_RCPTS, 0}}, + {"time_real", {RSPAMD_LOG_TIME_REAL, 0}}, + {"time_virtual", {RSPAMD_LOG_TIME_VIRTUAL, 0}}, + {"lua", {RSPAMD_LOG_LUA, 0}}, + {"digest", {RSPAMD_LOG_DIGEST, 0}}, + {"checksum", {RSPAMD_LOG_DIGEST, 0}}, + {"filename", {RSPAMD_LOG_FILENAME, 0}}, + {"forced_action", {RSPAMD_LOG_FORCED_ACTION, 0}}, + {"settings_id", {RSPAMD_LOG_SETTINGS_ID, 0}}, + {"mempool_size", {RSPAMD_LOG_MEMPOOL_SIZE, 0}}, + {"mempool_waste", {RSPAMD_LOG_MEMPOOL_WASTE, 0}}, + {"action", {RSPAMD_LOG_ACTION, 0}}, + {"scores", {RSPAMD_LOG_SCORES, 0}}, + {"symbols", {RSPAMD_LOG_SYMBOLS, 0}}, + {"symbols_scores", {RSPAMD_LOG_SYMBOLS, RSPAMD_LOG_FMT_FLAG_SYMBOLS_SCORES}}, + {"symbols_params", {RSPAMD_LOG_SYMBOLS, RSPAMD_LOG_FMT_FLAG_SYMBOLS_PARAMS}}, + {"symbols_scores_params", {RSPAMD_LOG_SYMBOLS, RSPAMD_LOG_FMT_FLAG_SYMBOLS_PARAMS | RSPAMD_LOG_FMT_FLAG_SYMBOLS_SCORES}}, + {"groups", {RSPAMD_LOG_GROUPS, 0}}, + {"public_groups", {RSPAMD_LOG_PUBLIC_GROUPS, 0}}, + {"is_spam", {RSPAMD_LOG_ISSPAM, 0}}, +}); + static gboolean rspamd_config_process_var(struct rspamd_config *cfg, const rspamd_ftok_t *var, const rspamd_ftok_t *content) { - guint flags = RSPAMD_LOG_FLAG_DEFAULT; - struct rspamd_log_format *lf; - enum rspamd_log_format_type type; - rspamd_ftok_t tok; - gint id; + g_assert(var != nullptr); - g_assert(var != NULL); + auto flags = 0; + auto lc_var = std::string{var->begin, var->len}; + std::transform(lc_var.begin(), lc_var.end(), lc_var.begin(), g_ascii_tolower); + auto tok = std::string_view{lc_var}; - if (var->len > 3 && rspamd_lc_cmp(var->begin, "if_", 3) == 0) { + if (var->len > 3 && tok.starts_with("if_")) { flags |= RSPAMD_LOG_FMT_FLAG_CONDITION; - tok.begin = var->begin + 3; - tok.len = var->len - 3; - } - else { - tok.begin = var->begin; - tok.len = var->len; + tok = tok.substr(3); } - /* Now compare variable and check what we have */ - if (rspamd_ftok_cstr_equal(&tok, "mid", TRUE)) { - type = RSPAMD_LOG_MID; - } - else if (rspamd_ftok_cstr_equal(&tok, "qid", TRUE)) { - type = RSPAMD_LOG_QID; - } - else if (rspamd_ftok_cstr_equal(&tok, "user", TRUE)) { - type = RSPAMD_LOG_USER; - } - else if (rspamd_ftok_cstr_equal(&tok, "is_spam", TRUE)) { - type = RSPAMD_LOG_ISSPAM; - } - else if (rspamd_ftok_cstr_equal(&tok, "action", TRUE)) { - type = RSPAMD_LOG_ACTION; - } - else if (rspamd_ftok_cstr_equal(&tok, "scores", TRUE)) { - type = RSPAMD_LOG_SCORES; - } - else if (rspamd_ftok_cstr_equal(&tok, "symbols", TRUE)) { - type = RSPAMD_LOG_SYMBOLS; - } - else if (rspamd_ftok_cstr_equal(&tok, "symbols_scores", TRUE)) { - type = RSPAMD_LOG_SYMBOLS; - flags |= RSPAMD_LOG_FMT_FLAG_SYMBOLS_SCORES; - } - else if (rspamd_ftok_cstr_equal(&tok, "symbols_params", TRUE)) { - type = RSPAMD_LOG_SYMBOLS; - flags |= RSPAMD_LOG_FMT_FLAG_SYMBOLS_PARAMS; - } - else if (rspamd_ftok_cstr_equal(&tok, "symbols_scores_params", TRUE)) { - type = RSPAMD_LOG_SYMBOLS; - flags |= RSPAMD_LOG_FMT_FLAG_SYMBOLS_PARAMS | RSPAMD_LOG_FMT_FLAG_SYMBOLS_SCORES; - } - else if (rspamd_ftok_cstr_equal(&tok, "groups", TRUE)) { - type = RSPAMD_LOG_GROUPS; - } - else if (rspamd_ftok_cstr_equal(&tok, "public_groups", TRUE)) { - type = RSPAMD_LOG_PUBLIC_GROUPS; - } - else if (rspamd_ftok_cstr_equal(&tok, "ip", TRUE)) { - type = RSPAMD_LOG_IP; - } - else if (rspamd_ftok_cstr_equal(&tok, "len", TRUE)) { - type = RSPAMD_LOG_LEN; - } - else if (rspamd_ftok_cstr_equal(&tok, "dns_req", TRUE)) { - type = RSPAMD_LOG_DNS_REQ; - } - else if (rspamd_ftok_cstr_equal(&tok, "smtp_from", TRUE)) { - type = RSPAMD_LOG_SMTP_FROM; - } - else if (rspamd_ftok_cstr_equal(&tok, "mime_from", TRUE)) { - type = RSPAMD_LOG_MIME_FROM; - } - else if (rspamd_ftok_cstr_equal(&tok, "smtp_rcpt", TRUE)) { - type = RSPAMD_LOG_SMTP_RCPT; - } - else if (rspamd_ftok_cstr_equal(&tok, "mime_rcpt", TRUE)) { - type = RSPAMD_LOG_MIME_RCPT; - } - else if (rspamd_ftok_cstr_equal(&tok, "smtp_rcpts", TRUE)) { - type = RSPAMD_LOG_SMTP_RCPTS; - } - else if (rspamd_ftok_cstr_equal(&tok, "mime_rcpts", TRUE)) { - type = RSPAMD_LOG_MIME_RCPTS; - } - else if (rspamd_ftok_cstr_equal(&tok, "time_real", TRUE)) { - type = RSPAMD_LOG_TIME_REAL; - } - else if (rspamd_ftok_cstr_equal(&tok, "time_virtual", TRUE)) { - type = RSPAMD_LOG_TIME_VIRTUAL; - } - else if (rspamd_ftok_cstr_equal(&tok, "lua", TRUE)) { - type = RSPAMD_LOG_LUA; - } - else if (rspamd_ftok_cstr_equal(&tok, "digest", TRUE) || - rspamd_ftok_cstr_equal(&tok, "checksum", TRUE)) { - type = RSPAMD_LOG_DIGEST; - } - else if (rspamd_ftok_cstr_equal(&tok, "filename", TRUE)) { - type = RSPAMD_LOG_FILENAME; - } - else if (rspamd_ftok_cstr_equal(&tok, "forced_action", TRUE)) { - type = RSPAMD_LOG_FORCED_ACTION; - } - else if (rspamd_ftok_cstr_equal(&tok, "settings_id", TRUE)) { - type = RSPAMD_LOG_SETTINGS_ID; - } - else if (rspamd_ftok_cstr_equal(&tok, "mempool_size", TRUE)) { - type = RSPAMD_LOG_MEMPOOL_SIZE; - } - else if (rspamd_ftok_cstr_equal(&tok, "mempool_waste", TRUE)) { - type = RSPAMD_LOG_MEMPOOL_WASTE; - } - else { - msg_err_config("unknown log variable: %T", &tok); - return FALSE; - } + auto maybe_fmt_var = rspamd::find_map(config_vars, tok); - lf = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*lf)); - lf->type = type; - lf->flags = flags; + if (maybe_fmt_var) { + auto &fmt_var = maybe_fmt_var.value().get(); + auto *log_format = rspamd_mempool_alloc0_type(cfg->cfg_pool, rspamd_log_format); - if (type != RSPAMD_LOG_LUA) { - if (content && content->len > 0) { - lf->data = rspamd_mempool_alloc0(cfg->cfg_pool, - sizeof(rspamd_ftok_t)); - memcpy(lf->data, content, sizeof(*content)); - lf->len = sizeof(*content); - } - } - else { - /* Load lua code and ensure that we have function ref returned */ - if (!content || content->len == 0) { - msg_err_config("lua variable needs content: %T", &tok); - return FALSE; - } + log_format->type = fmt_var.first; + log_format->flags = fmt_var.second | flags; - if (luaL_loadbuffer(cfg->lua_state, content->begin, content->len, - "lua log variable") != 0) { - msg_err_config("error loading lua code: '%T': %s", content, - lua_tostring(cfg->lua_state, -1)); - return FALSE; + if (log_format->type != RSPAMD_LOG_LUA) { + if (content && content->len > 0) { + log_format->data = rspamd_mempool_alloc0(cfg->cfg_pool, + sizeof(rspamd_ftok_t)); + memcpy(log_format->data, content, sizeof(*content)); + log_format->len = sizeof(*content); + } } - if (lua_pcall(cfg->lua_state, 0, 1, 0) != 0) { - msg_err_config("error executing lua code: '%T': %s", content, - lua_tostring(cfg->lua_state, -1)); - lua_pop(cfg->lua_state, 1); + else { + /* Load lua code and ensure that we have function ref returned */ + if (!content || content->len == 0) { + msg_err_config("lua variable needs content: %T", &tok); + return FALSE; + } - return FALSE; - } + if (luaL_loadbuffer(RSPAMD_LUA_CFG_STATE(cfg), content->begin, content->len, + "lua log variable") != 0) { + msg_err_config("error loading lua code: '%T': %s", content, + lua_tostring(RSPAMD_LUA_CFG_STATE(cfg), -1)); + return FALSE; + } + if (lua_pcall(RSPAMD_LUA_CFG_STATE(cfg), 0, 1, 0) != 0) { + msg_err_config("error executing lua code: '%T': %s", content, + lua_tostring(RSPAMD_LUA_CFG_STATE(cfg), -1)); + lua_pop(RSPAMD_LUA_CFG_STATE(cfg), 1); - if (lua_type(cfg->lua_state, -1) != LUA_TFUNCTION) { - msg_err_config("lua variable should return function: %T", content); - lua_pop(cfg->lua_state, 1); - return FALSE; + return FALSE; + } + + if (lua_type(RSPAMD_LUA_CFG_STATE(cfg), -1) != LUA_TFUNCTION) { + msg_err_config("lua variable should return function: %T", content); + lua_pop(RSPAMD_LUA_CFG_STATE(cfg), 1); + return FALSE; + } + + auto id = luaL_ref(RSPAMD_LUA_CFG_STATE(cfg), LUA_REGISTRYINDEX); + log_format->data = GINT_TO_POINTER(id); + log_format->len = 0; } - id = luaL_ref(cfg->lua_state, LUA_REGISTRYINDEX); - lf->data = GINT_TO_POINTER(id); - lf->len = 0; + DL_APPEND(cfg->log_format, log_format); } + else { + std::string known_formats; + + for (const auto &v: config_vars) { + known_formats += std::string_view{v.first.data(), v.first.size()}; + known_formats += ", "; + } - DL_APPEND(cfg->log_format, lf); + if (known_formats.size() > 2) { + // Remove last comma + known_formats.resize(known_formats.size() - 2); + } + msg_err_config("unknown log variable: %T, known vars are: \"%s\"", var, known_formats.c_str()); + return FALSE; + } return TRUE; } @@ -621,7 +625,7 @@ rspamd_config_parse_log_format(struct rspamd_config *cfg) { const gchar *p, *c, *end, *s; gchar *d; - struct rspamd_log_format *lf = NULL; + struct rspamd_log_format *lf = nullptr; rspamd_ftok_t var, var_content; enum { parse_str, @@ -631,10 +635,10 @@ rspamd_config_parse_log_format(struct rspamd_config *cfg) } state = parse_str; gint braces = 0; - g_assert(cfg != NULL); + g_assert(cfg != nullptr); c = cfg->log_format_str; - if (c == NULL) { + if (c == nullptr) { return FALSE; } @@ -654,12 +658,12 @@ rspamd_config_parse_log_format(struct rspamd_config *cfg) case parse_dollar: if (p > c) { /* We have string element that we need to store */ - lf = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*lf)); + lf = rspamd_mempool_alloc0_type(cfg->cfg_pool, struct rspamd_log_format); lf->type = RSPAMD_LOG_STRING; lf->data = rspamd_mempool_alloc(cfg->cfg_pool, p - c + 1); /* Filter \r\n from the destination */ s = c; - d = lf->data; + d = (char *) lf->data; while (s < p) { if (*s != '\r' && *s != '\n') { @@ -674,7 +678,7 @@ rspamd_config_parse_log_format(struct rspamd_config *cfg) lf->len = d - (char *) lf->data; DL_APPEND(cfg->log_format, lf); - lf = NULL; + lf = nullptr; } p++; c = p; @@ -695,7 +699,7 @@ rspamd_config_parse_log_format(struct rspamd_config *cfg) var.len = p - c; c = p; - if (!rspamd_config_process_var(cfg, &var, NULL)) { + if (!rspamd_config_process_var(cfg, &var, nullptr)) { return FALSE; } @@ -734,12 +738,12 @@ rspamd_config_parse_log_format(struct rspamd_config *cfg) case parse_str: if (p > c) { /* We have string element that we need to store */ - lf = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*lf)); + lf = rspamd_mempool_alloc0_type(cfg->cfg_pool, struct rspamd_log_format); lf->type = RSPAMD_LOG_STRING; lf->data = rspamd_mempool_alloc(cfg->cfg_pool, p - c + 1); /* Filter \r\n from the destination */ s = c; - d = lf->data; + d = (char *) lf->data; while (s < p) { if (*s != '\r' && *s != '\n') { @@ -754,7 +758,7 @@ rspamd_config_parse_log_format(struct rspamd_config *cfg) lf->len = d - (char *) lf->data; DL_APPEND(cfg->log_format, lf); - lf = NULL; + lf = nullptr; } break; @@ -762,7 +766,7 @@ rspamd_config_parse_log_format(struct rspamd_config *cfg) var.begin = c; var.len = p - c; - if (!rspamd_config_process_var(cfg, &var, NULL)) { + if (!rspamd_config_process_var(cfg, &var, nullptr)) { return FALSE; } break; @@ -783,17 +787,12 @@ rspamd_urls_config_dtor(gpointer _unused) rspamd_url_deinit(); } -/* - * Perform post load actions - */ -gboolean -rspamd_config_post_load(struct rspamd_config *cfg, - enum rspamd_post_load_options opts) +static void +rspamd_adjust_clocks_resolution(struct rspamd_config *cfg) { #ifdef HAVE_CLOCK_GETTIME struct timespec ts; #endif - gboolean ret = TRUE; #ifdef HAVE_CLOCK_GETTIME #ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID @@ -803,8 +802,6 @@ rspamd_config_post_load(struct rspamd_config *cfg, #else clock_getres(CLOCK_REALTIME, &ts); #endif - rspamd_logger_configure_modules(cfg->debug_modules); - cfg->clock_res = log10(1000000. / ts.tv_nsec); if (cfg->clock_res < 0) { cfg->clock_res = 0; @@ -816,6 +813,20 @@ rspamd_config_post_load(struct rspamd_config *cfg, /* For gettimeofday */ cfg->clock_res = 1; #endif +} + +/* + * Perform post load actions + */ +gboolean +rspamd_config_post_load(struct rspamd_config *cfg, + enum rspamd_post_load_options opts) +{ + + auto ret = TRUE; + + rspamd_adjust_clocks_resolution(cfg); + rspamd_logger_configure_modules(cfg->debug_modules); if (cfg->one_shot_mode) { msg_info_config("enabling one shot mode (was %d max shots)", @@ -823,9 +834,6 @@ rspamd_config_post_load(struct rspamd_config *cfg, cfg->default_max_shots = 1; } - rspamd_regexp_library_init(cfg); - rspamd_multipattern_library_init(cfg->hs_cache_dir); - #if defined(WITH_HYPERSCAN) && !defined(__aarch64__) && !defined(__powerpc64__) if (!cfg->disable_hyperscan) { if (!(cfg->libs_ctx->crypto_ctx->cpu_config & CPUID_SSSE3)) { @@ -836,20 +844,21 @@ rspamd_config_post_load(struct rspamd_config *cfg, } #endif + rspamd_regexp_library_init(cfg); + rspamd_multipattern_library_init(cfg->hs_cache_dir); + if (opts & RSPAMD_CONFIG_INIT_URL) { - if (cfg->tld_file == NULL) { + if (cfg->tld_file == nullptr) { /* Try to guess tld file */ - GString *fpath = g_string_new(NULL); + auto fpath = fmt::format("{0}{1}{2}", RSPAMD_SHAREDIR, + G_DIR_SEPARATOR, "effective_tld_names.dat"); - rspamd_printf_gstring(fpath, "%s%c%s", RSPAMD_SHAREDIR, - G_DIR_SEPARATOR, "effective_tld_names.dat"); - - if (access(fpath->str, R_OK) != -1) { + if (access(fpath.c_str(), R_OK) != -1) { msg_debug_config("url_tld option is not specified but %s is available," " therefore this file is assumed as TLD file for URL" " extraction", - fpath->str); - cfg->tld_file = rspamd_mempool_strdup(cfg->cfg_pool, fpath->str); + fpath.c_str()); + cfg->tld_file = rspamd_mempool_strdup(cfg->cfg_pool, fpath.c_str()); } else { if (opts & RSPAMD_CONFIG_INIT_VALIDATE) { @@ -857,8 +866,6 @@ rspamd_config_post_load(struct rspamd_config *cfg, ret = FALSE; } } - - g_string_free(fpath, TRUE); } else { if (access(cfg->tld_file, R_OK) == -1) { @@ -870,20 +877,20 @@ rspamd_config_post_load(struct rspamd_config *cfg, else { msg_debug_config("cannot access tld file %s: %s", cfg->tld_file, strerror(errno)); - cfg->tld_file = NULL; + cfg->tld_file = nullptr; } } } if (opts & RSPAMD_CONFIG_INIT_NO_TLD) { - rspamd_url_init(NULL); + rspamd_url_init(nullptr); } else { rspamd_url_init(cfg->tld_file); } rspamd_mempool_add_destructor(cfg->cfg_pool, rspamd_urls_config_dtor, - NULL); + nullptr); } init_dynamic_config(cfg); @@ -893,36 +900,46 @@ rspamd_config_post_load(struct rspamd_config *cfg, /* Parse format string that we have */ if (!rspamd_config_parse_log_format(cfg)) { msg_err_config("cannot parse log format, task logging will not be available"); + if (opts & RSPAMD_CONFIG_INIT_VALIDATE) { + ret = FALSE; + } } if (opts & RSPAMD_CONFIG_INIT_SYMCACHE) { /* Init config cache */ - rspamd_symcache_init(cfg->cache); + ret = rspamd_symcache_init(cfg->cache) && ret; /* Init re cache */ rspamd_re_cache_init(cfg->re_cache, cfg); /* Try load Hypersan */ - rspamd_re_cache_load_hyperscan(cfg->re_cache, - cfg->hs_cache_dir ? cfg->hs_cache_dir : RSPAMD_DBDIR "/", - true); + auto hs_ret = rspamd_re_cache_load_hyperscan(cfg->re_cache, + cfg->hs_cache_dir ? cfg->hs_cache_dir : RSPAMD_DBDIR "/", + true); + + if (hs_ret == RSPAMD_HYPERSCAN_LOAD_ERROR) { + msg_debug_config("cannot load hyperscan database, disable it"); + } } if (opts & RSPAMD_CONFIG_INIT_LIBS) { /* Config other libraries */ - rspamd_config_libs(cfg->libs_ctx, cfg); + ret = rspamd_config_libs(cfg->libs_ctx, cfg) && ret; + + if (!ret) { + msg_err_config("cannot configure libraries, fatal error"); + return FALSE; + } } /* Validate cache */ if (opts & RSPAMD_CONFIG_INIT_VALIDATE) { /* Check for actions sanity */ - gboolean seen_controller = FALSE; - GList *cur; - struct rspamd_worker_conf *wcf; + auto seen_controller = FALSE; - cur = cfg->workers; + auto *cur = cfg->workers; while (cur) { - wcf = cur->data; + auto *wcf = (struct rspamd_worker_conf *) cur->data; if (wcf->type == g_quark_from_static_string("controller")) { seen_controller = TRUE; @@ -942,7 +959,7 @@ rspamd_config_post_load(struct rspamd_config *cfg, } if (opts & RSPAMD_CONFIG_INIT_POST_LOAD_LUA) { - rspamd_lua_run_config_post_init(cfg->lua_state, cfg); + rspamd_lua_run_config_post_init(RSPAMD_LUA_CFG_STATE(cfg), cfg); } if (opts & RSPAMD_CONFIG_INIT_PRELOAD_MAPS) { @@ -956,18 +973,18 @@ struct rspamd_classifier_config * rspamd_config_new_classifier(struct rspamd_config *cfg, struct rspamd_classifier_config *c) { - if (c == NULL) { + if (c == nullptr) { c = - rspamd_mempool_alloc0(cfg->cfg_pool, - sizeof(struct rspamd_classifier_config)); + rspamd_mempool_alloc0_type(cfg->cfg_pool, + struct rspamd_classifier_config); c->min_prob_strength = 0.05; c->min_token_hits = 2; } - if (c->labels == NULL) { + if (c->labels == nullptr) { c->labels = g_hash_table_new_full(rspamd_str_hash, rspamd_str_equal, - NULL, + nullptr, (GDestroyNotify) g_list_free); rspamd_mempool_add_destructor(cfg->cfg_pool, (rspamd_mempool_destruct_t) g_hash_table_destroy, @@ -981,10 +998,9 @@ struct rspamd_statfile_config * rspamd_config_new_statfile(struct rspamd_config *cfg, struct rspamd_statfile_config *c) { - if (c == NULL) { + if (c == nullptr) { c = - rspamd_mempool_alloc0(cfg->cfg_pool, - sizeof(struct rspamd_statfile_config)); + rspamd_mempool_alloc0_type(cfg->cfg_pool, struct rspamd_statfile_config); } return c; @@ -1010,7 +1026,7 @@ rspamd_config_new_group(struct rspamd_config *cfg, const gchar *name) { struct rspamd_symbols_group *gr; - gr = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*gr)); + gr = rspamd_mempool_alloc0_type(cfg->cfg_pool, struct rspamd_symbols_group); gr->symbols = g_hash_table_new(rspamd_strcase_hash, rspamd_strcase_equal); rspamd_mempool_add_destructor(cfg->cfg_pool, @@ -1030,16 +1046,6 @@ static void rspamd_worker_conf_dtor(struct rspamd_worker_conf *wcf) { if (wcf) { - struct rspamd_worker_bind_conf *cnf, *tmp; - - LL_FOREACH_SAFE(wcf->bind_conf, cnf, tmp) - { - g_free(cnf->name); - g_free(cnf->bind_line); - g_ptr_array_free(cnf->addrs, TRUE); - g_free(cnf); - } - ucl_object_unref(wcf->options); g_queue_free(wcf->active_workers); g_hash_table_unref(wcf->params); @@ -1050,7 +1056,7 @@ rspamd_worker_conf_dtor(struct rspamd_worker_conf *wcf) static void rspamd_worker_conf_cfg_fin(gpointer d) { - struct rspamd_worker_conf *wcf = d; + auto *wcf = (struct rspamd_worker_conf *) d; REF_RELEASE(wcf); } @@ -1059,13 +1065,13 @@ struct rspamd_worker_conf * rspamd_config_new_worker(struct rspamd_config *cfg, struct rspamd_worker_conf *c) { - if (c == NULL) { - c = g_malloc0(sizeof(struct rspamd_worker_conf)); + if (c == nullptr) { + c = g_new0(struct rspamd_worker_conf, 1); c->params = g_hash_table_new(rspamd_str_hash, rspamd_str_equal); c->active_workers = g_queue_new(); #ifdef HAVE_SC_NPROCESSORS_ONLN - c->count = MIN(DEFAULT_MAX_WORKERS, - MAX(1, sysconf(_SC_NPROCESSORS_ONLN) - 2)); + auto nproc = sysconf(_SC_NPROCESSORS_ONLN); + c->count = MIN(DEFAULT_MAX_WORKERS, MAX(1, nproc - 2)); #else c->count = DEFAULT_MAX_WORKERS; #endif @@ -1086,18 +1092,13 @@ static bool rspamd_include_map_handler(const guchar *data, gsize len, const ucl_object_t *args, void *ud) { - struct rspamd_config *cfg = (struct rspamd_config *) ud; - struct rspamd_ucl_map_cbdata *cbdata, **pcbdata; - gchar *map_line; + auto *cfg = (struct rspamd_config *) ud; - map_line = rspamd_mempool_alloc(cfg->cfg_pool, len + 1); - rspamd_strlcpy(map_line, data, len + 1); + auto ftok = rspamd_ftok_t{.len = len + 1, .begin = (char *) data}; + auto *map_line = rspamd_mempool_ftokdup(cfg->cfg_pool, &ftok); - cbdata = g_malloc(sizeof(struct rspamd_ucl_map_cbdata)); - pcbdata = g_malloc(sizeof(struct rspamd_ucl_map_cbdata *)); - cbdata->buf = NULL; - cbdata->cfg = cfg; - *pcbdata = cbdata; + auto *cbdata = new rspamd_ucl_map_cbdata{cfg}; + auto **pcbdata = new rspamd_ucl_map_cbdata *(cbdata); return rspamd_map_add(cfg, map_line, @@ -1106,7 +1107,7 @@ rspamd_include_map_handler(const guchar *data, gsize len, rspamd_ucl_fin_cb, rspamd_ucl_dtor_cb, (void **) pcbdata, - NULL, RSPAMD_MAP_DEFAULT) != NULL; + nullptr, RSPAMD_MAP_DEFAULT) != nullptr; } /* @@ -1141,8 +1142,6 @@ void rspamd_ucl_add_conf_variables(struct ucl_parser *parser, GHashTable *vars) { GHashTableIter it; gpointer k, v; - gchar *hostbuf; - gsize hostlen; ucl_parser_register_variable(parser, RSPAMD_CONFDIR_MACRO, @@ -1177,7 +1176,7 @@ void rspamd_ucl_add_conf_variables(struct ucl_parser *parser, GHashTable *vars) ucl_parser_register_variable(parser, RSPAMD_BRANCH_VERSION_MACRO, RSPAMD_VERSION_BRANCH); - hostlen = sysconf(_SC_HOST_NAME_MAX); + auto hostlen = sysconf(_SC_HOST_NAME_MAX); if (hostlen <= 0) { hostlen = 256; @@ -1186,19 +1185,22 @@ void rspamd_ucl_add_conf_variables(struct ucl_parser *parser, GHashTable *vars) hostlen++; } - hostbuf = g_alloca(hostlen); - memset(hostbuf, 0, hostlen); - gethostname(hostbuf, hostlen - 1); + auto hostbuf = std::string{}; + hostbuf.resize(hostlen); + + if (gethostname(hostbuf.data(), hostlen) != 0) { + hostbuf = "unknown"; + } /* UCL copies variables, so it is safe to pass an ephemeral buffer here */ ucl_parser_register_variable(parser, RSPAMD_HOSTNAME_MACRO, - hostbuf); + hostbuf.c_str()); - if (vars != NULL) { + if (vars != nullptr) { g_hash_table_iter_init(&it, vars); while (g_hash_table_iter_next(&it, &k, &v)) { - ucl_parser_register_variable(parser, k, v); + ucl_parser_register_variable(parser, (const char *) k, (const char *) v); } } } @@ -1215,10 +1217,10 @@ void rspamd_ucl_add_conf_macros(struct ucl_parser *parser, static void symbols_classifiers_callback(gpointer key, gpointer value, gpointer ud) { - struct rspamd_config *cfg = ud; + auto *cfg = (struct rspamd_config *) ud; /* Actually, statistics should act like any ordinary symbol */ - rspamd_symcache_add_symbol(cfg->cache, key, 0, NULL, NULL, + rspamd_symcache_add_symbol(cfg->cache, (const char *) key, 0, nullptr, nullptr, SYMBOL_TYPE_CLASSIFIER | SYMBOL_TYPE_NOSTAT, -1); } @@ -1232,16 +1234,13 @@ void rspamd_config_insert_classify_symbols(struct rspamd_config *cfg) struct rspamd_classifier_config * rspamd_config_find_classifier(struct rspamd_config *cfg, const gchar *name) { - GList *cur; - struct rspamd_classifier_config *cf; - - if (name == NULL) { - return NULL; + if (name == nullptr) { + return nullptr; } - cur = cfg->classifiers; + auto *cur = cfg->classifiers; while (cur) { - cf = cur->data; + auto *cf = (struct rspamd_classifier_config *) cur->data; if (g_ascii_strcasecmp(cf->name, name) == 0) { return cf; @@ -1250,20 +1249,18 @@ rspamd_config_find_classifier(struct rspamd_config *cfg, const gchar *name) cur = g_list_next(cur); } - return NULL; + return nullptr; } gboolean rspamd_config_check_statfiles(struct rspamd_classifier_config *cf) { - struct rspamd_statfile_config *st; gboolean has_other = FALSE, res = FALSE, cur_class = FALSE; - GList *cur; /* First check classes directly */ - cur = cf->statfiles; + auto *cur = cf->statfiles; while (cur) { - st = cur->data; + auto *st = (struct rspamd_statfile_config *) cur->data; if (!has_other) { cur_class = st->is_spam; has_other = TRUE; @@ -1285,7 +1282,7 @@ rspamd_config_check_statfiles(struct rspamd_classifier_config *cf) has_other = FALSE; cur = cf->statfiles; while (cur) { - st = cur->data; + auto *st = (struct rspamd_statfile_config *) cur->data; if (rspamd_substring_search_caseless(st->symbol, strlen(st->symbol), "spam", 4) != -1) { st->is_spam = TRUE; @@ -1317,55 +1314,50 @@ rspamd_ucl_read_cb(gchar *chunk, struct map_cb_data *data, gboolean final) { - struct rspamd_ucl_map_cbdata *cbdata = data->cur_data, *prev; + auto *cbdata = (struct rspamd_ucl_map_cbdata *) data->cur_data; + auto *prev = (struct rspamd_ucl_map_cbdata *) data->prev_data; - if (cbdata == NULL) { - cbdata = g_malloc(sizeof(struct rspamd_ucl_map_cbdata)); - prev = data->prev_data; - cbdata->buf = g_string_sized_new(BUFSIZ); - cbdata->cfg = prev->cfg; + if (cbdata == nullptr) { + cbdata = new rspamd_ucl_map_cbdata{prev->cfg}; data->cur_data = cbdata; } - g_string_append_len(cbdata->buf, chunk, len); + cbdata->buf.append(chunk, len); /* Say not to copy any part of this buffer */ - return NULL; + return nullptr; } static void rspamd_ucl_fin_cb(struct map_cb_data *data, void **target) { - struct rspamd_ucl_map_cbdata *cbdata = data->cur_data, *prev = - data->prev_data; - ucl_object_t *obj; - struct ucl_parser *parser; - ucl_object_iter_t it = NULL; - const ucl_object_t *cur; - struct rspamd_config *cfg = data->map->cfg; - - if (cbdata == NULL) { - msg_err_config("map fin error: new data is NULL"); + auto *cbdata = (struct rspamd_ucl_map_cbdata *) data->cur_data; + auto *prev = (struct rspamd_ucl_map_cbdata *) data->prev_data; + auto *cfg = data->map->cfg; + + if (cbdata == nullptr) { + msg_err_config("map fin error: new data is nullptr"); return; } /* New data available */ - parser = ucl_parser_new(0); - if (!ucl_parser_add_chunk(parser, cbdata->buf->str, - cbdata->buf->len)) { + auto *parser = ucl_parser_new(0); + if (!ucl_parser_add_chunk(parser, (unsigned char *) cbdata->buf.data(), + cbdata->buf.size())) { msg_err_config("cannot parse map %s: %s", data->map->name, ucl_parser_get_error(parser)); ucl_parser_free(parser); } else { - obj = ucl_parser_get_object(parser); - ucl_parser_free(parser); - it = NULL; + auto *obj = ucl_parser_get_object(parser); + ucl_object_iter_t it = nullptr; - while ((cur = ucl_object_iterate(obj, &it, true))) { - ucl_object_replace_key(cbdata->cfg->rcl_obj, (ucl_object_t *) cur, + for (auto *cur = ucl_object_iterate(obj, &it, true); cur != nullptr; cur = ucl_object_iterate(obj, &it, true)) { + ucl_object_replace_key(cbdata->cfg->cfg_ucl_obj, (ucl_object_t *) cur, cur->key, cur->keylen, false); } + + ucl_parser_free(parser); ucl_object_unref(obj); } @@ -1373,25 +1365,15 @@ rspamd_ucl_fin_cb(struct map_cb_data *data, void **target) *target = data->cur_data; } - if (prev != NULL) { - if (prev->buf != NULL) { - g_string_free(prev->buf, TRUE); - } - g_free(prev); - } + delete prev; } static void rspamd_ucl_dtor_cb(struct map_cb_data *data) { - struct rspamd_ucl_map_cbdata *cbdata = data->cur_data; + auto *cbdata = (struct rspamd_ucl_map_cbdata *) data->cur_data; - if (cbdata != NULL) { - if (cbdata->buf != NULL) { - g_string_free(cbdata->buf, TRUE); - } - g_free(cbdata); - } + delete cbdata; } gboolean @@ -1399,7 +1381,7 @@ rspamd_check_module(struct rspamd_config *cfg, module_t *mod) { gboolean ret = TRUE; - if (mod != NULL) { + if (mod != nullptr) { if (mod->module_version != RSPAMD_CUR_MODULE_VERSION) { msg_err_config("module %s has incorrect version %xd (%xd expected)", mod->name, (gint) mod->module_version, RSPAMD_CUR_MODULE_VERSION); @@ -1428,7 +1410,7 @@ rspamd_check_worker(struct rspamd_config *cfg, worker_t *wrk) { gboolean ret = TRUE; - if (wrk != NULL) { + if (wrk != nullptr) { if (wrk->worker_version != RSPAMD_CUR_WORKER_VERSION) { msg_err_config("worker %s has incorrect version %xd (%xd expected)", wrk->name, wrk->worker_version, RSPAMD_CUR_WORKER_VERSION); @@ -1463,11 +1445,11 @@ rspamd_init_filters(struct rspamd_config *cfg, bool reconfig, bool strict) /* Init all compiled modules */ - for (pmod = cfg->compiled_modules; pmod != NULL && *pmod != NULL; pmod++) { + for (pmod = cfg->compiled_modules; pmod != nullptr && *pmod != nullptr; pmod++) { mod = *pmod; if (rspamd_check_module(cfg, mod)) { if (mod->module_init_func(cfg, &mod_ctx) == 0) { - g_assert(mod_ctx != NULL); + g_assert(mod_ctx != nullptr); g_ptr_array_add(cfg->c_modules, mod_ctx); mod_ctx->mod = mod; mod->ctx_offset = i++; @@ -1480,7 +1462,7 @@ rspamd_init_filters(struct rspamd_config *cfg, bool reconfig, bool strict) while (cur) { /* Perform modules configuring */ - mod_ctx = NULL; + mod_ctx = nullptr; PTR_ARRAY_FOREACH(cfg->c_modules, i, cur_ctx) { if (g_ascii_strcasecmp(cur_ctx->mod->name, @@ -1514,7 +1496,7 @@ rspamd_init_filters(struct rspamd_config *cfg, bool reconfig, bool strict) } } - if (mod_ctx == NULL) { + if (mod_ctx == nullptr) { msg_warn_config("requested unknown module %s", cur->data); } @@ -1533,11 +1515,11 @@ rspamd_config_new_symbol(struct rspamd_config *cfg, const gchar *symbol, { struct rspamd_symbols_group *sym_group; struct rspamd_symbol *sym_def; - gdouble *score_ptr; + double *score_ptr; sym_def = - rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(struct rspamd_symbol)); - score_ptr = rspamd_mempool_alloc(cfg->cfg_pool, sizeof(gdouble)); + rspamd_mempool_alloc0_type(cfg->cfg_pool, struct rspamd_symbol); + score_ptr = rspamd_mempool_alloc_type(cfg->cfg_pool, double); if (isnan(score)) { /* In fact, it could be defined later */ @@ -1572,7 +1554,7 @@ rspamd_config_new_symbol(struct rspamd_config *cfg, const gchar *symbol, g_hash_table_insert(cfg->symbols, sym_def->name, sym_def); /* Search for symbol group */ - if (group == NULL) { + if (group == nullptr) { group = "ungrouped"; sym_def->flags |= RSPAMD_SYMBOL_FLAG_UNGROUPED; } @@ -1582,8 +1564,8 @@ rspamd_config_new_symbol(struct rspamd_config *cfg, const gchar *symbol, } } - sym_group = g_hash_table_lookup(cfg->groups, group); - if (sym_group == NULL) { + sym_group = reinterpret_cast<rspamd_symbols_group *>(g_hash_table_lookup(cfg->groups, group)); + if (sym_group == nullptr) { /* Create new group */ sym_group = rspamd_config_new_group(cfg, group); } @@ -1611,13 +1593,13 @@ rspamd_config_add_symbol(struct rspamd_config *cfg, struct rspamd_symbols_group *sym_group; guint i; - g_assert(cfg != NULL); - g_assert(symbol != NULL); + g_assert(cfg != nullptr); + g_assert(symbol != nullptr); - sym_def = g_hash_table_lookup(cfg->symbols, symbol); + sym_def = reinterpret_cast<rspamd_symbol *>(g_hash_table_lookup(cfg->symbols, symbol)); - if (sym_def != NULL) { - if (group != NULL) { + if (sym_def != nullptr) { + if (group != nullptr) { gboolean has_group = FALSE; PTR_ARRAY_FOREACH(sym_def->groups, i, sym_group) @@ -1631,9 +1613,9 @@ rspamd_config_add_symbol(struct rspamd_config *cfg, if (!has_group) { /* Non-empty group has a priority over non-grouped one */ - sym_group = g_hash_table_lookup(cfg->groups, group); + sym_group = reinterpret_cast<rspamd_symbols_group *>(g_hash_table_lookup(cfg->groups, group)); - if (sym_group == NULL) { + if (sym_group == nullptr) { /* Create new group */ sym_group = rspamd_config_new_group(cfg, group); } @@ -1706,12 +1688,12 @@ rspamd_config_add_symbol(struct rspamd_config *cfg, /* We also check group information in this case */ - if (group != NULL && sym_def->gr != NULL && + if (group != nullptr && sym_def->gr != nullptr && strcmp(group, sym_def->gr->name) != 0) { - sym_group = g_hash_table_lookup(cfg->groups, group); + sym_group = reinterpret_cast<rspamd_symbols_group *>(g_hash_table_lookup(cfg->groups, group)); - if (sym_group == NULL) { + if (sym_group == nullptr) { /* Create new group */ sym_group = rspamd_config_new_group(cfg, group); } @@ -1745,13 +1727,13 @@ rspamd_config_add_symbol_group(struct rspamd_config *cfg, struct rspamd_symbols_group *sym_group; guint i; - g_assert(cfg != NULL); - g_assert(symbol != NULL); - g_assert(group != NULL); + g_assert(cfg != nullptr); + g_assert(symbol != nullptr); + g_assert(group != nullptr); - sym_def = g_hash_table_lookup(cfg->symbols, symbol); + sym_def = reinterpret_cast<rspamd_symbol *>(g_hash_table_lookup(cfg->symbols, symbol)); - if (sym_def != NULL) { + if (sym_def != nullptr) { gboolean has_group = FALSE; PTR_ARRAY_FOREACH(sym_def->groups, i, sym_group) @@ -1765,9 +1747,9 @@ rspamd_config_add_symbol_group(struct rspamd_config *cfg, if (!has_group) { /* Non-empty group has a priority over non-grouped one */ - sym_group = g_hash_table_lookup(cfg->groups, group); + sym_group = reinterpret_cast<rspamd_symbols_group *>(g_hash_table_lookup(cfg->groups, group)); - if (sym_group == NULL) { + if (sym_group == nullptr) { /* Create new group */ sym_group = rspamd_config_new_group(cfg, group); } @@ -1791,54 +1773,52 @@ gboolean rspamd_config_is_enabled_from_ucl(rspamd_mempool_t *pool, const ucl_object_t *obj) { - { - const ucl_object_t *enabled; - enabled = ucl_object_lookup(obj, "enabled"); + const ucl_object_t *enabled; - if (enabled) { - if (ucl_object_type(enabled) == UCL_BOOLEAN) { - return ucl_object_toboolean(enabled); - } - else if (ucl_object_type(enabled) == UCL_STRING) { - gint ret = rspamd_config_parse_flag(ucl_object_tostring(enabled), 0); + enabled = ucl_object_lookup(obj, "enabled"); - if (ret == 0) { - return FALSE; - } - else if (ret == -1) { + if (enabled) { + if (ucl_object_type(enabled) == UCL_BOOLEAN) { + return ucl_object_toboolean(enabled); + } + else if (ucl_object_type(enabled) == UCL_STRING) { + gint ret = rspamd_config_parse_flag(ucl_object_tostring(enabled), 0); - msg_info_pool_check("wrong value for the `enabled` key"); - return FALSE; - } - /* Default return is TRUE here */ + if (ret == 0) { + return FALSE; } + else if (ret == -1) { + + msg_info_pool_check("wrong value for the `enabled` key"); + return FALSE; + } + /* Default return is TRUE here */ } } - { - const ucl_object_t *disabled; - disabled = ucl_object_lookup(obj, "disabled"); + const ucl_object_t *disabled; - if (disabled) { - if (ucl_object_type(disabled) == UCL_BOOLEAN) { - return !ucl_object_toboolean(disabled); - } - else if (ucl_object_type(disabled) == UCL_STRING) { - gint ret = rspamd_config_parse_flag(ucl_object_tostring(disabled), 0); + disabled = ucl_object_lookup(obj, "disabled"); - if (ret == 0) { - return TRUE; - } - else if (ret == -1) { + if (disabled) { + if (ucl_object_type(disabled) == UCL_BOOLEAN) { + return !ucl_object_toboolean(disabled); + } + else if (ucl_object_type(disabled) == UCL_STRING) { + gint ret = rspamd_config_parse_flag(ucl_object_tostring(disabled), 0); - msg_info_pool_check("wrong value for the `disabled` key"); - return FALSE; - } + if (ret == 0) { + return TRUE; + } + else if (ret == -1) { + msg_info_pool_check("wrong value for the `disabled` key"); return FALSE; } + + return FALSE; } } @@ -1853,7 +1833,7 @@ rspamd_config_is_module_enabled(struct rspamd_config *cfg, const ucl_object_t *conf; GList *cur; struct rspamd_symbols_group *gr; - lua_State *L = cfg->lua_state; + lua_State *L = RSPAMD_LUA_CFG_STATE(cfg); struct module_ctx *cur_ctx; guint i; @@ -1865,7 +1845,7 @@ rspamd_config_is_module_enabled(struct rspamd_config *cfg, } } - if (g_hash_table_lookup(cfg->explicit_modules, module_name) != NULL) { + if (g_hash_table_lookup(cfg->explicit_modules, module_name) != nullptr) { /* Always load module */ rspamd_plugins_table_push_elt(L, "enabled", module_name); @@ -1878,7 +1858,7 @@ rspamd_config_is_module_enabled(struct rspamd_config *cfg, cur = g_list_first(cfg->filters); while (cur) { - if (strcmp(cur->data, module_name) == 0) { + if (strcmp((char *) cur->data, module_name) == 0) { found = TRUE; break; } @@ -1896,9 +1876,9 @@ rspamd_config_is_module_enabled(struct rspamd_config *cfg, } } - conf = ucl_object_lookup(cfg->rcl_obj, module_name); + conf = ucl_object_lookup(cfg->cfg_ucl_obj, module_name); - if (conf == NULL) { + if (conf == nullptr) { rspamd_plugins_table_push_elt(L, "disabled_unconfigured", module_name); msg_info_config("%s module %s is enabled but has not been configured", @@ -1924,7 +1904,7 @@ rspamd_config_is_module_enabled(struct rspamd_config *cfg, } /* Now we check symbols group */ - gr = g_hash_table_lookup(cfg->groups, module_name); + gr = reinterpret_cast<rspamd_symbols_group *>(g_hash_table_lookup(cfg->groups, module_name)); if (gr) { if (gr->flags & RSPAMD_SYMBOL_GROUP_DISABLED) { @@ -1949,16 +1929,15 @@ rspamd_config_action_from_ucl(struct rspamd_config *cfg, const ucl_object_t *obj, guint priority) { - const ucl_object_t *elt; - gdouble threshold = NAN; - guint flags = 0, std_act, obj_type; + auto threshold = NAN; + int flags = 0; - obj_type = ucl_object_type(obj); + auto obj_type = ucl_object_type(obj); if (obj_type == UCL_OBJECT) { obj_type = ucl_object_type(obj); - elt = ucl_object_lookup_any(obj, "score", "threshold", NULL); + const auto *elt = ucl_object_lookup_any(obj, "score", "threshold", nullptr); if (elt) { threshold = ucl_object_todouble(elt); @@ -1968,9 +1947,9 @@ rspamd_config_action_from_ucl(struct rspamd_config *cfg, if (elt && ucl_object_type(elt) == UCL_ARRAY) { const ucl_object_t *cur; - ucl_object_iter_t it = NULL; + ucl_object_iter_t it = nullptr; - while ((cur = ucl_object_iterate(elt, &it, true)) != NULL) { + while ((cur = ucl_object_iterate(elt, &it, true)) != nullptr) { if (ucl_object_type(cur) == UCL_STRING) { const gchar *fl_str = ucl_object_tostring(cur); @@ -2025,6 +2004,8 @@ rspamd_config_action_from_ucl(struct rspamd_config *cfg, act->threshold = threshold; act->flags = flags; + enum rspamd_action_type std_act; + if (!(flags & RSPAMD_ACTION_MILTER)) { if (rspamd_action_from_str(act->name, &std_act)) { act->action_type = std_act; @@ -2042,13 +2023,12 @@ rspamd_config_set_action_score(struct rspamd_config *cfg, const gchar *action_name, const ucl_object_t *obj) { - struct rspamd_action *act; enum rspamd_action_type std_act; const ucl_object_t *elt; guint priority = ucl_object_get_priority(obj), obj_type; - g_assert(cfg != NULL); - g_assert(action_name != NULL); + g_assert(cfg != nullptr); + g_assert(action_name != nullptr); obj_type = ucl_object_type(obj); @@ -2067,25 +2047,31 @@ rspamd_config_set_action_score(struct rspamd_config *cfg, * variance of names. */ - if (rspamd_action_from_str(action_name, (gint *) &std_act)) { + if (rspamd_action_from_str(action_name, &std_act)) { action_name = rspamd_action_to_str(std_act); } - HASH_FIND_STR(cfg->actions, action_name, act); + auto actions = RSPAMD_CFG_ACTIONS(cfg); + auto existing_act_it = actions->actions_by_name.find(action_name); - if (act) { + if (existing_act_it != actions->actions_by_name.end()) { + auto *act = existing_act_it->second.get(); /* Existing element */ if (act->priority <= priority) { /* We can replace data */ - msg_info_config("action %s has been already registered with " - "priority %ud, override it with new priority: %ud, " - "old score: %.2f", - action_name, - act->priority, - priority, - act->threshold); + auto old_pri = act->priority; + auto old_thr = act->threshold; + if (rspamd_config_action_from_ucl(cfg, act, obj, priority)) { - rspamd_actions_sort(cfg); + msg_info_config("action %s has been already registered with " + "priority %ud, override it with new priority: %ud, " + "old threshold: %.2f, new threshold: %.2f", + action_name, + old_pri, + priority, + old_thr, + act->threshold); + actions->sort(); } else { return FALSE; @@ -2101,13 +2087,11 @@ rspamd_config_set_action_score(struct rspamd_config *cfg, } else { /* Add new element */ - act = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*act)); + auto act = std::make_shared<rspamd_action>(); act->name = rspamd_mempool_strdup(cfg->cfg_pool, action_name); - if (rspamd_config_action_from_ucl(cfg, act, obj, priority)) { - HASH_ADD_KEYPTR(hh, cfg->actions, - act->name, strlen(act->name), act); - rspamd_actions_sort(cfg); + if (rspamd_config_action_from_ucl(cfg, act.get(), obj, priority)) { + actions->add_action(std::move(act)); } else { return FALSE; @@ -2122,11 +2106,11 @@ rspamd_config_maybe_disable_action(struct rspamd_config *cfg, const gchar *action_name, guint priority) { - struct rspamd_action *act; - - HASH_FIND_STR(cfg->actions, action_name, act); + auto actions = RSPAMD_CFG_ACTIONS(cfg); + auto maybe_act = rspamd::find_map(actions->actions_by_name, action_name); - if (act) { + if (maybe_act) { + auto *act = maybe_act.value().get().get(); if (priority >= act->priority) { msg_info_config("disable action %s; old priority: %ud, new priority: %ud", action_name, @@ -2154,27 +2138,50 @@ rspamd_config_maybe_disable_action(struct rspamd_config *cfg, struct rspamd_action * rspamd_config_get_action(struct rspamd_config *cfg, const gchar *name) { - struct rspamd_action *res = NULL; + auto actions = RSPAMD_CFG_ACTIONS(cfg); + auto maybe_act = rspamd::find_map(actions->actions_by_name, name); - HASH_FIND_STR(cfg->actions, name, res); + if (maybe_act) { + return maybe_act.value().get().get(); + } - return res; + return nullptr; } struct rspamd_action * rspamd_config_get_action_by_type(struct rspamd_config *cfg, enum rspamd_action_type type) { - struct rspamd_action *cur, *tmp; - - HASH_ITER(hh, cfg->actions, cur, tmp) - { - if (cur->action_type == type) { - return cur; + for (const auto &act: RSPAMD_CFG_ACTIONS(cfg)->actions) { + if (act->action_type == type) { + return act.get(); } } - return NULL; + return nullptr; +} + +void rspamd_config_actions_foreach(struct rspamd_config *cfg, + void (*func)(struct rspamd_action *act, void *d), + void *data) +{ + for (const auto &act: RSPAMD_CFG_ACTIONS(cfg)->actions) { + func(act.get(), data); + } +} + +void rspamd_config_actions_foreach_enumerate(struct rspamd_config *cfg, + void (*func)(int idx, struct rspamd_action *act, void *d), + void *data) +{ + for (const auto &[idx, act]: rspamd::enumerate(RSPAMD_CFG_ACTIONS(cfg)->actions)) { + func(idx, act.get(), data); + } +} + +gsize rspamd_config_actions_size(struct rspamd_config *cfg) +{ + return RSPAMD_CFG_ACTIONS(cfg)->actions.size(); } gboolean @@ -2183,12 +2190,12 @@ rspamd_config_radix_from_ucl(struct rspamd_config *cfg, const ucl_object_t *obj, struct rspamd_worker *worker, const gchar *map_name) { ucl_type_t type; - ucl_object_iter_t it = NULL; + ucl_object_iter_t it = nullptr; const ucl_object_t *cur, *cur_elt; const gchar *str; /* Cleanup */ - *target = NULL; + *target = nullptr; LL_FOREACH(obj, cur_elt) { @@ -2206,7 +2213,7 @@ rspamd_config_radix_from_ucl(struct rspamd_config *cfg, const ucl_object_t *obj, rspamd_radix_fin, rspamd_radix_dtor, (void **) target, - worker, RSPAMD_MAP_DEFAULT) == NULL) { + worker, RSPAMD_MAP_DEFAULT) == nullptr) { g_set_error(err, g_quark_from_static_string("rspamd-config"), EINVAL, "bad map definition %s for %s", str, @@ -2234,7 +2241,7 @@ rspamd_config_radix_from_ucl(struct rspamd_config *cfg, const ucl_object_t *obj, rspamd_radix_fin, rspamd_radix_dtor, (void **) target, - worker, RSPAMD_MAP_DEFAULT) == NULL) { + worker, RSPAMD_MAP_DEFAULT) == nullptr) { g_set_error(err, g_quark_from_static_string("rspamd-config"), EINVAL, "bad map object for %s", ucl_object_key(obj)); @@ -2247,7 +2254,7 @@ rspamd_config_radix_from_ucl(struct rspamd_config *cfg, const ucl_object_t *obj, /* List of IP addresses */ it = ucl_object_iterate_new(cur_elt); - while ((cur = ucl_object_iterate_safe(it, true)) != NULL) { + while ((cur = ucl_object_iterate_safe(it, true)) != nullptr) { if (ucl_object_type(cur) == UCL_STRING) { @@ -2288,49 +2295,35 @@ rspamd_config_radix_from_ucl(struct rspamd_config *cfg, const ucl_object_t *obj, return TRUE; } +constexpr const auto action_types = frozen::make_unordered_map<frozen::string, enum rspamd_action_type>({ + {"reject", METRIC_ACTION_REJECT}, + {"greylist", METRIC_ACTION_GREYLIST}, + {"add header", METRIC_ACTION_ADD_HEADER}, + {"add_header", METRIC_ACTION_ADD_HEADER}, + {"rewrite subject", METRIC_ACTION_REWRITE_SUBJECT}, + {"rewrite_subject", METRIC_ACTION_REWRITE_SUBJECT}, + {"soft reject", METRIC_ACTION_SOFT_REJECT}, + {"soft_reject", METRIC_ACTION_SOFT_REJECT}, + {"no action", METRIC_ACTION_NOACTION}, + {"no_action", METRIC_ACTION_NOACTION}, + {"accept", METRIC_ACTION_NOACTION}, + {"quarantine", METRIC_ACTION_QUARANTINE}, + {"discard", METRIC_ACTION_DISCARD}, + +}); + gboolean -rspamd_action_from_str(const gchar *data, gint *result) +rspamd_action_from_str(const gchar *data, enum rspamd_action_type *result) { - guint64 h; + auto maybe_action = rspamd::find_map(action_types, std::string_view{data}); - h = rspamd_cryptobox_fast_hash_specific(RSPAMD_CRYPTOBOX_XXHASH64, - data, strlen(data), 0xdeadbabe); - - switch (h) { - case 0x9917BFDB46332B8CULL: /* reject */ - *result = METRIC_ACTION_REJECT; - break; - case 0x7130EE37D07B3715ULL: /* greylist */ - *result = METRIC_ACTION_GREYLIST; - break; - case 0xCA6087E05480C60CULL: /* add_header */ - case 0x87A3D27783B16241ULL: /* add header */ - *result = METRIC_ACTION_ADD_HEADER; - break; - case 0x4963374ED8B90449ULL: /* rewrite_subject */ - case 0x5C9FC4679C025948ULL: /* rewrite subject */ - *result = METRIC_ACTION_REWRITE_SUBJECT; - break; - case 0xFC7D6502EE71FDD9ULL: /* soft reject */ - case 0x73576567C262A82DULL: /* soft_reject */ - *result = METRIC_ACTION_SOFT_REJECT; - break; - case 0x207091B927D1EC0DULL: /* no action */ - case 0xB7D92D002CD46325ULL: /* no_action */ - case 0x167C0DF4BAA9BCECULL: /* accept */ - *result = METRIC_ACTION_NOACTION; - break; - case 0x4E9666ECCD3FC314ULL: /* quarantine */ - *result = METRIC_ACTION_QUARANTINE; - break; - case 0x93B346242F7F69B3ULL: /* discard */ - *result = METRIC_ACTION_DISCARD; - break; - default: - return FALSE; + if (maybe_action) { + *result = maybe_action.value().get(); + return true; + } + else { + return false; } - - return TRUE; } const gchar * @@ -2391,36 +2384,6 @@ rspamd_action_to_str_alt(enum rspamd_action_type action) return "unknown action"; } -static int -rspamd_actions_cmp(const struct rspamd_action *a1, const struct rspamd_action *a2) -{ - if (!isnan(a1->threshold) && !isnan(a2->threshold)) { - if (a1->threshold < a2->threshold) { - return -1; - } - else if (a1->threshold > a2->threshold) { - return 1; - } - - return 0; - } - - if (isnan(a1->threshold) && isnan(a2->threshold)) { - return 0; - } - else if (isnan(a1->threshold)) { - return 1; - } - else { - return -1; - } -} - -void rspamd_actions_sort(struct rspamd_config *cfg) -{ - HASH_SORT(cfg->actions, rspamd_actions_cmp); -} - static void rspamd_config_settings_elt_dtor(struct rspamd_config_settings_elt *e) { @@ -2457,7 +2420,7 @@ rspamd_config_find_settings_id_ref(struct rspamd_config *cfg, } } - return NULL; + return nullptr; } struct rspamd_config_settings_elt *rspamd_config_find_settings_name_ref( @@ -2489,7 +2452,7 @@ void rspamd_config_register_settings_id(struct rspamd_config *cfg, DL_DELETE(cfg->setting_ids, elt); - nelt = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*nelt)); + nelt = rspamd_mempool_alloc0_type(cfg->cfg_pool, struct rspamd_config_settings_elt); nelt->id = id; nelt->name = rspamd_mempool_strdup(cfg->cfg_pool, name); @@ -2518,7 +2481,7 @@ void rspamd_config_register_settings_id(struct rspamd_config *cfg, REF_RELEASE(elt); } else { - elt = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*elt)); + elt = rspamd_mempool_alloc0_type(cfg->cfg_pool, struct rspamd_config_settings_elt); elt->id = id; elt->name = rspamd_mempool_strdup(cfg->cfg_pool, name); @@ -2543,7 +2506,7 @@ void rspamd_config_register_settings_id(struct rspamd_config *cfg, int rspamd_config_ev_backend_get(struct rspamd_config *cfg) { #define AUTO_BACKEND (ev_supported_backends() & ~EVBACKEND_IOURING) - if (cfg == NULL || cfg->events_backend == NULL) { + if (cfg == nullptr || cfg->events_backend == nullptr) { return AUTO_BACKEND; } @@ -2597,9 +2560,9 @@ int rspamd_config_ev_backend_get(struct rspamd_config *cfg) const gchar * rspamd_config_ev_backend_to_string(int ev_backend, gboolean *effective) { -#define SET_EFFECTIVE(b) \ - do { \ - if ((effective) != NULL) *(effective) = b; \ +#define SET_EFFECTIVE(b) \ + do { \ + if ((effective) != nullptr) *(effective) = b; \ } while (0) if ((ev_backend & EVBACKEND_ALL) == EVBACKEND_ALL) { @@ -2649,12 +2612,11 @@ struct rspamd_external_libs_ctx * rspamd_init_libs(void) { struct rlimit rlim; - struct rspamd_external_libs_ctx *ctx; struct ottery_config *ottery_cfg; - ctx = g_malloc0(sizeof(*ctx)); + auto *ctx = g_new0(struct rspamd_external_libs_ctx, 1); ctx->crypto_ctx = rspamd_cryptobox_init(); - ottery_cfg = g_malloc0(ottery_get_sizeof_config()); + ottery_cfg = (struct ottery_config *) g_malloc0(ottery_get_sizeof_config()); ottery_config_init(ottery_cfg); ctx->ottery_cfg = ottery_cfg; @@ -2664,10 +2626,12 @@ rspamd_init_libs(void) if ((ctx->crypto_ctx->cpu_config & CPUID_RDRAND) == 0) { ottery_config_disable_entropy_sources(ottery_cfg, OTTERY_ENTROPY_SRC_RDRAND); + } + + g_assert(ottery_init(ottery_cfg) == 0); #if OPENSSL_VERSION_NUMBER >= 0x1000104fL && OPENSSL_VERSION_NUMBER < 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) - RAND_set_rand_engine(NULL); + RAND_set_rand_engine(nullptr); #endif - } /* Configure utf8 library */ guint utf8_flags = 0; @@ -2681,10 +2645,8 @@ rspamd_init_libs(void) rspamd_fast_utf8_library_init(utf8_flags); - g_assert(ottery_init(ottery_cfg) == 0); - #ifdef HAVE_LOCALE_H - if (getenv("LANG") == NULL) { + if (getenv("LANG") == nullptr) { setlocale(LC_ALL, "C"); setlocale(LC_CTYPE, "C"); setlocale(LC_MESSAGES, "C"); @@ -2719,13 +2681,13 @@ rspamd_open_zstd_dictionary(const char *path) { struct zstd_dictionary *dict; - dict = g_malloc0(sizeof(*dict)); + dict = g_new0(zstd_dictionary, 1); dict->dict = rspamd_file_xmap(path, PROT_READ, &dict->size, TRUE); - if (dict->dict == NULL) { + if (dict->dict == nullptr) { g_free(dict); - return NULL; + return nullptr; } dict->id = -1; @@ -2733,7 +2695,7 @@ rspamd_open_zstd_dictionary(const char *path) if (dict->id == 0) { g_free(dict); - return NULL; + return nullptr; } return dict; @@ -2749,10 +2711,10 @@ rspamd_free_zstd_dictionary(struct zstd_dictionary *dict) } #ifdef HAVE_OPENBLAS_SET_NUM_THREADS -extern void openblas_set_num_threads(int num_threads); +extern "C" void openblas_set_num_threads(int num_threads); #endif #ifdef HAVE_BLI_THREAD_SET_NUM_THREADS -extern void bli_thread_set_num_threads(int num_threads); +extern "C" void bli_thread_set_num_threads(int num_threads); #endif gboolean @@ -2762,35 +2724,43 @@ rspamd_config_libs(struct rspamd_external_libs_ctx *ctx, size_t r; gboolean ret = TRUE; - g_assert(cfg != NULL); + g_assert(cfg != nullptr); - if (ctx != NULL) { + if (ctx != nullptr) { if (cfg->local_addrs) { + GError *err = nullptr; ret = rspamd_config_radix_from_ucl(cfg, cfg->local_addrs, "Local addresses", (struct rspamd_radix_map_helper **) ctx->local_addrs, - NULL, - NULL, "local addresses"); + &err, + nullptr, "local addresses"); + + if (!ret) { + msg_err_config("cannot load local addresses: %e", err); + g_error_free(err); + + return ret; + } } rspamd_free_zstd_dictionary(ctx->in_dict); rspamd_free_zstd_dictionary(ctx->out_dict); if (ctx->out_zstream) { - ZSTD_freeCStream(ctx->out_zstream); - ctx->out_zstream = NULL; + ZSTD_freeCStream((ZSTD_CCtx *) ctx->out_zstream); + ctx->out_zstream = nullptr; } if (ctx->in_zstream) { - ZSTD_freeDStream(ctx->in_zstream); - ctx->in_zstream = NULL; + ZSTD_freeDStream((ZSTD_DCtx *) ctx->in_zstream); + ctx->in_zstream = nullptr; } if (cfg->zstd_input_dictionary) { ctx->in_dict = rspamd_open_zstd_dictionary( cfg->zstd_input_dictionary); - if (ctx->in_dict == NULL) { + if (ctx->in_dict == nullptr) { msg_err_config("cannot open zstd dictionary in %s", cfg->zstd_input_dictionary); } @@ -2799,7 +2769,7 @@ rspamd_config_libs(struct rspamd_external_libs_ctx *ctx, ctx->out_dict = rspamd_open_zstd_dictionary( cfg->zstd_output_dictionary); - if (ctx->out_dict == NULL) { + if (ctx->out_dict == nullptr) { msg_err_config("cannot open zstd dictionary in %s", cfg->zstd_output_dictionary); } @@ -2813,7 +2783,7 @@ rspamd_config_libs(struct rspamd_external_libs_ctx *ctx, /* Toggle FIPS mode */ if (mode == 0) { #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) - if (EVP_set_default_properties(NULL, "fips=yes") != 1) { + if (EVP_set_default_properties(nullptr, "fips=yes") != 1) { #else if (FIPS_mode_set(1) != 1) { #endif @@ -2830,7 +2800,7 @@ rspamd_config_libs(struct rspamd_external_libs_ctx *ctx, #else msg_err_config("FIPS_mode_set failed: %s", #endif - ERR_error_string(err, NULL)); + ERR_error_string(err, nullptr)); ret = FALSE; } else { @@ -2846,24 +2816,24 @@ rspamd_config_libs(struct rspamd_external_libs_ctx *ctx, /* Init decompression */ ctx->in_zstream = ZSTD_createDStream(); - r = ZSTD_initDStream(ctx->in_zstream); + r = ZSTD_initDStream((ZSTD_DCtx *) ctx->in_zstream); if (ZSTD_isError(r)) { msg_err("cannot init decompression stream: %s", ZSTD_getErrorName(r)); - ZSTD_freeDStream(ctx->in_zstream); - ctx->in_zstream = NULL; + ZSTD_freeDStream((ZSTD_DCtx *) ctx->in_zstream); + ctx->in_zstream = nullptr; } /* Init compression */ ctx->out_zstream = ZSTD_createCStream(); - r = ZSTD_initCStream(ctx->out_zstream, 1); + r = ZSTD_initCStream((ZSTD_CCtx *) ctx->out_zstream, 1); if (ZSTD_isError(r)) { msg_err("cannot init compression stream: %s", ZSTD_getErrorName(r)); - ZSTD_freeCStream(ctx->out_zstream); - ctx->out_zstream = NULL; + ZSTD_freeCStream((ZSTD_CCtx *) ctx->out_zstream); + ctx->out_zstream = nullptr; } #ifdef HAVE_OPENBLAS_SET_NUM_THREADS openblas_set_num_threads(cfg->max_blas_threads); @@ -2881,17 +2851,17 @@ rspamd_libs_reset_decompression(struct rspamd_external_libs_ctx *ctx) { gsize r; - if (ctx->in_zstream == NULL) { + if (ctx->in_zstream == nullptr) { return FALSE; } else { - r = ZSTD_DCtx_reset(ctx->in_zstream, ZSTD_reset_session_only); + r = ZSTD_DCtx_reset((ZSTD_DCtx *) ctx->in_zstream, ZSTD_reset_session_only); if (ZSTD_isError(r)) { msg_err("cannot init decompression stream: %s", ZSTD_getErrorName(r)); - ZSTD_freeDStream(ctx->in_zstream); - ctx->in_zstream = NULL; + ZSTD_freeDStream((ZSTD_DCtx *) ctx->in_zstream); + ctx->in_zstream = nullptr; return FALSE; } @@ -2905,21 +2875,21 @@ rspamd_libs_reset_compression(struct rspamd_external_libs_ctx *ctx) { gsize r; - if (ctx->out_zstream == NULL) { + if (ctx->out_zstream == nullptr) { return FALSE; } else { /* Dictionary will be reused automatically if specified */ - r = ZSTD_CCtx_reset(ctx->out_zstream, ZSTD_reset_session_only); + r = ZSTD_CCtx_reset((ZSTD_CCtx *) ctx->out_zstream, ZSTD_reset_session_only); if (!ZSTD_isError(r)) { - r = ZSTD_CCtx_setPledgedSrcSize(ctx->out_zstream, ZSTD_CONTENTSIZE_UNKNOWN); + r = ZSTD_CCtx_setPledgedSrcSize((ZSTD_CCtx *) ctx->out_zstream, ZSTD_CONTENTSIZE_UNKNOWN); } if (ZSTD_isError(r)) { msg_err("cannot init compression stream: %s", ZSTD_getErrorName(r)); - ZSTD_freeCStream(ctx->out_zstream); - ctx->out_zstream = NULL; + ZSTD_freeCStream((ZSTD_CCtx *) ctx->out_zstream); + ctx->out_zstream = nullptr; return FALSE; } @@ -2930,7 +2900,7 @@ rspamd_libs_reset_compression(struct rspamd_external_libs_ctx *ctx) void rspamd_deinit_libs(struct rspamd_external_libs_ctx *ctx) { - if (ctx != NULL) { + if (ctx != nullptr) { g_free(ctx->ottery_cfg); #ifdef HAVE_OPENSSL @@ -2944,11 +2914,11 @@ void rspamd_deinit_libs(struct rspamd_external_libs_ctx *ctx) rspamd_free_zstd_dictionary(ctx->out_dict); if (ctx->out_zstream) { - ZSTD_freeCStream(ctx->out_zstream); + ZSTD_freeCStream((ZSTD_CCtx *) ctx->out_zstream); } if (ctx->in_zstream) { - ZSTD_freeDStream(ctx->in_zstream); + ZSTD_freeDStream((ZSTD_DCtx *) ctx->in_zstream); } rspamd_cryptobox_deinit(ctx->crypto_ctx); @@ -2961,7 +2931,7 @@ gboolean rspamd_ip_is_local_cfg(struct rspamd_config *cfg, const rspamd_inet_addr_t *addr) { - struct rspamd_radix_map_helper *local_addrs = NULL; + struct rspamd_radix_map_helper *local_addrs = nullptr; if (cfg && cfg->libs_ctx) { local_addrs = *(struct rspamd_radix_map_helper **) cfg->libs_ctx->local_addrs; @@ -2972,7 +2942,7 @@ rspamd_ip_is_local_cfg(struct rspamd_config *cfg, } if (local_addrs) { - if (rspamd_match_radix_map_addr(local_addrs, addr) != NULL) { + if (rspamd_match_radix_map_addr(local_addrs, addr) != nullptr) { return TRUE; } } diff --git a/src/libserver/dns.c b/src/libserver/dns.c index 84582202a..abe47dfdc 100644 --- a/src/libserver/dns.c +++ b/src/libserver/dns.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -948,11 +948,11 @@ rspamd_dns_resolver_init(rspamd_logger_t *logger, dns_resolver->ups); cfg->dns_resolver = dns_resolver; - if (cfg->rcl_obj) { + if (cfg->cfg_ucl_obj) { /* Configure additional options */ const ucl_object_t *opts_section, *dns_section, *tmp; - opts_section = ucl_object_lookup(cfg->rcl_obj, "options"); + opts_section = ucl_object_lookup(cfg->cfg_ucl_obj, "options"); if (opts_section) { /* TODO: implement a more simple merge logic */ diff --git a/src/libserver/dynamic_cfg.c b/src/libserver/dynamic_cfg.c index 8254ebc91..cd5cc4e30 100644 --- a/src/libserver/dynamic_cfg.c +++ b/src/libserver/dynamic_cfg.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -36,7 +36,7 @@ struct config_json_buf { static void apply_dynamic_conf(const ucl_object_t *top, struct rspamd_config *cfg) { - gint test_act; + enum rspamd_action_type test_act; const ucl_object_t *cur_elt, *cur_nm, *it_val; ucl_object_iter_t it = NULL; const gchar *name; diff --git a/src/libserver/fuzzy_backend/fuzzy_backend_redis.c b/src/libserver/fuzzy_backend/fuzzy_backend_redis.c index 2f9d1ed10..9b5b3bc02 100644 --- a/src/libserver/fuzzy_backend/fuzzy_backend_redis.c +++ b/src/libserver/fuzzy_backend/fuzzy_backend_redis.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -204,7 +204,7 @@ rspamd_fuzzy_backend_init_redis(struct rspamd_fuzzy_backend *bk, /* Now try global redis settings */ if (!ret) { - elt = ucl_object_lookup(cfg->rcl_obj, "redis"); + elt = ucl_object_lookup(cfg->cfg_ucl_obj, "redis"); if (elt) { const ucl_object_t *specific_obj; diff --git a/src/libserver/http/http_context.c b/src/libserver/http/http_context.c index 721bc2782..f08e33baf 100644 --- a/src/libserver/http/http_context.c +++ b/src/libserver/http/http_context.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2019 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -210,7 +210,7 @@ rspamd_http_context_create(struct rspamd_config *cfg, const ucl_object_t *http_obj; ctx = rspamd_http_context_new_default(cfg, ev_base, ups_ctx); - http_obj = ucl_object_lookup(cfg->rcl_obj, "http"); + http_obj = ucl_object_lookup(cfg->cfg_ucl_obj, "http"); if (http_obj) { const ucl_object_t *server_obj, *client_obj; diff --git a/src/libserver/protocol.c b/src/libserver/protocol.c index c8e3fe441..867455754 100644 --- a/src/libserver/protocol.c +++ b/src/libserver/protocol.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -793,65 +793,66 @@ rspamd_protocol_parse_task_flags(rspamd_mempool_t *pool, return TRUE; } -static struct rspamd_rcl_section *control_parser = NULL; +static struct rspamd_rcl_sections_map *control_parser = NULL; -static void -rspamd_protocol_control_parser_init(void) +RSPAMD_CONSTRUCTOR(rspamd_protocol_control_parser_ctor) { - struct rspamd_rcl_section *sub; - - if (control_parser == NULL) { - sub = rspamd_rcl_add_section(&control_parser, - "*", - NULL, - NULL, - UCL_OBJECT, - FALSE, - TRUE); - /* Default handlers */ - rspamd_rcl_add_default_handler(sub, - "ip", - rspamd_rcl_parse_struct_addr, - G_STRUCT_OFFSET(struct rspamd_task, from_addr), - 0, - NULL); - rspamd_rcl_add_default_handler(sub, - "from", - rspamd_rcl_parse_struct_mime_addr, - G_STRUCT_OFFSET(struct rspamd_task, from_envelope), - 0, - NULL); - rspamd_rcl_add_default_handler(sub, - "rcpt", - rspamd_rcl_parse_struct_mime_addr, - G_STRUCT_OFFSET(struct rspamd_task, rcpt_envelope), - 0, - NULL); - rspamd_rcl_add_default_handler(sub, - "helo", - rspamd_rcl_parse_struct_string, - G_STRUCT_OFFSET(struct rspamd_task, helo), - 0, - NULL); - rspamd_rcl_add_default_handler(sub, - "user", - rspamd_rcl_parse_struct_string, - G_STRUCT_OFFSET(struct rspamd_task, auth_user), - 0, - NULL); - rspamd_rcl_add_default_handler(sub, - "pass_all", - rspamd_protocol_parse_task_flags, - G_STRUCT_OFFSET(struct rspamd_task, flags), - 0, - NULL); - rspamd_rcl_add_default_handler(sub, - "json", - rspamd_protocol_parse_task_flags, - G_STRUCT_OFFSET(struct rspamd_task, flags), - 0, - NULL); - } + + struct rspamd_rcl_section *sub = rspamd_rcl_add_section(&control_parser, NULL, + "*", + NULL, + NULL, + UCL_OBJECT, + FALSE, + TRUE); + /* Default handlers */ + rspamd_rcl_add_default_handler(sub, + "ip", + rspamd_rcl_parse_struct_addr, + G_STRUCT_OFFSET(struct rspamd_task, from_addr), + 0, + NULL); + rspamd_rcl_add_default_handler(sub, + "from", + rspamd_rcl_parse_struct_mime_addr, + G_STRUCT_OFFSET(struct rspamd_task, from_envelope), + 0, + NULL); + rspamd_rcl_add_default_handler(sub, + "rcpt", + rspamd_rcl_parse_struct_mime_addr, + G_STRUCT_OFFSET(struct rspamd_task, rcpt_envelope), + 0, + NULL); + rspamd_rcl_add_default_handler(sub, + "helo", + rspamd_rcl_parse_struct_string, + G_STRUCT_OFFSET(struct rspamd_task, helo), + 0, + NULL); + rspamd_rcl_add_default_handler(sub, + "user", + rspamd_rcl_parse_struct_string, + G_STRUCT_OFFSET(struct rspamd_task, auth_user), + 0, + NULL); + rspamd_rcl_add_default_handler(sub, + "pass_all", + rspamd_protocol_parse_task_flags, + G_STRUCT_OFFSET(struct rspamd_task, flags), + 0, + NULL); + rspamd_rcl_add_default_handler(sub, + "json", + rspamd_protocol_parse_task_flags, + G_STRUCT_OFFSET(struct rspamd_task, flags), + 0, + NULL); +} + +RSPAMD_DESTRUCTOR(rspamd_protocol_control_parser_dtor) +{ + rspamd_rcl_sections_free(control_parser); } gboolean @@ -860,8 +861,6 @@ rspamd_protocol_handle_control(struct rspamd_task *task, { GError *err = NULL; - rspamd_protocol_control_parser_init(); - if (!rspamd_rcl_parse(control_parser, task->cfg, task, task->task_pool, control, &err)) { msg_warn_protocol("cannot parse control block: %e", err); diff --git a/src/libserver/rspamd_symcache.h b/src/libserver/rspamd_symcache.h index f2f95fcc5..45e460c11 100644 --- a/src/libserver/rspamd_symcache.h +++ b/src/libserver/rspamd_symcache.h @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -123,7 +123,7 @@ gint rspamd_symcache_add_symbol(struct rspamd_symcache *cache, gint priority, symbol_func_t func, gpointer user_data, - enum rspamd_symbol_type type, + int type, gint parent); /** diff --git a/src/libserver/symcache/symcache_c.cxx b/src/libserver/symcache/symcache_c.cxx index 52881f77e..06801d244 100644 --- a/src/libserver/symcache/symcache_c.cxx +++ b/src/libserver/symcache/symcache_c.cxx @@ -1,11 +1,11 @@ -/*- - * Copyright 2022 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -63,7 +63,7 @@ gint rspamd_symcache_add_symbol(struct rspamd_symcache *cache, gint priority, symbol_func_t func, gpointer user_data, - enum rspamd_symbol_type type, + int type, gint parent) { auto *real_cache = C_API_SYMCACHE(cache); diff --git a/src/libserver/symcache/symcache_impl.cxx b/src/libserver/symcache/symcache_impl.cxx index 94e90751b..6fd705be1 100644 --- a/src/libserver/symcache/symcache_impl.cxx +++ b/src/libserver/symcache/symcache_impl.cxx @@ -1,11 +1,11 @@ -/*- - * Copyright 2022 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -42,7 +42,7 @@ auto symcache::init() -> bool if (cfg->cache_filename != nullptr) { msg_debug_cache("loading symcache saved data from %s", cfg->cache_filename); - res = load_items(); + load_items(); } ankerl::unordered_dense::set<int> disabled_ids; @@ -717,7 +717,7 @@ auto symcache::add_symbol_with_callback(std::string_view name, int priority, symbol_func_t func, void *user_data, - enum rspamd_symbol_type flags_and_type) -> int + int flags_and_type) -> int { auto real_type_pair_maybe = item_type_from_c(flags_and_type); @@ -786,7 +786,7 @@ auto symcache::add_symbol_with_callback(std::string_view name, return id; } -auto symcache::add_virtual_symbol(std::string_view name, int parent_id, enum rspamd_symbol_type flags_and_type) -> int +auto symcache::add_virtual_symbol(std::string_view name, int parent_id, int flags_and_type) -> int { if (name.empty()) { msg_err_cache("cannot register a virtual symbol with no name; qed"); diff --git a/src/libserver/symcache/symcache_internal.hxx b/src/libserver/symcache/symcache_internal.hxx index 240939780..255a4b1c1 100644 --- a/src/libserver/symcache/symcache_internal.hxx +++ b/src/libserver/symcache/symcache_internal.hxx @@ -1,11 +1,11 @@ -/*- - * Copyright 2022 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -458,7 +458,7 @@ public: int priority, symbol_func_t func, void *user_data, - enum rspamd_symbol_type flags_and_type) -> int; + int flags_and_type) -> int; /** * A method to add a generic virtual symbol with no function associated * @param name must have some value, or a fatal error will strike you @@ -467,7 +467,7 @@ public: * @return id of a new symbol or -1 in case of failure */ auto add_virtual_symbol(std::string_view name, int parent_id, - enum rspamd_symbol_type flags_and_type) -> int; + int flags_and_type) -> int; /** * Sets a lua callback to be called on peaks in execution time diff --git a/src/libserver/symcache/symcache_item.cxx b/src/libserver/symcache/symcache_item.cxx index a468aaf03..24e198dd3 100644 --- a/src/libserver/symcache/symcache_item.cxx +++ b/src/libserver/symcache/symcache_item.cxx @@ -1,11 +1,11 @@ -/*- - * Copyright 2022 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -537,7 +537,7 @@ auto virtual_item::resolve_parent(const symcache &cache) -> bool return false; } -auto item_type_from_c(enum rspamd_symbol_type type) -> tl::expected<std::pair<symcache_item_type, int>, std::string> +auto item_type_from_c(int type) -> tl::expected<std::pair<symcache_item_type, int>, std::string> { constexpr const auto trivial_types = SYMBOL_TYPE_CONNFILTER | SYMBOL_TYPE_PREFILTER | SYMBOL_TYPE_POSTFILTER | SYMBOL_TYPE_IDEMPOTENT | SYMBOL_TYPE_COMPOSITE | SYMBOL_TYPE_CLASSIFIER | SYMBOL_TYPE_VIRTUAL; diff --git a/src/libserver/symcache/symcache_item.hxx b/src/libserver/symcache/symcache_item.hxx index 5ceffa121..c159e7c47 100644 --- a/src/libserver/symcache/symcache_item.hxx +++ b/src/libserver/symcache/symcache_item.hxx @@ -1,11 +1,11 @@ -/*- - * Copyright 2022 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -85,7 +85,7 @@ constexpr static auto item_type_to_str(symcache_item_type t) -> const char * * @param type input type as a C enum * @return pair of type safe symcache_item_type + the remaining flags or an error */ -auto item_type_from_c(enum rspamd_symbol_type type) -> tl::expected<std::pair<symcache_item_type, int>, std::string>; +auto item_type_from_c(int type) -> tl::expected<std::pair<symcache_item_type, int>, std::string>; struct item_condition { private: diff --git a/src/libstat/backends/redis_backend.c b/src/libstat/backends/redis_backend.c index 2e4711ae9..a0d11bb0d 100644 --- a/src/libstat/backends/redis_backend.c +++ b/src/libstat/backends/redis_backend.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -1559,7 +1559,7 @@ rspamd_redis_init(struct rspamd_stat_ctx *ctx, /* Now try global redis settings */ if (!ret) { - obj = ucl_object_lookup(cfg->rcl_obj, "redis"); + obj = ucl_object_lookup(cfg->cfg_ucl_obj, "redis"); if (obj) { const ucl_object_t *specific_obj; diff --git a/src/libstat/learn_cache/redis_cache.c b/src/libstat/learn_cache/redis_cache.c index d5fe4ad48..3026009bc 100644 --- a/src/libstat/learn_cache/redis_cache.c +++ b/src/libstat/learn_cache/redis_cache.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -275,7 +275,7 @@ rspamd_stat_cache_redis_init(struct rspamd_stat_ctx *ctx, /* Now try global redis settings */ if (!ret) { - obj = ucl_object_lookup(cfg->rcl_obj, "redis"); + obj = ucl_object_lookup(cfg->cfg_ucl_obj, "redis"); if (obj) { const ucl_object_t *specific_obj; diff --git a/src/libutil/addr.c b/src/libutil/addr.c index b54bd5539..e011c991a 100644 --- a/src/libutil/addr.c +++ b/src/libutil/addr.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -1477,7 +1477,7 @@ rspamd_parse_host_port_priority(const gchar *str, if (*addrs == NULL) { *addrs = g_ptr_array_new_full(1, - (GDestroyNotify) rspamd_inet_address_free); + pool == NULL ? NULL : (GDestroyNotify) rspamd_inet_address_free); if (pool != NULL) { rspamd_mempool_add_destructor(pool, @@ -1486,7 +1486,7 @@ rspamd_parse_host_port_priority(const gchar *str, } if (v4_any) { - cur_addr = rspamd_inet_addr_create(AF_INET, pool); + cur_addr = rspamd_inet_addr_create(AF_INET, NULL); rspamd_parse_inet_address_ip4("0.0.0.0", sizeof("0.0.0.0") - 1, &su.s4.sin_addr); memcpy(&cur_addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr, @@ -1496,7 +1496,7 @@ rspamd_parse_host_port_priority(const gchar *str, g_ptr_array_add(*addrs, cur_addr); } if (v6_any) { - cur_addr = rspamd_inet_addr_create(AF_INET6, pool); + cur_addr = rspamd_inet_addr_create(AF_INET6, NULL); rspamd_parse_inet_address_ip6("::", sizeof("::") - 1, &su.s6.sin6_addr); memcpy(&cur_addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr, diff --git a/src/libutil/cxx/file_util.hxx b/src/libutil/cxx/file_util.hxx index a0c624726..45289053e 100644 --- a/src/libutil/cxx/file_util.hxx +++ b/src/libutil/cxx/file_util.hxx @@ -1,11 +1,11 @@ -/*- - * Copyright 2022 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -33,7 +33,16 @@ public: virtual ~raii_file() noexcept; static auto open(const char *fname, int flags) -> tl::expected<raii_file, error>; + static auto open(const std::string &fname, int flags) -> tl::expected<raii_file, error> + { + return open(fname.c_str(), flags); + }; static auto create(const char *fname, int flags, int perms) -> tl::expected<raii_file, error>; + static auto create(const std::string &fname, int flags, int perms) -> tl::expected<raii_file, error> + { + return create(fname.c_str(), flags, perms); + }; + static auto create_temp(const char *fname, int flags, int perms) -> tl::expected<raii_file, error>; static auto mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_file, error>; diff --git a/src/libutil/cxx/util.hxx b/src/libutil/cxx/util.hxx index 9ef2f6295..32ec0b55c 100644 --- a/src/libutil/cxx/util.hxx +++ b/src/libutil/cxx/util.hxx @@ -1,11 +1,11 @@ -/*- - * Copyright 2021 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -40,6 +40,15 @@ constexpr auto array_of(Ts &&...t) -> std::array<typename std::decay_t<typename return {{std::forward<T>(t)...}}; } +/** + * Find a value in a map + * @tparam C Map type + * @tparam K Key type + * @tparam V Value type + * @param c Map to search + * @param k Key to search + * @return Value if found or std::nullopt otherwise + */ template<class C, class K, class V = typename C::mapped_type, typename std::enable_if_t<std::is_constructible_v<typename C::key_type, K> && std::is_constructible_v<typename C::mapped_type, V>, bool> = false> constexpr auto find_map(const C &c, const K &k) -> std::optional<std::reference_wrapper<const V>> { @@ -53,8 +62,8 @@ constexpr auto find_map(const C &c, const K &k) -> std::optional<std::reference_ } -template<typename _It> -inline constexpr auto make_string_view_from_it(_It begin, _It end) +template<typename It> +inline constexpr auto make_string_view_from_it(It begin, It end) { using result_type = std::string_view; @@ -91,6 +100,47 @@ inline auto string_foreach_line(const S &input, const F &functor) } } +/** + * Iterate over elements in a string + * @tparam S string type + * @tparam D delimiter type + * @tparam F functor type + * @param input string to iterate + * @param delim delimiter to use + * @param functor functor to call + * @param ignore_empty ignore empty elements + * @return nothing + */ +template<class S, class D, class F, + typename std::enable_if_t<std::is_invocable_v<F, std::string_view> && std::is_constructible_v<std::string_view, S> && std::is_constructible_v<std::string_view, D>, bool> = true> +inline auto string_foreach_delim(const S &input, const D &delim, const F &functor, const bool ignore_empty = true) -> void +{ + size_t first = 0; + auto sv_input = std::string_view{input}; + auto sv_delim = std::string_view{delim}; + + while (first < sv_input.size()) { + const auto second = sv_input.find_first_of(sv_delim, first); + + if (first != second || !ignore_empty) { + functor(sv_input.substr(first, second - first)); + } + + if (second == std::string_view::npos) { + break; + } + + first = second + 1; + } +} + +/** + * Split string on a character + * @tparam S string type + * @param input string to split + * @param chr character to split on + * @return pair of strings + */ template<class S, typename std::enable_if_t<std::is_constructible_v<std::string_view, S>, bool> = true> inline auto string_split_on(const S &input, std::string_view::value_type chr) -> std::pair<std::string_view, std::string_view> { @@ -111,6 +161,10 @@ inline auto string_split_on(const S &input, std::string_view::value_type chr) -> /** * Enumerate for range loop + * @tparam T iterable type + * @tparam TIter iterator type + * @param iterable iterable object + * @return iterator object */ template<typename T, typename TIter = decltype(std::begin(std::declval<T>())), diff --git a/src/libutil/cxx/util_tests.cxx b/src/libutil/cxx/util_tests.cxx index 2b3092779..6c3c17799 100644 --- a/src/libutil/cxx/util_tests.cxx +++ b/src/libutil/cxx/util_tests.cxx @@ -1,11 +1,11 @@ -/*- +/* * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -18,6 +18,7 @@ #define DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL #include "doctest/doctest.h" +#include <vector> using namespace rspamd; using namespace std::literals::string_view_literals; @@ -43,4 +44,39 @@ TEST_SUITE("cxx utils") CHECK(res.second == expected.second); } } + + TEST_CASE("string_foreach_delim") + { + std::tuple<std::string_view, std::string_view, std::pair<std::vector<std::string_view>, std::vector<std::string_view>>> cases[] = { + {"test"sv, ","sv, {{"test"}, {"test"}}}, + {"test,test"sv, ","sv, {{"test", "test"}, {"test", "test"}}}, + {"test, test"sv, ", "sv, {{"test", "test"}, {"test", "", "test"}}}, + {"test, test,,"sv, ", "sv, {{"test", "test"}, {"test", "", "test", ""}}}, + }; + + for (const auto &c: cases) { + auto res = std::vector<std::string_view>(); + string_foreach_delim(std::get<0>(c), std::get<1>(c), [&](const auto &v) { + res.push_back(v); + }); + + auto compare_vec = []<class T>(const std::vector<T> &v1, const std::vector<T> &v2) { + CHECK(v1.size() == v2.size()); + for (size_t i = 0; i < v1.size(); ++i) { + CHECK(v1[i] == v2[i]); + } + }; + + compare_vec(res, std::get<2>(c).first); + + res.clear(); + // Perform the same test but with no skip empty + string_foreach_delim( + std::get<0>(c), std::get<1>(c), [&](const auto &v) { + res.push_back(v); + }, + false); + compare_vec(res, std::get<2>(c).second); + } + } }
\ No newline at end of file diff --git a/src/libutil/mem_pool.c b/src/libutil/mem_pool.c index f5771ff7a..bbd302a23 100644 --- a/src/libutil/mem_pool.c +++ b/src/libutil/mem_pool.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -605,14 +605,21 @@ rspamd_mempool_alloc_shared_(rspamd_mempool_t *pool, gsize size, gsize alignment gchar * rspamd_mempool_strdup_(rspamd_mempool_t *pool, const gchar *src, const gchar *loc) { - gsize len; + if (src == NULL) { + return NULL; + } + return rspamd_mempool_strdup_len_(pool, src, strlen(src), loc); +} + +gchar * +rspamd_mempool_strdup_len_(rspamd_mempool_t *pool, const gchar *src, gsize len, const gchar *loc) +{ gchar *newstr; if (src == NULL) { return NULL; } - len = strlen(src); newstr = rspamd_mempool_alloc_(pool, len + 1, MIN_MEM_ALIGNMENT, loc); memcpy(newstr, src, len); newstr[len] = '\0'; diff --git a/src/libutil/mem_pool.h b/src/libutil/mem_pool.h index 23f70092f..425a6b297 100644 --- a/src/libutil/mem_pool.h +++ b/src/libutil/mem_pool.h @@ -1,11 +1,11 @@ -/*- - * Copyright 2019 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -216,6 +216,10 @@ gchar *rspamd_mempool_strdup_(rspamd_mempool_t *pool, const gchar *src, const gc RSPAMD_ATTR_ALLOC_ALIGN(MIN_MEM_ALIGNMENT); #define rspamd_mempool_strdup(pool, src) \ rspamd_mempool_strdup_((pool), (src), (G_STRLOC)) +gchar *rspamd_mempool_strdup_len_(rspamd_mempool_t *pool, const gchar *src, gsize len, const gchar *loc) + RSPAMD_ATTR_ALLOC_ALIGN(MIN_MEM_ALIGNMENT); +#define rspamd_mempool_strdup_len(pool, src, len) \ + rspamd_mempool_strdup_len_((pool), (src), (len), (G_STRLOC)) struct f_str_tok; diff --git a/src/lua/lua_cfg_file.c b/src/lua/lua_cfg_file.c index 0386c0969..75bc3806d 100644 --- a/src/lua/lua_cfg_file.c +++ b/src/lua/lua_cfg_file.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -124,7 +124,7 @@ void rspamd_lua_post_load_config(struct rspamd_config *cfg) if (obj != NULL) { ucl_object_sort_keys(obj, UCL_SORT_KEYS_DEFAULT); - ucl_object_insert_key_merged(cfg->rcl_obj, + ucl_object_insert_key_merged(cfg->cfg_ucl_obj, obj, name, strlen(name), diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h index bf887e301..cc2b94390 100644 --- a/src/lua/lua_common.h +++ b/src/lua/lua_common.h @@ -97,7 +97,7 @@ static inline int lua_absindex(lua_State *L, int i) extern const luaL_reg null_reg[]; -#define RSPAMD_LUA_API_VERSION 12 +#define RSPAMD_LUA_CFG_STATE(cfg) ((lua_State *) ((cfg)->lua_state)) /** * Lua IP address structure */ @@ -427,15 +427,6 @@ double rspamd_lua_normalize(struct rspamd_config *cfg, /* Config file functions */ void rspamd_lua_post_load_config(struct rspamd_config *cfg); -gboolean rspamd_lua_handle_param(struct rspamd_task *task, - gchar *mname, - gchar *optname, - enum lua_var_type expected_type, - gpointer *res); - -gboolean rspamd_lua_check_condition(struct rspamd_config *cfg, - const gchar *condition); - void rspamd_lua_dumpstack(lua_State *L); /* Set lua path according to the configuration */ diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index d36245247..a044827a7 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -1044,7 +1044,7 @@ lua_config_get_all_opt(lua_State *L) mname = luaL_checkstring(L, 2); if (mname) { - obj = ucl_obj_get_key(cfg->rcl_obj, mname); + obj = ucl_obj_get_key(cfg->cfg_ucl_obj, mname); /* Flatten object */ if (obj != NULL && (ucl_object_type(obj) == UCL_OBJECT || ucl_object_type(obj) == UCL_ARRAY)) { @@ -1114,8 +1114,8 @@ lua_config_get_ucl(lua_State *L) lua_rawgeti(L, LUA_REGISTRYINDEX, cached->ref); } else { - if (cfg->rcl_obj) { - ucl_object_push_lua(L, cfg->rcl_obj, true); + if (cfg->cfg_ucl_obj) { + ucl_object_push_lua(L, cfg->cfg_ucl_obj, true); lua_pushvalue(L, -1); cached = rspamd_mempool_alloc(cfg->cfg_pool, sizeof(*cached)); cached->L = L; @@ -1725,7 +1725,7 @@ lua_config_get_key(lua_State *L) name = luaL_checklstring(L, 2, &namelen); if (name && cfg) { - val = ucl_object_lookup_len(cfg->rcl_obj, name, namelen); + val = ucl_object_lookup_len(cfg->cfg_ucl_obj, name, namelen); if (val != NULL) { ucl_object_push_lua(L, val, val->type != UCL_ARRAY); } @@ -2581,24 +2581,27 @@ lua_config_get_metric_action(lua_State *L) return 1; } +static void +lua_config_actions_cb(struct rspamd_action *act, void *cbd) +{ + lua_State *L = (lua_State *) cbd; + + if (!isnan(act->threshold)) { + lua_pushstring(L, act->name); + lua_pushnumber(L, act->threshold); + lua_settable(L, -3); + } +} + static gint lua_config_get_all_actions(lua_State *L) { LUA_TRACE_POINT; struct rspamd_config *cfg = lua_check_config(L, 1); - struct rspamd_action *act, *tmp; if (cfg) { - lua_createtable(L, 0, HASH_COUNT(cfg->actions)); - - HASH_ITER(hh, cfg->actions, act, tmp) - { - if (!isnan(act->threshold)) { - lua_pushstring(L, act->name); - lua_pushnumber(L, act->threshold); - lua_settable(L, -3); - } - } + lua_createtable(L, 0, rspamd_config_actions_size(cfg)); + rspamd_config_actions_foreach(cfg, lua_config_actions_cb, L); } else { return luaL_error(L, "invalid arguments, rspamd_config expected"); @@ -4420,7 +4423,7 @@ lua_config_parse_rcl(lua_State *L) GHashTable *excluded = g_hash_table_new_full(rspamd_str_hash, rspamd_str_equal, g_free, NULL); GError *err = NULL; - struct rspamd_rcl_section *top; + struct rspamd_rcl_sections_map *top; if (cfg) { if (lua_istable(L, 2)) { @@ -4436,12 +4439,12 @@ lua_config_parse_rcl(lua_State *L) top = rspamd_rcl_config_init(cfg, excluded); - if (!rspamd_rcl_parse(top, cfg, cfg, cfg->cfg_pool, cfg->rcl_obj, &err)) { + if (!rspamd_rcl_parse(top, cfg, cfg, cfg->cfg_pool, cfg->cfg_ucl_obj, &err)) { lua_pushboolean(L, false); lua_pushfstring(L, "failed to load config: %s", err->message); g_error_free(err); g_hash_table_unref(excluded); - rspamd_rcl_section_free(top); + rspamd_rcl_sections_free(top); return 2; } @@ -4451,7 +4454,7 @@ lua_config_parse_rcl(lua_State *L) } g_hash_table_unref(excluded); - rspamd_rcl_section_free(top); + rspamd_rcl_sections_free(top); lua_pushboolean(L, true); return 1; diff --git a/src/lua/lua_task.c b/src/lua/lua_task.c index 4fb6fe347..351dd9208 100644 --- a/src/lua/lua_task.c +++ b/src/lua/lua_task.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -2299,7 +2299,7 @@ lua_task_set_pre_result(lua_State *L) } } - gint internal_type; + enum rspamd_action_type internal_type; if (strcmp(act_str, "accept") == 0) { /* Compatibility! */ @@ -2313,14 +2313,6 @@ lua_task_set_pre_result(lua_State *L) action = rspamd_config_get_action(task->cfg, act_str); if (action == NULL) { - struct rspamd_action *tmp; - - HASH_ITER(hh, task->cfg->actions, action, tmp) - { - msg_err_task("known defined action: %s = %f", - action->name, action->threshold); - } - return luaL_error(L, "unknown action %s", act_str); } @@ -5700,7 +5692,7 @@ lua_task_set_settings(lua_State *L) const gchar *act_name = ucl_object_key(cur); struct rspamd_action_config *action_config = NULL; double act_score; - int act_type; + enum rspamd_action_type act_type; if (!rspamd_action_from_str(act_name, &act_type)) { act_type = -1; @@ -5730,7 +5722,7 @@ lua_task_set_settings(lua_State *L) if (!isnan(act_score)) { struct rspamd_action *new_act; - HASH_FIND_STR(task->cfg->actions, act_name, new_act); + new_act = rspamd_config_get_action(task->cfg, act_name); if (new_act == NULL) { /* New action! */ diff --git a/src/lua/lua_util.c b/src/lua/lua_util.c index 503dd8ffb..40f6f6c48 100644 --- a/src/lua/lua_util.c +++ b/src/lua/lua_util.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -858,7 +858,7 @@ lua_util_config_from_ucl(lua_State *L) { LUA_TRACE_POINT; struct rspamd_config *cfg = NULL, **pcfg; - struct rspamd_rcl_section *top; + struct rspamd_rcl_sections_map *top; GError *err = NULL; ucl_object_t *obj; const char *str_options = NULL; @@ -882,10 +882,10 @@ lua_util_config_from_ucl(lua_State *L) cfg = rspamd_config_new(RSPAMD_CONFIG_INIT_SKIP_LUA); cfg->lua_state = L; - cfg->rcl_obj = obj; + cfg->cfg_ucl_obj = obj; top = rspamd_rcl_config_init(cfg, NULL); - if (!rspamd_rcl_parse(top, cfg, cfg, cfg->cfg_pool, cfg->rcl_obj, &err)) { + if (!rspamd_rcl_parse(top, cfg, cfg, cfg->cfg_pool, cfg->cfg_ucl_obj, &err)) { msg_err("rcl parse error: %s", err->message); ucl_object_unref(obj); lua_pushnil(L); @@ -901,6 +901,8 @@ lua_util_config_from_ucl(lua_State *L) rspamd_lua_setclass(L, "rspamd{config}", -1); *pcfg = cfg; } + + rspamd_rcl_sections_free(top); } return 1; diff --git a/src/plugins/regexp.c b/src/plugins/regexp.c index 22a348669..59a84c507 100644 --- a/src/plugins/regexp.c +++ b/src/plugins/regexp.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -140,7 +140,7 @@ gint regexp_module_config(struct rspamd_config *cfg, bool validate) return TRUE; } - sec = ucl_object_lookup(cfg->rcl_obj, "regexp"); + sec = ucl_object_lookup(cfg->cfg_ucl_obj, "regexp"); if (sec == NULL) { msg_err_config("regexp module enabled, but no rules are defined"); return TRUE; diff --git a/src/rspamadm/configdump.c b/src/rspamadm/configdump.c index 23e02db58..dc8b82218 100644 --- a/src/rspamadm/configdump.c +++ b/src/rspamadm/configdump.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -298,7 +298,7 @@ rspamadm_configdump(gint argc, gchar **argv, const struct rspamadm_command *cmd) rspamadm_execute_lua_ucl_subr(argc, argv, - cfg->rcl_obj, + cfg->cfg_ucl_obj, "plugins_stats", FALSE); @@ -316,7 +316,7 @@ rspamadm_configdump(gint argc, gchar **argv, const struct rspamadm_command *cmd) g_hash_table_iter_init(&it, cfg->symbols); ucl_object_t *sym_ucl = ucl_object_typed_new(UCL_OBJECT); - const ucl_object_t *all_symbols_ucl = ucl_object_lookup(cfg->rcl_obj, "symbols"); + const ucl_object_t *all_symbols_ucl = ucl_object_lookup(cfg->cfg_ucl_obj, "symbols"); while (g_hash_table_iter_next(&it, &sk, &sv)) { const gchar *sym_name = (const gchar *) sk; @@ -521,11 +521,11 @@ rspamadm_configdump(gint argc, gchar **argv, const struct rspamadm_command *cmd) /* Output configuration */ if (argc == 1) { - rspamadm_dump_section_obj(cfg, cfg->rcl_obj, cfg->doc_strings); + rspamadm_dump_section_obj(cfg, cfg->cfg_ucl_obj, cfg->doc_strings); } else { for (i = 1; i < argc; i++) { - obj = ucl_object_lookup_path(cfg->rcl_obj, argv[i]); + obj = ucl_object_lookup_path(cfg->cfg_ucl_obj, argv[i]); doc_obj = ucl_object_lookup_path(cfg->doc_strings, argv[i]); if (!obj) { diff --git a/src/rspamadm/confighelp.c b/src/rspamadm/confighelp.c index b81f23621..2ad07c0a6 100644 --- a/src/rspamadm/confighelp.c +++ b/src/rspamadm/confighelp.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -233,7 +233,7 @@ rspamadm_confighelp(gint argc, gchar **argv, const struct rspamadm_command *cmd) rspamd_rcl_config_init(cfg, NULL); lua_pushboolean(cfg->lua_state, true); lua_setglobal(cfg->lua_state, "confighelp"); - rspamd_rcl_add_lua_plugins_path(cfg, plugins_path, FALSE, NULL, NULL); + rspamd_rcl_add_lua_plugins_path(cfg->rcl_top_section, cfg, plugins_path, FALSE, NULL); /* Init modules to get documentation strings */ i = 0; @@ -254,7 +254,7 @@ rspamadm_confighelp(gint argc, gchar **argv, const struct rspamadm_command *cmd) } /* Init lua modules */ - rspamd_lua_set_path(cfg->lua_state, cfg->rcl_obj, ucl_vars); + rspamd_lua_set_path(cfg->lua_state, cfg->cfg_ucl_obj, ucl_vars); rspamd_init_lua_filters(cfg, true, false); if (argc > 1) { diff --git a/src/rspamd.h b/src/rspamd.h index b3aef558b..523ea79c3 100644 --- a/src/rspamd.h +++ b/src/rspamd.h @@ -1,11 +1,11 @@ -/*- - * Copyright 2016-2017 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -68,6 +68,7 @@ enum rspamd_worker_flags { RSPAMD_WORKER_CONTROLLER = (1 << 6), RSPAMD_WORKER_NO_TERMINATE_DELAY = (1 << 7), RSPAMD_WORKER_OLD_CONFIG = (1 << 8), + RSPAMD_WORKER_NO_STRICT_CONFIG = (1 << 9), }; struct rspamd_worker_accept_event { @@ -352,8 +353,8 @@ struct rspamd_external_libs_ctx { void **local_addrs; struct rspamd_cryptobox_library_ctx *crypto_ctx; struct ottery_config *ottery_cfg; - SSL_CTX *ssl_ctx; - SSL_CTX *ssl_ctx_noverify; + void *ssl_ctx; + void *ssl_ctx_noverify; struct zstd_dictionary *in_dict; struct zstd_dictionary *out_dict; void *out_zstream; |