Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. /*
  2. * Copyright (c) 2009, Rambler media
  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 Rambler media ''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 Rambler 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 "filter.h"
  28. #include "classifiers/classifiers.h"
  29. #define DEFAULT_SCORE 10.0
  30. extern int yylineno;
  31. extern char *yytext;
  32. int
  33. add_memcached_server (struct config_file *cf, char *str)
  34. {
  35. char *cur_tok, *err_str;
  36. struct memcached_server *mc;
  37. struct hostent *hent;
  38. uint16_t port;
  39. if (str == NULL) return 0;
  40. cur_tok = strsep (&str, ":");
  41. if (cur_tok == NULL || *cur_tok == '\0') return 0;
  42. if(cf->memcached_servers_num == MAX_MEMCACHED_SERVERS) {
  43. yywarn ("yyparse: maximum number of memcached servers is reached %d", MAX_MEMCACHED_SERVERS);
  44. }
  45. mc = &cf->memcached_servers[cf->memcached_servers_num];
  46. if (mc == NULL) return 0;
  47. /* cur_tok - server name, str - server port */
  48. if (str == NULL) {
  49. port = DEFAULT_MEMCACHED_PORT;
  50. }
  51. else {
  52. port = (uint16_t)strtoul (str, &err_str, 10);
  53. if (*err_str != '\0') {
  54. return 0;
  55. }
  56. }
  57. if (!inet_aton (cur_tok, &mc->addr)) {
  58. /* Try to call gethostbyname */
  59. hent = gethostbyname (cur_tok);
  60. if (hent == NULL) {
  61. return 0;
  62. }
  63. else {
  64. memcpy((char *)&mc->addr, hent->h_addr, sizeof(struct in_addr));
  65. }
  66. }
  67. mc->port = port;
  68. cf->memcached_servers_num++;
  69. return 1;
  70. }
  71. int
  72. parse_bind_line (struct config_file *cf, char *str, enum rspamd_cred_type type)
  73. {
  74. char *cur_tok, *err_str;
  75. struct hostent *hent;
  76. size_t s;
  77. char **host;
  78. int16_t *family, *port;
  79. struct in_addr *addr;
  80. if (str == NULL) return 0;
  81. cur_tok = strsep (&str, ":");
  82. switch (type) {
  83. case CRED_NORMAL:
  84. host = &cf->bind_host;
  85. port = &cf->bind_port;
  86. *port = DEFAULT_BIND_PORT;
  87. family = &cf->bind_family;
  88. addr = &cf->bind_addr;
  89. break;
  90. case CRED_CONTROL:
  91. host = &cf->control_host;
  92. port = &cf->control_port;
  93. *port = DEFAULT_CONTROL_PORT;
  94. family = &cf->control_family;
  95. addr = &cf->control_addr;
  96. break;
  97. case CRED_LMTP:
  98. host = &cf->lmtp_host;
  99. port = &cf->lmtp_port;
  100. *port = DEFAULT_LMTP_PORT;
  101. family = &cf->lmtp_family;
  102. addr = &cf->lmtp_addr;
  103. break;
  104. case CRED_DELIVERY:
  105. host = &cf->deliver_host;
  106. port = &cf->deliver_port;
  107. *port = 25;
  108. family = &cf->deliver_family;
  109. addr = &cf->deliver_addr;
  110. break;
  111. }
  112. if (cur_tok[0] == '/' || cur_tok[0] == '.') {
  113. #ifdef HAVE_DIRNAME
  114. /* Try to check path of bind credit */
  115. struct stat st;
  116. int fd;
  117. char *copy = memory_pool_strdup (cf->cfg_pool, cur_tok);
  118. if (stat (copy, &st) == -1) {
  119. if (errno == ENOENT) {
  120. if ((fd = open (cur_tok, O_RDWR | O_TRUNC | O_CREAT, S_IWUSR | S_IRUSR)) == -1) {
  121. yyerror ("parse_bind_line: cannot open path %s for making socket, %m", cur_tok);
  122. return 0;
  123. }
  124. else {
  125. close (fd);
  126. unlink (cur_tok);
  127. }
  128. }
  129. else {
  130. yyerror ("parse_bind_line: cannot stat path %s for making socket, %m", cur_tok);
  131. return 0;
  132. }
  133. }
  134. else {
  135. if (unlink (cur_tok) == -1) {
  136. yyerror ("parse_bind_line: cannot remove path %s for making socket, %m", cur_tok);
  137. return 0;
  138. }
  139. }
  140. #endif
  141. *host = memory_pool_strdup (cf->cfg_pool, cur_tok);
  142. *family = AF_UNIX;
  143. return 1;
  144. } else {
  145. if (*str != '\0') {
  146. *port = (uint16_t)strtoul (str, &err_str, 10);
  147. if (*err_str != '\0') {
  148. yyerror ("parse_bind_line: cannot read numeric value: %s", err_str);
  149. return 0;
  150. }
  151. }
  152. if (!inet_aton (cur_tok, addr)) {
  153. /* Try to call gethostbyname */
  154. hent = gethostbyname (cur_tok);
  155. if (hent == NULL) {
  156. return 0;
  157. }
  158. else {
  159. *host = memory_pool_strdup (cf->cfg_pool, cur_tok);
  160. memcpy((char *)addr, hent->h_addr, sizeof(struct in_addr));
  161. s = strlen (cur_tok) + 1;
  162. }
  163. }
  164. else {
  165. *host = memory_pool_strdup (cf->cfg_pool, cur_tok);
  166. }
  167. *family = AF_INET;
  168. return 1;
  169. }
  170. return 0;
  171. }
  172. void
  173. init_defaults (struct config_file *cfg)
  174. {
  175. struct metric *def_metric;
  176. cfg->memcached_error_time = DEFAULT_UPSTREAM_ERROR_TIME;
  177. cfg->memcached_dead_time = DEFAULT_UPSTREAM_DEAD_TIME;
  178. cfg->memcached_maxerrors = DEFAULT_UPSTREAM_MAXERRORS;
  179. cfg->memcached_protocol = TCP_TEXT;
  180. #ifdef HAVE_SC_NPROCESSORS_ONLN
  181. cfg->workers_number = sysconf (_SC_NPROCESSORS_ONLN);
  182. #else
  183. cfg->workers_number = DEFAULT_WORKERS_NUM;
  184. #endif
  185. cfg->max_statfile_size = DEFAULT_STATFILE_SIZE;
  186. cfg->modules_opts = g_hash_table_new (g_str_hash, g_str_equal);
  187. cfg->variables = g_hash_table_new (g_str_hash, g_str_equal);
  188. cfg->metrics = g_hash_table_new (g_str_hash, g_str_equal);
  189. cfg->factors = g_hash_table_new (g_str_hash, g_str_equal);
  190. cfg->c_modules = g_hash_table_new (g_str_hash, g_str_equal);
  191. cfg->composite_symbols = g_hash_table_new (g_str_hash, g_str_equal);
  192. cfg->statfiles = g_hash_table_new (g_str_hash, g_str_equal);
  193. cfg->cfg_params = g_hash_table_new (g_str_hash, g_str_equal);
  194. cfg->lmtp_metric = "default";
  195. def_metric = memory_pool_alloc (cfg->cfg_pool, sizeof (struct metric));
  196. def_metric->name = "default";
  197. def_metric->func_name = "factors";
  198. def_metric->func = factor_consolidation_func;
  199. def_metric->required_score = DEFAULT_SCORE;
  200. def_metric->classifier = get_classifier ("winnow");
  201. g_hash_table_insert (cfg->metrics, "default", def_metric);
  202. LIST_INIT (&cfg->perl_modules);
  203. }
  204. void
  205. free_config (struct config_file *cfg)
  206. {
  207. g_hash_table_remove_all (cfg->modules_opts);
  208. g_hash_table_unref (cfg->modules_opts);
  209. g_hash_table_remove_all (cfg->variables);
  210. g_hash_table_unref (cfg->variables);
  211. g_hash_table_remove_all (cfg->metrics);
  212. g_hash_table_unref (cfg->metrics);
  213. g_hash_table_remove_all (cfg->factors);
  214. g_hash_table_unref (cfg->factors);
  215. g_hash_table_remove_all (cfg->c_modules);
  216. g_hash_table_unref (cfg->c_modules);
  217. g_hash_table_remove_all (cfg->composite_symbols);
  218. g_hash_table_unref (cfg->composite_symbols);
  219. g_hash_table_remove_all (cfg->statfiles);
  220. g_hash_table_unref (cfg->statfiles);
  221. g_hash_table_remove_all (cfg->cfg_params);
  222. g_hash_table_unref (cfg->cfg_params);
  223. memory_pool_delete (cfg->cfg_pool);
  224. }
  225. char*
  226. get_module_opt (struct config_file *cfg, char *module_name, char *opt_name)
  227. {
  228. LIST_HEAD (moduleoptq, module_opt) *cur_module_opt = NULL;
  229. struct module_opt *cur;
  230. cur_module_opt = g_hash_table_lookup (cfg->modules_opts, module_name);
  231. if (cur_module_opt == NULL) {
  232. return NULL;
  233. }
  234. LIST_FOREACH (cur, cur_module_opt, next) {
  235. if (strcmp (cur->param, opt_name) == 0) {
  236. return cur->value;
  237. }
  238. }
  239. return NULL;
  240. }
  241. size_t
  242. parse_limit (const char *limit)
  243. {
  244. size_t result = 0;
  245. char *err_str;
  246. if (!limit || *limit == '\0') return 0;
  247. result = strtoul (limit, &err_str, 10);
  248. if (*err_str != '\0') {
  249. /* Megabytes */
  250. if (*err_str == 'm' || *err_str == 'M') {
  251. result *= 1048576L;
  252. }
  253. /* Kilobytes */
  254. else if (*err_str == 'k' || *err_str == 'K') {
  255. result *= 1024;
  256. }
  257. /* Gigabytes */
  258. else if (*err_str == 'g' || *err_str == 'G') {
  259. result *= 1073741824L;
  260. }
  261. }
  262. return result;
  263. }
  264. unsigned int
  265. parse_seconds (const char *t)
  266. {
  267. unsigned int result = 0;
  268. char *err_str;
  269. if (!t || *t == '\0') return 0;
  270. result = strtoul (t, &err_str, 10);
  271. if (*err_str != '\0') {
  272. /* Seconds */
  273. if (*err_str == 's' || *err_str == 'S') {
  274. result *= 1000;
  275. }
  276. }
  277. return result;
  278. }
  279. char
  280. parse_flag (const char *str)
  281. {
  282. if (!str || !*str) return -1;
  283. if ((*str == 'Y' || *str == 'y') && *(str + 1) == '\0') {
  284. return 1;
  285. }
  286. if ((*str == 'Y' || *str == 'y') &&
  287. (*(str + 1) == 'E' || *(str + 1) == 'e') &&
  288. (*(str + 2) == 'S' || *(str + 2) == 's') &&
  289. *(str + 3) == '\0') {
  290. return 1;
  291. }
  292. if ((*str == 'N' || *str == 'n') && *(str + 1) == '\0') {
  293. return 0;
  294. }
  295. if ((*str == 'N' || *str == 'n') &&
  296. (*(str + 1) == 'O' || *(str + 1) == 'o') &&
  297. *(str + 2) == '\0') {
  298. return 0;
  299. }
  300. return -1;
  301. }
  302. /*
  303. * Try to substitute all variables in given string
  304. * Return: newly allocated string with substituted variables (original string may be freed if variables are found)
  305. */
  306. char *
  307. substitute_variable (struct config_file *cfg, char *str, u_char recursive)
  308. {
  309. char *var, *new, *v_begin, *v_end;
  310. size_t len;
  311. while ((v_begin = strstr (str, "${")) != NULL) {
  312. len = strlen (str);
  313. *v_begin = '\0';
  314. v_begin += 2;
  315. if ((v_end = strstr (v_begin, "}")) == NULL) {
  316. /* Not a variable, skip */
  317. continue;
  318. }
  319. *v_end = '\0';
  320. var = g_hash_table_lookup (cfg->variables, v_begin);
  321. if (var == NULL) {
  322. yywarn ("substitute_variable: variable %s is not defined", v_begin);
  323. /* Substitute unknown variables with empty string */
  324. var = "";
  325. }
  326. else if (recursive) {
  327. var = substitute_variable (cfg, var, recursive);
  328. }
  329. /* Allocate new string */
  330. new = memory_pool_alloc (cfg->cfg_pool, len - strlen (v_begin) + strlen (var) + 1);
  331. snprintf (new, len - strlen (v_begin) + strlen (var) + 1, "%s%s%s",
  332. str, var, v_end + 1);
  333. str = new;
  334. }
  335. return str;
  336. }
  337. static void
  338. substitute_module_variables (gpointer key, gpointer value, gpointer data)
  339. {
  340. struct config_file *cfg = (struct config_file *)data;
  341. LIST_HEAD (moduleoptq, module_opt) *cur_module_opt = (struct moduleoptq *)value;
  342. struct module_opt *cur, *tmp;
  343. LIST_FOREACH_SAFE (cur, cur_module_opt, next, tmp) {
  344. if (cur->value) {
  345. cur->value = substitute_variable (cfg, cur->value, 0);
  346. }
  347. }
  348. }
  349. static void
  350. substitute_all_variables (gpointer key, gpointer value, gpointer data)
  351. {
  352. struct config_file *cfg = (struct config_file *)data;
  353. char *var;
  354. var = value;
  355. /* Do recursive substitution */
  356. var = substitute_variable (cfg, var, 1);
  357. }
  358. static void
  359. parse_filters_str (struct config_file *cfg, const char *str, enum script_type type)
  360. {
  361. gchar **strvec, **p;
  362. struct filter *cur;
  363. int i;
  364. if (str == NULL) {
  365. return;
  366. }
  367. strvec = g_strsplit (str, ",", 0);
  368. if (strvec == NULL) {
  369. return;
  370. }
  371. p = strvec;
  372. while (*p) {
  373. cur = NULL;
  374. /* Search modules from known C modules */
  375. for (i = 0; i < MODULES_NUM; i++) {
  376. if (strcasecmp (modules[i].name, *p) == 0) {
  377. cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct filter));
  378. cur->type = C_FILTER;
  379. msg_debug ("parse_filters_str: found C filter %s", *p);
  380. switch (type) {
  381. case SCRIPT_HEADER:
  382. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  383. LIST_INSERT_HEAD (&cfg->header_filters, cur, next);
  384. break;
  385. case SCRIPT_MIME:
  386. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  387. LIST_INSERT_HEAD (&cfg->mime_filters, cur, next);
  388. break;
  389. case SCRIPT_MESSAGE:
  390. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  391. LIST_INSERT_HEAD (&cfg->message_filters, cur, next);
  392. break;
  393. case SCRIPT_URL:
  394. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  395. LIST_INSERT_HEAD (&cfg->url_filters, cur, next);
  396. break;
  397. }
  398. break;
  399. }
  400. }
  401. if (cur != NULL) {
  402. /* Go to next iteration */
  403. p++;
  404. continue;
  405. }
  406. cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct filter));
  407. cur->type = PERL_FILTER;
  408. switch (type) {
  409. case SCRIPT_HEADER:
  410. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  411. LIST_INSERT_HEAD (&cfg->header_filters, cur, next);
  412. break;
  413. case SCRIPT_MIME:
  414. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  415. LIST_INSERT_HEAD (&cfg->mime_filters, cur, next);
  416. break;
  417. case SCRIPT_MESSAGE:
  418. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  419. LIST_INSERT_HEAD (&cfg->message_filters, cur, next);
  420. break;
  421. case SCRIPT_URL:
  422. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  423. LIST_INSERT_HEAD (&cfg->url_filters, cur, next);
  424. break;
  425. }
  426. p ++;
  427. }
  428. g_strfreev (strvec);
  429. }
  430. /*
  431. * Place pointers to cfg_file structure to hash cfg_params
  432. */
  433. static void
  434. fill_cfg_params (struct config_file *cfg)
  435. {
  436. struct config_scalar *scalars;
  437. scalars = memory_pool_alloc (cfg->cfg_pool, 10 * sizeof (struct config_scalar));
  438. scalars[0].type = SCALAR_TYPE_STR;
  439. scalars[0].pointer = &cfg->cfg_name;
  440. g_hash_table_insert (cfg->cfg_params, "cfg_name", &scalars[0]);
  441. scalars[1].type = SCALAR_TYPE_STR;
  442. scalars[1].pointer = &cfg->pid_file;
  443. g_hash_table_insert (cfg->cfg_params, "pid_file", &scalars[1]);
  444. scalars[2].type = SCALAR_TYPE_STR;
  445. scalars[2].pointer = &cfg->temp_dir;
  446. g_hash_table_insert (cfg->cfg_params, "temp_dir", &scalars[2]);
  447. scalars[3].type = SCALAR_TYPE_STR;
  448. scalars[3].pointer = &cfg->bind_host;
  449. g_hash_table_insert (cfg->cfg_params, "bind_host", &scalars[3]);
  450. scalars[4].type = SCALAR_TYPE_STR;
  451. scalars[4].pointer = &cfg->control_host;
  452. g_hash_table_insert (cfg->cfg_params, "control_host", &scalars[4]);
  453. scalars[5].type = SCALAR_TYPE_INT;
  454. scalars[5].pointer = &cfg->controller_enabled;
  455. g_hash_table_insert (cfg->cfg_params, "controller_enabled", &scalars[5]);
  456. scalars[6].type = SCALAR_TYPE_STR;
  457. scalars[6].pointer = &cfg->control_password;
  458. g_hash_table_insert (cfg->cfg_params, "control_password", &scalars[6]);
  459. scalars[7].type = SCALAR_TYPE_INT;
  460. scalars[7].pointer = &cfg->no_fork;
  461. g_hash_table_insert (cfg->cfg_params, "no_fork", &scalars[7]);
  462. scalars[8].type = SCALAR_TYPE_UINT;
  463. scalars[8].pointer = &cfg->workers_number;
  464. g_hash_table_insert (cfg->cfg_params, "workers_number", &scalars[8]);
  465. scalars[9].type = SCALAR_TYPE_SIZE;
  466. scalars[9].pointer = &cfg->max_statfile_size;
  467. g_hash_table_insert (cfg->cfg_params, "max_statfile_size", &scalars[9]);
  468. }
  469. /*
  470. * Perform post load actions
  471. */
  472. void
  473. post_load_config (struct config_file *cfg)
  474. {
  475. if (cfg->lmtp_enable && !cfg->delivery_enable) {
  476. yywarn ("post_load_config: lmtp is enabled, but delivery is not enabled, disabling lmtp");
  477. cfg->lmtp_enable = FALSE;
  478. }
  479. g_hash_table_foreach (cfg->variables, substitute_all_variables, cfg);
  480. g_hash_table_foreach (cfg->modules_opts, substitute_module_variables, cfg);
  481. parse_filters_str (cfg, cfg->header_filters_str, SCRIPT_HEADER);
  482. parse_filters_str (cfg, cfg->mime_filters_str, SCRIPT_MIME);
  483. parse_filters_str (cfg, cfg->message_filters_str, SCRIPT_MESSAGE);
  484. parse_filters_str (cfg, cfg->url_filters_str, SCRIPT_URL);
  485. fill_cfg_params (cfg);
  486. }
  487. /*
  488. * Rspamd regexp utility functions
  489. */
  490. struct rspamd_regexp*
  491. parse_regexp (memory_pool_t *pool, char *line)
  492. {
  493. char *begin, *end, *p;
  494. struct rspamd_regexp *result;
  495. int regexp_flags = 0;
  496. enum rspamd_regexp_type type = REGEXP_NONE;
  497. GError *err = NULL;
  498. result = memory_pool_alloc0 (pool, sizeof (struct rspamd_regexp));
  499. /* First try to find header name */
  500. begin = strchr (line, '=');
  501. if (begin != NULL) {
  502. *begin = '\0';
  503. result->header = memory_pool_strdup (pool, line);
  504. result->type = REGEXP_HEADER;
  505. *begin = '=';
  506. line = begin;
  507. }
  508. /* Find begin of regexp */
  509. while (*line != '/') {
  510. line ++;
  511. }
  512. if (*line != '\0') {
  513. begin = line + 1;
  514. }
  515. else if (result->header == NULL) {
  516. /* Assume that line without // is just a header name */
  517. result->header = memory_pool_strdup (pool, line);
  518. result->type = REGEXP_HEADER;
  519. return result;
  520. }
  521. else {
  522. /* We got header name earlier but have not found // expression, so it is invalid regexp */
  523. return NULL;
  524. }
  525. /* Find end */
  526. end = begin;
  527. while (*end && (*end != '/' || *(end - 1) == '\\')) {
  528. end ++;
  529. }
  530. if (end == begin || *end != '/') {
  531. return NULL;
  532. }
  533. /* Parse flags */
  534. p = end + 1;
  535. while (p != NULL) {
  536. switch (*p) {
  537. case 'i':
  538. regexp_flags |= G_REGEX_CASELESS;
  539. p ++;
  540. break;
  541. case 'm':
  542. regexp_flags |= G_REGEX_MULTILINE;
  543. p ++;
  544. break;
  545. case 's':
  546. regexp_flags |= G_REGEX_DOTALL;
  547. p ++;
  548. break;
  549. case 'x':
  550. regexp_flags |= G_REGEX_EXTENDED;
  551. p ++;
  552. break;
  553. case 'u':
  554. regexp_flags |= G_REGEX_UNGREEDY;
  555. p ++;
  556. break;
  557. case 'o':
  558. regexp_flags |= G_REGEX_OPTIMIZE;
  559. p ++;
  560. break;
  561. /* Type flags */
  562. case 'H':
  563. if (type != REGEXP_NONE) {
  564. type = REGEXP_HEADER;
  565. }
  566. p ++;
  567. break;
  568. case 'M':
  569. if (type != REGEXP_NONE) {
  570. type = REGEXP_MESSAGE;
  571. }
  572. p ++;
  573. break;
  574. case 'P':
  575. if (type != REGEXP_NONE) {
  576. type = REGEXP_MIME;
  577. }
  578. p ++;
  579. break;
  580. case 'U':
  581. if (type != REGEXP_NONE) {
  582. type = REGEXP_URL;
  583. }
  584. p ++;
  585. break;
  586. /* Stop flags parsing */
  587. default:
  588. p = NULL;
  589. break;
  590. }
  591. }
  592. result = memory_pool_alloc (pool, sizeof (struct rspamd_regexp));
  593. result->type = type;
  594. *end = '\0';
  595. result->regexp = g_regex_new (begin, regexp_flags, 0, &err);
  596. result->regexp_text = memory_pool_strdup (pool, begin);
  597. memory_pool_add_destructor (pool, (pool_destruct_func)g_regex_unref, (void *)result->regexp);
  598. *end = '/';
  599. return result;
  600. }
  601. void
  602. parse_err (const char *fmt, ...)
  603. {
  604. va_list aq;
  605. char logbuf[BUFSIZ], readbuf[32];
  606. int r;
  607. va_start (aq, fmt);
  608. g_strlcpy (readbuf, yytext, sizeof (readbuf));
  609. r = snprintf (logbuf, sizeof (logbuf), "config file parse error! line: %d, text: %s, reason: ", yylineno, readbuf);
  610. r += vsnprintf (logbuf + r, sizeof (logbuf) - r, fmt, aq);
  611. va_end (aq);
  612. g_error ("%s", logbuf);
  613. }
  614. void
  615. parse_warn (const char *fmt, ...)
  616. {
  617. va_list aq;
  618. char logbuf[BUFSIZ], readbuf[32];
  619. int r;
  620. va_start (aq, fmt);
  621. g_strlcpy (readbuf, yytext, sizeof (readbuf));
  622. r = snprintf (logbuf, sizeof (logbuf), "config file parse warning! line: %d, text: %s, reason: ", yylineno, readbuf);
  623. r += vsnprintf (logbuf + r, sizeof (logbuf) - r, fmt, aq);
  624. va_end (aq);
  625. g_warning ("%s", logbuf);
  626. }
  627. /*
  628. * vi:ts=4
  629. */