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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821
  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 "uthash_strcase.h"
  20. #include "filter.h"
  21. #include "lua/lua_common.h"
  22. #include "map.h"
  23. #include "map_private.h"
  24. #include "dynamic_cfg.h"
  25. #include "utlist.h"
  26. #include "stat_api.h"
  27. #include "unix-std.h"
  28. #include "libutil/multipattern.h"
  29. #include "monitored.h"
  30. #include "ref.h"
  31. #include <math.h>
  32. #define DEFAULT_SCORE 10.0
  33. #define DEFAULT_RLIMIT_NOFILE 2048
  34. #define DEFAULT_RLIMIT_MAXCORE 0
  35. #define DEFAULT_MAP_TIMEOUT 10
  36. #define DEFAULT_MIN_WORD 4
  37. #define DEFAULT_MAX_WORD 40
  38. #define DEFAULT_WORDS_DECAY 200
  39. #define DEFAULT_MAX_MESSAGE (50 * 1024 * 1024)
  40. #define DEFAULT_MAX_PIC (1 * 1024 * 1024)
  41. struct rspamd_ucl_map_cbdata {
  42. struct rspamd_config *cfg;
  43. GString *buf;
  44. };
  45. static gchar * rspamd_ucl_read_cb (gchar * chunk,
  46. gint len,
  47. struct map_cb_data *data,
  48. gboolean final);
  49. static void rspamd_ucl_fin_cb (struct map_cb_data *data);
  50. gboolean
  51. rspamd_parse_bind_line (struct rspamd_config *cfg,
  52. struct rspamd_worker_conf *cf,
  53. const gchar *str)
  54. {
  55. struct rspamd_worker_bind_conf *cnf;
  56. gchar *err;
  57. gboolean ret = TRUE;
  58. if (str == NULL) {
  59. return FALSE;
  60. }
  61. cnf =
  62. rspamd_mempool_alloc0 (cfg->cfg_pool,
  63. sizeof (struct rspamd_worker_bind_conf));
  64. cnf->cnt = 1024;
  65. if (g_ascii_strncasecmp (str, "systemd:", sizeof ("systemd:") - 1) == 0) {
  66. /* The actual socket will be passed by systemd environment */
  67. cnf->is_systemd = TRUE;
  68. cnf->cnt = strtoul (str + sizeof ("systemd:") - 1, &err, 10);
  69. cnf->addrs = NULL;
  70. if (err == NULL || *err == '\0') {
  71. cnf->name = rspamd_mempool_strdup (cfg->cfg_pool, str);
  72. LL_PREPEND (cf->bind_conf, cnf);
  73. }
  74. else {
  75. msg_err_config ("cannot parse bind line: %s", str);
  76. ret = FALSE;
  77. }
  78. }
  79. else {
  80. if (!rspamd_parse_host_port_priority (str, &cnf->addrs,
  81. NULL, &cnf->name, DEFAULT_BIND_PORT, cfg->cfg_pool)) {
  82. msg_err_config ("cannot parse bind line: %s", str);
  83. ret = FALSE;
  84. }
  85. else {
  86. cnf->cnt = cnf->addrs->len;
  87. LL_PREPEND (cf->bind_conf, cnf);
  88. }
  89. }
  90. return ret;
  91. }
  92. struct rspamd_config *
  93. rspamd_config_new (void)
  94. {
  95. struct rspamd_config *cfg;
  96. cfg = g_slice_alloc0 (sizeof (*cfg));
  97. cfg->cfg_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (), "cfg");
  98. cfg->dns_timeout = 1000;
  99. cfg->dns_retransmits = 5;
  100. /* After 20 errors do throttling for 10 seconds */
  101. cfg->dns_throttling_errors = 20;
  102. cfg->dns_throttling_time = 10000;
  103. /* 16 sockets per DNS server */
  104. cfg->dns_io_per_server = 16;
  105. /* 20 Kb */
  106. cfg->max_diff = 20480;
  107. cfg->metrics = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  108. cfg->c_modules = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  109. cfg->composite_symbols =
  110. g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  111. cfg->classifiers_symbols = g_hash_table_new (rspamd_str_hash,
  112. rspamd_str_equal);
  113. cfg->cfg_params = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  114. cfg->metrics_symbols = g_hash_table_new_full (rspamd_str_hash, rspamd_str_equal,
  115. NULL, (GDestroyNotify)g_list_free);
  116. cfg->debug_modules = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  117. cfg->explicit_modules = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  118. cfg->wrk_parsers = g_hash_table_new (g_int_hash, g_int_equal);
  119. cfg->trusted_keys = g_hash_table_new (rspamd_str_hash,
  120. rspamd_str_equal);
  121. cfg->map_timeout = DEFAULT_MAP_TIMEOUT;
  122. cfg->log_level = G_LOG_LEVEL_WARNING;
  123. cfg->log_extended = TRUE;
  124. cfg->check_text_attachements = TRUE;
  125. cfg->dns_max_requests = 64;
  126. cfg->history_rows = 200;
  127. cfg->log_error_elts = 10;
  128. cfg->log_error_elt_maxlen = 1000;
  129. /* Default log line */
  130. cfg->log_format_str = "id: <$mid>,$if_qid{ qid: <$>,}$if_ip{ ip: $,}"
  131. "$if_user{ user: $,}$if_smtp_from{ from: <$>,} (default: $is_spam "
  132. "($action): [$scores] [$symbols_scores_params]), len: $len, time: $time_real real,"
  133. " $time_virtual virtual, dns req: $dns_req, digest: <$digest>"
  134. "$if_smtp_rcpts{ rcpts: <$>, }$if_mime_rcpt{ mime_rcpt: <$>, }";
  135. /* Allow non-mime input by default */
  136. cfg->allow_raw_input = TRUE;
  137. /* Default maximum words processed */
  138. cfg->words_decay = DEFAULT_WORDS_DECAY;
  139. cfg->min_word_len = DEFAULT_MIN_WORD;
  140. cfg->max_word_len = DEFAULT_MAX_WORD;
  141. cfg->lua_state = rspamd_lua_init ();
  142. cfg->cache = rspamd_symbols_cache_new (cfg);
  143. cfg->ups_ctx = rspamd_upstreams_library_init ();
  144. cfg->re_cache = rspamd_re_cache_new ();
  145. cfg->doc_strings = ucl_object_typed_new (UCL_OBJECT);
  146. /*
  147. * Unless exim is fixed
  148. */
  149. cfg->enable_shutdown_workaround = TRUE;
  150. cfg->ssl_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4";
  151. cfg->max_message = DEFAULT_MAX_MESSAGE;
  152. cfg->max_pic_size = DEFAULT_MAX_PIC;
  153. cfg->images_cache_size = 256;
  154. cfg->monitored_ctx = rspamd_monitored_ctx_init ();
  155. cfg->neighbours = ucl_object_typed_new (UCL_OBJECT);
  156. #ifdef WITH_HIREDIS
  157. cfg->redis_pool = rspamd_redis_pool_init ();
  158. #endif
  159. REF_INIT_RETAIN (cfg, rspamd_config_free);
  160. return cfg;
  161. }
  162. void
  163. rspamd_config_free (struct rspamd_config *cfg)
  164. {
  165. struct rspamd_config_post_load_script *sc, *sctmp;
  166. rspamd_map_remove_all (cfg);
  167. DL_FOREACH_SAFE (cfg->finish_callbacks, sc, sctmp) {
  168. luaL_unref (cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref);
  169. g_slice_free1 (sizeof (*sc), sc);
  170. }
  171. DL_FOREACH_SAFE (cfg->on_load, sc, sctmp) {
  172. luaL_unref (cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref);
  173. g_slice_free1 (sizeof (*sc), sc);
  174. }
  175. if (cfg->monitored_ctx) {
  176. rspamd_monitored_ctx_destroy (cfg->monitored_ctx);
  177. }
  178. g_list_free (cfg->classifiers);
  179. g_list_free (cfg->metrics_list);
  180. g_list_free (cfg->workers);
  181. rspamd_symbols_cache_destroy (cfg->cache);
  182. #ifdef WITH_HIREDIS
  183. if (cfg->redis_pool) {
  184. rspamd_redis_pool_destroy (cfg->redis_pool);
  185. }
  186. #endif
  187. ucl_object_unref (cfg->rcl_obj);
  188. ucl_object_unref (cfg->config_comments);
  189. ucl_object_unref (cfg->doc_strings);
  190. ucl_object_unref (cfg->neighbours);
  191. g_hash_table_remove_all (cfg->metrics);
  192. g_hash_table_unref (cfg->metrics);
  193. g_hash_table_unref (cfg->c_modules);
  194. g_hash_table_remove_all (cfg->composite_symbols);
  195. g_hash_table_unref (cfg->composite_symbols);
  196. g_hash_table_remove_all (cfg->cfg_params);
  197. g_hash_table_unref (cfg->cfg_params);
  198. g_hash_table_destroy (cfg->metrics_symbols);
  199. g_hash_table_unref (cfg->classifiers_symbols);
  200. g_hash_table_unref (cfg->debug_modules);
  201. g_hash_table_unref (cfg->explicit_modules);
  202. g_hash_table_unref (cfg->wrk_parsers);
  203. g_hash_table_unref (cfg->trusted_keys);
  204. if (cfg->checksum) {
  205. g_free (cfg->checksum);
  206. }
  207. rspamd_re_cache_unref (cfg->re_cache);
  208. rspamd_upstreams_library_unref (cfg->ups_ctx);
  209. rspamd_mempool_delete (cfg->cfg_pool);
  210. lua_close (cfg->lua_state);
  211. REF_RELEASE (cfg->libs_ctx);
  212. g_slice_free1 (sizeof (*cfg), cfg);
  213. }
  214. const ucl_object_t *
  215. rspamd_config_get_module_opt (struct rspamd_config *cfg,
  216. const gchar *module_name,
  217. const gchar *opt_name)
  218. {
  219. const ucl_object_t *res = NULL, *sec;
  220. sec = ucl_obj_get_key (cfg->rcl_obj, module_name);
  221. if (sec != NULL) {
  222. res = ucl_obj_get_key (sec, opt_name);
  223. }
  224. return res;
  225. }
  226. gchar
  227. rspamd_config_parse_flag (const gchar *str, guint len)
  228. {
  229. gchar c;
  230. if (!str || !*str) {
  231. return -1;
  232. }
  233. if (len == 0) {
  234. len = strlen (str);
  235. }
  236. switch (len) {
  237. case 1:
  238. c = g_ascii_tolower (*str);
  239. if (c == 'y' || c == '1') {
  240. return 1;
  241. }
  242. else if (c == 'n' || c == '0') {
  243. return 0;
  244. }
  245. break;
  246. case 2:
  247. if (g_ascii_strncasecmp (str, "no", len) == 0) {
  248. return 0;
  249. }
  250. else if (g_ascii_strncasecmp (str, "on", len) == 0) {
  251. return 1;
  252. }
  253. break;
  254. case 3:
  255. if (g_ascii_strncasecmp (str, "yes", len) == 0) {
  256. return 1;
  257. }
  258. else if (g_ascii_strncasecmp (str, "off", len) == 0) {
  259. return 0;
  260. }
  261. break;
  262. case 4:
  263. if (g_ascii_strncasecmp (str, "true", len) == 0) {
  264. return 1;
  265. }
  266. break;
  267. case 5:
  268. if (g_ascii_strncasecmp (str, "false", len) == 0) {
  269. return 0;
  270. }
  271. break;
  272. }
  273. return -1;
  274. }
  275. static gboolean
  276. rspamd_config_process_var (struct rspamd_config *cfg, const rspamd_ftok_t *var,
  277. const rspamd_ftok_t *content)
  278. {
  279. guint flags = RSPAMD_LOG_FLAG_DEFAULT;
  280. struct rspamd_log_format *lf;
  281. enum rspamd_log_format_type type;
  282. rspamd_ftok_t tok;
  283. gint id;
  284. g_assert (var != NULL);
  285. if (var->len > 3 && rspamd_lc_cmp (var->begin, "if_", 3) == 0) {
  286. flags |= RSPAMD_LOG_FLAG_CONDITION;
  287. tok.begin = var->begin + 3;
  288. tok.len = var->len - 3;
  289. }
  290. else {
  291. tok.begin = var->begin;
  292. tok.len = var->len;
  293. }
  294. /* Now compare variable and check what we have */
  295. if (rspamd_ftok_cstr_equal (&tok, "mid", TRUE)) {
  296. type = RSPAMD_LOG_MID;
  297. }
  298. else if (rspamd_ftok_cstr_equal (&tok, "qid", TRUE)) {
  299. type = RSPAMD_LOG_QID;
  300. }
  301. else if (rspamd_ftok_cstr_equal (&tok, "user", TRUE)) {
  302. type = RSPAMD_LOG_USER;
  303. }
  304. else if (rspamd_ftok_cstr_equal (&tok, "is_spam", TRUE)) {
  305. type = RSPAMD_LOG_ISSPAM;
  306. }
  307. else if (rspamd_ftok_cstr_equal (&tok, "action", TRUE)) {
  308. type = RSPAMD_LOG_ACTION;
  309. }
  310. else if (rspamd_ftok_cstr_equal (&tok, "scores", TRUE)) {
  311. type = RSPAMD_LOG_SCORES;
  312. }
  313. else if (rspamd_ftok_cstr_equal (&tok, "symbols", TRUE)) {
  314. type = RSPAMD_LOG_SYMBOLS;
  315. }
  316. else if (rspamd_ftok_cstr_equal (&tok, "symbols_scores", TRUE)) {
  317. type = RSPAMD_LOG_SYMBOLS;
  318. flags |= RSPAMD_LOG_FLAG_SYMBOLS_SCORES;
  319. }
  320. else if (rspamd_ftok_cstr_equal (&tok, "symbols_params", TRUE)) {
  321. type = RSPAMD_LOG_SYMBOLS;
  322. flags |= RSPAMD_LOG_FLAG_SYMBOLS_PARAMS;
  323. }
  324. else if (rspamd_ftok_cstr_equal (&tok, "symbols_scores_params", TRUE)) {
  325. type = RSPAMD_LOG_SYMBOLS;
  326. flags |= RSPAMD_LOG_FLAG_SYMBOLS_PARAMS|RSPAMD_LOG_FLAG_SYMBOLS_SCORES;
  327. }
  328. else if (rspamd_ftok_cstr_equal (&tok, "ip", TRUE)) {
  329. type = RSPAMD_LOG_IP;
  330. }
  331. else if (rspamd_ftok_cstr_equal (&tok, "len", TRUE)) {
  332. type = RSPAMD_LOG_LEN;
  333. }
  334. else if (rspamd_ftok_cstr_equal (&tok, "dns_req", TRUE)) {
  335. type = RSPAMD_LOG_DNS_REQ;
  336. }
  337. else if (rspamd_ftok_cstr_equal (&tok, "smtp_from", TRUE)) {
  338. type = RSPAMD_LOG_SMTP_FROM;
  339. }
  340. else if (rspamd_ftok_cstr_equal (&tok, "mime_from", TRUE)) {
  341. type = RSPAMD_LOG_MIME_FROM;
  342. }
  343. else if (rspamd_ftok_cstr_equal (&tok, "smtp_rcpt", TRUE)) {
  344. type = RSPAMD_LOG_SMTP_RCPT;
  345. }
  346. else if (rspamd_ftok_cstr_equal (&tok, "mime_rcpt", TRUE)) {
  347. type = RSPAMD_LOG_MIME_RCPT;
  348. }
  349. else if (rspamd_ftok_cstr_equal (&tok, "smtp_rcpts", TRUE)) {
  350. type = RSPAMD_LOG_SMTP_RCPTS;
  351. }
  352. else if (rspamd_ftok_cstr_equal (&tok, "mime_rcpts", TRUE)) {
  353. type = RSPAMD_LOG_MIME_RCPTS;
  354. }
  355. else if (rspamd_ftok_cstr_equal (&tok, "time_real", TRUE)) {
  356. type = RSPAMD_LOG_TIME_REAL;
  357. }
  358. else if (rspamd_ftok_cstr_equal (&tok, "time_virtual", TRUE)) {
  359. type = RSPAMD_LOG_TIME_VIRTUAL;
  360. }
  361. else if (rspamd_ftok_cstr_equal (&tok, "lua", TRUE)) {
  362. type = RSPAMD_LOG_LUA;
  363. }
  364. else if (rspamd_ftok_cstr_equal (&tok, "digest", TRUE) ||
  365. rspamd_ftok_cstr_equal (&tok, "checksum", TRUE)) {
  366. type = RSPAMD_LOG_DIGEST;
  367. }
  368. else {
  369. msg_err_config ("unknown log variable: %T", &tok);
  370. return FALSE;
  371. }
  372. lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
  373. lf->type = type;
  374. lf->flags = flags;
  375. if (type != RSPAMD_LOG_LUA) {
  376. if (content && content->len > 0) {
  377. lf->data = rspamd_mempool_alloc0 (cfg->cfg_pool,
  378. sizeof (rspamd_ftok_t));
  379. memcpy (lf->data, content, sizeof (*content));
  380. lf->len = sizeof (*content);
  381. }
  382. }
  383. else {
  384. /* Load lua code and ensure that we have function ref returned */
  385. if (!content || content->len == 0) {
  386. msg_err_config ("lua variable needs content: %T", &tok);
  387. return FALSE;
  388. }
  389. if (luaL_loadbuffer (cfg->lua_state, content->begin, content->len,
  390. "lua log variable") != 0) {
  391. msg_err_config ("error loading lua code: '%T': %s", content,
  392. lua_tostring (cfg->lua_state, -1));
  393. return FALSE;
  394. }
  395. if (lua_pcall (cfg->lua_state, 0, 1, 0) != 0) {
  396. msg_err_config ("error executing lua code: '%T': %s", content,
  397. lua_tostring (cfg->lua_state, -1));
  398. lua_pop (cfg->lua_state, 1);
  399. return FALSE;
  400. }
  401. if (lua_type (cfg->lua_state, -1) != LUA_TFUNCTION) {
  402. msg_err_config ("lua variable should return function: %T", content);
  403. lua_pop (cfg->lua_state, 1);
  404. return FALSE;
  405. }
  406. id = luaL_ref (cfg->lua_state, LUA_REGISTRYINDEX);
  407. lf->data = GINT_TO_POINTER (id);
  408. lf->len = 0;
  409. }
  410. DL_APPEND (cfg->log_format, lf);
  411. return TRUE;
  412. }
  413. static gboolean
  414. rspamd_config_parse_log_format (struct rspamd_config *cfg)
  415. {
  416. const gchar *p, *c, *end, *s;
  417. gchar *d;
  418. struct rspamd_log_format *lf = NULL;
  419. rspamd_ftok_t var, var_content;
  420. enum {
  421. parse_str,
  422. parse_dollar,
  423. parse_var_name,
  424. parse_var_content,
  425. } state = parse_str;
  426. gint braces = 0;
  427. g_assert (cfg != NULL);
  428. c = cfg->log_format_str;
  429. if (c == NULL) {
  430. return FALSE;
  431. }
  432. p = c;
  433. end = p + strlen (p);
  434. while (p < end) {
  435. switch (state) {
  436. case parse_str:
  437. if (*p == '$') {
  438. state = parse_dollar;
  439. }
  440. else {
  441. p ++;
  442. }
  443. break;
  444. case parse_dollar:
  445. if (p > c) {
  446. /* We have string element that we need to store */
  447. lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
  448. lf->type = RSPAMD_LOG_STRING;
  449. lf->data = rspamd_mempool_alloc (cfg->cfg_pool, p - c + 1);
  450. /* Filter \r\n from the destination */
  451. s = c;
  452. d = lf->data;
  453. while (s < p) {
  454. if (*s != '\r' && *s != '\n') {
  455. *d++ = *s++;
  456. }
  457. else {
  458. *d ++ = ' ';
  459. s++;
  460. }
  461. }
  462. *d = '\0';
  463. lf->len = d - (char *) lf->data;
  464. DL_APPEND (cfg->log_format, lf);
  465. lf = NULL;
  466. }
  467. p++;
  468. c = p;
  469. state = parse_var_name;
  470. break;
  471. case parse_var_name:
  472. if (*p == '{') {
  473. var.begin = c;
  474. var.len = p - c;
  475. p ++;
  476. c = p;
  477. state = parse_var_content;
  478. braces = 1;
  479. }
  480. else if (*p != '_' && *p != '-' && !g_ascii_isalnum (*p)) {
  481. /* Variable with no content */
  482. var.begin = c;
  483. var.len = p - c;
  484. c = p;
  485. if (!rspamd_config_process_var (cfg, &var, NULL)) {
  486. return FALSE;
  487. }
  488. state = parse_str;
  489. }
  490. else {
  491. p++;
  492. }
  493. break;
  494. case parse_var_content:
  495. if (*p == '}' && --braces == 0) {
  496. var_content.begin = c;
  497. var_content.len = p - c;
  498. p ++;
  499. c = p;
  500. if (!rspamd_config_process_var (cfg, &var, &var_content)) {
  501. return FALSE;
  502. }
  503. state = parse_str;
  504. }
  505. else if (*p == '{') {
  506. braces ++;
  507. p ++;
  508. }
  509. else {
  510. p++;
  511. }
  512. break;
  513. }
  514. }
  515. /* Last state */
  516. switch (state) {
  517. case parse_str:
  518. if (p > c) {
  519. /* We have string element that we need to store */
  520. lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
  521. lf->type = RSPAMD_LOG_STRING;
  522. lf->data = rspamd_mempool_alloc (cfg->cfg_pool, p - c + 1);
  523. /* Filter \r\n from the destination */
  524. s = c;
  525. d = lf->data;
  526. while (s < p) {
  527. if (*s != '\r' && *s != '\n') {
  528. *d++ = *s++;
  529. }
  530. else {
  531. *d++ = ' ';
  532. s++;
  533. }
  534. }
  535. *d = '\0';
  536. lf->len = d - (char *)lf->data;
  537. DL_APPEND (cfg->log_format, lf);
  538. lf = NULL;
  539. }
  540. break;
  541. case parse_var_name:
  542. var.begin = c;
  543. var.len = p - c;
  544. if (!rspamd_config_process_var (cfg, &var, NULL)) {
  545. return FALSE;
  546. }
  547. break;
  548. case parse_dollar:
  549. case parse_var_content:
  550. msg_err_config ("cannot parse log format %s: incomplete string",
  551. cfg->log_format_str);
  552. return FALSE;
  553. break;
  554. }
  555. return TRUE;
  556. }
  557. /*
  558. * Perform post load actions
  559. */
  560. gboolean
  561. rspamd_config_post_load (struct rspamd_config *cfg,
  562. enum rspamd_post_load_options opts)
  563. {
  564. #ifdef HAVE_CLOCK_GETTIME
  565. struct timespec ts;
  566. #endif
  567. struct rspamd_metric *def_metric;
  568. gboolean ret = TRUE;
  569. #ifdef HAVE_CLOCK_GETTIME
  570. #ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
  571. clock_getres (CLOCK_PROCESS_CPUTIME_ID, &ts);
  572. # elif defined(HAVE_CLOCK_VIRTUAL)
  573. clock_getres (CLOCK_VIRTUAL, &ts);
  574. # else
  575. clock_getres (CLOCK_REALTIME, &ts);
  576. # endif
  577. cfg->clock_res = log10 (1000000. / ts.tv_nsec);
  578. if (cfg->clock_res < 0) {
  579. cfg->clock_res = 0;
  580. }
  581. if (cfg->clock_res > 3) {
  582. cfg->clock_res = 3;
  583. }
  584. #else
  585. /* For gettimeofday */
  586. cfg->clock_res = 1;
  587. #endif
  588. rspamd_regexp_library_init ();
  589. rspamd_multipattern_library_init (cfg->hs_cache_dir,
  590. cfg->libs_ctx->crypto_ctx);
  591. #ifdef WITH_HYPERSCAN
  592. if (!cfg->disable_hyperscan) {
  593. if (!(cfg->libs_ctx->crypto_ctx->cpu_config & CPUID_SSSE3)) {
  594. msg_warn_config ("CPU doesn't have SSSE3 instructions set "
  595. "required for hyperscan, disable it");
  596. cfg->disable_hyperscan = TRUE;
  597. }
  598. }
  599. #endif
  600. if ((def_metric =
  601. g_hash_table_lookup (cfg->metrics, DEFAULT_METRIC)) == NULL) {
  602. def_metric = rspamd_config_new_metric (cfg, NULL, DEFAULT_METRIC);
  603. def_metric->actions[METRIC_ACTION_REJECT].score = DEFAULT_SCORE;
  604. }
  605. if (opts & RSPAMD_CONFIG_INIT_URL) {
  606. if (cfg->tld_file == NULL) {
  607. /* Try to guess tld file */
  608. GString *fpath = g_string_new (NULL);
  609. rspamd_printf_gstring (fpath, "%s%c%s", RSPAMD_PLUGINSDIR,
  610. G_DIR_SEPARATOR, "effective_tld_names.dat");
  611. if (access (fpath->str, R_OK) != -1) {
  612. msg_debug_config ("url_tld option is not specified but %s is available,"
  613. " therefore this file is assumed as TLD file for URL"
  614. " extraction", fpath->str);
  615. cfg->tld_file = rspamd_mempool_strdup (cfg->cfg_pool, fpath->str);
  616. }
  617. else {
  618. if (opts & RSPAMD_CONFIG_INIT_VALIDATE) {
  619. msg_err_config ("no url_tld option has been specified");
  620. ret = FALSE;
  621. }
  622. }
  623. g_string_free (fpath, TRUE);
  624. }
  625. else {
  626. if (access (cfg->tld_file, R_OK) == -1) {
  627. if (opts & RSPAMD_CONFIG_INIT_VALIDATE) {
  628. ret = FALSE;
  629. msg_err_config ("cannot access tld file %s: %s", cfg->tld_file,
  630. strerror (errno));
  631. }
  632. else {
  633. msg_debug_config ("cannot access tld file %s: %s", cfg->tld_file,
  634. strerror (errno));
  635. cfg->tld_file = NULL;
  636. }
  637. }
  638. }
  639. if (opts & RSPAMD_CONFIG_INIT_NO_TLD) {
  640. rspamd_url_init (NULL);
  641. }
  642. else {
  643. rspamd_url_init (cfg->tld_file);
  644. }
  645. }
  646. init_dynamic_config (cfg);
  647. /* Insert classifiers symbols */
  648. rspamd_config_insert_classify_symbols (cfg);
  649. /* Parse format string that we have */
  650. if (!rspamd_config_parse_log_format (cfg)) {
  651. msg_err_config ("cannot parse log format, task logging will not be available");
  652. }
  653. if (opts & RSPAMD_CONFIG_INIT_SYMCACHE) {
  654. /* Init config cache */
  655. rspamd_symbols_cache_init (cfg->cache);
  656. /* Init re cache */
  657. rspamd_re_cache_init (cfg->re_cache, cfg);
  658. }
  659. if (opts & RSPAMD_CONFIG_INIT_LIBS) {
  660. /* Config other libraries */
  661. rspamd_config_libs (cfg->libs_ctx, cfg);
  662. }
  663. /* Validate cache */
  664. if (opts & RSPAMD_CONFIG_INIT_VALIDATE) {
  665. return rspamd_symbols_cache_validate (cfg->cache, cfg, FALSE) && ret;
  666. }
  667. return ret;
  668. }
  669. #if 0
  670. void
  671. parse_err (const gchar *fmt, ...)
  672. {
  673. va_list aq;
  674. gchar logbuf[BUFSIZ], readbuf[32];
  675. gint r;
  676. va_start (aq, fmt);
  677. rspamd_strlcpy (readbuf, yytext, sizeof (readbuf));
  678. r = snprintf (logbuf,
  679. sizeof (logbuf),
  680. "config file parse error! line: %d, text: %s, reason: ",
  681. yylineno,
  682. readbuf);
  683. r += vsnprintf (logbuf + r, sizeof (logbuf) - r, fmt, aq);
  684. va_end (aq);
  685. g_critical ("%s", logbuf);
  686. }
  687. void
  688. parse_warn (const gchar *fmt, ...)
  689. {
  690. va_list aq;
  691. gchar logbuf[BUFSIZ], readbuf[32];
  692. gint r;
  693. va_start (aq, fmt);
  694. rspamd_strlcpy (readbuf, yytext, sizeof (readbuf));
  695. r = snprintf (logbuf,
  696. sizeof (logbuf),
  697. "config file parse warning! line: %d, text: %s, reason: ",
  698. yylineno,
  699. readbuf);
  700. r += vsnprintf (logbuf + r, sizeof (logbuf) - r, fmt, aq);
  701. va_end (aq);
  702. g_warning ("%s", logbuf);
  703. }
  704. #endif
  705. void
  706. rspamd_config_unescape_quotes (gchar *line)
  707. {
  708. gchar *c = line, *t;
  709. while (*c) {
  710. if (*c == '\\' && *(c + 1) == '"') {
  711. t = c;
  712. while (*t) {
  713. *t = *(t + 1);
  714. t++;
  715. }
  716. }
  717. c++;
  718. }
  719. }
  720. GList *
  721. rspamd_config_parse_comma_list (rspamd_mempool_t * pool, const gchar *line)
  722. {
  723. GList *res = NULL;
  724. const gchar *c, *p;
  725. gchar *str;
  726. c = line;
  727. p = c;
  728. while (*p) {
  729. if (*p == ',' && *c != *p) {
  730. str = rspamd_mempool_alloc (pool, p - c + 1);
  731. rspamd_strlcpy (str, c, p - c + 1);
  732. res = g_list_prepend (res, str);
  733. /* Skip spaces */
  734. while (g_ascii_isspace (*(++p))) ;
  735. c = p;
  736. continue;
  737. }
  738. p++;
  739. }
  740. if (res != NULL) {
  741. rspamd_mempool_add_destructor (pool,
  742. (rspamd_mempool_destruct_t) g_list_free,
  743. res);
  744. }
  745. return res;
  746. }
  747. struct rspamd_classifier_config *
  748. rspamd_config_new_classifier (struct rspamd_config *cfg,
  749. struct rspamd_classifier_config *c)
  750. {
  751. if (c == NULL) {
  752. c =
  753. rspamd_mempool_alloc0 (cfg->cfg_pool,
  754. sizeof (struct rspamd_classifier_config));
  755. }
  756. if (c->labels == NULL) {
  757. c->labels = g_hash_table_new_full (rspamd_str_hash,
  758. rspamd_str_equal,
  759. NULL,
  760. (GDestroyNotify)g_list_free);
  761. rspamd_mempool_add_destructor (cfg->cfg_pool,
  762. (rspamd_mempool_destruct_t) g_hash_table_destroy,
  763. c->labels);
  764. }
  765. return c;
  766. }
  767. struct rspamd_statfile_config *
  768. rspamd_config_new_statfile (struct rspamd_config *cfg,
  769. struct rspamd_statfile_config *c)
  770. {
  771. if (c == NULL) {
  772. c =
  773. rspamd_mempool_alloc0 (cfg->cfg_pool,
  774. sizeof (struct rspamd_statfile_config));
  775. }
  776. return c;
  777. }
  778. struct rspamd_metric *
  779. rspamd_config_new_metric (struct rspamd_config *cfg, struct rspamd_metric *c,
  780. const gchar *name)
  781. {
  782. int i;
  783. if (c == NULL) {
  784. c = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (struct rspamd_metric));
  785. c->grow_factor = 1.0;
  786. c->symbols = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  787. c->groups = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
  788. for (i = METRIC_ACTION_REJECT; i < METRIC_ACTION_MAX; i++) {
  789. c->actions[i].score = NAN;
  790. c->actions[i].action = i;
  791. c->actions[i].priority = 0;
  792. }
  793. c->subject = SPAM_SUBJECT;
  794. c->name = rspamd_mempool_strdup (cfg->cfg_pool, name);
  795. rspamd_mempool_add_destructor (cfg->cfg_pool,
  796. (rspamd_mempool_destruct_t) g_hash_table_unref,
  797. c->symbols);
  798. rspamd_mempool_add_destructor (cfg->cfg_pool,
  799. (rspamd_mempool_destruct_t) g_hash_table_unref,
  800. c->groups);
  801. g_hash_table_insert (cfg->metrics, (void *)c->name, c);
  802. cfg->metrics_list = g_list_prepend (cfg->metrics_list, c);
  803. if (strcmp (c->name, DEFAULT_METRIC) == 0) {
  804. cfg->default_metric = c;
  805. }
  806. }
  807. return c;
  808. }
  809. struct rspamd_symbols_group *
  810. rspamd_config_new_group (struct rspamd_config *cfg, struct rspamd_metric *metric,
  811. const gchar *name)
  812. {
  813. struct rspamd_symbols_group *gr;
  814. gr = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*gr));
  815. gr->symbols = g_hash_table_new (rspamd_strcase_hash,
  816. rspamd_strcase_equal);
  817. rspamd_mempool_add_destructor (cfg->cfg_pool,
  818. (rspamd_mempool_destruct_t)g_hash_table_unref, gr->symbols);
  819. gr->name = rspamd_mempool_strdup (cfg->cfg_pool, name);
  820. g_hash_table_insert (metric->groups, gr->name, gr);
  821. return gr;
  822. }
  823. static void
  824. rspamd_worker_conf_dtor (struct rspamd_worker_conf *wcf)
  825. {
  826. if (wcf) {
  827. /* XXX: fix reload memory leak somehow */
  828. /* ucl_object_unref (wcf->options); */
  829. g_queue_free (wcf->active_workers);
  830. g_hash_table_unref (wcf->params);
  831. g_slice_free1 (sizeof (*wcf), wcf);
  832. }
  833. }
  834. static void
  835. rspamd_worker_conf_cfg_fin (gpointer d)
  836. {
  837. struct rspamd_worker_conf *wcf = d;
  838. REF_RELEASE (wcf);
  839. }
  840. struct rspamd_worker_conf *
  841. rspamd_config_new_worker (struct rspamd_config *cfg,
  842. struct rspamd_worker_conf *c)
  843. {
  844. if (c == NULL) {
  845. c = g_slice_alloc0 (sizeof (struct rspamd_worker_conf));
  846. c->params = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  847. c->active_workers = g_queue_new ();
  848. #ifdef HAVE_SC_NPROCESSORS_ONLN
  849. c->count = sysconf (_SC_NPROCESSORS_ONLN);
  850. #else
  851. c->count = DEFAULT_WORKERS_NUM;
  852. #endif
  853. c->rlimit_nofile = 0;
  854. c->rlimit_maxcore = 0;
  855. REF_INIT_RETAIN (c, rspamd_worker_conf_dtor);
  856. rspamd_mempool_add_destructor (cfg->cfg_pool,
  857. rspamd_worker_conf_cfg_fin, c);
  858. }
  859. return c;
  860. }
  861. static bool
  862. rspamd_include_map_handler (const guchar *data, gsize len,
  863. const ucl_object_t *args, void * ud)
  864. {
  865. struct rspamd_config *cfg = (struct rspamd_config *)ud;
  866. struct rspamd_ucl_map_cbdata *cbdata, **pcbdata;
  867. gchar *map_line;
  868. map_line = rspamd_mempool_alloc (cfg->cfg_pool, len + 1);
  869. rspamd_strlcpy (map_line, data, len + 1);
  870. cbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata));
  871. pcbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata *));
  872. cbdata->buf = NULL;
  873. cbdata->cfg = cfg;
  874. *pcbdata = cbdata;
  875. return rspamd_map_add (cfg,
  876. map_line,
  877. "ucl include",
  878. rspamd_ucl_read_cb,
  879. rspamd_ucl_fin_cb,
  880. (void **)pcbdata);
  881. }
  882. /*
  883. * Variables:
  884. * $CONFDIR - configuration directory
  885. * $LOCAL_CONFDIR - local configuration directory
  886. * $RUNDIR - local states directory
  887. * $DBDIR - databases dir
  888. * $LOGDIR - logs dir
  889. * $PLUGINSDIR - pluggins dir
  890. * $PREFIX - installation prefix
  891. * $VERSION - rspamd version
  892. */
  893. #define RSPAMD_CONFDIR_MACRO "CONFDIR"
  894. #define RSPAMD_LOCAL_CONFDIR_MACRO "LOCAL_CONFDIR"
  895. #define RSPAMD_RUNDIR_MACRO "RUNDIR"
  896. #define RSPAMD_DBDIR_MACRO "DBDIR"
  897. #define RSPAMD_LOGDIR_MACRO "LOGDIR"
  898. #define RSPAMD_PLUGINSDIR_MACRO "PLUGINSDIR"
  899. #define RSPAMD_RULESDIR_MACRO "RULESDIR"
  900. #define RSPAMD_WWWDIR_MACRO "WWWDIR"
  901. #define RSPAMD_PREFIX_MACRO "PREFIX"
  902. #define RSPAMD_VERSION_MACRO "VERSION"
  903. #define RSPAMD_VERSION_MAJOR_MACRO "VERSION_MAJOR"
  904. #define RSPAMD_VERSION_MINOR_MACRO "VERSION_MINOR"
  905. #define RSPAMD_VERSION_PATCH_MACRO "VERSION_PATCH"
  906. #define RSPAMD_BRANCH_VERSION_MACRO "BRANCH_VERSION"
  907. void
  908. rspamd_ucl_add_conf_variables (struct ucl_parser *parser, GHashTable *vars)
  909. {
  910. GHashTableIter it;
  911. gpointer k, v;
  912. ucl_parser_register_variable (parser,
  913. RSPAMD_CONFDIR_MACRO,
  914. RSPAMD_CONFDIR);
  915. ucl_parser_register_variable (parser,
  916. RSPAMD_LOCAL_CONFDIR_MACRO,
  917. RSPAMD_LOCAL_CONFDIR);
  918. ucl_parser_register_variable (parser, RSPAMD_RUNDIR_MACRO,
  919. RSPAMD_RUNDIR);
  920. ucl_parser_register_variable (parser, RSPAMD_DBDIR_MACRO,
  921. RSPAMD_DBDIR);
  922. ucl_parser_register_variable (parser, RSPAMD_LOGDIR_MACRO,
  923. RSPAMD_LOGDIR);
  924. ucl_parser_register_variable (parser,
  925. RSPAMD_PLUGINSDIR_MACRO,
  926. RSPAMD_PLUGINSDIR);
  927. ucl_parser_register_variable (parser,
  928. RSPAMD_RULESDIR_MACRO,
  929. RSPAMD_RULESDIR);
  930. ucl_parser_register_variable (parser, RSPAMD_WWWDIR_MACRO,
  931. RSPAMD_WWWDIR);
  932. ucl_parser_register_variable (parser, RSPAMD_PREFIX_MACRO,
  933. RSPAMD_PREFIX);
  934. ucl_parser_register_variable (parser, RSPAMD_VERSION_MACRO, RVERSION);
  935. ucl_parser_register_variable (parser, RSPAMD_VERSION_MAJOR_MACRO,
  936. RSPAMD_VERSION_MAJOR);
  937. ucl_parser_register_variable (parser, RSPAMD_VERSION_MINOR_MACRO,
  938. RSPAMD_VERSION_MINOR);
  939. ucl_parser_register_variable (parser, RSPAMD_VERSION_PATCH_MACRO,
  940. RSPAMD_VERSION_PATCH);
  941. ucl_parser_register_variable (parser, RSPAMD_BRANCH_VERSION_MACRO,
  942. RSPAMD_VERSION_BRANCH);
  943. if (vars != NULL) {
  944. g_hash_table_iter_init (&it, vars);
  945. while (g_hash_table_iter_next (&it, &k, &v)) {
  946. ucl_parser_register_variable (parser, k, v);
  947. }
  948. }
  949. }
  950. void
  951. rspamd_ucl_add_conf_macros (struct ucl_parser *parser,
  952. struct rspamd_config *cfg)
  953. {
  954. ucl_parser_register_macro (parser,
  955. "include_map",
  956. rspamd_include_map_handler,
  957. cfg);
  958. }
  959. static void
  960. symbols_classifiers_callback (gpointer key, gpointer value, gpointer ud)
  961. {
  962. struct rspamd_config *cfg = ud;
  963. /* Actually, statistics should act like any ordinary symbol */
  964. rspamd_symbols_cache_add_symbol (cfg->cache, key, 0, NULL, NULL,
  965. SYMBOL_TYPE_CLASSIFIER, -1);
  966. }
  967. void
  968. rspamd_config_insert_classify_symbols (struct rspamd_config *cfg)
  969. {
  970. g_hash_table_foreach (cfg->classifiers_symbols,
  971. symbols_classifiers_callback,
  972. cfg);
  973. }
  974. struct rspamd_classifier_config *
  975. rspamd_config_find_classifier (struct rspamd_config *cfg, const gchar *name)
  976. {
  977. GList *cur;
  978. struct rspamd_classifier_config *cf;
  979. if (name == NULL) {
  980. return NULL;
  981. }
  982. cur = cfg->classifiers;
  983. while (cur) {
  984. cf = cur->data;
  985. if (g_ascii_strcasecmp (cf->name, name) == 0) {
  986. return cf;
  987. }
  988. cur = g_list_next (cur);
  989. }
  990. return NULL;
  991. }
  992. gboolean
  993. rspamd_config_check_statfiles (struct rspamd_classifier_config *cf)
  994. {
  995. struct rspamd_statfile_config *st;
  996. gboolean has_other = FALSE, res = FALSE, cur_class;
  997. GList *cur;
  998. /* First check classes directly */
  999. cur = cf->statfiles;
  1000. while (cur) {
  1001. st = cur->data;
  1002. if (!has_other) {
  1003. cur_class = st->is_spam;
  1004. has_other = TRUE;
  1005. }
  1006. else {
  1007. if (cur_class != st->is_spam) {
  1008. return TRUE;
  1009. }
  1010. }
  1011. cur = g_list_next (cur);
  1012. }
  1013. if (!has_other) {
  1014. /* We have only one statfile */
  1015. return FALSE;
  1016. }
  1017. /* We have not detected any statfile that has different class, so turn on euristic based on symbol's name */
  1018. has_other = FALSE;
  1019. cur = cf->statfiles;
  1020. while (cur) {
  1021. st = cur->data;
  1022. if (rspamd_strncasestr (st->symbol, "spam", -1) != NULL) {
  1023. st->is_spam = TRUE;
  1024. }
  1025. else if (rspamd_strncasestr (st->symbol, "ham", -1) != NULL) {
  1026. st->is_spam = FALSE;
  1027. }
  1028. if (!has_other) {
  1029. cur_class = st->is_spam;
  1030. has_other = TRUE;
  1031. }
  1032. else {
  1033. if (cur_class != st->is_spam) {
  1034. res = TRUE;
  1035. }
  1036. }
  1037. cur = g_list_next (cur);
  1038. }
  1039. return res;
  1040. }
  1041. static gchar *
  1042. rspamd_ucl_read_cb (gchar * chunk,
  1043. gint len,
  1044. struct map_cb_data *data,
  1045. gboolean final)
  1046. {
  1047. struct rspamd_ucl_map_cbdata *cbdata = data->cur_data, *prev;
  1048. if (cbdata == NULL) {
  1049. cbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata));
  1050. prev = data->prev_data;
  1051. cbdata->buf = g_string_sized_new (BUFSIZ);
  1052. cbdata->cfg = prev->cfg;
  1053. data->cur_data = cbdata;
  1054. }
  1055. g_string_append_len (cbdata->buf, chunk, len);
  1056. /* Say not to copy any part of this buffer */
  1057. return NULL;
  1058. }
  1059. static void
  1060. rspamd_ucl_fin_cb (struct map_cb_data *data)
  1061. {
  1062. struct rspamd_ucl_map_cbdata *cbdata = data->cur_data, *prev =
  1063. data->prev_data;
  1064. ucl_object_t *obj;
  1065. struct ucl_parser *parser;
  1066. ucl_object_iter_t it = NULL;
  1067. const ucl_object_t *cur;
  1068. struct rspamd_config *cfg = data->map->cfg;
  1069. if (prev != NULL) {
  1070. if (prev->buf != NULL) {
  1071. g_string_free (prev->buf, TRUE);
  1072. }
  1073. g_free (prev);
  1074. }
  1075. if (cbdata == NULL) {
  1076. msg_err_config ("map fin error: new data is NULL");
  1077. return;
  1078. }
  1079. /* New data available */
  1080. parser = ucl_parser_new (0);
  1081. if (!ucl_parser_add_chunk (parser, cbdata->buf->str,
  1082. cbdata->buf->len)) {
  1083. msg_err_config ("cannot parse map %s: %s",
  1084. data->map->name,
  1085. ucl_parser_get_error (parser));
  1086. ucl_parser_free (parser);
  1087. }
  1088. else {
  1089. obj = ucl_parser_get_object (parser);
  1090. ucl_parser_free (parser);
  1091. it = NULL;
  1092. while ((cur = ucl_object_iterate (obj, &it, true))) {
  1093. ucl_object_replace_key (cbdata->cfg->rcl_obj, (ucl_object_t *)cur,
  1094. cur->key, cur->keylen, false);
  1095. }
  1096. ucl_object_unref (obj);
  1097. }
  1098. }
  1099. gboolean
  1100. rspamd_check_module (struct rspamd_config *cfg, module_t *mod)
  1101. {
  1102. gboolean ret = TRUE;
  1103. if (mod != NULL) {
  1104. if (mod->module_version != RSPAMD_CUR_MODULE_VERSION) {
  1105. msg_err_config ("module %s has incorrect version %xd (%xd expected)",
  1106. mod->name, (gint)mod->module_version, RSPAMD_CUR_MODULE_VERSION);
  1107. ret = FALSE;
  1108. }
  1109. if (ret && mod->rspamd_version != RSPAMD_VERSION_NUM) {
  1110. msg_err_config ("module %s has incorrect rspamd version %xL (%xL expected)",
  1111. mod->name, mod->rspamd_version, RSPAMD_VERSION_NUM);
  1112. ret = FALSE;
  1113. }
  1114. if (ret && strcmp (mod->rspamd_features, RSPAMD_FEATURES) != 0) {
  1115. msg_err_config ("module %s has incorrect rspamd features '%s' ('%s' expected)",
  1116. mod->name, mod->rspamd_features, RSPAMD_FEATURES);
  1117. ret = FALSE;
  1118. }
  1119. }
  1120. else {
  1121. ret = FALSE;
  1122. }
  1123. return ret;
  1124. }
  1125. gboolean
  1126. rspamd_check_worker (struct rspamd_config *cfg, worker_t *wrk)
  1127. {
  1128. gboolean ret = TRUE;
  1129. if (wrk != NULL) {
  1130. if (wrk->worker_version != RSPAMD_CUR_WORKER_VERSION) {
  1131. msg_err_config ("worker %s has incorrect version %xd (%xd expected)",
  1132. wrk->name, wrk->worker_version, RSPAMD_CUR_WORKER_VERSION);
  1133. ret = FALSE;
  1134. }
  1135. if (ret && wrk->rspamd_version != RSPAMD_VERSION_NUM) {
  1136. msg_err_config ("worker %s has incorrect rspamd version %xL (%xL expected)",
  1137. wrk->name, wrk->rspamd_version, RSPAMD_VERSION_NUM);
  1138. ret = FALSE;
  1139. }
  1140. if (ret && strcmp (wrk->rspamd_features, RSPAMD_FEATURES) != 0) {
  1141. msg_err_config ("worker %s has incorrect rspamd features '%s' ('%s' expected)",
  1142. wrk->name, wrk->rspamd_features, RSPAMD_FEATURES);
  1143. ret = FALSE;
  1144. }
  1145. }
  1146. else {
  1147. ret = FALSE;
  1148. }
  1149. return ret;
  1150. }
  1151. gboolean
  1152. rspamd_init_filters (struct rspamd_config *cfg, bool reconfig)
  1153. {
  1154. GList *cur;
  1155. module_t *mod, **pmod;
  1156. struct module_ctx *mod_ctx;
  1157. /* Init all compiled modules */
  1158. if (!reconfig) {
  1159. for (pmod = cfg->compiled_modules; pmod != NULL && *pmod != NULL; pmod ++) {
  1160. mod = *pmod;
  1161. if (rspamd_check_module (cfg, mod)) {
  1162. mod_ctx = g_slice_alloc0 (sizeof (struct module_ctx));
  1163. if (mod->module_init_func (cfg, &mod_ctx) == 0) {
  1164. g_hash_table_insert (cfg->c_modules,
  1165. (gpointer) mod->name,
  1166. mod_ctx);
  1167. mod_ctx->mod = mod;
  1168. }
  1169. }
  1170. }
  1171. }
  1172. /* Now check what's enabled */
  1173. cur = g_list_first (cfg->filters);
  1174. while (cur) {
  1175. /* Perform modules configuring */
  1176. mod_ctx = NULL;
  1177. mod_ctx = g_hash_table_lookup (cfg->c_modules, cur->data);
  1178. if (mod_ctx) {
  1179. mod = mod_ctx->mod;
  1180. mod_ctx->enabled = TRUE;
  1181. if (reconfig) {
  1182. (void)mod->module_reconfig_func (cfg);
  1183. msg_info_config ("reconfig of %s", mod->name);
  1184. }
  1185. else {
  1186. (void)mod->module_config_func (cfg);
  1187. }
  1188. }
  1189. if (mod_ctx == NULL) {
  1190. msg_warn_config ("requested unknown module %s", cur->data);
  1191. }
  1192. cur = g_list_next (cur);
  1193. }
  1194. return rspamd_init_lua_filters (cfg);
  1195. }
  1196. static void
  1197. rspamd_config_new_metric_symbol (struct rspamd_config *cfg,
  1198. struct rspamd_metric *metric, const gchar *symbol,
  1199. gdouble score, const gchar *description, const gchar *group,
  1200. guint flags, guint priority)
  1201. {
  1202. struct rspamd_symbols_group *sym_group;
  1203. struct rspamd_symbol *sym_def;
  1204. GList *metric_list;
  1205. gdouble *score_ptr;
  1206. sym_def =
  1207. rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (struct rspamd_symbol));
  1208. score_ptr = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (gdouble));
  1209. *score_ptr = score;
  1210. sym_def->score = score;
  1211. sym_def->weight_ptr = score_ptr;
  1212. sym_def->name = rspamd_mempool_strdup (cfg->cfg_pool, symbol);
  1213. sym_def->priority = priority;
  1214. sym_def->flags = flags;
  1215. if (description) {
  1216. sym_def->description = rspamd_mempool_strdup (cfg->cfg_pool, description);
  1217. }
  1218. msg_debug_config ("registered symbol %s with weight %.2f in metric %s and group %s",
  1219. sym_def->name, score, metric->name, group);
  1220. g_hash_table_insert (metric->symbols, sym_def->name, sym_def);
  1221. if ((metric_list =
  1222. g_hash_table_lookup (cfg->metrics_symbols, sym_def->name)) == NULL) {
  1223. metric_list = g_list_prepend (NULL, metric);
  1224. g_hash_table_insert (cfg->metrics_symbols, sym_def->name, metric_list);
  1225. }
  1226. else {
  1227. /* Slow but keep start element of list in safe */
  1228. if (!g_list_find (metric_list, metric)) {
  1229. metric_list = g_list_append (metric_list, metric);
  1230. }
  1231. }
  1232. /* Search for symbol group */
  1233. if (group == NULL) {
  1234. group = "ungrouped";
  1235. }
  1236. sym_group = g_hash_table_lookup (metric->groups, group);
  1237. if (sym_group == NULL) {
  1238. /* Create new group */
  1239. sym_group = rspamd_config_new_group (cfg, metric, group);
  1240. }
  1241. sym_def->gr = sym_group;
  1242. g_hash_table_insert (sym_group->symbols, sym_def->name, sym_def);
  1243. }
  1244. gboolean
  1245. rspamd_config_add_metric_symbol (struct rspamd_config *cfg,
  1246. const gchar *metric_name, const gchar *symbol,
  1247. gdouble score, const gchar *description, const gchar *group,
  1248. guint flags, guint priority)
  1249. {
  1250. struct rspamd_symbol *sym_def;
  1251. struct rspamd_metric *metric;
  1252. g_assert (cfg != NULL);
  1253. g_assert (symbol != NULL);
  1254. if (metric_name == NULL) {
  1255. metric_name = DEFAULT_METRIC;
  1256. }
  1257. metric = g_hash_table_lookup (cfg->metrics, metric_name);
  1258. if (metric == NULL) {
  1259. msg_err_config ("metric %s has not been found", metric_name);
  1260. return FALSE;
  1261. }
  1262. sym_def = g_hash_table_lookup (metric->symbols, symbol);
  1263. if (sym_def != NULL) {
  1264. if (sym_def->priority > priority) {
  1265. msg_info_config ("symbol %s has been already registered with "
  1266. "priority %ud, do not override (new priority: %ud)",
  1267. symbol,
  1268. sym_def->priority,
  1269. priority);
  1270. /* But we can still add description */
  1271. if (!sym_def->description && description) {
  1272. sym_def->description = rspamd_mempool_strdup (cfg->cfg_pool,
  1273. description);
  1274. }
  1275. return FALSE;
  1276. }
  1277. else {
  1278. msg_info_config ("symbol %s has been already registered with "
  1279. "priority %ud, override it with new priority: %ud, "
  1280. "old score: %.2f, new score: %.2f",
  1281. symbol,
  1282. sym_def->priority,
  1283. priority,
  1284. sym_def->score,
  1285. score);
  1286. *sym_def->weight_ptr = score;
  1287. sym_def->score = score;
  1288. sym_def->flags = flags;
  1289. if (description) {
  1290. sym_def->description = rspamd_mempool_strdup (cfg->cfg_pool,
  1291. description);
  1292. }
  1293. sym_def->priority = priority;
  1294. return TRUE;
  1295. }
  1296. }
  1297. rspamd_config_new_metric_symbol (cfg, metric, symbol, score, description,
  1298. group, flags, priority);
  1299. return TRUE;
  1300. }
  1301. gboolean
  1302. rspamd_config_is_module_enabled (struct rspamd_config *cfg,
  1303. const gchar *module_name)
  1304. {
  1305. gboolean is_c = FALSE;
  1306. struct rspamd_metric *metric;
  1307. const ucl_object_t *conf, *enabled;
  1308. GList *cur;
  1309. struct rspamd_symbols_group *gr;
  1310. metric = cfg->default_metric;
  1311. if (g_hash_table_lookup (cfg->c_modules, module_name)) {
  1312. is_c = TRUE;
  1313. }
  1314. if (g_hash_table_lookup (cfg->explicit_modules, module_name) != NULL) {
  1315. /* Always load module */
  1316. return TRUE;
  1317. }
  1318. if (is_c) {
  1319. gboolean found = FALSE;
  1320. cur = g_list_first (cfg->filters);
  1321. while (cur) {
  1322. if (strcmp (cur->data, module_name) == 0) {
  1323. found = TRUE;
  1324. break;
  1325. }
  1326. cur = g_list_next (cur);
  1327. }
  1328. if (!found) {
  1329. msg_info_config ("internal module %s is disable in `filters` line",
  1330. module_name);
  1331. return FALSE;
  1332. }
  1333. }
  1334. conf = ucl_object_lookup (cfg->rcl_obj, module_name);
  1335. if (conf == NULL) {
  1336. msg_info_config ("%s module %s is enabled but has not been configured",
  1337. is_c ? "internal" : "lua", module_name);
  1338. if (!is_c) {
  1339. msg_info_config ("%s disabling unconfigured lua module", module_name);
  1340. return FALSE;
  1341. }
  1342. }
  1343. else {
  1344. enabled = ucl_object_lookup (conf, "enabled");
  1345. if (enabled && ucl_object_type (enabled) == UCL_BOOLEAN) {
  1346. if (!ucl_object_toboolean (enabled)) {
  1347. msg_info_config ("%s module %s is disabled in the configuration",
  1348. is_c ? "internal" : "lua", module_name);
  1349. return FALSE;
  1350. }
  1351. }
  1352. }
  1353. if (metric) {
  1354. /* Now we check symbols group */
  1355. gr = g_hash_table_lookup (metric->groups, module_name);
  1356. if (gr) {
  1357. if (gr->disabled) {
  1358. msg_info_config ("%s module %s is disabled in the configuration as "
  1359. "its group has been disabled",
  1360. is_c ? "internal" : "lua", module_name);
  1361. return FALSE;
  1362. }
  1363. }
  1364. }
  1365. return TRUE;
  1366. }
  1367. gboolean
  1368. rspamd_config_set_action_score (struct rspamd_config *cfg,
  1369. const gchar *metric_name,
  1370. const gchar *action_name,
  1371. gdouble score,
  1372. guint priority)
  1373. {
  1374. struct metric_action *act;
  1375. struct rspamd_metric *metric;
  1376. gint act_num;
  1377. g_assert (cfg != NULL);
  1378. g_assert (action_name != NULL);
  1379. if (metric_name == NULL) {
  1380. metric_name = DEFAULT_METRIC;
  1381. }
  1382. metric = g_hash_table_lookup (cfg->metrics, metric_name);
  1383. if (metric == NULL) {
  1384. msg_err_config ("metric %s has not been found", metric_name);
  1385. return FALSE;
  1386. }
  1387. if (!rspamd_action_from_str (action_name, &act_num)) {
  1388. msg_err_config ("invalid action name: %s", action_name);
  1389. return FALSE;
  1390. }
  1391. g_assert (act_num >= METRIC_ACTION_REJECT && act_num < METRIC_ACTION_MAX);
  1392. act = &metric->actions[act_num];
  1393. if (isnan (act->score)) {
  1394. act->score = score;
  1395. act->priority = priority;
  1396. }
  1397. else {
  1398. if (act->priority > priority) {
  1399. msg_info_config ("action %s has been already registered with "
  1400. "priority %ud, do not override (new priority: %ud)",
  1401. action_name,
  1402. act->priority,
  1403. priority);
  1404. return FALSE;
  1405. }
  1406. else {
  1407. msg_info_config ("action %s has been already registered with "
  1408. "priority %ud, override it with new priority: %ud, "
  1409. "old score: %.2f, new score: %.2f",
  1410. action_name,
  1411. act->priority,
  1412. priority,
  1413. act->score,
  1414. score);
  1415. act->score = score;
  1416. act->priority = priority;
  1417. }
  1418. }
  1419. return TRUE;
  1420. }
  1421. gboolean
  1422. rspamd_config_radix_from_ucl (struct rspamd_config *cfg,
  1423. const ucl_object_t *obj,
  1424. const gchar *description,
  1425. radix_compressed_t **target,
  1426. GError **err)
  1427. {
  1428. ucl_type_t type;
  1429. ucl_object_iter_t it = NULL;
  1430. const ucl_object_t *cur, *cur_elt;
  1431. const gchar *str;
  1432. LL_FOREACH (obj, cur_elt) {
  1433. type = ucl_object_type (cur_elt);
  1434. switch (type) {
  1435. case UCL_STRING:
  1436. /* Either map or a list of IPs */
  1437. str = ucl_object_tostring (cur_elt);
  1438. if (rspamd_map_is_map (str)) {
  1439. if (rspamd_map_add_from_ucl (cfg, cur_elt,
  1440. description, rspamd_radix_read, rspamd_radix_fin,
  1441. (void **)target) == NULL) {
  1442. g_set_error (err, g_quark_from_static_string ("rspamd-config"),
  1443. EINVAL, "bad map definition %s for %s", str,
  1444. ucl_object_key (obj));
  1445. return FALSE;
  1446. }
  1447. }
  1448. else {
  1449. /* Just a list */
  1450. if (!radix_add_generic_iplist (str, target, TRUE)) {
  1451. g_set_error (err, g_quark_from_static_string ("rspamd-config"),
  1452. EINVAL, "bad map definition %s for %s", str,
  1453. ucl_object_key (obj));
  1454. return FALSE;
  1455. }
  1456. }
  1457. break;
  1458. case UCL_OBJECT:
  1459. /* Should be a map description */
  1460. if (rspamd_map_add_from_ucl (cfg, cur_elt,
  1461. description, rspamd_radix_read, rspamd_radix_fin,
  1462. (void **)target) == NULL) {
  1463. g_set_error (err, g_quark_from_static_string ("rspamd-config"),
  1464. EINVAL, "bad map object for %s", ucl_object_key (obj));
  1465. return FALSE;
  1466. }
  1467. break;
  1468. case UCL_ARRAY:
  1469. /* List of IP addresses */
  1470. it = ucl_object_iterate_new (cur_elt);
  1471. while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
  1472. str = ucl_object_tostring (cur);
  1473. if (str == NULL || !radix_add_generic_iplist (str, target, TRUE)) {
  1474. g_set_error (err, g_quark_from_static_string ("rspamd-config"),
  1475. EINVAL, "bad map element %s for %s", str,
  1476. ucl_object_key (obj));
  1477. if (*target) {
  1478. radix_destroy_compressed (*target);
  1479. }
  1480. ucl_object_iterate_free (it);
  1481. return FALSE;
  1482. }
  1483. }
  1484. ucl_object_iterate_free (it);
  1485. break;
  1486. default:
  1487. g_set_error (err, g_quark_from_static_string ("rspamd-config"),
  1488. EINVAL, "bad map type %s for %s",
  1489. ucl_object_type_to_string (type),
  1490. ucl_object_key (obj));
  1491. return FALSE;
  1492. }
  1493. }
  1494. return TRUE;
  1495. }
  1496. gboolean
  1497. rspamd_action_from_str (const gchar *data, gint *result)
  1498. {
  1499. guint64 h;
  1500. h = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64,
  1501. data, strlen (data), 0xdeadbabe);
  1502. switch (h) {
  1503. case 0x9917BFDB46332B8CULL: /* reject */
  1504. *result = METRIC_ACTION_REJECT;
  1505. break;
  1506. case 0x7130EE37D07B3715ULL: /* greylist */
  1507. *result = METRIC_ACTION_GREYLIST;
  1508. break;
  1509. case 0xCA6087E05480C60CULL: /* add_header */
  1510. case 0x87A3D27783B16241ULL: /* add header */
  1511. *result = METRIC_ACTION_ADD_HEADER;
  1512. break;
  1513. case 0x4963374ED8B90449ULL: /* rewrite_subject */
  1514. case 0x5C9FC4679C025948ULL: /* rewrite subject */
  1515. *result = METRIC_ACTION_REWRITE_SUBJECT;
  1516. break;
  1517. case 0xFC7D6502EE71FDD9ULL: /* soft reject */
  1518. case 0x73576567C262A82DULL: /* soft_reject */
  1519. *result = METRIC_ACTION_SOFT_REJECT;
  1520. break;
  1521. case 0x207091B927D1EC0DULL: /* no action */
  1522. case 0xB7D92D002CD46325ULL: /* no_action */
  1523. case 0x167C0DF4BAA9BCECULL: /* accept */
  1524. *result = METRIC_ACTION_NOACTION;
  1525. break;
  1526. default:
  1527. return FALSE;
  1528. }
  1529. return TRUE;
  1530. }
  1531. const gchar *
  1532. rspamd_action_to_str (enum rspamd_metric_action action)
  1533. {
  1534. switch (action) {
  1535. case METRIC_ACTION_REJECT:
  1536. return "reject";
  1537. case METRIC_ACTION_SOFT_REJECT:
  1538. return "soft reject";
  1539. case METRIC_ACTION_REWRITE_SUBJECT:
  1540. return "rewrite subject";
  1541. case METRIC_ACTION_ADD_HEADER:
  1542. return "add header";
  1543. case METRIC_ACTION_GREYLIST:
  1544. return "greylist";
  1545. case METRIC_ACTION_NOACTION:
  1546. return "no action";
  1547. case METRIC_ACTION_MAX:
  1548. return "invalid max action";
  1549. }
  1550. return "unknown action";
  1551. }
  1552. const gchar *
  1553. rspamd_action_to_str_alt (enum rspamd_metric_action action)
  1554. {
  1555. switch (action) {
  1556. case METRIC_ACTION_REJECT:
  1557. return "reject";
  1558. case METRIC_ACTION_SOFT_REJECT:
  1559. return "soft_reject";
  1560. case METRIC_ACTION_REWRITE_SUBJECT:
  1561. return "rewrite_subject";
  1562. case METRIC_ACTION_ADD_HEADER:
  1563. return "add_header";
  1564. case METRIC_ACTION_GREYLIST:
  1565. return "greylist";
  1566. case METRIC_ACTION_NOACTION:
  1567. return "no action";
  1568. case METRIC_ACTION_MAX:
  1569. return "invalid max action";
  1570. }
  1571. return "unknown action";
  1572. }