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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. /*
  2. * Copyright (c) 2009-2012, Vsevolod Stakhov
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  17. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  18. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  19. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  20. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  21. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  22. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. */
  24. #include "config.h"
  25. #include "cfg_file.h"
  26. #include "main.h"
  27. #include "uthash_strcase.h"
  28. #include "filter.h"
  29. #include "classifiers.h"
  30. #include "lua/lua_common.h"
  31. #include "kvstorage_config.h"
  32. #include "map.h"
  33. #include "dynamic_cfg.h"
  34. #include "utlist.h"
  35. #define DEFAULT_SCORE 10.0
  36. #define DEFAULT_RLIMIT_NOFILE 2048
  37. #define DEFAULT_RLIMIT_MAXCORE 0
  38. #define DEFAULT_MAP_TIMEOUT 10
  39. struct rspamd_ucl_map_cbdata {
  40. struct rspamd_config *cfg;
  41. GString *buf;
  42. };
  43. static gchar * rspamd_ucl_read_cb (rspamd_mempool_t * pool,
  44. gchar * chunk,
  45. gint len,
  46. struct map_cb_data *data);
  47. static void rspamd_ucl_fin_cb (rspamd_mempool_t * pool,
  48. struct map_cb_data *data);
  49. gboolean
  50. rspamd_parse_bind_line (struct rspamd_config *cfg,
  51. struct rspamd_worker_conf *cf,
  52. const gchar *str)
  53. {
  54. struct rspamd_worker_bind_conf *cnf;
  55. gchar **tokens, *err;
  56. gboolean ret = TRUE;
  57. if (str == NULL) {
  58. return FALSE;
  59. }
  60. if (str[0] == '[') {
  61. /* This is an ipv6 address */
  62. gsize len, ntok;
  63. const gchar *start, *ip_pos;
  64. start = str + 1;
  65. len = strcspn (start, "]");
  66. if (start[len] != ']') {
  67. return FALSE;
  68. }
  69. ip_pos = start;
  70. start += len + 1;
  71. ntok = 1;
  72. if (*start == ':') {
  73. ntok = 2;
  74. start ++;
  75. }
  76. tokens = g_malloc_n (ntok + 1, sizeof (gchar *));
  77. tokens[ntok] = NULL;
  78. tokens[0] = g_malloc (len + 1);
  79. rspamd_strlcpy (tokens[0], ip_pos, len + 1);
  80. if (ntok > 1) {
  81. tokens[1] = g_strdup (start);
  82. }
  83. }
  84. else {
  85. tokens = g_strsplit_set (str, ":", 0);
  86. }
  87. if (!tokens || !tokens[0]) {
  88. return FALSE;
  89. }
  90. cnf =
  91. rspamd_mempool_alloc0 (cfg->cfg_pool,
  92. sizeof (struct rspamd_worker_bind_conf));
  93. cnf->cnt = 1024;
  94. if (strcmp (tokens[0], "systemd") == 0) {
  95. /* The actual socket will be passed by systemd environment */
  96. cnf->is_systemd = TRUE;
  97. cnf->cnt = strtoul (tokens[1], &err, 10);
  98. cnf->addrs = NULL;
  99. if (err == NULL || *err == '\0') {
  100. LL_PREPEND (cf->bind_conf, cnf);
  101. }
  102. else {
  103. msg_err ("cannot parse bind line: %s", str);
  104. ret = FALSE;
  105. }
  106. }
  107. else {
  108. if (!rspamd_parse_host_port_priority_strv (tokens, &cnf->addrs,
  109. &cnf->cnt, NULL, &cnf->name, DEFAULT_BIND_PORT, cfg->cfg_pool)) {
  110. msg_err ("cannot parse bind line: %s", str);
  111. ret = FALSE;
  112. }
  113. else {
  114. LL_PREPEND (cf->bind_conf, cnf);
  115. }
  116. }
  117. g_strfreev (tokens);
  118. return ret;
  119. }
  120. void
  121. rspamd_config_defaults (struct rspamd_config *cfg)
  122. {
  123. cfg->dns_timeout = 1000;
  124. cfg->dns_retransmits = 5;
  125. /* After 20 errors do throttling for 10 seconds */
  126. cfg->dns_throttling_errors = 20;
  127. cfg->dns_throttling_time = 10000;
  128. /* 16 sockets per DNS server */
  129. cfg->dns_io_per_server = 16;
  130. cfg->statfile_sync_interval = 60000;
  131. cfg->statfile_sync_timeout = 20000;
  132. /* 20 Kb */
  133. cfg->max_diff = 20480;
  134. cfg->metrics = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  135. if (cfg->c_modules == NULL) {
  136. cfg->c_modules = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  137. }
  138. cfg->composite_symbols =
  139. g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  140. cfg->classifiers_symbols = g_hash_table_new (rspamd_str_hash,
  141. rspamd_str_equal);
  142. cfg->cfg_params = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  143. cfg->metrics_symbols = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  144. cfg->map_timeout = DEFAULT_MAP_TIMEOUT;
  145. cfg->log_level = G_LOG_LEVEL_WARNING;
  146. cfg->log_extended = TRUE;
  147. }
  148. void
  149. rspamd_config_free (struct rspamd_config *cfg)
  150. {
  151. GList *cur;
  152. struct rspamd_symbols_group *gr;
  153. rspamd_map_remove_all (cfg);
  154. ucl_obj_unref (cfg->rcl_obj);
  155. g_hash_table_remove_all (cfg->metrics);
  156. g_hash_table_unref (cfg->metrics);
  157. g_hash_table_unref (cfg->c_modules);
  158. g_hash_table_remove_all (cfg->composite_symbols);
  159. g_hash_table_unref (cfg->composite_symbols);
  160. g_hash_table_remove_all (cfg->cfg_params);
  161. g_hash_table_unref (cfg->cfg_params);
  162. g_hash_table_destroy (cfg->metrics_symbols);
  163. g_hash_table_destroy (cfg->classifiers_symbols);
  164. /* Free symbols groups */
  165. cur = cfg->symbols_groups;
  166. while (cur) {
  167. gr = cur->data;
  168. if (gr->symbols) {
  169. g_list_free (gr->symbols);
  170. }
  171. cur = g_list_next (cur);
  172. }
  173. if (cfg->symbols_groups) {
  174. g_list_free (cfg->symbols_groups);
  175. }
  176. if (cfg->checksum) {
  177. g_free (cfg->checksum);
  178. }
  179. g_list_free (cfg->classifiers);
  180. g_list_free (cfg->metrics_list);
  181. rspamd_mempool_delete (cfg->cfg_pool);
  182. }
  183. const ucl_object_t *
  184. rspamd_config_get_module_opt (struct rspamd_config *cfg,
  185. const gchar *module_name,
  186. const gchar *opt_name)
  187. {
  188. const ucl_object_t *res = NULL, *sec;
  189. sec = ucl_obj_get_key (cfg->rcl_obj, module_name);
  190. if (sec != NULL) {
  191. res = ucl_obj_get_key (sec, opt_name);
  192. }
  193. return res;
  194. }
  195. guint64
  196. rspamd_config_parse_limit (const gchar *limit, guint len)
  197. {
  198. guint64 result = 0;
  199. const gchar *err_str;
  200. if (!limit || *limit == '\0' || len == 0) {
  201. return 0;
  202. }
  203. errno = 0;
  204. result = strtoull (limit, (gchar **)&err_str, 10);
  205. if (*err_str != '\0') {
  206. /* Megabytes */
  207. if (*err_str == 'm' || *err_str == 'M') {
  208. result *= 1048576L;
  209. }
  210. /* Kilobytes */
  211. else if (*err_str == 'k' || *err_str == 'K') {
  212. result *= 1024;
  213. }
  214. /* Gigabytes */
  215. else if (*err_str == 'g' || *err_str == 'G') {
  216. result *= 1073741824L;
  217. }
  218. else if (len > 0 && err_str - limit != (gint)len) {
  219. msg_warn ("invalid limit value '%s' at position '%s'",
  220. limit,
  221. err_str);
  222. result = 0;
  223. }
  224. }
  225. return result;
  226. }
  227. gchar
  228. rspamd_config_parse_flag (const gchar *str)
  229. {
  230. guint len;
  231. gchar c;
  232. if (!str || !*str) {
  233. return -1;
  234. }
  235. len = strlen (str);
  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. gboolean
  276. rspamd_config_calculate_checksum (struct rspamd_config *cfg)
  277. {
  278. gint fd;
  279. void *map;
  280. struct stat st;
  281. /* Compute checksum for config file that should be used by xml dumper */
  282. if ((fd = open (cfg->cfg_name, O_RDONLY)) == -1) {
  283. msg_err (
  284. "config file %s is no longer available, cannot calculate checksum");
  285. return FALSE;
  286. }
  287. if (stat (cfg->cfg_name, &st) == -1) {
  288. msg_err ("cannot stat %s: %s", cfg->cfg_name, strerror (errno));
  289. return FALSE;
  290. }
  291. /* Now mmap this file to simplify reading process */
  292. if ((map =
  293. mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
  294. msg_err ("cannot mmap %s: %s", cfg->cfg_name, strerror (errno));
  295. close (fd);
  296. return FALSE;
  297. }
  298. close (fd);
  299. /* Get checksum for a file */
  300. cfg->checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5,
  301. map,
  302. st.st_size);
  303. munmap (map, st.st_size);
  304. return TRUE;
  305. }
  306. /*
  307. * Perform post load actions
  308. */
  309. void
  310. rspamd_config_post_load (struct rspamd_config *cfg)
  311. {
  312. #ifdef HAVE_CLOCK_GETTIME
  313. struct timespec ts;
  314. #endif
  315. struct metric *def_metric;
  316. #ifdef HAVE_CLOCK_GETTIME
  317. #ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
  318. clock_getres (CLOCK_PROCESS_CPUTIME_ID, &ts);
  319. # elif defined(HAVE_CLOCK_VIRTUAL)
  320. clock_getres (CLOCK_VIRTUAL, &ts);
  321. # else
  322. clock_getres (CLOCK_REALTIME, &ts);
  323. # endif
  324. cfg->clock_res = (gint)log10 (1000000 / ts.tv_nsec);
  325. if (cfg->clock_res < 0) {
  326. cfg->clock_res = 0;
  327. }
  328. if (cfg->clock_res > 3) {
  329. cfg->clock_res = 3;
  330. }
  331. #else
  332. /* For gettimeofday */
  333. cfg->clock_res = 1;
  334. #endif
  335. if ((def_metric =
  336. g_hash_table_lookup (cfg->metrics, DEFAULT_METRIC)) == NULL) {
  337. def_metric = rspamd_config_new_metric (cfg, NULL);
  338. def_metric->name = DEFAULT_METRIC;
  339. def_metric->actions[METRIC_ACTION_REJECT].score = DEFAULT_SCORE;
  340. cfg->metrics_list = g_list_prepend (cfg->metrics_list, def_metric);
  341. g_hash_table_insert (cfg->metrics, DEFAULT_METRIC, def_metric);
  342. }
  343. cfg->default_metric = def_metric;
  344. /* Lua options */
  345. (void)rspamd_lua_post_load_config (cfg);
  346. init_dynamic_config (cfg);
  347. }
  348. #if 0
  349. void
  350. parse_err (const gchar *fmt, ...)
  351. {
  352. va_list aq;
  353. gchar logbuf[BUFSIZ], readbuf[32];
  354. gint r;
  355. va_start (aq, fmt);
  356. rspamd_strlcpy (readbuf, yytext, sizeof (readbuf));
  357. r = snprintf (logbuf,
  358. sizeof (logbuf),
  359. "config file parse error! line: %d, text: %s, reason: ",
  360. yylineno,
  361. readbuf);
  362. r += vsnprintf (logbuf + r, sizeof (logbuf) - r, fmt, aq);
  363. va_end (aq);
  364. g_critical ("%s", logbuf);
  365. }
  366. void
  367. parse_warn (const gchar *fmt, ...)
  368. {
  369. va_list aq;
  370. gchar logbuf[BUFSIZ], readbuf[32];
  371. gint r;
  372. va_start (aq, fmt);
  373. rspamd_strlcpy (readbuf, yytext, sizeof (readbuf));
  374. r = snprintf (logbuf,
  375. sizeof (logbuf),
  376. "config file parse warning! line: %d, text: %s, reason: ",
  377. yylineno,
  378. readbuf);
  379. r += vsnprintf (logbuf + r, sizeof (logbuf) - r, fmt, aq);
  380. va_end (aq);
  381. g_warning ("%s", logbuf);
  382. }
  383. #endif
  384. void
  385. rspamd_config_unescape_quotes (gchar *line)
  386. {
  387. gchar *c = line, *t;
  388. while (*c) {
  389. if (*c == '\\' && *(c + 1) == '"') {
  390. t = c;
  391. while (*t) {
  392. *t = *(t + 1);
  393. t++;
  394. }
  395. }
  396. c++;
  397. }
  398. }
  399. GList *
  400. rspamd_config_parse_comma_list (rspamd_mempool_t * pool, const gchar *line)
  401. {
  402. GList *res = NULL;
  403. const gchar *c, *p;
  404. gchar *str;
  405. c = line;
  406. p = c;
  407. while (*p) {
  408. if (*p == ',' && *c != *p) {
  409. str = rspamd_mempool_alloc (pool, p - c + 1);
  410. rspamd_strlcpy (str, c, p - c + 1);
  411. res = g_list_prepend (res, str);
  412. /* Skip spaces */
  413. while (g_ascii_isspace (*(++p))) ;
  414. c = p;
  415. continue;
  416. }
  417. p++;
  418. }
  419. if (res != NULL) {
  420. rspamd_mempool_add_destructor (pool,
  421. (rspamd_mempool_destruct_t) g_list_free,
  422. res);
  423. }
  424. return res;
  425. }
  426. struct rspamd_classifier_config *
  427. rspamd_config_new_classifier (struct rspamd_config *cfg,
  428. struct rspamd_classifier_config *c)
  429. {
  430. if (c == NULL) {
  431. c =
  432. rspamd_mempool_alloc0 (cfg->cfg_pool,
  433. sizeof (struct rspamd_classifier_config));
  434. }
  435. if (c->opts == NULL) {
  436. c->opts = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  437. rspamd_mempool_add_destructor (cfg->cfg_pool,
  438. (rspamd_mempool_destruct_t) g_hash_table_destroy,
  439. c->opts);
  440. }
  441. if (c->labels == NULL) {
  442. c->labels = g_hash_table_new_full (rspamd_str_hash,
  443. rspamd_str_equal,
  444. NULL,
  445. (GDestroyNotify)g_list_free);
  446. rspamd_mempool_add_destructor (cfg->cfg_pool,
  447. (rspamd_mempool_destruct_t) g_hash_table_destroy,
  448. c->labels);
  449. }
  450. return c;
  451. }
  452. struct rspamd_statfile_config *
  453. rspamd_config_new_statfile (struct rspamd_config *cfg,
  454. struct rspamd_statfile_config *c)
  455. {
  456. if (c == NULL) {
  457. c =
  458. rspamd_mempool_alloc0 (cfg->cfg_pool,
  459. sizeof (struct rspamd_statfile_config));
  460. }
  461. return c;
  462. }
  463. struct metric *
  464. rspamd_config_new_metric (struct rspamd_config *cfg, struct metric *c)
  465. {
  466. int i;
  467. if (c == NULL) {
  468. c = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (struct metric));
  469. c->grow_factor = 1.0;
  470. c->symbols = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  471. c->descriptions = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  472. for (i = METRIC_ACTION_REJECT; i < METRIC_ACTION_MAX; i++) {
  473. c->actions[i].score = -1.0;
  474. }
  475. c->subject = SPAM_SUBJECT;
  476. rspamd_mempool_add_destructor (cfg->cfg_pool,
  477. (rspamd_mempool_destruct_t) g_hash_table_destroy,
  478. c->symbols);
  479. rspamd_mempool_add_destructor (cfg->cfg_pool,
  480. (rspamd_mempool_destruct_t) g_hash_table_destroy,
  481. c->descriptions);
  482. }
  483. return c;
  484. }
  485. struct rspamd_worker_conf *
  486. rspamd_config_new_worker (struct rspamd_config *cfg,
  487. struct rspamd_worker_conf *c)
  488. {
  489. if (c == NULL) {
  490. c =
  491. rspamd_mempool_alloc0 (cfg->cfg_pool,
  492. sizeof (struct rspamd_worker_conf));
  493. c->params = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  494. c->active_workers = g_queue_new ();
  495. rspamd_mempool_add_destructor (cfg->cfg_pool,
  496. (rspamd_mempool_destruct_t)g_hash_table_destroy,
  497. c->params);
  498. rspamd_mempool_add_destructor (cfg->cfg_pool,
  499. (rspamd_mempool_destruct_t)g_queue_free,
  500. c->active_workers);
  501. #ifdef HAVE_SC_NPROCESSORS_ONLN
  502. c->count = sysconf (_SC_NPROCESSORS_ONLN);
  503. #else
  504. c->count = DEFAULT_WORKERS_NUM;
  505. #endif
  506. c->rlimit_nofile = 0;
  507. c->rlimit_maxcore = 0;
  508. }
  509. return c;
  510. }
  511. static bool
  512. rspamd_include_map_handler (const guchar *data, gsize len,
  513. const ucl_object_t *args, void * ud)
  514. {
  515. struct rspamd_config *cfg = (struct rspamd_config *)ud;
  516. struct rspamd_ucl_map_cbdata *cbdata, **pcbdata;
  517. gchar *map_line;
  518. map_line = rspamd_mempool_alloc (cfg->cfg_pool, len + 1);
  519. rspamd_strlcpy (map_line, data, len + 1);
  520. cbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata));
  521. pcbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata *));
  522. cbdata->buf = NULL;
  523. cbdata->cfg = cfg;
  524. *pcbdata = cbdata;
  525. return rspamd_map_add (cfg,
  526. map_line,
  527. "ucl include",
  528. rspamd_ucl_read_cb,
  529. rspamd_ucl_fin_cb,
  530. (void **)pcbdata);
  531. }
  532. /*
  533. * Variables:
  534. * $CONFDIR - configuration directory
  535. * $RUNDIR - local states directory
  536. * $DBDIR - databases dir
  537. * $LOGDIR - logs dir
  538. * $PLUGINSDIR - pluggins dir
  539. * $PREFIX - installation prefix
  540. * $VERSION - rspamd version
  541. */
  542. #define RSPAMD_CONFDIR_MACRO "CONFDIR"
  543. #define RSPAMD_RUNDIR_MACRO "RUNDIR"
  544. #define RSPAMD_DBDIR_MACRO "DBDIR"
  545. #define RSPAMD_LOGDIR_MACRO "LOGDIR"
  546. #define RSPAMD_PLUGINSDIR_MACRO "PLUGINSDIR"
  547. #define RSPAMD_WWWDIR_MACRO "WWWDIR"
  548. #define RSPAMD_PREFIX_MACRO "PREFIX"
  549. #define RSPAMD_VERSION_MACRO "VERSION"
  550. void
  551. rspamd_ucl_add_conf_variables (struct ucl_parser *parser)
  552. {
  553. ucl_parser_register_variable (parser,
  554. RSPAMD_CONFDIR_MACRO,
  555. RSPAMD_CONFDIR);
  556. ucl_parser_register_variable (parser, RSPAMD_RUNDIR_MACRO,
  557. RSPAMD_RUNDIR);
  558. ucl_parser_register_variable (parser, RSPAMD_DBDIR_MACRO,
  559. RSPAMD_DBDIR);
  560. ucl_parser_register_variable (parser, RSPAMD_LOGDIR_MACRO,
  561. RSPAMD_LOGDIR);
  562. ucl_parser_register_variable (parser,
  563. RSPAMD_PLUGINSDIR_MACRO,
  564. RSPAMD_PLUGINSDIR);
  565. ucl_parser_register_variable (parser, RSPAMD_WWWDIR_MACRO,
  566. RSPAMD_WWWDIR);
  567. ucl_parser_register_variable (parser, RSPAMD_PREFIX_MACRO,
  568. RSPAMD_PREFIX);
  569. ucl_parser_register_variable (parser, RSPAMD_VERSION_MACRO, RVERSION);
  570. }
  571. void
  572. rspamd_ucl_add_conf_macros (struct ucl_parser *parser,
  573. struct rspamd_config *cfg)
  574. {
  575. ucl_parser_register_macro (parser,
  576. "include_map",
  577. rspamd_include_map_handler,
  578. cfg);
  579. }
  580. static void
  581. symbols_classifiers_callback (gpointer key, gpointer value, gpointer ud)
  582. {
  583. struct rspamd_config *cfg = ud;
  584. register_virtual_symbol (&cfg->cache, key, 1.0);
  585. }
  586. void
  587. rspamd_config_insert_classify_symbols (struct rspamd_config *cfg)
  588. {
  589. g_hash_table_foreach (cfg->classifiers_symbols,
  590. symbols_classifiers_callback,
  591. cfg);
  592. }
  593. struct rspamd_classifier_config *
  594. rspamd_config_find_classifier (struct rspamd_config *cfg, const gchar *name)
  595. {
  596. GList *cur;
  597. struct rspamd_classifier_config *cf;
  598. if (name == NULL) {
  599. return NULL;
  600. }
  601. cur = cfg->classifiers;
  602. while (cur) {
  603. cf = cur->data;
  604. if (g_ascii_strcasecmp (cf->classifier->name, name) == 0) {
  605. return cf;
  606. }
  607. cur = g_list_next (cur);
  608. }
  609. return NULL;
  610. }
  611. gboolean
  612. rspamd_config_check_statfiles (struct rspamd_classifier_config *cf)
  613. {
  614. struct rspamd_statfile_config *st;
  615. gboolean has_other = FALSE, res = FALSE, cur_class;
  616. GList *cur;
  617. /* First check classes directly */
  618. cur = cf->statfiles;
  619. while (cur) {
  620. st = cur->data;
  621. if (!has_other) {
  622. cur_class = st->is_spam;
  623. has_other = TRUE;
  624. }
  625. else {
  626. if (cur_class != st->is_spam) {
  627. return TRUE;
  628. }
  629. }
  630. cur = g_list_next (cur);
  631. }
  632. if (!has_other) {
  633. /* We have only one statfile */
  634. return FALSE;
  635. }
  636. /* We have not detected any statfile that has different class, so turn on euristic based on symbol's name */
  637. has_other = FALSE;
  638. cur = cf->statfiles;
  639. while (cur) {
  640. st = cur->data;
  641. if (rspamd_strncasestr (st->symbol, "spam", -1) != NULL) {
  642. st->is_spam = TRUE;
  643. }
  644. else if (rspamd_strncasestr (st->symbol, "ham", -1) != NULL) {
  645. st->is_spam = FALSE;
  646. }
  647. if (!has_other) {
  648. cur_class = st->is_spam;
  649. has_other = TRUE;
  650. }
  651. else {
  652. if (cur_class != st->is_spam) {
  653. res = TRUE;
  654. }
  655. }
  656. cur = g_list_next (cur);
  657. }
  658. return res;
  659. }
  660. static gchar *
  661. rspamd_ucl_read_cb (rspamd_mempool_t * pool,
  662. gchar * chunk,
  663. gint len,
  664. struct map_cb_data *data)
  665. {
  666. struct rspamd_ucl_map_cbdata *cbdata = data->cur_data, *prev;
  667. if (cbdata == NULL) {
  668. cbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata));
  669. prev = data->prev_data;
  670. cbdata->buf = g_string_sized_new (BUFSIZ);
  671. cbdata->cfg = prev->cfg;
  672. data->cur_data = cbdata;
  673. }
  674. g_string_append_len (cbdata->buf, chunk, len);
  675. /* Say not to copy any part of this buffer */
  676. return NULL;
  677. }
  678. static void
  679. rspamd_ucl_fin_cb (rspamd_mempool_t * pool, struct map_cb_data *data)
  680. {
  681. struct rspamd_ucl_map_cbdata *cbdata = data->cur_data, *prev =
  682. data->prev_data;
  683. ucl_object_t *obj;
  684. struct ucl_parser *parser;
  685. guint32 checksum;
  686. ucl_object_iter_t it = NULL;
  687. const ucl_object_t *cur;
  688. if (prev != NULL) {
  689. if (prev->buf != NULL) {
  690. g_string_free (prev->buf, TRUE);
  691. }
  692. g_free (prev);
  693. }
  694. if (cbdata == NULL) {
  695. msg_err ("map fin error: new data is NULL");
  696. return;
  697. }
  698. checksum = XXH32 (cbdata->buf->str, cbdata->buf->len, 0xdead);
  699. if (data->map->checksum != checksum) {
  700. /* New data available */
  701. parser = ucl_parser_new (0);
  702. if (!ucl_parser_add_chunk (parser, cbdata->buf->str,
  703. cbdata->buf->len)) {
  704. msg_err ("cannot parse map %s: %s",
  705. data->map->uri,
  706. ucl_parser_get_error (parser));
  707. ucl_parser_free (parser);
  708. }
  709. else {
  710. obj = ucl_parser_get_object (parser);
  711. ucl_parser_free (parser);
  712. it = NULL;
  713. while ((cur = ucl_iterate_object (obj, &it, true))) {
  714. ucl_object_replace_key (cbdata->cfg->rcl_obj, (ucl_object_t *)cur,
  715. cur->key, cur->keylen, false);
  716. }
  717. ucl_object_unref (obj);
  718. data->map->checksum = checksum;
  719. }
  720. }
  721. else {
  722. msg_info ("do not reload map %s, checksum is the same: %d",
  723. data->map->uri,
  724. checksum);
  725. }
  726. }
  727. /*
  728. * vi:ts=4
  729. */