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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <ctype.h>
  4. #include <errno.h>
  5. #include <stdarg.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/un.h>
  10. #include <netinet/in.h>
  11. #include <arpa/inet.h>
  12. #include <syslog.h>
  13. #include <netdb.h>
  14. #include <math.h>
  15. #include <netinet/in.h>
  16. #include <arpa/inet.h>
  17. #include "config.h"
  18. #include "cfg_file.h"
  19. #include "main.h"
  20. #ifndef HAVE_OWN_QUEUE_H
  21. #include <sys/queue.h>
  22. #else
  23. #include "queue.h"
  24. #endif
  25. extern int yylineno;
  26. extern char *yytext;
  27. int
  28. add_memcached_server (struct config_file *cf, char *str)
  29. {
  30. char *cur_tok, *err_str;
  31. struct memcached_server *mc;
  32. struct hostent *hent;
  33. uint16_t port;
  34. if (str == NULL) return 0;
  35. cur_tok = strsep (&str, ":");
  36. if (cur_tok == NULL || *cur_tok == '\0') return 0;
  37. if(cf->memcached_servers_num == MAX_MEMCACHED_SERVERS) {
  38. yywarn ("yyparse: maximum number of memcached servers is reached %d", MAX_MEMCACHED_SERVERS);
  39. }
  40. mc = &cf->memcached_servers[cf->memcached_servers_num];
  41. if (mc == NULL) return 0;
  42. /* cur_tok - server name, str - server port */
  43. if (str == NULL) {
  44. port = DEFAULT_MEMCACHED_PORT;
  45. }
  46. else {
  47. port = (uint16_t)strtoul (str, &err_str, 10);
  48. if (*err_str != '\0') {
  49. return 0;
  50. }
  51. }
  52. if (!inet_aton (cur_tok, &mc->addr)) {
  53. /* Try to call gethostbyname */
  54. hent = gethostbyname (cur_tok);
  55. if (hent == NULL) {
  56. return 0;
  57. }
  58. else {
  59. memcpy((char *)&mc->addr, hent->h_addr, sizeof(struct in_addr));
  60. }
  61. }
  62. mc->port = port;
  63. cf->memcached_servers_num++;
  64. return 1;
  65. }
  66. int
  67. parse_bind_line (struct config_file *cf, char *str, char is_control)
  68. {
  69. char *cur_tok, *err_str;
  70. struct hostent *hent;
  71. size_t s;
  72. if (str == NULL) return 0;
  73. cur_tok = strsep (&str, ":");
  74. if (cur_tok[0] == '/' || cur_tok[0] == '.') {
  75. if (is_control) {
  76. cf->control_host = memory_pool_strdup (cf->cfg_pool, cur_tok);
  77. cf->control_family = AF_UNIX;
  78. }
  79. else {
  80. cf->bind_host = memory_pool_strdup (cf->cfg_pool, cur_tok);
  81. cf->bind_family = AF_UNIX;
  82. }
  83. return 1;
  84. } else {
  85. if (str == '\0') {
  86. if (is_control) {
  87. cf->control_port = DEFAULT_CONTROL_PORT;
  88. }
  89. else {
  90. cf->bind_port = DEFAULT_BIND_PORT;
  91. }
  92. }
  93. else {
  94. if (is_control) {
  95. cf->control_port = (uint16_t)strtoul (str, &err_str, 10);
  96. }
  97. else {
  98. cf->bind_port = (uint16_t)strtoul (str, &err_str, 10);
  99. }
  100. if (*err_str != '\0') {
  101. return 0;
  102. }
  103. }
  104. if (is_control) {
  105. if (!inet_aton (cur_tok, &cf->control_addr)) {
  106. /* Try to call gethostbyname */
  107. hent = gethostbyname (cur_tok);
  108. if (hent == NULL) {
  109. return 0;
  110. }
  111. else {
  112. cf->bind_host = memory_pool_strdup (cf->cfg_pool, cur_tok);
  113. memcpy((char *)&cf->control_addr, hent->h_addr, sizeof(struct in_addr));
  114. s = strlen (cur_tok) + 1;
  115. }
  116. }
  117. cf->control_family = AF_INET;
  118. }
  119. else {
  120. if (!inet_aton (cur_tok, &cf->bind_addr)) {
  121. /* Try to call gethostbyname */
  122. hent = gethostbyname (cur_tok);
  123. if (hent == NULL) {
  124. return 0;
  125. }
  126. else {
  127. cf->bind_host = memory_pool_strdup (cf->cfg_pool, cur_tok);
  128. memcpy((char *)&cf->bind_addr, hent->h_addr, sizeof(struct in_addr));
  129. s = strlen (cur_tok) + 1;
  130. }
  131. }
  132. cf->bind_family = AF_INET;
  133. }
  134. return 1;
  135. }
  136. return 0;
  137. }
  138. void
  139. init_defaults (struct config_file *cfg)
  140. {
  141. cfg->memcached_error_time = DEFAULT_UPSTREAM_ERROR_TIME;
  142. cfg->memcached_dead_time = DEFAULT_UPSTREAM_DEAD_TIME;
  143. cfg->memcached_maxerrors = DEFAULT_UPSTREAM_MAXERRORS;
  144. cfg->memcached_protocol = TCP_TEXT;
  145. cfg->workers_number = DEFAULT_WORKERS_NUM;
  146. cfg->max_statfile_size = DEFAULT_STATFILE_SIZE;
  147. cfg->modules_opts = g_hash_table_new (g_str_hash, g_str_equal);
  148. cfg->variables = g_hash_table_new (g_str_hash, g_str_equal);
  149. cfg->metrics = g_hash_table_new (g_str_hash, g_str_equal);
  150. cfg->factors = g_hash_table_new (g_str_hash, g_str_equal);
  151. cfg->c_modules = g_hash_table_new (g_str_hash, g_str_equal);
  152. cfg->composite_symbols = g_hash_table_new (g_str_hash, g_str_equal);
  153. cfg->statfiles = g_hash_table_new (g_str_hash, g_str_equal);
  154. LIST_INIT (&cfg->perl_modules);
  155. }
  156. void
  157. free_config (struct config_file *cfg)
  158. {
  159. g_hash_table_remove_all (cfg->modules_opts);
  160. g_hash_table_unref (cfg->modules_opts);
  161. g_hash_table_remove_all (cfg->variables);
  162. g_hash_table_unref (cfg->variables);
  163. g_hash_table_remove_all (cfg->metrics);
  164. g_hash_table_unref (cfg->metrics);
  165. g_hash_table_remove_all (cfg->factors);
  166. g_hash_table_unref (cfg->factors);
  167. g_hash_table_remove_all (cfg->c_modules);
  168. g_hash_table_unref (cfg->c_modules);
  169. g_hash_table_remove_all (cfg->composite_symbols);
  170. g_hash_table_unref (cfg->composite_symbols);
  171. g_hash_table_remove_all (cfg->statfiles);
  172. g_hash_table_unref (cfg->statfiles);
  173. memory_pool_delete (cfg->cfg_pool);
  174. }
  175. char*
  176. get_module_opt (struct config_file *cfg, char *module_name, char *opt_name)
  177. {
  178. LIST_HEAD (moduleoptq, module_opt) *cur_module_opt = NULL;
  179. struct module_opt *cur;
  180. cur_module_opt = g_hash_table_lookup (cfg->modules_opts, module_name);
  181. if (cur_module_opt == NULL) {
  182. return NULL;
  183. }
  184. LIST_FOREACH (cur, cur_module_opt, next) {
  185. if (strcmp (cur->param, opt_name) == 0) {
  186. return cur->value;
  187. }
  188. }
  189. return NULL;
  190. }
  191. size_t
  192. parse_limit (const char *limit)
  193. {
  194. size_t result = 0;
  195. char *err_str;
  196. if (!limit || *limit == '\0') return 0;
  197. result = strtoul (limit, &err_str, 10);
  198. if (*err_str != '\0') {
  199. /* Megabytes */
  200. if (*err_str == 'm' || *err_str == 'M') {
  201. result *= 1048576L;
  202. }
  203. /* Kilobytes */
  204. else if (*err_str == 'k' || *err_str == 'K') {
  205. result *= 1024;
  206. }
  207. /* Gigabytes */
  208. else if (*err_str == 'g' || *err_str == 'G') {
  209. result *= 1073741824L;
  210. }
  211. }
  212. return result;
  213. }
  214. unsigned int
  215. parse_seconds (const char *t)
  216. {
  217. unsigned int result = 0;
  218. char *err_str;
  219. if (!t || *t == '\0') return 0;
  220. result = strtoul (t, &err_str, 10);
  221. if (*err_str != '\0') {
  222. /* Seconds */
  223. if (*err_str == 's' || *err_str == 'S') {
  224. result *= 1000;
  225. }
  226. }
  227. return result;
  228. }
  229. char
  230. parse_flag (const char *str)
  231. {
  232. if (!str || !*str) return -1;
  233. if ((*str == 'Y' || *str == 'y') && *(str + 1) == '\0') {
  234. return 1;
  235. }
  236. if ((*str == 'Y' || *str == 'y') &&
  237. (*(str + 1) == 'E' || *(str + 1) == 'e') &&
  238. (*(str + 2) == 'S' || *(str + 2) == 's') &&
  239. *(str + 3) == '\0') {
  240. return 1;
  241. }
  242. if ((*str == 'N' || *str == 'n') && *(str + 1) == '\0') {
  243. return 0;
  244. }
  245. if ((*str == 'N' || *str == 'n') &&
  246. (*(str + 1) == 'O' || *(str + 1) == 'o') &&
  247. *(str + 2) == '\0') {
  248. return 0;
  249. }
  250. return -1;
  251. }
  252. /*
  253. * Try to substitute all variables in given string
  254. * Return: newly allocated string with substituted variables (original string may be freed if variables are found)
  255. */
  256. char *
  257. substitute_variable (struct config_file *cfg, char *str, u_char recursive)
  258. {
  259. char *var, *new, *v_begin, *v_end;
  260. size_t len;
  261. while ((v_begin = strstr (str, "${")) != NULL) {
  262. len = strlen (str);
  263. *v_begin = '\0';
  264. v_begin += 2;
  265. if ((v_end = strstr (v_begin, "}")) == NULL) {
  266. /* Not a variable, skip */
  267. continue;
  268. }
  269. *v_end = '\0';
  270. var = g_hash_table_lookup (cfg->variables, v_begin);
  271. if (var == NULL) {
  272. yywarn ("substitute_variable: variable %s is not defined", v_begin);
  273. /* Substitute unknown variables with empty string */
  274. var = "";
  275. }
  276. else if (recursive) {
  277. var = substitute_variable (cfg, var, recursive);
  278. }
  279. /* Allocate new string */
  280. new = memory_pool_alloc (cfg->cfg_pool, len - strlen (v_begin) + strlen (var) + 1);
  281. snprintf (new, len - strlen (v_begin) + strlen (var) + 1, "%s%s%s",
  282. str, var, v_end + 1);
  283. str = new;
  284. }
  285. return str;
  286. }
  287. static void
  288. substitute_module_variables (gpointer key, gpointer value, gpointer data)
  289. {
  290. struct config_file *cfg = (struct config_file *)data;
  291. LIST_HEAD (moduleoptq, module_opt) *cur_module_opt = (struct moduleoptq *)value;
  292. struct module_opt *cur, *tmp;
  293. LIST_FOREACH_SAFE (cur, cur_module_opt, next, tmp) {
  294. if (cur->value) {
  295. cur->value = substitute_variable (cfg, cur->value, 0);
  296. }
  297. }
  298. }
  299. static void
  300. substitute_all_variables (gpointer key, gpointer value, gpointer data)
  301. {
  302. struct config_file *cfg = (struct config_file *)data;
  303. char *var;
  304. var = value;
  305. /* Do recursive substitution */
  306. var = substitute_variable (cfg, var, 1);
  307. }
  308. static void
  309. parse_filters_str (struct config_file *cfg, const char *str, enum script_type type)
  310. {
  311. gchar **strvec, **p;
  312. struct filter *cur;
  313. int i;
  314. if (str == NULL) {
  315. return;
  316. }
  317. strvec = g_strsplit (str, ",", 0);
  318. if (strvec == NULL) {
  319. return;
  320. }
  321. p = strvec;
  322. while (*p++) {
  323. cur = NULL;
  324. /* Search modules from known C modules */
  325. for (i = 0; i < MODULES_NUM; i++) {
  326. if (strcasecmp (modules[i].name, *p) == 0) {
  327. cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct filter));
  328. cur->type = C_FILTER;
  329. switch (type) {
  330. case SCRIPT_HEADER:
  331. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  332. LIST_INSERT_HEAD (&cfg->header_filters, cur, next);
  333. break;
  334. case SCRIPT_MIME:
  335. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  336. LIST_INSERT_HEAD (&cfg->mime_filters, cur, next);
  337. break;
  338. case SCRIPT_MESSAGE:
  339. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  340. LIST_INSERT_HEAD (&cfg->message_filters, cur, next);
  341. break;
  342. case SCRIPT_URL:
  343. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  344. LIST_INSERT_HEAD (&cfg->url_filters, cur, next);
  345. break;
  346. }
  347. break;
  348. }
  349. }
  350. if (cur != NULL) {
  351. /* Go to next iteration */
  352. continue;
  353. }
  354. cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct filter));
  355. cur->type = PERL_FILTER;
  356. switch (type) {
  357. case SCRIPT_HEADER:
  358. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  359. LIST_INSERT_HEAD (&cfg->header_filters, cur, next);
  360. break;
  361. case SCRIPT_MIME:
  362. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  363. LIST_INSERT_HEAD (&cfg->mime_filters, cur, next);
  364. break;
  365. case SCRIPT_MESSAGE:
  366. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  367. LIST_INSERT_HEAD (&cfg->message_filters, cur, next);
  368. break;
  369. case SCRIPT_URL:
  370. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  371. LIST_INSERT_HEAD (&cfg->url_filters, cur, next);
  372. break;
  373. }
  374. }
  375. g_strfreev (strvec);
  376. }
  377. /*
  378. * Substitute all variables in strings
  379. */
  380. void
  381. post_load_config (struct config_file *cfg)
  382. {
  383. g_hash_table_foreach (cfg->variables, substitute_all_variables, cfg);
  384. g_hash_table_foreach (cfg->modules_opts, substitute_module_variables, cfg);
  385. parse_filters_str (cfg, cfg->header_filters_str, SCRIPT_HEADER);
  386. parse_filters_str (cfg, cfg->mime_filters_str, SCRIPT_MIME);
  387. parse_filters_str (cfg, cfg->message_filters_str, SCRIPT_MESSAGE);
  388. parse_filters_str (cfg, cfg->url_filters_str, SCRIPT_URL);
  389. }
  390. /*
  391. * Rspamd regexp utility functions
  392. */
  393. struct rspamd_regexp*
  394. parse_regexp (memory_pool_t *pool, char *line)
  395. {
  396. char *begin, *end, *p;
  397. struct rspamd_regexp *result;
  398. int regexp_flags = 0;
  399. enum rspamd_regexp_type type = REGEXP_NONE;
  400. GError *err = NULL;
  401. result = memory_pool_alloc0 (pool, sizeof (struct rspamd_regexp));
  402. /* First try to find header name */
  403. begin = strchr (line, '=');
  404. if (begin != NULL) {
  405. *begin = '\0';
  406. result->header = memory_pool_strdup (pool, line);
  407. result->type = REGEXP_HEADER;
  408. *begin = '=';
  409. line = begin;
  410. }
  411. /* Find begin of regexp */
  412. while (*line != '/') {
  413. line ++;
  414. }
  415. if (*line != '\0') {
  416. begin = line + 1;
  417. }
  418. else if (result->header == NULL) {
  419. /* Assume that line without // is just a header name */
  420. result->header = memory_pool_strdup (pool, line);
  421. result->type = REGEXP_HEADER;
  422. return result;
  423. }
  424. else {
  425. /* We got header name earlier but have not found // expression, so it is invalid regexp */
  426. return NULL;
  427. }
  428. /* Find end */
  429. end = begin;
  430. while (*end && (*end != '/' || *(end - 1) == '\\')) {
  431. end ++;
  432. }
  433. if (end == begin || *end != '/') {
  434. return NULL;
  435. }
  436. /* Parse flags */
  437. p = end + 1;
  438. while (p != NULL) {
  439. switch (*p) {
  440. case 'i':
  441. regexp_flags |= G_REGEX_CASELESS;
  442. p ++;
  443. break;
  444. case 'm':
  445. regexp_flags |= G_REGEX_MULTILINE;
  446. p ++;
  447. break;
  448. case 's':
  449. regexp_flags |= G_REGEX_DOTALL;
  450. p ++;
  451. break;
  452. case 'x':
  453. regexp_flags |= G_REGEX_EXTENDED;
  454. p ++;
  455. break;
  456. case 'u':
  457. regexp_flags |= G_REGEX_UNGREEDY;
  458. p ++;
  459. break;
  460. case 'o':
  461. regexp_flags |= G_REGEX_OPTIMIZE;
  462. p ++;
  463. break;
  464. /* Type flags */
  465. case 'H':
  466. if (type != REGEXP_NONE) {
  467. type = REGEXP_HEADER;
  468. }
  469. p ++;
  470. break;
  471. case 'M':
  472. if (type != REGEXP_NONE) {
  473. type = REGEXP_MESSAGE;
  474. }
  475. p ++;
  476. break;
  477. case 'P':
  478. if (type != REGEXP_NONE) {
  479. type = REGEXP_MIME;
  480. }
  481. p ++;
  482. break;
  483. case 'U':
  484. if (type != REGEXP_NONE) {
  485. type = REGEXP_URL;
  486. }
  487. p ++;
  488. break;
  489. /* Stop flags parsing */
  490. default:
  491. p = NULL;
  492. break;
  493. }
  494. }
  495. result = memory_pool_alloc (pool, sizeof (struct rspamd_regexp));
  496. result->type = type;
  497. *end = '\0';
  498. result->regexp = g_regex_new (begin, regexp_flags, 0, &err);
  499. result->regexp_text = memory_pool_strdup (pool, begin);
  500. memory_pool_add_destructor (pool, (pool_destruct_func)g_regex_unref, (void *)result->regexp);
  501. *end = '/';
  502. return result;
  503. }
  504. /*
  505. * vi:ts=4
  506. */