You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cfg_utils.c 60KB

10 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
16 years ago
10 years ago
8 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "config.h"
  17. #include "cfg_file.h"
  18. #include "rspamd.h"
  19. #include "cfg_file_private.h"
  20. #include "scan_result.h"
  21. #include "lua/lua_common.h"
  22. #include "lua/lua_thread_pool.h"
  23. #include "map.h"
  24. #include "map_helpers.h"
  25. #include "map_private.h"
  26. #include "dynamic_cfg.h"
  27. #include "utlist.h"
  28. #include "stat_api.h"
  29. #include "unix-std.h"
  30. #include "libutil/multipattern.h"
  31. #include "monitored.h"
  32. #include "ref.h"
  33. #include <math.h>
  34. #define DEFAULT_SCORE 10.0
  35. #define DEFAULT_RLIMIT_NOFILE 2048
  36. #define DEFAULT_RLIMIT_MAXCORE 0
  37. #define DEFAULT_MAP_TIMEOUT 60.0 * 5
  38. #define DEFAULT_MAP_FILE_WATCH_MULTIPLIER 1
  39. #define DEFAULT_MIN_WORD 0
  40. #define DEFAULT_MAX_WORD 40
  41. #define DEFAULT_WORDS_DECAY 600
  42. #define DEFAULT_MAX_MESSAGE (50 * 1024 * 1024)
  43. #define DEFAULT_MAX_PIC (1 * 1024 * 1024)
  44. #define DEFAULT_MAX_SHOTS 100
  45. #define DEFAULT_MAX_SESSIONS 100
  46. #define DEFAULT_MAX_WORKERS 4
  47. /* Timeout for task processing */
  48. #define DEFAULT_TASK_TIMEOUT 8.0
  49. #define DEFAULT_LUA_GC_STEP 200
  50. #define DEFAULT_LUA_GC_PAUSE 200
  51. #define DEFAULT_GC_MAXITERS 0
  52. struct rspamd_ucl_map_cbdata {
  53. struct rspamd_config *cfg;
  54. GString *buf;
  55. };
  56. static gchar * rspamd_ucl_read_cb (gchar * chunk,
  57. gint len,
  58. struct map_cb_data *data,
  59. gboolean final);
  60. static void rspamd_ucl_fin_cb (struct map_cb_data *data, void **target);
  61. static void rspamd_ucl_dtor_cb (struct map_cb_data *data);
  62. guint rspamd_config_log_id = (guint)-1;
  63. RSPAMD_CONSTRUCTOR(rspamd_config_log_init)
  64. {
  65. rspamd_config_log_id = rspamd_logger_add_debug_module("config");
  66. }
  67. gboolean
  68. rspamd_parse_bind_line (struct rspamd_config *cfg,
  69. struct rspamd_worker_conf *cf,
  70. const gchar *str)
  71. {
  72. struct rspamd_worker_bind_conf *cnf;
  73. gchar *err;
  74. gboolean ret = TRUE;
  75. if (str == NULL) {
  76. return FALSE;
  77. }
  78. cnf = g_malloc0 (sizeof (struct rspamd_worker_bind_conf));
  79. cnf->cnt = 1024;
  80. cnf->bind_line = g_strdup (str);
  81. if (g_ascii_strncasecmp (str, "systemd:", sizeof ("systemd:") - 1) == 0) {
  82. /* The actual socket will be passed by systemd environment */
  83. cnf->is_systemd = TRUE;
  84. cnf->cnt = strtoul (str + sizeof ("systemd:") - 1, &err, 10);
  85. cnf->addrs = g_ptr_array_new ();
  86. if (err == NULL || *err == '\0') {
  87. cnf->name = g_strdup (str);
  88. LL_PREPEND (cf->bind_conf, cnf);
  89. }
  90. else {
  91. msg_err_config ("cannot parse bind line: %s", str);
  92. ret = FALSE;
  93. }
  94. }
  95. else {
  96. if (rspamd_parse_host_port_priority (str, &cnf->addrs,
  97. NULL, &cnf->name, DEFAULT_BIND_PORT, NULL) == RSPAMD_PARSE_ADDR_FAIL) {
  98. msg_err_config ("cannot parse bind line: %s", str);
  99. ret = FALSE;
  100. }
  101. else {
  102. cnf->cnt = cnf->addrs->len;
  103. LL_PREPEND (cf->bind_conf, cnf);
  104. }
  105. }
  106. if (!ret) {
  107. if (cnf->addrs) {
  108. g_ptr_array_free (cnf->addrs, TRUE);
  109. }
  110. g_free (cnf->name);
  111. g_free (cnf);
  112. }
  113. return ret;
  114. }
  115. struct rspamd_config *
  116. rspamd_config_new (enum rspamd_config_init_flags flags)
  117. {
  118. struct rspamd_config *cfg;
  119. rspamd_mempool_t *pool;
  120. pool = rspamd_mempool_new (8 * 1024 * 1024, "cfg");
  121. cfg = rspamd_mempool_alloc0 (pool, sizeof (*cfg));
  122. /* Allocate larger pool for cfg */
  123. cfg->cfg_pool = pool;
  124. cfg->dns_timeout = 1.0;
  125. cfg->dns_retransmits = 5;
  126. /* 16 sockets per DNS server */
  127. cfg->dns_io_per_server = 16;
  128. /* Add all internal actions to keep compatibility */
  129. for (int i = METRIC_ACTION_REJECT; i < METRIC_ACTION_MAX; i ++) {
  130. struct rspamd_action *action;
  131. action = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*action));
  132. action->threshold = NAN;
  133. action->name = rspamd_mempool_strdup (cfg->cfg_pool,
  134. rspamd_action_to_str (i));
  135. action->action_type = i;
  136. if (i == METRIC_ACTION_SOFT_REJECT) {
  137. action->flags |= RSPAMD_ACTION_NO_THRESHOLD|RSPAMD_ACTION_HAM;
  138. }
  139. else if (i == METRIC_ACTION_GREYLIST) {
  140. action->flags |= RSPAMD_ACTION_THRESHOLD_ONLY|RSPAMD_ACTION_HAM;
  141. }
  142. else if (i == METRIC_ACTION_NOACTION) {
  143. action->flags |= RSPAMD_ACTION_HAM;
  144. }
  145. HASH_ADD_KEYPTR (hh, cfg->actions,
  146. action->name, strlen (action->name), action);
  147. }
  148. /* Disable timeout */
  149. cfg->task_timeout = DEFAULT_TASK_TIMEOUT;
  150. rspamd_config_init_metric (cfg);
  151. cfg->composite_symbols =
  152. g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  153. cfg->classifiers_symbols = g_hash_table_new (rspamd_str_hash,
  154. rspamd_str_equal);
  155. cfg->cfg_params = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  156. cfg->debug_modules = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  157. cfg->explicit_modules = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  158. cfg->wrk_parsers = g_hash_table_new (g_int_hash, g_int_equal);
  159. cfg->trusted_keys = g_hash_table_new (rspamd_str_hash,
  160. rspamd_str_equal);
  161. cfg->map_timeout = DEFAULT_MAP_TIMEOUT;
  162. cfg->map_file_watch_multiplier = DEFAULT_MAP_FILE_WATCH_MULTIPLIER;
  163. cfg->log_level = G_LOG_LEVEL_WARNING;
  164. cfg->log_flags = RSPAMD_LOG_FLAG_DEFAULT;
  165. cfg->check_text_attachements = TRUE;
  166. cfg->dns_max_requests = 64;
  167. cfg->history_rows = 200;
  168. cfg->log_error_elts = 10;
  169. cfg->log_error_elt_maxlen = 1000;
  170. cfg->cache_reload_time = 30.0;
  171. cfg->max_lua_urls = 1024;
  172. cfg->max_blas_threads = 1;
  173. /* Default log line */
  174. cfg->log_format_str = "id: <$mid>,$if_qid{ qid: <$>,}$if_ip{ ip: $,}"
  175. "$if_user{ user: $,}$if_smtp_from{ from: <$>,} (default: $is_spam "
  176. "($action): [$scores] [$symbols_scores_params]), len: $len, time: $time_real, "
  177. "dns req: $dns_req, digest: <$digest>"
  178. "$if_smtp_rcpts{ rcpts: <$>, }$if_mime_rcpt{ mime_rcpt: <$>, }";
  179. /* Allow non-mime input by default */
  180. cfg->allow_raw_input = TRUE;
  181. /* Default maximum words processed */
  182. cfg->words_decay = DEFAULT_WORDS_DECAY;
  183. cfg->min_word_len = DEFAULT_MIN_WORD;
  184. cfg->max_word_len = DEFAULT_MAX_WORD;
  185. /* GC limits */
  186. cfg->lua_gc_pause = DEFAULT_LUA_GC_PAUSE;
  187. cfg->lua_gc_step = DEFAULT_LUA_GC_STEP;
  188. cfg->full_gc_iters = DEFAULT_GC_MAXITERS;
  189. if (!(flags & RSPAMD_CONFIG_INIT_SKIP_LUA)) {
  190. cfg->lua_state = rspamd_lua_init (flags & RSPAMD_CONFIG_INIT_WIPE_LUA_MEM);
  191. cfg->own_lua_state = TRUE;
  192. cfg->lua_thread_pool = lua_thread_pool_new (cfg->lua_state);
  193. }
  194. cfg->cache = rspamd_symcache_new (cfg);
  195. cfg->ups_ctx = rspamd_upstreams_library_init ();
  196. cfg->re_cache = rspamd_re_cache_new ();
  197. cfg->doc_strings = ucl_object_typed_new (UCL_OBJECT);
  198. /*
  199. * Unless exim is fixed
  200. */
  201. cfg->enable_shutdown_workaround = TRUE;
  202. cfg->ssl_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4";
  203. cfg->max_message = DEFAULT_MAX_MESSAGE;
  204. cfg->max_pic_size = DEFAULT_MAX_PIC;
  205. cfg->images_cache_size = 256;
  206. cfg->monitored_ctx = rspamd_monitored_ctx_init ();
  207. cfg->neighbours = ucl_object_typed_new (UCL_OBJECT);
  208. #ifdef WITH_HIREDIS
  209. cfg->redis_pool = rspamd_redis_pool_init ();
  210. #endif
  211. cfg->default_max_shots = DEFAULT_MAX_SHOTS;
  212. cfg->max_sessions_cache = DEFAULT_MAX_SESSIONS;
  213. cfg->maps_cache_dir = rspamd_mempool_strdup (cfg->cfg_pool, RSPAMD_DBDIR);
  214. cfg->c_modules = g_ptr_array_new ();
  215. cfg->heartbeat_interval = 10.0;
  216. REF_INIT_RETAIN (cfg, rspamd_config_free);
  217. return cfg;
  218. }
  219. void
  220. rspamd_config_free (struct rspamd_config *cfg)
  221. {
  222. struct rspamd_config_cfg_lua_script *sc, *sctmp;
  223. struct rspamd_config_settings_elt *set, *stmp;
  224. struct rspamd_worker_log_pipe *lp, *ltmp;
  225. rspamd_lua_run_config_unload (cfg->lua_state, cfg);
  226. /* Scripts part */
  227. DL_FOREACH_SAFE (cfg->on_term_scripts, sc, sctmp) {
  228. luaL_unref (cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref);
  229. }
  230. DL_FOREACH_SAFE (cfg->on_load_scripts, sc, sctmp) {
  231. luaL_unref (cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref);
  232. }
  233. DL_FOREACH_SAFE (cfg->post_init_scripts, sc, sctmp) {
  234. luaL_unref (cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref);
  235. }
  236. DL_FOREACH_SAFE (cfg->config_unload_scripts, sc, sctmp) {
  237. luaL_unref (cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref);
  238. }
  239. DL_FOREACH_SAFE (cfg->setting_ids, set, stmp) {
  240. REF_RELEASE (set);
  241. }
  242. rspamd_map_remove_all (cfg);
  243. rspamd_mempool_destructors_enforce (cfg->cfg_pool);
  244. g_list_free (cfg->classifiers);
  245. g_list_free (cfg->workers);
  246. rspamd_symcache_destroy (cfg->cache);
  247. ucl_object_unref (cfg->rcl_obj);
  248. ucl_object_unref (cfg->config_comments);
  249. ucl_object_unref (cfg->doc_strings);
  250. ucl_object_unref (cfg->neighbours);
  251. g_hash_table_remove_all (cfg->composite_symbols);
  252. g_hash_table_unref (cfg->composite_symbols);
  253. g_hash_table_remove_all (cfg->cfg_params);
  254. g_hash_table_unref (cfg->cfg_params);
  255. g_hash_table_unref (cfg->classifiers_symbols);
  256. g_hash_table_unref (cfg->debug_modules);
  257. g_hash_table_unref (cfg->explicit_modules);
  258. g_hash_table_unref (cfg->wrk_parsers);
  259. g_hash_table_unref (cfg->trusted_keys);
  260. rspamd_re_cache_unref (cfg->re_cache);
  261. rspamd_upstreams_library_unref (cfg->ups_ctx);
  262. g_ptr_array_free (cfg->c_modules, TRUE);
  263. if (cfg->lua_state && cfg->own_lua_state) {
  264. lua_thread_pool_free (cfg->lua_thread_pool);
  265. lua_close (cfg->lua_state);
  266. }
  267. #ifdef WITH_HIREDIS
  268. if (cfg->redis_pool) {
  269. rspamd_redis_pool_destroy (cfg->redis_pool);
  270. }
  271. #endif
  272. if (cfg->monitored_ctx) {
  273. rspamd_monitored_ctx_destroy (cfg->monitored_ctx);
  274. }
  275. HASH_CLEAR (hh, cfg->actions);
  276. rspamd_mempool_destructors_enforce (cfg->cfg_pool);
  277. if (cfg->checksum) {
  278. g_free (cfg->checksum);
  279. }
  280. REF_RELEASE (cfg->libs_ctx);
  281. DL_FOREACH_SAFE (cfg->log_pipes, lp, ltmp) {
  282. close (lp->fd);
  283. g_free (lp);
  284. }
  285. rspamd_mempool_delete (cfg->cfg_pool);
  286. }
  287. const ucl_object_t *
  288. rspamd_config_get_module_opt (struct rspamd_config *cfg,
  289. const gchar *module_name,
  290. const gchar *opt_name)
  291. {
  292. const ucl_object_t *res = NULL, *sec;
  293. sec = ucl_obj_get_key (cfg->rcl_obj, module_name);
  294. if (sec != NULL) {
  295. res = ucl_obj_get_key (sec, opt_name);
  296. }
  297. return res;
  298. }
  299. gchar
  300. rspamd_config_parse_flag (const gchar *str, guint len)
  301. {
  302. gchar c;
  303. if (!str || !*str) {
  304. return -1;
  305. }
  306. if (len == 0) {
  307. len = strlen (str);
  308. }
  309. switch (len) {
  310. case 1:
  311. c = g_ascii_tolower (*str);
  312. if (c == 'y' || c == '1') {
  313. return 1;
  314. }
  315. else if (c == 'n' || c == '0') {
  316. return 0;
  317. }
  318. break;
  319. case 2:
  320. if (g_ascii_strncasecmp (str, "no", len) == 0) {
  321. return 0;
  322. }
  323. else if (g_ascii_strncasecmp (str, "on", len) == 0) {
  324. return 1;
  325. }
  326. break;
  327. case 3:
  328. if (g_ascii_strncasecmp (str, "yes", len) == 0) {
  329. return 1;
  330. }
  331. else if (g_ascii_strncasecmp (str, "off", len) == 0) {
  332. return 0;
  333. }
  334. break;
  335. case 4:
  336. if (g_ascii_strncasecmp (str, "true", len) == 0) {
  337. return 1;
  338. }
  339. break;
  340. case 5:
  341. if (g_ascii_strncasecmp (str, "false", len) == 0) {
  342. return 0;
  343. }
  344. break;
  345. }
  346. return -1;
  347. }
  348. static gboolean
  349. rspamd_config_process_var (struct rspamd_config *cfg, const rspamd_ftok_t *var,
  350. const rspamd_ftok_t *content)
  351. {
  352. guint flags = RSPAMD_LOG_FLAG_DEFAULT;
  353. struct rspamd_log_format *lf;
  354. enum rspamd_log_format_type type;
  355. rspamd_ftok_t tok;
  356. gint id;
  357. g_assert (var != NULL);
  358. if (var->len > 3 && rspamd_lc_cmp (var->begin, "if_", 3) == 0) {
  359. flags |= RSPAMD_LOG_FMT_FLAG_CONDITION;
  360. tok.begin = var->begin + 3;
  361. tok.len = var->len - 3;
  362. }
  363. else {
  364. tok.begin = var->begin;
  365. tok.len = var->len;
  366. }
  367. /* Now compare variable and check what we have */
  368. if (rspamd_ftok_cstr_equal (&tok, "mid", TRUE)) {
  369. type = RSPAMD_LOG_MID;
  370. }
  371. else if (rspamd_ftok_cstr_equal (&tok, "qid", TRUE)) {
  372. type = RSPAMD_LOG_QID;
  373. }
  374. else if (rspamd_ftok_cstr_equal (&tok, "user", TRUE)) {
  375. type = RSPAMD_LOG_USER;
  376. }
  377. else if (rspamd_ftok_cstr_equal (&tok, "is_spam", TRUE)) {
  378. type = RSPAMD_LOG_ISSPAM;
  379. }
  380. else if (rspamd_ftok_cstr_equal (&tok, "action", TRUE)) {
  381. type = RSPAMD_LOG_ACTION;
  382. }
  383. else if (rspamd_ftok_cstr_equal (&tok, "scores", TRUE)) {
  384. type = RSPAMD_LOG_SCORES;
  385. }
  386. else if (rspamd_ftok_cstr_equal (&tok, "symbols", TRUE)) {
  387. type = RSPAMD_LOG_SYMBOLS;
  388. }
  389. else if (rspamd_ftok_cstr_equal (&tok, "symbols_scores", TRUE)) {
  390. type = RSPAMD_LOG_SYMBOLS;
  391. flags |= RSPAMD_LOG_FMT_FLAG_SYMBOLS_SCORES;
  392. }
  393. else if (rspamd_ftok_cstr_equal (&tok, "symbols_params", TRUE)) {
  394. type = RSPAMD_LOG_SYMBOLS;
  395. flags |= RSPAMD_LOG_FMT_FLAG_SYMBOLS_PARAMS;
  396. }
  397. else if (rspamd_ftok_cstr_equal (&tok, "symbols_scores_params", TRUE)) {
  398. type = RSPAMD_LOG_SYMBOLS;
  399. flags |= RSPAMD_LOG_FMT_FLAG_SYMBOLS_PARAMS|RSPAMD_LOG_FMT_FLAG_SYMBOLS_SCORES;
  400. }
  401. else if (rspamd_ftok_cstr_equal (&tok, "groups", TRUE)) {
  402. type = RSPAMD_LOG_GROUPS;
  403. }
  404. else if (rspamd_ftok_cstr_equal (&tok, "public_groups", TRUE)) {
  405. type = RSPAMD_LOG_PUBLIC_GROUPS;
  406. }
  407. else if (rspamd_ftok_cstr_equal (&tok, "ip", TRUE)) {
  408. type = RSPAMD_LOG_IP;
  409. }
  410. else if (rspamd_ftok_cstr_equal (&tok, "len", TRUE)) {
  411. type = RSPAMD_LOG_LEN;
  412. }
  413. else if (rspamd_ftok_cstr_equal (&tok, "dns_req", TRUE)) {
  414. type = RSPAMD_LOG_DNS_REQ;
  415. }
  416. else if (rspamd_ftok_cstr_equal (&tok, "smtp_from", TRUE)) {
  417. type = RSPAMD_LOG_SMTP_FROM;
  418. }
  419. else if (rspamd_ftok_cstr_equal (&tok, "mime_from", TRUE)) {
  420. type = RSPAMD_LOG_MIME_FROM;
  421. }
  422. else if (rspamd_ftok_cstr_equal (&tok, "smtp_rcpt", TRUE)) {
  423. type = RSPAMD_LOG_SMTP_RCPT;
  424. }
  425. else if (rspamd_ftok_cstr_equal (&tok, "mime_rcpt", TRUE)) {
  426. type = RSPAMD_LOG_MIME_RCPT;
  427. }
  428. else if (rspamd_ftok_cstr_equal (&tok, "smtp_rcpts", TRUE)) {
  429. type = RSPAMD_LOG_SMTP_RCPTS;
  430. }
  431. else if (rspamd_ftok_cstr_equal (&tok, "mime_rcpts", TRUE)) {
  432. type = RSPAMD_LOG_MIME_RCPTS;
  433. }
  434. else if (rspamd_ftok_cstr_equal (&tok, "time_real", TRUE)) {
  435. type = RSPAMD_LOG_TIME_REAL;
  436. }
  437. else if (rspamd_ftok_cstr_equal (&tok, "time_virtual", TRUE)) {
  438. type = RSPAMD_LOG_TIME_VIRTUAL;
  439. }
  440. else if (rspamd_ftok_cstr_equal (&tok, "lua", TRUE)) {
  441. type = RSPAMD_LOG_LUA;
  442. }
  443. else if (rspamd_ftok_cstr_equal (&tok, "digest", TRUE) ||
  444. rspamd_ftok_cstr_equal (&tok, "checksum", TRUE)) {
  445. type = RSPAMD_LOG_DIGEST;
  446. }
  447. else if (rspamd_ftok_cstr_equal (&tok, "filename", TRUE)) {
  448. type = RSPAMD_LOG_FILENAME;
  449. }
  450. else if (rspamd_ftok_cstr_equal (&tok, "forced_action", TRUE)) {
  451. type = RSPAMD_LOG_FORCED_ACTION;
  452. }
  453. else if (rspamd_ftok_cstr_equal (&tok, "settings_id", TRUE)) {
  454. type = RSPAMD_LOG_SETTINGS_ID;
  455. }
  456. else {
  457. msg_err_config ("unknown log variable: %T", &tok);
  458. return FALSE;
  459. }
  460. lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
  461. lf->type = type;
  462. lf->flags = flags;
  463. if (type != RSPAMD_LOG_LUA) {
  464. if (content && content->len > 0) {
  465. lf->data = rspamd_mempool_alloc0 (cfg->cfg_pool,
  466. sizeof (rspamd_ftok_t));
  467. memcpy (lf->data, content, sizeof (*content));
  468. lf->len = sizeof (*content);
  469. }
  470. }
  471. else {
  472. /* Load lua code and ensure that we have function ref returned */
  473. if (!content || content->len == 0) {
  474. msg_err_config ("lua variable needs content: %T", &tok);
  475. return FALSE;
  476. }
  477. if (luaL_loadbuffer (cfg->lua_state, content->begin, content->len,
  478. "lua log variable") != 0) {
  479. msg_err_config ("error loading lua code: '%T': %s", content,
  480. lua_tostring (cfg->lua_state, -1));
  481. return FALSE;
  482. }
  483. if (lua_pcall (cfg->lua_state, 0, 1, 0) != 0) {
  484. msg_err_config ("error executing lua code: '%T': %s", content,
  485. lua_tostring (cfg->lua_state, -1));
  486. lua_pop (cfg->lua_state, 1);
  487. return FALSE;
  488. }
  489. if (lua_type (cfg->lua_state, -1) != LUA_TFUNCTION) {
  490. msg_err_config ("lua variable should return function: %T", content);
  491. lua_pop (cfg->lua_state, 1);
  492. return FALSE;
  493. }
  494. id = luaL_ref (cfg->lua_state, LUA_REGISTRYINDEX);
  495. lf->data = GINT_TO_POINTER (id);
  496. lf->len = 0;
  497. }
  498. DL_APPEND (cfg->log_format, lf);
  499. return TRUE;
  500. }
  501. static gboolean
  502. rspamd_config_parse_log_format (struct rspamd_config *cfg)
  503. {
  504. const gchar *p, *c, *end, *s;
  505. gchar *d;
  506. struct rspamd_log_format *lf = NULL;
  507. rspamd_ftok_t var, var_content;
  508. enum {
  509. parse_str,
  510. parse_dollar,
  511. parse_var_name,
  512. parse_var_content,
  513. } state = parse_str;
  514. gint braces = 0;
  515. g_assert (cfg != NULL);
  516. c = cfg->log_format_str;
  517. if (c == NULL) {
  518. return FALSE;
  519. }
  520. p = c;
  521. end = p + strlen (p);
  522. while (p < end) {
  523. switch (state) {
  524. case parse_str:
  525. if (*p == '$') {
  526. state = parse_dollar;
  527. }
  528. else {
  529. p ++;
  530. }
  531. break;
  532. case parse_dollar:
  533. if (p > c) {
  534. /* We have string element that we need to store */
  535. lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
  536. lf->type = RSPAMD_LOG_STRING;
  537. lf->data = rspamd_mempool_alloc (cfg->cfg_pool, p - c + 1);
  538. /* Filter \r\n from the destination */
  539. s = c;
  540. d = lf->data;
  541. while (s < p) {
  542. if (*s != '\r' && *s != '\n') {
  543. *d++ = *s++;
  544. }
  545. else {
  546. *d ++ = ' ';
  547. s++;
  548. }
  549. }
  550. *d = '\0';
  551. lf->len = d - (char *) lf->data;
  552. DL_APPEND (cfg->log_format, lf);
  553. lf = NULL;
  554. }
  555. p++;
  556. c = p;
  557. state = parse_var_name;
  558. break;
  559. case parse_var_name:
  560. if (*p == '{') {
  561. var.begin = c;
  562. var.len = p - c;
  563. p ++;
  564. c = p;
  565. state = parse_var_content;
  566. braces = 1;
  567. }
  568. else if (*p != '_' && *p != '-' && !g_ascii_isalnum (*p)) {
  569. /* Variable with no content */
  570. var.begin = c;
  571. var.len = p - c;
  572. c = p;
  573. if (!rspamd_config_process_var (cfg, &var, NULL)) {
  574. return FALSE;
  575. }
  576. state = parse_str;
  577. }
  578. else {
  579. p++;
  580. }
  581. break;
  582. case parse_var_content:
  583. if (*p == '}' && --braces == 0) {
  584. var_content.begin = c;
  585. var_content.len = p - c;
  586. p ++;
  587. c = p;
  588. if (!rspamd_config_process_var (cfg, &var, &var_content)) {
  589. return FALSE;
  590. }
  591. state = parse_str;
  592. }
  593. else if (*p == '{') {
  594. braces ++;
  595. p ++;
  596. }
  597. else {
  598. p++;
  599. }
  600. break;
  601. }
  602. }
  603. /* Last state */
  604. switch (state) {
  605. case parse_str:
  606. if (p > c) {
  607. /* We have string element that we need to store */
  608. lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
  609. lf->type = RSPAMD_LOG_STRING;
  610. lf->data = rspamd_mempool_alloc (cfg->cfg_pool, p - c + 1);
  611. /* Filter \r\n from the destination */
  612. s = c;
  613. d = lf->data;
  614. while (s < p) {
  615. if (*s != '\r' && *s != '\n') {
  616. *d++ = *s++;
  617. }
  618. else {
  619. *d++ = ' ';
  620. s++;
  621. }
  622. }
  623. *d = '\0';
  624. lf->len = d - (char *)lf->data;
  625. DL_APPEND (cfg->log_format, lf);
  626. lf = NULL;
  627. }
  628. break;
  629. case parse_var_name:
  630. var.begin = c;
  631. var.len = p - c;
  632. if (!rspamd_config_process_var (cfg, &var, NULL)) {
  633. return FALSE;
  634. }
  635. break;
  636. case parse_dollar:
  637. case parse_var_content:
  638. msg_err_config ("cannot parse log format %s: incomplete string",
  639. cfg->log_format_str);
  640. return FALSE;
  641. break;
  642. }
  643. return TRUE;
  644. }
  645. static void
  646. rspamd_urls_config_dtor (gpointer _unused)
  647. {
  648. rspamd_url_deinit ();
  649. }
  650. /*
  651. * Perform post load actions
  652. */
  653. gboolean
  654. rspamd_config_post_load (struct rspamd_config *cfg,
  655. enum rspamd_post_load_options opts)
  656. {
  657. #ifdef HAVE_CLOCK_GETTIME
  658. struct timespec ts;
  659. #endif
  660. gboolean ret = TRUE;
  661. #ifdef HAVE_CLOCK_GETTIME
  662. #ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
  663. clock_getres (CLOCK_PROCESS_CPUTIME_ID, &ts);
  664. # elif defined(HAVE_CLOCK_VIRTUAL)
  665. clock_getres (CLOCK_VIRTUAL, &ts);
  666. # else
  667. clock_getres (CLOCK_REALTIME, &ts);
  668. # endif
  669. rspamd_logger_configure_modules (cfg->debug_modules);
  670. cfg->clock_res = log10 (1000000. / ts.tv_nsec);
  671. if (cfg->clock_res < 0) {
  672. cfg->clock_res = 0;
  673. }
  674. if (cfg->clock_res > 3) {
  675. cfg->clock_res = 3;
  676. }
  677. #else
  678. /* For gettimeofday */
  679. cfg->clock_res = 1;
  680. #endif
  681. if (cfg->one_shot_mode) {
  682. msg_info_config ("enabling one shot mode (was %d max shots)",
  683. cfg->default_max_shots);
  684. cfg->default_max_shots = 1;
  685. }
  686. rspamd_regexp_library_init (cfg);
  687. rspamd_multipattern_library_init (cfg->hs_cache_dir);
  688. #ifdef WITH_HYPERSCAN
  689. if (!cfg->disable_hyperscan) {
  690. if (!(cfg->libs_ctx->crypto_ctx->cpu_config & CPUID_SSSE3)) {
  691. msg_warn_config ("CPU doesn't have SSSE3 instructions set "
  692. "required for hyperscan, disable it");
  693. cfg->disable_hyperscan = TRUE;
  694. }
  695. }
  696. #endif
  697. if (opts & RSPAMD_CONFIG_INIT_URL) {
  698. if (cfg->tld_file == NULL) {
  699. /* Try to guess tld file */
  700. GString *fpath = g_string_new (NULL);
  701. rspamd_printf_gstring (fpath, "%s%c%s", RSPAMD_SHAREDIR,
  702. G_DIR_SEPARATOR, "effective_tld_names.dat");
  703. if (access (fpath->str, R_OK) != -1) {
  704. msg_debug_config ("url_tld option is not specified but %s is available,"
  705. " therefore this file is assumed as TLD file for URL"
  706. " extraction", fpath->str);
  707. cfg->tld_file = rspamd_mempool_strdup (cfg->cfg_pool, fpath->str);
  708. }
  709. else {
  710. if (opts & RSPAMD_CONFIG_INIT_VALIDATE) {
  711. msg_err_config ("no url_tld option has been specified");
  712. ret = FALSE;
  713. }
  714. }
  715. g_string_free (fpath, TRUE);
  716. }
  717. else {
  718. if (access (cfg->tld_file, R_OK) == -1) {
  719. if (opts & RSPAMD_CONFIG_INIT_VALIDATE) {
  720. ret = FALSE;
  721. msg_err_config ("cannot access tld file %s: %s", cfg->tld_file,
  722. strerror (errno));
  723. }
  724. else {
  725. msg_debug_config ("cannot access tld file %s: %s", cfg->tld_file,
  726. strerror (errno));
  727. cfg->tld_file = NULL;
  728. }
  729. }
  730. }
  731. if (opts & RSPAMD_CONFIG_INIT_NO_TLD) {
  732. rspamd_url_init (NULL);
  733. }
  734. else {
  735. rspamd_url_init (cfg->tld_file);
  736. }
  737. rspamd_mempool_add_destructor (cfg->cfg_pool, rspamd_urls_config_dtor,
  738. NULL);
  739. }
  740. init_dynamic_config (cfg);
  741. /* Insert classifiers symbols */
  742. rspamd_config_insert_classify_symbols (cfg);
  743. /* Parse format string that we have */
  744. if (!rspamd_config_parse_log_format (cfg)) {
  745. msg_err_config ("cannot parse log format, task logging will not be available");
  746. }
  747. if (opts & RSPAMD_CONFIG_INIT_SYMCACHE) {
  748. /* Init config cache */
  749. rspamd_symcache_init (cfg->cache);
  750. /* Init re cache */
  751. rspamd_re_cache_init (cfg->re_cache, cfg);
  752. }
  753. if (opts & RSPAMD_CONFIG_INIT_LIBS) {
  754. /* Config other libraries */
  755. rspamd_config_libs (cfg->libs_ctx, cfg);
  756. }
  757. /* Validate cache */
  758. if (opts & RSPAMD_CONFIG_INIT_VALIDATE) {
  759. /* Check for actions sanity */
  760. gboolean seen_controller = FALSE;
  761. GList *cur;
  762. struct rspamd_worker_conf *wcf;
  763. cur = cfg->workers;
  764. while (cur) {
  765. wcf = cur->data;
  766. if (wcf->type == g_quark_from_static_string ("controller")) {
  767. seen_controller = TRUE;
  768. break;
  769. }
  770. cur = g_list_next (cur);
  771. }
  772. if (!seen_controller) {
  773. msg_warn_config ("controller worker is unconfigured: learning,"
  774. " periodic scripts, maps watching and many other"
  775. " Rspamd features will be broken");
  776. ret = FALSE;
  777. }
  778. ret = rspamd_symcache_validate (cfg->cache, cfg, FALSE) && ret;
  779. }
  780. if (opts & RSPAMD_CONFIG_INIT_PRELOAD_MAPS) {
  781. rspamd_map_preload (cfg);
  782. }
  783. if (opts & RSPAMD_CONFIG_INIT_POST_LOAD_LUA) {
  784. rspamd_lua_run_config_post_init (cfg->lua_state, cfg);
  785. }
  786. return ret;
  787. }
  788. #if 0
  789. void
  790. parse_err (const gchar *fmt, ...)
  791. {
  792. va_list aq;
  793. gchar logbuf[BUFSIZ], readbuf[32];
  794. gint r;
  795. va_start (aq, fmt);
  796. rspamd_strlcpy (readbuf, yytext, sizeof (readbuf));
  797. r = snprintf (logbuf,
  798. sizeof (logbuf),
  799. "config file parse error! line: %d, text: %s, reason: ",
  800. yylineno,
  801. readbuf);
  802. r += vsnprintf (logbuf + r, sizeof (logbuf) - r, fmt, aq);
  803. va_end (aq);
  804. g_critical ("%s", logbuf);
  805. }
  806. void
  807. parse_warn (const gchar *fmt, ...)
  808. {
  809. va_list aq;
  810. gchar logbuf[BUFSIZ], readbuf[32];
  811. gint r;
  812. va_start (aq, fmt);
  813. rspamd_strlcpy (readbuf, yytext, sizeof (readbuf));
  814. r = snprintf (logbuf,
  815. sizeof (logbuf),
  816. "config file parse warning! line: %d, text: %s, reason: ",
  817. yylineno,
  818. readbuf);
  819. r += vsnprintf (logbuf + r, sizeof (logbuf) - r, fmt, aq);
  820. va_end (aq);
  821. g_warning ("%s", logbuf);
  822. }
  823. #endif
  824. void
  825. rspamd_config_unescape_quotes (gchar *line)
  826. {
  827. gchar *c = line, *t;
  828. while (*c) {
  829. if (*c == '\\' && *(c + 1) == '"') {
  830. t = c;
  831. while (*t) {
  832. *t = *(t + 1);
  833. t++;
  834. }
  835. }
  836. c++;
  837. }
  838. }
  839. GList *
  840. rspamd_config_parse_comma_list (rspamd_mempool_t * pool, const gchar *line)
  841. {
  842. GList *res = NULL;
  843. const gchar *c, *p;
  844. gchar *str;
  845. c = line;
  846. p = c;
  847. while (*p) {
  848. if (*p == ',' && *c != *p) {
  849. str = rspamd_mempool_alloc (pool, p - c + 1);
  850. rspamd_strlcpy (str, c, p - c + 1);
  851. res = g_list_prepend (res, str);
  852. /* Skip spaces */
  853. while (g_ascii_isspace (*(++p))) ;
  854. c = p;
  855. continue;
  856. }
  857. p++;
  858. }
  859. if (res != NULL) {
  860. rspamd_mempool_add_destructor (pool,
  861. (rspamd_mempool_destruct_t) g_list_free,
  862. res);
  863. }
  864. return res;
  865. }
  866. struct rspamd_classifier_config *
  867. rspamd_config_new_classifier (struct rspamd_config *cfg,
  868. struct rspamd_classifier_config *c)
  869. {
  870. if (c == NULL) {
  871. c =
  872. rspamd_mempool_alloc0 (cfg->cfg_pool,
  873. sizeof (struct rspamd_classifier_config));
  874. c->min_prob_strength = 0.05;
  875. c->min_token_hits = 2;
  876. }
  877. if (c->labels == NULL) {
  878. c->labels = g_hash_table_new_full (rspamd_str_hash,
  879. rspamd_str_equal,
  880. NULL,
  881. (GDestroyNotify)g_list_free);
  882. rspamd_mempool_add_destructor (cfg->cfg_pool,
  883. (rspamd_mempool_destruct_t) g_hash_table_destroy,
  884. c->labels);
  885. }
  886. return c;
  887. }
  888. struct rspamd_statfile_config *
  889. rspamd_config_new_statfile (struct rspamd_config *cfg,
  890. struct rspamd_statfile_config *c)
  891. {
  892. if (c == NULL) {
  893. c =
  894. rspamd_mempool_alloc0 (cfg->cfg_pool,
  895. sizeof (struct rspamd_statfile_config));
  896. }
  897. return c;
  898. }
  899. void
  900. rspamd_config_init_metric (struct rspamd_config *cfg)
  901. {
  902. cfg->grow_factor = 1.0;
  903. cfg->symbols = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  904. cfg->groups = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
  905. cfg->subject = SPAM_SUBJECT;
  906. rspamd_mempool_add_destructor (cfg->cfg_pool,
  907. (rspamd_mempool_destruct_t) g_hash_table_unref,
  908. cfg->symbols);
  909. rspamd_mempool_add_destructor (cfg->cfg_pool,
  910. (rspamd_mempool_destruct_t) g_hash_table_unref,
  911. cfg->groups);
  912. }
  913. struct rspamd_symbols_group *
  914. rspamd_config_new_group (struct rspamd_config *cfg, const gchar *name)
  915. {
  916. struct rspamd_symbols_group *gr;
  917. gr = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*gr));
  918. gr->symbols = g_hash_table_new (rspamd_strcase_hash,
  919. rspamd_strcase_equal);
  920. rspamd_mempool_add_destructor (cfg->cfg_pool,
  921. (rspamd_mempool_destruct_t)g_hash_table_unref, gr->symbols);
  922. gr->name = rspamd_mempool_strdup (cfg->cfg_pool, name);
  923. if (strcmp (gr->name, "ungrouped") == 0) {
  924. gr->flags |= RSPAMD_SYMBOL_GROUP_UNGROUPED;
  925. }
  926. g_hash_table_insert (cfg->groups, gr->name, gr);
  927. return gr;
  928. }
  929. static void
  930. rspamd_worker_conf_dtor (struct rspamd_worker_conf *wcf)
  931. {
  932. if (wcf) {
  933. struct rspamd_worker_bind_conf *cnf, *tmp;
  934. LL_FOREACH_SAFE (wcf->bind_conf, cnf, tmp) {
  935. g_free (cnf->name);
  936. g_free (cnf->bind_line);
  937. g_ptr_array_free (cnf->addrs, TRUE);
  938. g_free (cnf);
  939. }
  940. ucl_object_unref (wcf->options);
  941. g_queue_free (wcf->active_workers);
  942. g_hash_table_unref (wcf->params);
  943. g_free (wcf);
  944. }
  945. }
  946. static void
  947. rspamd_worker_conf_cfg_fin (gpointer d)
  948. {
  949. struct rspamd_worker_conf *wcf = d;
  950. REF_RELEASE (wcf);
  951. }
  952. struct rspamd_worker_conf *
  953. rspamd_config_new_worker (struct rspamd_config *cfg,
  954. struct rspamd_worker_conf *c)
  955. {
  956. if (c == NULL) {
  957. c = g_malloc0 (sizeof (struct rspamd_worker_conf));
  958. c->params = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  959. c->active_workers = g_queue_new ();
  960. #ifdef HAVE_SC_NPROCESSORS_ONLN
  961. c->count = MIN (DEFAULT_MAX_WORKERS,
  962. MAX (1, sysconf (_SC_NPROCESSORS_ONLN) - 2));
  963. #else
  964. c->count = DEFAULT_MAX_WORKERS;
  965. #endif
  966. c->rlimit_nofile = 0;
  967. c->rlimit_maxcore = 0;
  968. c->enabled = TRUE;
  969. REF_INIT_RETAIN (c, rspamd_worker_conf_dtor);
  970. rspamd_mempool_add_destructor (cfg->cfg_pool,
  971. rspamd_worker_conf_cfg_fin, c);
  972. }
  973. return c;
  974. }
  975. static bool
  976. rspamd_include_map_handler (const guchar *data, gsize len,
  977. const ucl_object_t *args, void * ud)
  978. {
  979. struct rspamd_config *cfg = (struct rspamd_config *)ud;
  980. struct rspamd_ucl_map_cbdata *cbdata, **pcbdata;
  981. gchar *map_line;
  982. map_line = rspamd_mempool_alloc (cfg->cfg_pool, len + 1);
  983. rspamd_strlcpy (map_line, data, len + 1);
  984. cbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata));
  985. pcbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata *));
  986. cbdata->buf = NULL;
  987. cbdata->cfg = cfg;
  988. *pcbdata = cbdata;
  989. return rspamd_map_add (cfg,
  990. map_line,
  991. "ucl include",
  992. rspamd_ucl_read_cb,
  993. rspamd_ucl_fin_cb,
  994. rspamd_ucl_dtor_cb,
  995. (void **)pcbdata) != NULL;
  996. }
  997. /*
  998. * Variables:
  999. * $CONFDIR - configuration directory
  1000. * $LOCAL_CONFDIR - local configuration directory
  1001. * $RUNDIR - local states directory
  1002. * $DBDIR - databases dir
  1003. * $LOGDIR - logs dir
  1004. * $PLUGINSDIR - pluggins dir
  1005. * $PREFIX - installation prefix
  1006. * $VERSION - rspamd version
  1007. */
  1008. #define RSPAMD_CONFDIR_MACRO "CONFDIR"
  1009. #define RSPAMD_LOCAL_CONFDIR_MACRO "LOCAL_CONFDIR"
  1010. #define RSPAMD_RUNDIR_MACRO "RUNDIR"
  1011. #define RSPAMD_DBDIR_MACRO "DBDIR"
  1012. #define RSPAMD_LOGDIR_MACRO "LOGDIR"
  1013. #define RSPAMD_PLUGINSDIR_MACRO "PLUGINSDIR"
  1014. #define RSPAMD_SHAREDIR_MACRO "SHAREDIR"
  1015. #define RSPAMD_RULESDIR_MACRO "RULESDIR"
  1016. #define RSPAMD_WWWDIR_MACRO "WWWDIR"
  1017. #define RSPAMD_PREFIX_MACRO "PREFIX"
  1018. #define RSPAMD_VERSION_MACRO "VERSION"
  1019. #define RSPAMD_VERSION_MAJOR_MACRO "VERSION_MAJOR"
  1020. #define RSPAMD_VERSION_MINOR_MACRO "VERSION_MINOR"
  1021. #define RSPAMD_BRANCH_VERSION_MACRO "BRANCH_VERSION"
  1022. #define RSPAMD_HOSTNAME_MACRO "HOSTNAME"
  1023. void
  1024. rspamd_ucl_add_conf_variables (struct ucl_parser *parser, GHashTable *vars)
  1025. {
  1026. GHashTableIter it;
  1027. gpointer k, v;
  1028. gchar *hostbuf;
  1029. gsize hostlen;
  1030. ucl_parser_register_variable (parser,
  1031. RSPAMD_CONFDIR_MACRO,
  1032. RSPAMD_CONFDIR);
  1033. ucl_parser_register_variable (parser,
  1034. RSPAMD_LOCAL_CONFDIR_MACRO,
  1035. RSPAMD_LOCAL_CONFDIR);
  1036. ucl_parser_register_variable (parser, RSPAMD_RUNDIR_MACRO,
  1037. RSPAMD_RUNDIR);
  1038. ucl_parser_register_variable (parser, RSPAMD_DBDIR_MACRO,
  1039. RSPAMD_DBDIR);
  1040. ucl_parser_register_variable (parser, RSPAMD_LOGDIR_MACRO,
  1041. RSPAMD_LOGDIR);
  1042. ucl_parser_register_variable (parser,
  1043. RSPAMD_PLUGINSDIR_MACRO,
  1044. RSPAMD_PLUGINSDIR);
  1045. ucl_parser_register_variable (parser,
  1046. RSPAMD_SHAREDIR_MACRO,
  1047. RSPAMD_SHAREDIR);
  1048. ucl_parser_register_variable (parser,
  1049. RSPAMD_RULESDIR_MACRO,
  1050. RSPAMD_RULESDIR);
  1051. ucl_parser_register_variable (parser, RSPAMD_WWWDIR_MACRO,
  1052. RSPAMD_WWWDIR);
  1053. ucl_parser_register_variable (parser, RSPAMD_PREFIX_MACRO,
  1054. RSPAMD_PREFIX);
  1055. ucl_parser_register_variable (parser, RSPAMD_VERSION_MACRO, RVERSION);
  1056. ucl_parser_register_variable (parser, RSPAMD_VERSION_MAJOR_MACRO,
  1057. RSPAMD_VERSION_MAJOR);
  1058. ucl_parser_register_variable (parser, RSPAMD_VERSION_MINOR_MACRO,
  1059. RSPAMD_VERSION_MINOR);
  1060. ucl_parser_register_variable (parser, RSPAMD_BRANCH_VERSION_MACRO,
  1061. RSPAMD_VERSION_BRANCH);
  1062. hostlen = sysconf (_SC_HOST_NAME_MAX);
  1063. if (hostlen <= 0) {
  1064. hostlen = 256;
  1065. }
  1066. else {
  1067. hostlen ++;
  1068. }
  1069. hostbuf = g_alloca (hostlen);
  1070. memset (hostbuf, 0, hostlen);
  1071. gethostname (hostbuf, hostlen - 1);
  1072. /* UCL copies variables, so it is safe to pass an ephemeral buffer here */
  1073. ucl_parser_register_variable (parser, RSPAMD_HOSTNAME_MACRO,
  1074. hostbuf);
  1075. if (vars != NULL) {
  1076. g_hash_table_iter_init (&it, vars);
  1077. while (g_hash_table_iter_next (&it, &k, &v)) {
  1078. ucl_parser_register_variable (parser, k, v);
  1079. }
  1080. }
  1081. }
  1082. void
  1083. rspamd_ucl_add_conf_macros (struct ucl_parser *parser,
  1084. struct rspamd_config *cfg)
  1085. {
  1086. ucl_parser_register_macro (parser,
  1087. "include_map",
  1088. rspamd_include_map_handler,
  1089. cfg);
  1090. }
  1091. static void
  1092. symbols_classifiers_callback (gpointer key, gpointer value, gpointer ud)
  1093. {
  1094. struct rspamd_config *cfg = ud;
  1095. /* Actually, statistics should act like any ordinary symbol */
  1096. rspamd_symcache_add_symbol (cfg->cache, key, 0, NULL, NULL,
  1097. SYMBOL_TYPE_CLASSIFIER | SYMBOL_TYPE_NOSTAT, -1);
  1098. }
  1099. void
  1100. rspamd_config_insert_classify_symbols (struct rspamd_config *cfg)
  1101. {
  1102. g_hash_table_foreach (cfg->classifiers_symbols,
  1103. symbols_classifiers_callback,
  1104. cfg);
  1105. }
  1106. struct rspamd_classifier_config *
  1107. rspamd_config_find_classifier (struct rspamd_config *cfg, const gchar *name)
  1108. {
  1109. GList *cur;
  1110. struct rspamd_classifier_config *cf;
  1111. if (name == NULL) {
  1112. return NULL;
  1113. }
  1114. cur = cfg->classifiers;
  1115. while (cur) {
  1116. cf = cur->data;
  1117. if (g_ascii_strcasecmp (cf->name, name) == 0) {
  1118. return cf;
  1119. }
  1120. cur = g_list_next (cur);
  1121. }
  1122. return NULL;
  1123. }
  1124. gboolean
  1125. rspamd_config_check_statfiles (struct rspamd_classifier_config *cf)
  1126. {
  1127. struct rspamd_statfile_config *st;
  1128. gboolean has_other = FALSE, res = FALSE, cur_class = FALSE;
  1129. GList *cur;
  1130. /* First check classes directly */
  1131. cur = cf->statfiles;
  1132. while (cur) {
  1133. st = cur->data;
  1134. if (!has_other) {
  1135. cur_class = st->is_spam;
  1136. has_other = TRUE;
  1137. }
  1138. else {
  1139. if (cur_class != st->is_spam) {
  1140. return TRUE;
  1141. }
  1142. }
  1143. cur = g_list_next (cur);
  1144. }
  1145. if (!has_other) {
  1146. /* We have only one statfile */
  1147. return FALSE;
  1148. }
  1149. /* We have not detected any statfile that has different class, so turn on euristic based on symbol's name */
  1150. has_other = FALSE;
  1151. cur = cf->statfiles;
  1152. while (cur) {
  1153. st = cur->data;
  1154. if (rspamd_substring_search_caseless (st->symbol,
  1155. strlen (st->symbol),"spam", 4) != -1) {
  1156. st->is_spam = TRUE;
  1157. }
  1158. else if (rspamd_substring_search_caseless (st->symbol,
  1159. strlen (st->symbol),"ham", 3) != -1) {
  1160. st->is_spam = FALSE;
  1161. }
  1162. if (!has_other) {
  1163. cur_class = st->is_spam;
  1164. has_other = TRUE;
  1165. }
  1166. else {
  1167. if (cur_class != st->is_spam) {
  1168. res = TRUE;
  1169. }
  1170. }
  1171. cur = g_list_next (cur);
  1172. }
  1173. return res;
  1174. }
  1175. static gchar *
  1176. rspamd_ucl_read_cb (gchar * chunk,
  1177. gint len,
  1178. struct map_cb_data *data,
  1179. gboolean final)
  1180. {
  1181. struct rspamd_ucl_map_cbdata *cbdata = data->cur_data, *prev;
  1182. if (cbdata == NULL) {
  1183. cbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata));
  1184. prev = data->prev_data;
  1185. cbdata->buf = g_string_sized_new (BUFSIZ);
  1186. cbdata->cfg = prev->cfg;
  1187. data->cur_data = cbdata;
  1188. }
  1189. g_string_append_len (cbdata->buf, chunk, len);
  1190. /* Say not to copy any part of this buffer */
  1191. return NULL;
  1192. }
  1193. static void
  1194. rspamd_ucl_fin_cb (struct map_cb_data *data, void **target)
  1195. {
  1196. struct rspamd_ucl_map_cbdata *cbdata = data->cur_data, *prev =
  1197. data->prev_data;
  1198. ucl_object_t *obj;
  1199. struct ucl_parser *parser;
  1200. ucl_object_iter_t it = NULL;
  1201. const ucl_object_t *cur;
  1202. struct rspamd_config *cfg = data->map->cfg;
  1203. if (cbdata == NULL) {
  1204. msg_err_config ("map fin error: new data is NULL");
  1205. return;
  1206. }
  1207. /* New data available */
  1208. parser = ucl_parser_new (0);
  1209. if (!ucl_parser_add_chunk (parser, cbdata->buf->str,
  1210. cbdata->buf->len)) {
  1211. msg_err_config ("cannot parse map %s: %s",
  1212. data->map->name,
  1213. ucl_parser_get_error (parser));
  1214. ucl_parser_free (parser);
  1215. }
  1216. else {
  1217. obj = ucl_parser_get_object (parser);
  1218. ucl_parser_free (parser);
  1219. it = NULL;
  1220. while ((cur = ucl_object_iterate (obj, &it, true))) {
  1221. ucl_object_replace_key (cbdata->cfg->rcl_obj, (ucl_object_t *)cur,
  1222. cur->key, cur->keylen, false);
  1223. }
  1224. ucl_object_unref (obj);
  1225. }
  1226. if (target) {
  1227. *target = data->cur_data;
  1228. }
  1229. if (prev != NULL) {
  1230. if (prev->buf != NULL) {
  1231. g_string_free (prev->buf, TRUE);
  1232. }
  1233. g_free (prev);
  1234. }
  1235. }
  1236. static void
  1237. rspamd_ucl_dtor_cb (struct map_cb_data *data)
  1238. {
  1239. struct rspamd_ucl_map_cbdata *cbdata = data->cur_data;
  1240. if (cbdata != NULL) {
  1241. if (cbdata->buf != NULL) {
  1242. g_string_free (cbdata->buf, TRUE);
  1243. }
  1244. g_free (cbdata);
  1245. }
  1246. }
  1247. gboolean
  1248. rspamd_check_module (struct rspamd_config *cfg, module_t *mod)
  1249. {
  1250. gboolean ret = TRUE;
  1251. if (mod != NULL) {
  1252. if (mod->module_version != RSPAMD_CUR_MODULE_VERSION) {
  1253. msg_err_config ("module %s has incorrect version %xd (%xd expected)",
  1254. mod->name, (gint)mod->module_version, RSPAMD_CUR_MODULE_VERSION);
  1255. ret = FALSE;
  1256. }
  1257. if (ret && mod->rspamd_version != RSPAMD_VERSION_NUM) {
  1258. msg_err_config ("module %s has incorrect rspamd version %xL (%xL expected)",
  1259. mod->name, mod->rspamd_version, RSPAMD_VERSION_NUM);
  1260. ret = FALSE;
  1261. }
  1262. if (ret && strcmp (mod->rspamd_features, RSPAMD_FEATURES) != 0) {
  1263. msg_err_config ("module %s has incorrect rspamd features '%s' ('%s' expected)",
  1264. mod->name, mod->rspamd_features, RSPAMD_FEATURES);
  1265. ret = FALSE;
  1266. }
  1267. }
  1268. else {
  1269. ret = FALSE;
  1270. }
  1271. return ret;
  1272. }
  1273. gboolean
  1274. rspamd_check_worker (struct rspamd_config *cfg, worker_t *wrk)
  1275. {
  1276. gboolean ret = TRUE;
  1277. if (wrk != NULL) {
  1278. if (wrk->worker_version != RSPAMD_CUR_WORKER_VERSION) {
  1279. msg_err_config ("worker %s has incorrect version %xd (%xd expected)",
  1280. wrk->name, wrk->worker_version, RSPAMD_CUR_WORKER_VERSION);
  1281. ret = FALSE;
  1282. }
  1283. if (ret && wrk->rspamd_version != RSPAMD_VERSION_NUM) {
  1284. msg_err_config ("worker %s has incorrect rspamd version %xL (%xL expected)",
  1285. wrk->name, wrk->rspamd_version, RSPAMD_VERSION_NUM);
  1286. ret = FALSE;
  1287. }
  1288. if (ret && strcmp (wrk->rspamd_features, RSPAMD_FEATURES) != 0) {
  1289. msg_err_config ("worker %s has incorrect rspamd features '%s' ('%s' expected)",
  1290. wrk->name, wrk->rspamd_features, RSPAMD_FEATURES);
  1291. ret = FALSE;
  1292. }
  1293. }
  1294. else {
  1295. ret = FALSE;
  1296. }
  1297. return ret;
  1298. }
  1299. gboolean
  1300. rspamd_init_filters (struct rspamd_config *cfg, bool reconfig)
  1301. {
  1302. GList *cur;
  1303. module_t *mod, **pmod;
  1304. guint i = 0;
  1305. struct module_ctx *mod_ctx, *cur_ctx;
  1306. gboolean ret = TRUE;
  1307. /* Init all compiled modules */
  1308. for (pmod = cfg->compiled_modules; pmod != NULL && *pmod != NULL; pmod ++) {
  1309. mod = *pmod;
  1310. if (rspamd_check_module (cfg, mod)) {
  1311. if (mod->module_init_func (cfg, &mod_ctx) == 0) {
  1312. g_assert (mod_ctx != NULL);
  1313. g_ptr_array_add (cfg->c_modules, mod_ctx);
  1314. mod_ctx->mod = mod;
  1315. mod->ctx_offset = i ++;
  1316. }
  1317. }
  1318. }
  1319. /* Now check what's enabled */
  1320. cur = g_list_first (cfg->filters);
  1321. while (cur) {
  1322. /* Perform modules configuring */
  1323. mod_ctx = NULL;
  1324. PTR_ARRAY_FOREACH (cfg->c_modules, i, cur_ctx) {
  1325. if (g_ascii_strcasecmp (cur_ctx->mod->name,
  1326. (const gchar *)cur->data) == 0) {
  1327. mod_ctx = cur_ctx;
  1328. break;
  1329. }
  1330. }
  1331. if (mod_ctx) {
  1332. mod = mod_ctx->mod;
  1333. mod_ctx->enabled = rspamd_config_is_module_enabled (cfg, mod->name);
  1334. if (reconfig) {
  1335. if (!mod->module_reconfig_func (cfg)) {
  1336. msg_err_config ("reconfig of %s failed!", mod->name);
  1337. }
  1338. else {
  1339. msg_info_config ("reconfig of %s", mod->name);
  1340. }
  1341. }
  1342. else {
  1343. if (!mod->module_config_func (cfg)) {
  1344. msg_info_config ("config of %s failed!", mod->name);
  1345. ret = FALSE;
  1346. }
  1347. }
  1348. }
  1349. if (mod_ctx == NULL) {
  1350. msg_warn_config ("requested unknown module %s", cur->data);
  1351. }
  1352. cur = g_list_next (cur);
  1353. }
  1354. ret = rspamd_init_lua_filters (cfg, 0) && ret;
  1355. return ret;
  1356. }
  1357. static void
  1358. rspamd_config_new_symbol (struct rspamd_config *cfg, const gchar *symbol,
  1359. gdouble score, const gchar *description, const gchar *group,
  1360. guint flags, guint priority, gint nshots)
  1361. {
  1362. struct rspamd_symbols_group *sym_group;
  1363. struct rspamd_symbol *sym_def;
  1364. gdouble *score_ptr;
  1365. sym_def =
  1366. rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (struct rspamd_symbol));
  1367. score_ptr = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (gdouble));
  1368. if (isnan (score)) {
  1369. /* In fact, it could be defined later */
  1370. msg_debug_config ("score is not defined for symbol %s, set it to zero",
  1371. symbol);
  1372. score = 0.0;
  1373. /* Also set priority to 0 to allow override by anything */
  1374. sym_def->priority = 0;
  1375. }
  1376. else {
  1377. sym_def->priority = priority;
  1378. }
  1379. *score_ptr = score;
  1380. sym_def->score = score;
  1381. sym_def->weight_ptr = score_ptr;
  1382. sym_def->name = rspamd_mempool_strdup (cfg->cfg_pool, symbol);
  1383. sym_def->flags = flags;
  1384. sym_def->nshots = nshots;
  1385. sym_def->groups = g_ptr_array_sized_new (1);
  1386. rspamd_mempool_add_destructor (cfg->cfg_pool, rspamd_ptr_array_free_hard,
  1387. sym_def->groups);
  1388. if (description) {
  1389. sym_def->description = rspamd_mempool_strdup (cfg->cfg_pool, description);
  1390. }
  1391. msg_debug_config ("registered symbol %s with weight %.2f in and group %s",
  1392. sym_def->name, score, group);
  1393. g_hash_table_insert (cfg->symbols, sym_def->name, sym_def);
  1394. /* Search for symbol group */
  1395. if (group == NULL) {
  1396. group = "ungrouped";
  1397. sym_def->flags |= RSPAMD_SYMBOL_FLAG_UNGROUPPED;
  1398. }
  1399. else {
  1400. if (strcmp (group, "ungrouped") == 0) {
  1401. sym_def->flags |= RSPAMD_SYMBOL_FLAG_UNGROUPPED;
  1402. }
  1403. }
  1404. sym_group = g_hash_table_lookup (cfg->groups, group);
  1405. if (sym_group == NULL) {
  1406. /* Create new group */
  1407. sym_group = rspamd_config_new_group (cfg, group);
  1408. }
  1409. sym_def->gr = sym_group;
  1410. g_hash_table_insert (sym_group->symbols, sym_def->name, sym_def);
  1411. if (!(sym_def->flags & RSPAMD_SYMBOL_FLAG_UNGROUPPED)) {
  1412. g_ptr_array_add (sym_def->groups, sym_group);
  1413. }
  1414. }
  1415. gboolean
  1416. rspamd_config_add_symbol (struct rspamd_config *cfg,
  1417. const gchar *symbol,
  1418. gdouble score,
  1419. const gchar *description,
  1420. const gchar *group,
  1421. guint flags,
  1422. guint priority,
  1423. gint nshots)
  1424. {
  1425. struct rspamd_symbol *sym_def;
  1426. struct rspamd_symbols_group *sym_group;
  1427. guint i;
  1428. g_assert (cfg != NULL);
  1429. g_assert (symbol != NULL);
  1430. sym_def = g_hash_table_lookup (cfg->symbols, symbol);
  1431. if (sym_def != NULL) {
  1432. if (group != NULL) {
  1433. gboolean has_group = FALSE;
  1434. PTR_ARRAY_FOREACH (sym_def->groups, i, sym_group) {
  1435. if (g_ascii_strcasecmp (sym_group->name, group) == 0) {
  1436. /* Group is already here */
  1437. has_group = TRUE;
  1438. break;
  1439. }
  1440. }
  1441. if (!has_group) {
  1442. /* Non-empty group has a priority over non-groupped one */
  1443. sym_group = g_hash_table_lookup (cfg->groups, group);
  1444. if (sym_group == NULL) {
  1445. /* Create new group */
  1446. sym_group = rspamd_config_new_group (cfg, group);
  1447. }
  1448. if (!sym_def->gr) {
  1449. sym_def->gr = sym_group;
  1450. }
  1451. g_hash_table_insert (sym_group->symbols, sym_def->name, sym_def);
  1452. sym_def->flags &= ~(RSPAMD_SYMBOL_FLAG_UNGROUPPED);
  1453. g_ptr_array_add (sym_def->groups, sym_group);
  1454. }
  1455. }
  1456. if (sym_def->priority > priority) {
  1457. msg_debug_config ("symbol %s has been already registered with "
  1458. "priority %ud, do not override (new priority: %ud)",
  1459. symbol,
  1460. sym_def->priority,
  1461. priority);
  1462. /* But we can still add description */
  1463. if (!sym_def->description && description) {
  1464. sym_def->description = rspamd_mempool_strdup (cfg->cfg_pool,
  1465. description);
  1466. }
  1467. return FALSE;
  1468. }
  1469. else {
  1470. if (!isnan (score)) {
  1471. msg_debug_config ("symbol %s has been already registered with "
  1472. "priority %ud, override it with new priority: %ud, "
  1473. "old score: %.2f, new score: %.2f",
  1474. symbol,
  1475. sym_def->priority,
  1476. priority,
  1477. sym_def->score,
  1478. score);
  1479. *sym_def->weight_ptr = score;
  1480. sym_def->score = score;
  1481. sym_def->priority = priority;
  1482. }
  1483. sym_def->flags = flags;
  1484. sym_def->nshots = nshots;
  1485. if (description) {
  1486. sym_def->description = rspamd_mempool_strdup (cfg->cfg_pool,
  1487. description);
  1488. }
  1489. /* We also check group information in this case */
  1490. if (group != NULL && sym_def->gr != NULL &&
  1491. strcmp (group, sym_def->gr->name) != 0) {
  1492. sym_group = g_hash_table_lookup (cfg->groups, group);
  1493. if (sym_group == NULL) {
  1494. /* Create new group */
  1495. sym_group = rspamd_config_new_group (cfg, group);
  1496. }
  1497. if (!(sym_group->flags & RSPAMD_SYMBOL_GROUP_UNGROUPED)) {
  1498. msg_debug_config ("move symbol %s from group %s to %s",
  1499. sym_def->name, sym_def->gr->name, group);
  1500. g_hash_table_remove (sym_def->gr->symbols, sym_def->name);
  1501. sym_def->gr = sym_group;
  1502. g_hash_table_insert (sym_group->symbols, sym_def->name, sym_def);
  1503. }
  1504. }
  1505. return TRUE;
  1506. }
  1507. }
  1508. /* This is called merely when we have an undefined symbol */
  1509. rspamd_config_new_symbol (cfg, symbol, score, description,
  1510. group, flags, priority, nshots);
  1511. return TRUE;
  1512. }
  1513. gboolean
  1514. rspamd_config_add_symbol_group (struct rspamd_config *cfg,
  1515. const gchar *symbol,
  1516. const gchar *group)
  1517. {
  1518. struct rspamd_symbol *sym_def;
  1519. struct rspamd_symbols_group *sym_group;
  1520. guint i;
  1521. g_assert (cfg != NULL);
  1522. g_assert (symbol != NULL);
  1523. g_assert (group != NULL);
  1524. sym_def = g_hash_table_lookup (cfg->symbols, symbol);
  1525. if (sym_def != NULL) {
  1526. gboolean has_group = FALSE;
  1527. PTR_ARRAY_FOREACH (sym_def->groups, i, sym_group) {
  1528. if (g_ascii_strcasecmp (sym_group->name, group) == 0) {
  1529. /* Group is already here */
  1530. has_group = TRUE;
  1531. break;
  1532. }
  1533. }
  1534. if (!has_group) {
  1535. /* Non-empty group has a priority over non-groupped one */
  1536. sym_group = g_hash_table_lookup (cfg->groups, group);
  1537. if (sym_group == NULL) {
  1538. /* Create new group */
  1539. sym_group = rspamd_config_new_group (cfg, group);
  1540. }
  1541. if (!sym_def->gr) {
  1542. sym_def->gr = sym_group;
  1543. }
  1544. g_hash_table_insert (sym_group->symbols, sym_def->name, sym_def);
  1545. sym_def->flags &= ~(RSPAMD_SYMBOL_FLAG_UNGROUPPED);
  1546. g_ptr_array_add (sym_def->groups, sym_group);
  1547. return TRUE;
  1548. }
  1549. }
  1550. return FALSE;
  1551. }
  1552. gboolean
  1553. rspamd_config_is_module_enabled (struct rspamd_config *cfg,
  1554. const gchar *module_name)
  1555. {
  1556. gboolean is_c = FALSE;
  1557. const ucl_object_t *conf, *enabled;
  1558. GList *cur;
  1559. struct rspamd_symbols_group *gr;
  1560. lua_State *L = cfg->lua_state;
  1561. struct module_ctx *cur_ctx;
  1562. guint i;
  1563. PTR_ARRAY_FOREACH (cfg->c_modules, i, cur_ctx) {
  1564. if (g_ascii_strcasecmp (cur_ctx->mod->name, module_name) == 0) {
  1565. is_c = TRUE;
  1566. break;
  1567. }
  1568. }
  1569. if (g_hash_table_lookup (cfg->explicit_modules, module_name) != NULL) {
  1570. /* Always load module */
  1571. rspamd_plugins_table_push_elt (L, "enabled", module_name);
  1572. return TRUE;
  1573. }
  1574. if (is_c) {
  1575. gboolean found = FALSE;
  1576. cur = g_list_first (cfg->filters);
  1577. while (cur) {
  1578. if (strcmp (cur->data, module_name) == 0) {
  1579. found = TRUE;
  1580. break;
  1581. }
  1582. cur = g_list_next (cur);
  1583. }
  1584. if (!found) {
  1585. msg_info_config ("internal module %s is disable in `filters` line",
  1586. module_name);
  1587. rspamd_plugins_table_push_elt (L,
  1588. "disabled_explicitly", module_name);
  1589. return FALSE;
  1590. }
  1591. }
  1592. conf = ucl_object_lookup (cfg->rcl_obj, module_name);
  1593. if (conf == NULL) {
  1594. rspamd_plugins_table_push_elt (L, "disabled_unconfigured", module_name);
  1595. msg_info_config ("%s module %s is enabled but has not been configured",
  1596. is_c ? "internal" : "lua", module_name);
  1597. if (!is_c) {
  1598. msg_info_config ("%s disabling unconfigured lua module", module_name);
  1599. return FALSE;
  1600. }
  1601. }
  1602. else {
  1603. enabled = ucl_object_lookup (conf, "enabled");
  1604. if (enabled) {
  1605. if (ucl_object_type (enabled) == UCL_BOOLEAN) {
  1606. if (!ucl_object_toboolean (enabled)) {
  1607. rspamd_plugins_table_push_elt (L,
  1608. "disabled_explicitly", module_name);
  1609. msg_info_config (
  1610. "%s module %s is disabled in the configuration",
  1611. is_c ? "internal" : "lua", module_name);
  1612. return FALSE;
  1613. }
  1614. }
  1615. else if (ucl_object_type (enabled) == UCL_STRING) {
  1616. gint ret;
  1617. ret = rspamd_config_parse_flag (ucl_object_tostring (enabled), 0);
  1618. if (ret == 0) {
  1619. rspamd_plugins_table_push_elt (L,
  1620. "disabled_explicitly", module_name);
  1621. msg_info_config (
  1622. "%s module %s is disabled in the configuration",
  1623. is_c ? "internal" : "lua", module_name);
  1624. return FALSE;
  1625. }
  1626. else if (ret == -1) {
  1627. rspamd_plugins_table_push_elt (L,
  1628. "disabled_failed", module_name);
  1629. msg_info_config (
  1630. "%s module %s has wrong enabled flag (%s) in the configuration",
  1631. is_c ? "internal" : "lua", module_name,
  1632. ucl_object_tostring (enabled));
  1633. return FALSE;
  1634. }
  1635. }
  1636. }
  1637. }
  1638. /* Now we check symbols group */
  1639. gr = g_hash_table_lookup (cfg->groups, module_name);
  1640. if (gr) {
  1641. if (gr->flags & RSPAMD_SYMBOL_GROUP_DISABLED) {
  1642. rspamd_plugins_table_push_elt (L,
  1643. "disabled_explicitly", module_name);
  1644. msg_info_config ("%s module %s is disabled in the configuration as "
  1645. "its group has been disabled",
  1646. is_c ? "internal" : "lua", module_name);
  1647. return FALSE;
  1648. }
  1649. }
  1650. rspamd_plugins_table_push_elt (L, "enabled", module_name);
  1651. return TRUE;
  1652. }
  1653. static gboolean
  1654. rspamd_config_action_from_ucl (struct rspamd_config *cfg,
  1655. struct rspamd_action *act,
  1656. const ucl_object_t *obj,
  1657. guint priority)
  1658. {
  1659. const ucl_object_t *elt;
  1660. gdouble threshold = NAN;
  1661. guint flags = 0, std_act, obj_type;
  1662. obj_type = ucl_object_type (obj);
  1663. if (obj_type == UCL_OBJECT) {
  1664. obj_type = ucl_object_type (obj);
  1665. elt = ucl_object_lookup_any (obj, "score", "threshold", NULL);
  1666. if (elt) {
  1667. threshold = ucl_object_todouble (elt);
  1668. }
  1669. elt = ucl_object_lookup (obj, "flags");
  1670. if (elt && ucl_object_type (elt) == UCL_ARRAY) {
  1671. const ucl_object_t *cur;
  1672. ucl_object_iter_t it = NULL;
  1673. while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) {
  1674. if (ucl_object_type (cur) == UCL_STRING) {
  1675. const gchar *fl_str = ucl_object_tostring (cur);
  1676. if (g_ascii_strcasecmp (fl_str, "no_threshold") == 0) {
  1677. flags |= RSPAMD_ACTION_NO_THRESHOLD;
  1678. } else if (g_ascii_strcasecmp (fl_str, "threshold_only") == 0) {
  1679. flags |= RSPAMD_ACTION_THRESHOLD_ONLY;
  1680. } else if (g_ascii_strcasecmp (fl_str, "ham") == 0) {
  1681. flags |= RSPAMD_ACTION_HAM;
  1682. } else {
  1683. msg_warn_config ("unknown action flag: %s", fl_str);
  1684. }
  1685. }
  1686. }
  1687. }
  1688. elt = ucl_object_lookup (obj, "milter");
  1689. if (elt) {
  1690. const gchar *milter_action = ucl_object_tostring (elt);
  1691. if (strcmp (milter_action, "discard") == 0) {
  1692. flags |= RSPAMD_ACTION_MILTER;
  1693. act->action_type = METRIC_ACTION_DISCARD;
  1694. }
  1695. else if (strcmp (milter_action, "quarantine") == 0) {
  1696. flags |= RSPAMD_ACTION_MILTER;
  1697. act->action_type = METRIC_ACTION_QUARANTINE;
  1698. }
  1699. else {
  1700. msg_warn_config ("unknown milter action: %s", milter_action);
  1701. }
  1702. }
  1703. }
  1704. else if (obj_type == UCL_FLOAT || obj_type == UCL_INT) {
  1705. threshold = ucl_object_todouble (obj);
  1706. }
  1707. /* TODO: add lua references support */
  1708. if (isnan (threshold) && !(flags & RSPAMD_ACTION_NO_THRESHOLD)) {
  1709. msg_err_config ("action %s has no threshold being set and it is not"
  1710. " a no threshold action", act->name);
  1711. return FALSE;
  1712. }
  1713. act->threshold = threshold;
  1714. act->flags = flags;
  1715. if (!(flags & RSPAMD_ACTION_MILTER)) {
  1716. if (rspamd_action_from_str (act->name, &std_act)) {
  1717. act->action_type = std_act;
  1718. } else {
  1719. act->action_type = METRIC_ACTION_CUSTOM;
  1720. }
  1721. }
  1722. return TRUE;
  1723. }
  1724. gboolean
  1725. rspamd_config_set_action_score (struct rspamd_config *cfg,
  1726. const gchar *action_name,
  1727. const ucl_object_t *obj)
  1728. {
  1729. struct rspamd_action *act;
  1730. enum rspamd_action_type std_act;
  1731. const ucl_object_t *elt;
  1732. guint priority = ucl_object_get_priority (obj), obj_type;
  1733. g_assert (cfg != NULL);
  1734. g_assert (action_name != NULL);
  1735. obj_type = ucl_object_type (obj);
  1736. if (obj_type == UCL_OBJECT) {
  1737. elt = ucl_object_lookup (obj, "priority");
  1738. if (elt) {
  1739. priority = ucl_object_toint (elt);
  1740. }
  1741. }
  1742. /* Here are dragons:
  1743. * We have `canonical` name for actions, such as `soft reject` and
  1744. * configuration names for actions (used to be more convenient), such
  1745. * as `soft_reject`. Unfortunately, we must have heuristic for this
  1746. * variance of names.
  1747. */
  1748. if (rspamd_action_from_str (action_name, (gint *)&std_act)) {
  1749. action_name = rspamd_action_to_str (std_act);
  1750. }
  1751. HASH_FIND_STR (cfg->actions, action_name, act);
  1752. if (act) {
  1753. /* Existing element */
  1754. if (act->priority <= priority) {
  1755. /* We can replace data */
  1756. msg_info_config ("action %s has been already registered with "
  1757. "priority %ud, override it with new priority: %ud, "
  1758. "old score: %.2f",
  1759. action_name,
  1760. act->priority,
  1761. priority,
  1762. act->threshold);
  1763. if (rspamd_config_action_from_ucl (cfg, act, obj, priority)) {
  1764. rspamd_actions_sort (cfg);
  1765. }
  1766. else {
  1767. return FALSE;
  1768. }
  1769. }
  1770. else {
  1771. msg_info_config ("action %s has been already registered with "
  1772. "priority %ud, do not override (new priority: %ud)",
  1773. action_name,
  1774. act->priority,
  1775. priority);
  1776. }
  1777. }
  1778. else {
  1779. /* Add new element */
  1780. act = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*act));
  1781. act->name = rspamd_mempool_strdup (cfg->cfg_pool, action_name);
  1782. if (rspamd_config_action_from_ucl (cfg, act, obj, priority)) {
  1783. HASH_ADD_KEYPTR (hh, cfg->actions,
  1784. act->name, strlen (act->name), act);
  1785. rspamd_actions_sort (cfg);
  1786. }
  1787. else {
  1788. return FALSE;
  1789. }
  1790. }
  1791. return TRUE;
  1792. }
  1793. gboolean
  1794. rspamd_config_maybe_disable_action (struct rspamd_config *cfg,
  1795. const gchar *action_name,
  1796. guint priority)
  1797. {
  1798. struct rspamd_action *act;
  1799. HASH_FIND_STR (cfg->actions, action_name, act);
  1800. if (act) {
  1801. if (priority >= act->priority) {
  1802. msg_info_config ("disable action %s; old priority: %ud, new priority: %ud",
  1803. action_name,
  1804. act->priority,
  1805. priority);
  1806. act->threshold = NAN;
  1807. act->priority = priority;
  1808. act->flags |= RSPAMD_ACTION_NO_THRESHOLD;
  1809. return TRUE;
  1810. }
  1811. else {
  1812. msg_info_config ("action %s has been already registered with "
  1813. "priority %ud, cannot disable it with new priority: %ud",
  1814. action_name,
  1815. act->priority,
  1816. priority);
  1817. }
  1818. }
  1819. return FALSE;
  1820. }
  1821. struct rspamd_action *
  1822. rspamd_config_get_action (struct rspamd_config *cfg, const gchar *name)
  1823. {
  1824. struct rspamd_action *res = NULL;
  1825. HASH_FIND_STR (cfg->actions, name, res);
  1826. return res;
  1827. }
  1828. struct rspamd_action *
  1829. rspamd_config_get_action_by_type (struct rspamd_config *cfg,
  1830. enum rspamd_action_type type)
  1831. {
  1832. struct rspamd_action *cur, *tmp;
  1833. HASH_ITER (hh, cfg->actions, cur, tmp) {
  1834. if (cur->action_type == type) {
  1835. return cur;
  1836. }
  1837. }
  1838. return NULL;
  1839. }
  1840. gboolean
  1841. rspamd_config_radix_from_ucl (struct rspamd_config *cfg,
  1842. const ucl_object_t *obj,
  1843. const gchar *description,
  1844. struct rspamd_radix_map_helper **target,
  1845. GError **err)
  1846. {
  1847. ucl_type_t type;
  1848. ucl_object_iter_t it = NULL;
  1849. const ucl_object_t *cur, *cur_elt;
  1850. const gchar *str;
  1851. /* Cleanup */
  1852. *target = NULL;
  1853. LL_FOREACH (obj, cur_elt) {
  1854. type = ucl_object_type (cur_elt);
  1855. switch (type) {
  1856. case UCL_STRING:
  1857. /* Either map or a list of IPs */
  1858. str = ucl_object_tostring (cur_elt);
  1859. if (rspamd_map_is_map (str)) {
  1860. if (rspamd_map_add_from_ucl (cfg, cur_elt,
  1861. description,
  1862. rspamd_radix_read,
  1863. rspamd_radix_fin,
  1864. rspamd_radix_dtor,
  1865. (void **)target) == NULL) {
  1866. g_set_error (err, g_quark_from_static_string ("rspamd-config"),
  1867. EINVAL, "bad map definition %s for %s", str,
  1868. ucl_object_key (obj));
  1869. return FALSE;
  1870. }
  1871. return TRUE;
  1872. }
  1873. else {
  1874. /* Just a list */
  1875. if (!*target) {
  1876. *target = rspamd_map_helper_new_radix (NULL);
  1877. }
  1878. rspamd_map_helper_insert_radix_resolve (*target, str, "");
  1879. }
  1880. break;
  1881. case UCL_OBJECT:
  1882. /* Should be a map description */
  1883. if (rspamd_map_add_from_ucl (cfg, cur_elt,
  1884. description,
  1885. rspamd_radix_read,
  1886. rspamd_radix_fin,
  1887. rspamd_radix_dtor,
  1888. (void **)target) == NULL) {
  1889. g_set_error (err, g_quark_from_static_string ("rspamd-config"),
  1890. EINVAL, "bad map object for %s", ucl_object_key (obj));
  1891. return FALSE;
  1892. }
  1893. return TRUE;
  1894. break;
  1895. case UCL_ARRAY:
  1896. /* List of IP addresses */
  1897. it = ucl_object_iterate_new (cur_elt);
  1898. while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
  1899. str = ucl_object_tostring (cur);
  1900. if (!*target) {
  1901. *target = rspamd_map_helper_new_radix (NULL);
  1902. }
  1903. rspamd_map_helper_insert_radix_resolve (*target, str, "");
  1904. }
  1905. ucl_object_iterate_free (it);
  1906. break;
  1907. default:
  1908. g_set_error (err, g_quark_from_static_string ("rspamd-config"),
  1909. EINVAL, "bad map type %s for %s",
  1910. ucl_object_type_to_string (type),
  1911. ucl_object_key (obj));
  1912. return FALSE;
  1913. }
  1914. }
  1915. /* Destroy on cfg cleanup */
  1916. rspamd_mempool_add_destructor (cfg->cfg_pool,
  1917. (rspamd_mempool_destruct_t)rspamd_map_helper_destroy_radix,
  1918. *target);
  1919. return TRUE;
  1920. }
  1921. gboolean
  1922. rspamd_action_from_str (const gchar *data, gint *result)
  1923. {
  1924. guint64 h;
  1925. h = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64,
  1926. data, strlen (data), 0xdeadbabe);
  1927. switch (h) {
  1928. case 0x9917BFDB46332B8CULL: /* reject */
  1929. *result = METRIC_ACTION_REJECT;
  1930. break;
  1931. case 0x7130EE37D07B3715ULL: /* greylist */
  1932. *result = METRIC_ACTION_GREYLIST;
  1933. break;
  1934. case 0xCA6087E05480C60CULL: /* add_header */
  1935. case 0x87A3D27783B16241ULL: /* add header */
  1936. *result = METRIC_ACTION_ADD_HEADER;
  1937. break;
  1938. case 0x4963374ED8B90449ULL: /* rewrite_subject */
  1939. case 0x5C9FC4679C025948ULL: /* rewrite subject */
  1940. *result = METRIC_ACTION_REWRITE_SUBJECT;
  1941. break;
  1942. case 0xFC7D6502EE71FDD9ULL: /* soft reject */
  1943. case 0x73576567C262A82DULL: /* soft_reject */
  1944. *result = METRIC_ACTION_SOFT_REJECT;
  1945. break;
  1946. case 0x207091B927D1EC0DULL: /* no action */
  1947. case 0xB7D92D002CD46325ULL: /* no_action */
  1948. case 0x167C0DF4BAA9BCECULL: /* accept */
  1949. *result = METRIC_ACTION_NOACTION;
  1950. break;
  1951. case 0x4E9666ECCD3FC314ULL: /* quarantine */
  1952. *result = METRIC_ACTION_QUARANTINE;
  1953. break;
  1954. case 0x93B346242F7F69B3ULL: /* discard */
  1955. *result = METRIC_ACTION_DISCARD;
  1956. break;
  1957. default:
  1958. return FALSE;
  1959. }
  1960. return TRUE;
  1961. }
  1962. const gchar *
  1963. rspamd_action_to_str (enum rspamd_action_type action)
  1964. {
  1965. switch (action) {
  1966. case METRIC_ACTION_REJECT:
  1967. return "reject";
  1968. case METRIC_ACTION_SOFT_REJECT:
  1969. return "soft reject";
  1970. case METRIC_ACTION_REWRITE_SUBJECT:
  1971. return "rewrite subject";
  1972. case METRIC_ACTION_ADD_HEADER:
  1973. return "add header";
  1974. case METRIC_ACTION_GREYLIST:
  1975. return "greylist";
  1976. case METRIC_ACTION_NOACTION:
  1977. return "no action";
  1978. case METRIC_ACTION_MAX:
  1979. return "invalid max action";
  1980. case METRIC_ACTION_CUSTOM:
  1981. return "custom";
  1982. case METRIC_ACTION_DISCARD:
  1983. return "discard";
  1984. case METRIC_ACTION_QUARANTINE:
  1985. return "quarantine";
  1986. }
  1987. return "unknown action";
  1988. }
  1989. const gchar *
  1990. rspamd_action_to_str_alt (enum rspamd_action_type action)
  1991. {
  1992. switch (action) {
  1993. case METRIC_ACTION_REJECT:
  1994. return "reject";
  1995. case METRIC_ACTION_SOFT_REJECT:
  1996. return "soft_reject";
  1997. case METRIC_ACTION_REWRITE_SUBJECT:
  1998. return "rewrite_subject";
  1999. case METRIC_ACTION_ADD_HEADER:
  2000. return "add_header";
  2001. case METRIC_ACTION_GREYLIST:
  2002. return "greylist";
  2003. case METRIC_ACTION_NOACTION:
  2004. return "no action";
  2005. case METRIC_ACTION_MAX:
  2006. return "invalid max action";
  2007. case METRIC_ACTION_CUSTOM:
  2008. return "custom";
  2009. case METRIC_ACTION_DISCARD:
  2010. return "discard";
  2011. case METRIC_ACTION_QUARANTINE:
  2012. return "quarantine";
  2013. }
  2014. return "unknown action";
  2015. }
  2016. static int
  2017. rspamd_actions_cmp (const struct rspamd_action *a1, const struct rspamd_action *a2)
  2018. {
  2019. if (!isnan (a1->threshold) && !isnan (a2->threshold)) {
  2020. if (a1->threshold < a2->threshold) {
  2021. return -1;
  2022. }
  2023. else if (a1->threshold > a2->threshold) {
  2024. return 1;
  2025. }
  2026. return 0;
  2027. }
  2028. if (isnan (a1->threshold) && isnan (a2->threshold)) {
  2029. return 0;
  2030. }
  2031. else if (isnan (a1->threshold)) {
  2032. return 1;
  2033. }
  2034. else {
  2035. return -1;
  2036. }
  2037. }
  2038. void
  2039. rspamd_actions_sort (struct rspamd_config *cfg)
  2040. {
  2041. HASH_SORT (cfg->actions, rspamd_actions_cmp);
  2042. }
  2043. static void
  2044. rspamd_config_settings_elt_dtor (struct rspamd_config_settings_elt *e)
  2045. {
  2046. if (e->symbols_enabled) {
  2047. ucl_object_unref (e->symbols_enabled);
  2048. }
  2049. if (e->symbols_disabled) {
  2050. ucl_object_unref (e->symbols_disabled);
  2051. }
  2052. }
  2053. guint32
  2054. rspamd_config_name_to_id (const gchar *name, gsize namelen)
  2055. {
  2056. guint64 h;
  2057. h = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64,
  2058. name, namelen, 0x0);
  2059. /* Take the lower part of hash as LE number */
  2060. return ((guint32)GUINT64_TO_LE (h));
  2061. }
  2062. struct rspamd_config_settings_elt *
  2063. rspamd_config_find_settings_id_ref (struct rspamd_config *cfg,
  2064. guint32 id)
  2065. {
  2066. struct rspamd_config_settings_elt *cur;
  2067. DL_FOREACH (cfg->setting_ids, cur) {
  2068. if (cur->id == id) {
  2069. REF_RETAIN (cur);
  2070. return cur;
  2071. }
  2072. }
  2073. return NULL;
  2074. }
  2075. struct rspamd_config_settings_elt *rspamd_config_find_settings_name_ref (
  2076. struct rspamd_config *cfg,
  2077. const gchar *name, gsize namelen)
  2078. {
  2079. guint32 id;
  2080. id = rspamd_config_name_to_id (name, namelen);
  2081. return rspamd_config_find_settings_id_ref (cfg, id);
  2082. }
  2083. void
  2084. rspamd_config_register_settings_id (struct rspamd_config *cfg,
  2085. const gchar *name,
  2086. ucl_object_t *symbols_enabled,
  2087. ucl_object_t *symbols_disabled,
  2088. enum rspamd_config_settings_policy policy)
  2089. {
  2090. struct rspamd_config_settings_elt *elt;
  2091. guint32 id;
  2092. id = rspamd_config_name_to_id (name, strlen (name));
  2093. elt = rspamd_config_find_settings_id_ref (cfg, id);
  2094. if (elt) {
  2095. /* Need to replace */
  2096. struct rspamd_config_settings_elt *nelt;
  2097. DL_DELETE (cfg->setting_ids, elt);
  2098. nelt = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*nelt));
  2099. nelt->id = id;
  2100. nelt->name = rspamd_mempool_strdup (cfg->cfg_pool, name);
  2101. if (symbols_enabled) {
  2102. nelt->symbols_enabled = ucl_object_ref (symbols_enabled);
  2103. }
  2104. if (symbols_disabled) {
  2105. nelt->symbols_disabled = ucl_object_ref (symbols_disabled);
  2106. }
  2107. nelt->policy = policy;
  2108. REF_INIT_RETAIN (nelt, rspamd_config_settings_elt_dtor);
  2109. msg_warn_config ("replace settings id %ud (%s)", id, name);
  2110. rspamd_symcache_process_settings_elt (cfg->cache, elt);
  2111. DL_APPEND (cfg->setting_ids, nelt);
  2112. /*
  2113. * Need to unref old element twice as there are two reference holders:
  2114. * 1. Config structure as we call REF_INIT_RETAIN
  2115. * 2. rspamd_config_find_settings_id_ref also increases refcount
  2116. */
  2117. REF_RELEASE (elt);
  2118. REF_RELEASE (elt);
  2119. }
  2120. else {
  2121. elt = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*elt));
  2122. elt->id = id;
  2123. elt->name = rspamd_mempool_strdup (cfg->cfg_pool, name);
  2124. if (symbols_enabled) {
  2125. elt->symbols_enabled = ucl_object_ref (symbols_enabled);
  2126. }
  2127. if (symbols_disabled) {
  2128. elt->symbols_disabled = ucl_object_ref (symbols_disabled);
  2129. }
  2130. elt->policy = policy;
  2131. msg_info_config ("register new settings id %ud (%s)", id, name);
  2132. REF_INIT_RETAIN (elt, rspamd_config_settings_elt_dtor);
  2133. rspamd_symcache_process_settings_elt (cfg->cache, elt);
  2134. DL_APPEND (cfg->setting_ids, elt);
  2135. }
  2136. }