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 55KB

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