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.

util.c 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. #include <sys/param.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <time.h>
  6. #include <fcntl.h>
  7. #include <netdb.h>
  8. #include <errno.h>
  9. #include <unistd.h>
  10. #include <stdarg.h>
  11. #include <sys/file.h>
  12. #include "config.h"
  13. #ifdef HAVE_LIBUTIL_H
  14. #include <libutil.h>
  15. #endif
  16. #include "util.h"
  17. #include "cfg_file.h"
  18. int
  19. event_make_socket_nonblocking (int fd)
  20. {
  21. if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
  22. return -1;
  23. }
  24. return 0;
  25. }
  26. static int
  27. make_socket_ai (struct addrinfo *ai)
  28. {
  29. struct linger linger;
  30. int fd, on = 1, r;
  31. int serrno;
  32. /* Create listen socket */
  33. fd = socket(AF_INET, SOCK_STREAM, 0);
  34. if (fd == -1) {
  35. return (-1);
  36. }
  37. if (event_make_socket_nonblocking(fd) < 0)
  38. goto out;
  39. if (fcntl(fd, F_SETFD, 1) == -1) {
  40. goto out;
  41. }
  42. setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
  43. setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
  44. linger.l_onoff = 1;
  45. linger.l_linger = 5;
  46. setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
  47. r = bind(fd, ai->ai_addr, ai->ai_addrlen);
  48. if (r == -1) {
  49. if (errno != EINPROGRESS) {
  50. goto out;
  51. }
  52. }
  53. return (fd);
  54. out:
  55. serrno = errno;
  56. close(fd);
  57. errno = serrno;
  58. return (-1);
  59. }
  60. int
  61. make_socket (const char *address, u_short port)
  62. {
  63. int fd;
  64. struct addrinfo ai, *aitop = NULL;
  65. char strport[NI_MAXSERV];
  66. int ai_result;
  67. memset(&ai, 0, sizeof (ai));
  68. ai.ai_family = AF_INET;
  69. ai.ai_socktype = SOCK_STREAM;
  70. ai.ai_flags = AI_PASSIVE;
  71. snprintf(strport, sizeof (strport), "%d", port);
  72. if ((ai_result = getaddrinfo(address, strport, &ai, &aitop)) != 0) {
  73. return (-1);
  74. }
  75. fd = make_socket_ai(aitop);
  76. freeaddrinfo(aitop);
  77. return (fd);
  78. }
  79. int
  80. make_unix_socket (const char *path, struct sockaddr_un *addr)
  81. {
  82. size_t len = strlen (path);
  83. int sock;
  84. if (len > sizeof (addr->sun_path) - 1) return -1;
  85. #ifdef FREEBSD
  86. addr->sun_len = sizeof (struct sockaddr_un);
  87. #endif
  88. addr->sun_family = AF_UNIX;
  89. strncpy (addr->sun_path, path, len);
  90. sock = socket (PF_LOCAL, SOCK_STREAM, 0);
  91. if (sock != -1) {
  92. if (bind (sock, (struct sockaddr *) addr, sizeof (struct sockaddr_un)) == -1) return -1;
  93. }
  94. return sock;
  95. }
  96. void
  97. read_cmd_line (int argc, char **argv, struct config_file *cfg)
  98. {
  99. int ch;
  100. while ((ch = getopt(argc, argv, "hfc:")) != -1) {
  101. switch (ch) {
  102. case 'f':
  103. cfg->no_fork = 1;
  104. break;
  105. case 'c':
  106. if (optarg && cfg->cfg_name) {
  107. free (cfg->cfg_name);
  108. cfg->cfg_name = strdup (optarg);
  109. }
  110. break;
  111. case 'h':
  112. case '?':
  113. default:
  114. /* Show help message and exit */
  115. printf ("Rspamd version " RVERSION "\n"
  116. "Usage: rspamd [-h] [-n] [-f] [-c config_file]\n"
  117. "-h: This help message\n"
  118. "-f: Do not daemonize main process\n"
  119. "-c: Specify config file (./rspamd.conf is used by default)\n");
  120. exit (0);
  121. break;
  122. }
  123. }
  124. }
  125. int
  126. write_pid (struct rspamd_main *main)
  127. {
  128. pid_t pid;
  129. main->pfh = pidfile_open (main->cfg->pid_file, 0644, &pid);
  130. if (main->pfh == NULL) {
  131. return -1;
  132. }
  133. pidfile_write (main->pfh);
  134. return 0;
  135. }
  136. void
  137. init_signals (struct sigaction *signals, sig_t sig_handler)
  138. {
  139. /* Setting up signal handlers */
  140. /* SIGUSR1 - reopen config file */
  141. /* SIGUSR2 - worker is ready for accept */
  142. sigemptyset(&signals->sa_mask);
  143. sigaddset(&signals->sa_mask, SIGTERM);
  144. sigaddset(&signals->sa_mask, SIGINT);
  145. sigaddset(&signals->sa_mask, SIGHUP);
  146. sigaddset(&signals->sa_mask, SIGCHLD);
  147. sigaddset(&signals->sa_mask, SIGUSR1);
  148. sigaddset(&signals->sa_mask, SIGUSR2);
  149. signals->sa_handler = sig_handler;
  150. sigaction (SIGTERM, signals, NULL);
  151. sigaction (SIGINT, signals, NULL);
  152. sigaction (SIGHUP, signals, NULL);
  153. sigaction (SIGCHLD, signals, NULL);
  154. sigaction (SIGUSR1, signals, NULL);
  155. sigaction (SIGUSR2, signals, NULL);
  156. }
  157. void
  158. pass_signal_worker (struct workq *workers, int signo)
  159. {
  160. struct rspamd_worker *cur;
  161. TAILQ_FOREACH (cur, workers, next) {
  162. kill (cur->pid, signo);
  163. }
  164. }
  165. void convert_to_lowercase (char *str, unsigned int size)
  166. {
  167. while (size--) {
  168. *str = tolower (*str);
  169. str ++;
  170. }
  171. }
  172. #ifndef HAVE_SETPROCTITLE
  173. static char *title_buffer = 0;
  174. static size_t title_buffer_size = 0;
  175. static char *title_progname, *title_progname_full;
  176. int
  177. setproctitle(const char *fmt, ...)
  178. {
  179. if (!title_buffer || !title_buffer_size) {
  180. errno = ENOMEM;
  181. return -1;
  182. }
  183. memset (title_buffer, '\0', title_buffer_size);
  184. ssize_t written;
  185. if (fmt) {
  186. ssize_t written2;
  187. va_list ap;
  188. written = snprintf (title_buffer, title_buffer_size, "%s: ", title_progname);
  189. if (written < 0 || (size_t) written >= title_buffer_size)
  190. return -1;
  191. va_start (ap, fmt);
  192. written2 =
  193. vsnprintf (title_buffer + written,
  194. title_buffer_size - written, fmt, ap);
  195. va_end (ap);
  196. if (written2 < 0
  197. || (size_t) written2 >= title_buffer_size - written)
  198. return -1;
  199. } else {
  200. written =
  201. snprintf (title_buffer, title_buffer_size, "%s",
  202. title_progname);
  203. if (written < 0 || (size_t) written >= title_buffer_size)
  204. return -1;
  205. }
  206. written = strlen (title_buffer);
  207. memset (title_buffer + written, '\0', title_buffer_size - written);
  208. return 0;
  209. }
  210. /*
  211. It has to be _init function, because __attribute__((constructor))
  212. functions gets called without arguments.
  213. */
  214. int
  215. init_title(int argc, char *argv[], char *envp[])
  216. {
  217. char *begin_of_buffer = 0, *end_of_buffer = 0;
  218. int i;
  219. for (i = 0; i < argc; ++i) {
  220. if (!begin_of_buffer)
  221. begin_of_buffer = argv[i];
  222. if (!end_of_buffer || end_of_buffer + 1 == argv[i])
  223. end_of_buffer = argv[i] + strlen (argv[i]);
  224. }
  225. for (i = 0; envp[i]; ++i) {
  226. if (!begin_of_buffer)
  227. begin_of_buffer = envp[i];
  228. if (!end_of_buffer || end_of_buffer + 1 == envp[i])
  229. end_of_buffer = envp[i] + strlen(envp[i]);
  230. }
  231. if (!end_of_buffer)
  232. return 0;
  233. char **new_environ = g_malloc ((i + 1) * sizeof (envp[0]));
  234. if (!new_environ)
  235. return 0;
  236. for (i = 0; envp[i]; ++i) {
  237. if (!(new_environ[i] = strdup (envp[i])))
  238. goto cleanup_enomem;
  239. }
  240. new_environ[i] = 0;
  241. if (program_invocation_name) {
  242. title_progname_full = strdup (program_invocation_name);
  243. if (!title_progname_full)
  244. goto cleanup_enomem;
  245. char *p = strrchr (title_progname_full, '/');
  246. if (p)
  247. title_progname = p + 1;
  248. else
  249. title_progname = title_progname_full;
  250. program_invocation_name = title_progname_full;
  251. program_invocation_short_name = title_progname;
  252. }
  253. environ = new_environ;
  254. title_buffer = begin_of_buffer;
  255. title_buffer_size = end_of_buffer - begin_of_buffer;
  256. return 0;
  257. cleanup_enomem:
  258. for (--i; i >= 0; --i) {
  259. free(new_environ[i]);
  260. }
  261. free(new_environ);
  262. return 0;
  263. }
  264. #endif
  265. #ifndef HAVE_PIDFILE
  266. extern char * __progname;
  267. static int _pidfile_remove(struct pidfh *pfh, int freeit);
  268. static int
  269. pidfile_verify(struct pidfh *pfh)
  270. {
  271. struct stat sb;
  272. if (pfh == NULL || pfh->pf_fd == -1)
  273. return (-1);
  274. /*
  275. * Check remembered descriptor.
  276. */
  277. if (fstat(pfh->pf_fd, &sb) == -1)
  278. return (errno);
  279. if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino)
  280. return (-1);
  281. return (0);
  282. }
  283. static int
  284. pidfile_read(const char *path, pid_t *pidptr)
  285. {
  286. char buf[16], *endptr;
  287. int error, fd, i;
  288. fd = open(path, O_RDONLY);
  289. if (fd == -1)
  290. return (errno);
  291. i = read(fd, buf, sizeof(buf) - 1);
  292. error = errno; /* Remember errno in case close() wants to change it. */
  293. close(fd);
  294. if (i == -1)
  295. return (error);
  296. else if (i == 0)
  297. return (EAGAIN);
  298. buf[i] = '\0';
  299. *pidptr = strtol(buf, &endptr, 10);
  300. if (endptr != &buf[i])
  301. return (EINVAL);
  302. return (0);
  303. }
  304. struct pidfh *
  305. pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
  306. {
  307. struct pidfh *pfh;
  308. struct stat sb;
  309. int error, fd, len, count;
  310. struct timespec rqtp;
  311. pfh = g_malloc(sizeof(*pfh));
  312. if (pfh == NULL)
  313. return (NULL);
  314. if (path == NULL)
  315. len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
  316. "/var/run/%s.pid", __progname);
  317. else
  318. len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
  319. "%s", path);
  320. if (len >= (int)sizeof(pfh->pf_path)) {
  321. free(pfh);
  322. errno = ENAMETOOLONG;
  323. return (NULL);
  324. }
  325. /*
  326. * Open the PID file and obtain exclusive lock.
  327. * We truncate PID file here only to remove old PID immediatelly,
  328. * PID file will be truncated again in pidfile_write(), so
  329. * pidfile_write() can be called multiple times.
  330. */
  331. fd = open(pfh->pf_path,
  332. O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode);
  333. flock (fd, LOCK_EX | LOCK_NB);
  334. if (fd == -1) {
  335. count = 0;
  336. rqtp.tv_sec = 0;
  337. rqtp.tv_nsec = 5000000;
  338. if (errno == EWOULDBLOCK && pidptr != NULL) {
  339. again:
  340. errno = pidfile_read(pfh->pf_path, pidptr);
  341. if (errno == 0)
  342. errno = EEXIST;
  343. else if (errno == EAGAIN) {
  344. if (++count <= 3) {
  345. nanosleep(&rqtp, 0);
  346. goto again;
  347. }
  348. }
  349. }
  350. free(pfh);
  351. return (NULL);
  352. }
  353. /*
  354. * Remember file information, so in pidfile_write() we are sure we write
  355. * to the proper descriptor.
  356. */
  357. if (fstat(fd, &sb) == -1) {
  358. error = errno;
  359. unlink(pfh->pf_path);
  360. close(fd);
  361. free(pfh);
  362. errno = error;
  363. return (NULL);
  364. }
  365. pfh->pf_fd = fd;
  366. pfh->pf_dev = sb.st_dev;
  367. pfh->pf_ino = sb.st_ino;
  368. return (pfh);
  369. }
  370. int
  371. pidfile_write(struct pidfh *pfh)
  372. {
  373. char pidstr[16];
  374. int error, fd;
  375. /*
  376. * Check remembered descriptor, so we don't overwrite some other
  377. * file if pidfile was closed and descriptor reused.
  378. */
  379. errno = pidfile_verify(pfh);
  380. if (errno != 0) {
  381. /*
  382. * Don't close descriptor, because we are not sure if it's ours.
  383. */
  384. return (-1);
  385. }
  386. fd = pfh->pf_fd;
  387. /*
  388. * Truncate PID file, so multiple calls of pidfile_write() are allowed.
  389. */
  390. if (ftruncate(fd, 0) == -1) {
  391. error = errno;
  392. _pidfile_remove(pfh, 0);
  393. errno = error;
  394. return (-1);
  395. }
  396. snprintf(pidstr, sizeof(pidstr), "%u", getpid());
  397. if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
  398. error = errno;
  399. _pidfile_remove(pfh, 0);
  400. errno = error;
  401. return (-1);
  402. }
  403. return (0);
  404. }
  405. int
  406. pidfile_close(struct pidfh *pfh)
  407. {
  408. int error;
  409. error = pidfile_verify(pfh);
  410. if (error != 0) {
  411. errno = error;
  412. return (-1);
  413. }
  414. if (close(pfh->pf_fd) == -1)
  415. error = errno;
  416. free(pfh);
  417. if (error != 0) {
  418. errno = error;
  419. return (-1);
  420. }
  421. return (0);
  422. }
  423. static int
  424. _pidfile_remove(struct pidfh *pfh, int freeit)
  425. {
  426. int error;
  427. error = pidfile_verify(pfh);
  428. if (error != 0) {
  429. errno = error;
  430. return (-1);
  431. }
  432. if (unlink(pfh->pf_path) == -1)
  433. error = errno;
  434. if (flock(pfh->pf_fd, LOCK_UN) == -1) {
  435. if (error == 0)
  436. error = errno;
  437. }
  438. if (close(pfh->pf_fd) == -1) {
  439. if (error == 0)
  440. error = errno;
  441. }
  442. if (freeit)
  443. free(pfh);
  444. else
  445. pfh->pf_fd = -1;
  446. if (error != 0) {
  447. errno = error;
  448. return (-1);
  449. }
  450. return (0);
  451. }
  452. int
  453. pidfile_remove(struct pidfh *pfh)
  454. {
  455. return (_pidfile_remove(pfh, 1));
  456. }
  457. #endif
  458. /*
  459. * Functions for parsing expressions
  460. */
  461. struct expression_stack {
  462. char op;
  463. struct expression_stack *next;
  464. };
  465. /*
  466. * Push operand or operator to stack
  467. */
  468. static struct expression_stack*
  469. push_expression_stack (memory_pool_t *pool, struct expression_stack *head, char op)
  470. {
  471. struct expression_stack *new;
  472. new = memory_pool_alloc (pool, sizeof (struct expression_stack));
  473. new->op = op;
  474. new->next = head;
  475. return new;
  476. }
  477. /*
  478. * Delete symbol from stack, return pointer to operand or operator (casted to void* )
  479. */
  480. static char
  481. delete_expression_stack (struct expression_stack **head)
  482. {
  483. struct expression_stack *cur;
  484. char res;
  485. if(*head == NULL) return 0;
  486. cur = *head;
  487. res = cur->op;
  488. *head = cur->next;
  489. return res;
  490. }
  491. /*
  492. * Return operation priority
  493. */
  494. static int
  495. logic_priority (char a)
  496. {
  497. switch (a) {
  498. case '!':
  499. return 3;
  500. case '|':
  501. case '&':
  502. return 2;
  503. case '(':
  504. return 1;
  505. default:
  506. return 0;
  507. }
  508. }
  509. /*
  510. * Return 0 if symbol is not operation symbol (operand)
  511. * Return 1 if symbol is operation symbol
  512. */
  513. static int
  514. is_operation_symbol (char a)
  515. {
  516. switch (a) {
  517. case '!':
  518. case '&':
  519. case '|':
  520. case '(':
  521. case ')':
  522. return 1;
  523. default:
  524. return 0;
  525. }
  526. }
  527. static void
  528. insert_expression (memory_pool_t *pool, struct expression **head, int type, char op, void *operand)
  529. {
  530. struct expression *new, *cur;
  531. new = memory_pool_alloc (pool, sizeof (struct expression));
  532. new->type = type;
  533. if (new->type == EXPR_OPERAND) {
  534. new->content.operand = operand;
  535. }
  536. else {
  537. new->content.operation = op;
  538. }
  539. new->next = NULL;
  540. if (!*head) {
  541. *head = new;
  542. }
  543. else {
  544. cur = *head;
  545. while (cur->next) {
  546. cur = cur->next;
  547. }
  548. cur->next = new;
  549. }
  550. }
  551. /*
  552. * Make inverse polish record for specified expression
  553. * Memory is allocated from given pool
  554. */
  555. struct expression*
  556. parse_expression (memory_pool_t *pool, char *line)
  557. {
  558. struct expression *expr = NULL;
  559. struct expression_stack *stack = NULL;
  560. char *p, *c, *str, op, in_regexp = 0;
  561. if (line == NULL || pool == NULL) {
  562. return NULL;
  563. }
  564. p = line;
  565. c = p;
  566. while (*p) {
  567. if (is_operation_symbol (*p) && !in_regexp) {
  568. if (c != p) {
  569. /* Copy operand */
  570. str = memory_pool_alloc (pool, p - c + 1);
  571. strlcpy (str, c, (p - c + 1));
  572. insert_expression (pool, &expr, EXPR_OPERAND, 0, str);
  573. }
  574. if (*p == ')') {
  575. if (stack == NULL) {
  576. return NULL;
  577. }
  578. /* Pop all operators from stack to nearest '(' or to head */
  579. while (stack->op != '(') {
  580. op = delete_expression_stack (&stack);
  581. if (op != '(') {
  582. insert_expression (pool, &expr, EXPR_OPERATION, op, NULL);
  583. }
  584. }
  585. }
  586. else if (*p == '(') {
  587. /* Push it to stack */
  588. stack = push_expression_stack (pool, stack, *p);
  589. }
  590. else {
  591. if (stack == NULL) {
  592. stack = push_expression_stack (pool, stack, *p);
  593. }
  594. /* Check priority of logic operation */
  595. else {
  596. if (logic_priority (stack->op) < logic_priority (*p)) {
  597. stack = push_expression_stack (pool, stack, *p);
  598. }
  599. else {
  600. /* Pop all operations that have higher priority than this one */
  601. while((stack != NULL) && (logic_priority (stack->op) >= logic_priority (*p))) {
  602. op = delete_expression_stack (&stack);
  603. if (op != '(') {
  604. insert_expression (pool, &expr, EXPR_OPERATION, op, NULL);
  605. }
  606. }
  607. stack = push_expression_stack (pool, stack, *p);
  608. }
  609. }
  610. }
  611. c = p + 1;
  612. }
  613. if (*p == '/' && (p == line || *(p - 1) != '\\')) {
  614. in_regexp = !in_regexp;
  615. }
  616. p++;
  617. }
  618. /* Write last operand if it exists */
  619. if (c != p) {
  620. /* Copy operand */
  621. str = memory_pool_alloc (pool, p - c + 1);
  622. strlcpy (str, c, (p - c + 1));
  623. insert_expression (pool, &expr, EXPR_OPERAND, 0, str);
  624. }
  625. /* Pop everything from stack */
  626. while(stack != NULL) {
  627. op = delete_expression_stack (&stack);
  628. if (op != '(') {
  629. insert_expression (pool, &expr, EXPR_OPERATION, op, NULL);
  630. }
  631. }
  632. return expr;
  633. }
  634. /*
  635. * vi:ts=4
  636. */