123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223 |
- /*
- * Copyright (c) 2009-2012, Vsevolod Stakhov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
- #include "config.h"
- #include "util.h"
- #include "cfg_file.h"
- #include "main.h"
- #include "statfile.h"
- #include "filter.h"
- #include "message.h"
-
- #ifdef HAVE_OPENSSL
- #include <openssl/rand.h>
- #include <openssl/err.h>
- #endif
-
- #ifdef HAVE_TERMIOS_H
- #include <termios.h>
- #endif
- #ifdef HAVE_READPASSPHRASE_H
- #include <readpassphrase.h>
- #endif
-
- /* Check log messages intensity once per minute */
- #define CHECK_TIME 60
- /* More than 2 log messages per second */
- #define BUF_INTENSITY 2
- /* Default connect timeout for sync sockets */
- #define CONNECT_TIMEOUT 3
-
- gint
- make_socket_nonblocking (gint fd)
- {
- gint ofl;
-
- ofl = fcntl (fd, F_GETFL, 0);
-
- if (fcntl (fd, F_SETFL, ofl | O_NONBLOCK) == -1) {
- msg_warn ("fcntl failed: %d, '%s'", errno, strerror (errno));
- return -1;
- }
- return 0;
- }
-
- gint
- make_socket_blocking (gint fd)
- {
- gint ofl;
-
- ofl = fcntl (fd, F_GETFL, 0);
-
- if (fcntl (fd, F_SETFL, ofl & (~O_NONBLOCK)) == -1) {
- msg_warn ("fcntl failed: %d, '%s'", errno, strerror (errno));
- return -1;
- }
- return 0;
- }
-
- gint
- poll_sync_socket (gint fd, gint timeout, short events)
- {
- gint r;
- struct pollfd fds[1];
-
- fds->fd = fd;
- fds->events = events;
- fds->revents = 0;
- while ((r = poll (fds, 1, timeout)) < 0) {
- if (errno != EINTR) {
- break;
- }
- }
-
- return r;
- }
-
- static gint
- make_inet_socket (gint type, struct addrinfo *addr, gboolean is_server, gboolean async, GList **list)
- {
- gint fd, r, optlen, on = 1, s_error;
- struct addrinfo *cur;
-
- cur = addr;
- while (cur) {
- /* Create socket */
- fd = socket (cur->ai_family, type, 0);
- if (fd == -1) {
- msg_warn ("socket failed: %d, '%s'", errno, strerror (errno));
- goto out;
- }
-
- if (make_socket_nonblocking (fd) < 0) {
- goto out;
- }
-
- /* Set close on exec */
- if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) {
- msg_warn ("fcntl failed: %d, '%s'", errno, strerror (errno));
- goto out;
- }
-
- if (is_server) {
- setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
- #ifdef HAVE_IPV6_V6ONLY
- if (cur->ai_family == AF_INET6) {
- setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&on, sizeof (gint));
- }
- #endif
- r = bind (fd, cur->ai_addr, cur->ai_addrlen);
- }
- else {
- r = connect (fd, cur->ai_addr, cur->ai_addrlen);
- }
-
- if (r == -1) {
- if (errno != EINPROGRESS) {
- msg_warn ("bind/connect failed: %d, '%s'", errno, strerror (errno));
- goto out;
- }
- if (!async) {
- /* Try to poll */
- if (poll_sync_socket (fd, CONNECT_TIMEOUT * 1000, POLLOUT) <= 0) {
- errno = ETIMEDOUT;
- msg_warn ("bind/connect failed: timeout");
- goto out;
- }
- else {
- /* Make synced again */
- if (make_socket_blocking (fd) < 0) {
- goto out;
- }
- }
- }
- }
- else {
- /* Still need to check SO_ERROR on socket */
- optlen = sizeof (s_error);
- getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *)&s_error, &optlen);
- if (s_error) {
- errno = s_error;
- goto out;
- }
- }
- if (list == NULL) {
- /* Go out immediately */
- break;
- }
- else if (fd != -1) {
- *list = g_list_prepend (*list, GINT_TO_POINTER (fd));
- cur = cur->ai_next;
- continue;
- }
- out:
- if (fd != -1) {
- close (fd);
- }
- fd = -1;
- cur = cur->ai_next;
- }
- return (fd);
- }
-
- gint
- make_tcp_socket (struct addrinfo *addr, gboolean is_server, gboolean async)
- {
- return make_inet_socket (SOCK_STREAM, addr, is_server, async, NULL);
- }
-
- gint
- make_udp_socket (struct addrinfo *addr, gboolean is_server, gboolean async)
- {
- return make_inet_socket (SOCK_DGRAM, addr, is_server, async, NULL);
- }
-
- gint
- accept_from_socket (gint listen_sock, struct sockaddr *addr, socklen_t * len)
- {
- gint nfd;
- gint serrno;
-
- if ((nfd = accept (listen_sock, addr, len)) == -1) {
- if (errno == EAGAIN) {
- return 0;
- }
- msg_warn ("accept failed: %d, '%s'", errno, strerror (errno));
- return -1;
- }
- if (make_socket_nonblocking (nfd) < 0) {
- goto out;
- }
-
- /* Set close on exec */
- if (fcntl (nfd, F_SETFD, FD_CLOEXEC) == -1) {
- msg_warn ("fcntl failed: %d, '%s'", errno, strerror (errno));
- goto out;
- }
-
-
-
- return (nfd);
-
- out:
- serrno = errno;
- close (nfd);
- errno = serrno;
- return (-1);
-
- }
-
- gint
- make_unix_socket (const gchar *path, struct sockaddr_un *addr, gint type, gboolean is_server, gboolean async)
- {
- gint fd = -1, s_error, r, optlen, serrno, on = 1;
- struct stat st;
-
- if (path == NULL)
- return -1;
-
- addr->sun_family = AF_UNIX;
-
- rspamd_strlcpy (addr->sun_path, path, sizeof (addr->sun_path));
- #ifdef FREEBSD
- addr->sun_len = SUN_LEN (addr);
- #endif
-
- if (is_server) {
- /* Unlink socket if it exists already */
- if (lstat (addr->sun_path, &st) != -1) {
- if (S_ISSOCK (st.st_mode)) {
- if (unlink (addr->sun_path) == -1) {
- msg_warn ("unlink %s failed: %d, '%s'", addr->sun_path, errno, strerror (errno));
- goto out;
- }
- }
- else {
- msg_warn ("%s is not a socket", addr->sun_path);
- goto out;
- }
- }
- }
- fd = socket (PF_LOCAL, type, 0);
-
- if (fd == -1) {
- msg_warn ("socket failed %s: %d, '%s'", addr->sun_path, errno, strerror (errno));
- return -1;
- }
-
- if (make_socket_nonblocking (fd) < 0) {
- goto out;
- }
-
- /* Set close on exec */
- if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) {
- msg_warn ("fcntl failed %s: %d, '%s'", addr->sun_path, errno, strerror (errno));
- goto out;
- }
- if (is_server) {
- setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
- r = bind (fd, (struct sockaddr *)addr, SUN_LEN (addr));
- }
- else {
- r = connect (fd, (struct sockaddr *)addr, SUN_LEN (addr));
- }
-
- if (r == -1) {
- if (errno != EINPROGRESS) {
- msg_warn ("bind/connect failed %s: %d, '%s'", addr->sun_path, errno, strerror (errno));
- goto out;
- }
- if (!async) {
- /* Try to poll */
- if (poll_sync_socket (fd, CONNECT_TIMEOUT * 1000, POLLOUT) <= 0) {
- errno = ETIMEDOUT;
- msg_warn ("bind/connect failed %s: timeout", addr->sun_path);
- goto out;
- }
- else {
- /* Make synced again */
- if (make_socket_blocking (fd) < 0) {
- goto out;
- }
- }
- }
- }
- else {
- /* Still need to check SO_ERROR on socket */
- optlen = sizeof (s_error);
- getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *)&s_error, &optlen);
- if (s_error) {
- errno = s_error;
- goto out;
- }
- }
-
-
- return (fd);
-
- out:
- serrno = errno;
- if (fd != -1) {
- close (fd);
- }
- errno = serrno;
- return (-1);
- }
-
- /**
- * Make a universal socket
- * @param credits host, ip or path to unix socket
- * @param port port (used for network sockets)
- * @param async make this socket asynced
- * @param is_server make this socket as server socket
- * @param try_resolve try name resolution for a socket (BLOCKING)
- */
- gint
- make_universal_socket (const gchar *credits, guint16 port,
- gint type, gboolean async, gboolean is_server, gboolean try_resolve)
- {
- struct sockaddr_un un;
- struct stat st;
- struct addrinfo hints, *res;
- gint r;
- gchar portbuf[8];
-
- if (*credits == '/') {
- if (is_server) {
- return make_unix_socket (credits, &un, type, is_server, async);
- }
- else {
- r = stat (credits, &st);
- if (r == -1) {
- /* Unix socket doesn't exists it must be created first */
- errno = ENOENT;
- return -1;
- }
- else {
- if ((st.st_mode & S_IFSOCK) == 0) {
- /* Path is not valid socket */
- errno = EINVAL;
- return -1;
- }
- else {
- return make_unix_socket (credits, &un, type, is_server, async);
- }
- }
- }
- }
- else {
- /* TCP related part */
- memset (&hints, 0, sizeof (hints));
- hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
- hints.ai_socktype = type; /* Type of the socket */
- hints.ai_flags = is_server ? AI_PASSIVE : 0;
- hints.ai_protocol = 0; /* Any protocol */
- hints.ai_canonname = NULL;
- hints.ai_addr = NULL;
- hints.ai_next = NULL;
-
- if (!try_resolve) {
- hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
- }
-
- rspamd_snprintf (portbuf, sizeof (portbuf), "%d", (int)port);
- if ((r = getaddrinfo (credits, portbuf, &hints, &res)) == 0) {
- r = make_inet_socket (type, res, is_server, async, NULL);
- freeaddrinfo (res);
- return r;
- }
- else {
- msg_err ("address resolution for %s failed: %s", credits, gai_strerror (r));
- return FALSE;
- }
- }
- }
-
- /**
- * Make universal stream socket
- * @param credits host, ip or path to unix socket
- * @param port port (used for network sockets)
- * @param async make this socket asynced
- * @param is_server make this socket as server socket
- * @param try_resolve try name resolution for a socket (BLOCKING)
- */
- GList*
- make_universal_sockets_list (const gchar *credits, guint16 port,
- gint type, gboolean async, gboolean is_server, gboolean try_resolve)
- {
- struct sockaddr_un un;
- struct stat st;
- struct addrinfo hints, *res;
- gint r, fd, serrno;
- gchar portbuf[8], **strv, **cur;
- GList *result = NULL, *rcur;
-
- strv = g_strsplit_set (credits, ",", -1);
- if (strv == NULL) {
- msg_err ("invalid sockets credentials: %s", credits);
- return NULL;
- }
- cur = strv;
- while (*cur != NULL) {
- if (*credits == '/') {
- if (is_server) {
- fd = make_unix_socket (credits, &un, type, is_server, async);
- }
- else {
- r = stat (credits, &st);
- if (r == -1) {
- /* Unix socket doesn't exists it must be created first */
- errno = ENOENT;
- goto err;
- }
- else {
- if ((st.st_mode & S_IFSOCK) == 0) {
- /* Path is not valid socket */
- errno = EINVAL;
- goto err;
- }
- else {
- fd = make_unix_socket (credits, &un, type, is_server, async);
- }
- }
- }
- if (fd != -1) {
- result = g_list_prepend (result, GINT_TO_POINTER (fd));
- }
- else {
- goto err;
- }
- }
- else {
- /* TCP related part */
- memset (&hints, 0, sizeof (hints));
- hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
- hints.ai_socktype = type; /* Type of the socket */
- hints.ai_flags = is_server ? AI_PASSIVE : 0;
- hints.ai_protocol = 0; /* Any protocol */
- hints.ai_canonname = NULL;
- hints.ai_addr = NULL;
- hints.ai_next = NULL;
-
- if (!try_resolve) {
- hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
- }
-
- rspamd_snprintf (portbuf, sizeof (portbuf), "%d", (int)port);
- if ((r = getaddrinfo (credits, portbuf, &hints, &res)) == 0) {
- r = make_inet_socket (type, res, is_server, async, &result);
- freeaddrinfo (res);
- if (r == -1) {
- goto err;
- }
- }
- else {
- msg_err ("address resolution for %s failed: %s", credits, gai_strerror (r));
- goto err;
- }
- }
- cur ++;
- }
-
- g_strfreev (strv);
- return result;
-
- err:
- g_strfreev (strv);
- serrno = errno;
- rcur = result;
- while (rcur != NULL) {
- fd = GPOINTER_TO_INT (rcur->data);
- if (fd != -1) {
- close (fd);
- }
- rcur = g_list_next (rcur);
- }
- if (result != NULL) {
- g_list_free (result);
- }
-
- errno = serrno;
- return NULL;
- }
-
- gint
- make_socketpair (gint pair[2])
- {
- gint r;
-
- r = socketpair (AF_LOCAL, SOCK_STREAM, 0, pair);
-
- if (r == -1) {
- msg_warn ("socketpair failed: %d, '%s'", errno, strerror (errno), pair[0], pair[1]);
- return -1;
- }
- /* Set close on exec */
- if (fcntl (pair[0], F_SETFD, FD_CLOEXEC) == -1) {
- msg_warn ("fcntl failed: %d, '%s'", errno, strerror (errno));
- goto out;
- }
- if (fcntl (pair[1], F_SETFD, FD_CLOEXEC) == -1) {
- msg_warn ("fcntl failed: %d, '%s'", errno, strerror (errno));
- goto out;
- }
-
- return 0;
-
- out:
- close (pair[0]);
- close (pair[1]);
- return (-1);
- }
-
- gint
- write_pid (struct rspamd_main *main)
- {
- pid_t pid;
-
- if (main->cfg->pid_file == NULL) {
- return -1;
- }
- main->pfh = rspamd_pidfile_open (main->cfg->pid_file, 0644, &pid);
-
- if (main->pfh == NULL) {
- return -1;
- }
-
- if (main->is_privilleged) {
- /* Force root user as owner of pid file */
- #ifdef HAVE_PIDFILE_FILENO
- if (fchown (pidfile_fileno (main->pfh), 0, 0) == -1) {
- #else
- if (fchown (main->pfh->pf_fd, 0, 0) == -1) {
- #endif
- msg_err ("cannot chown of pidfile %s to 0:0 user", main->cfg->pid_file);
- }
- }
-
- rspamd_pidfile_write (main->pfh);
-
- return 0;
- }
-
- #ifdef HAVE_SA_SIGINFO
- void
- init_signals (struct sigaction *signals, void (*sig_handler)(gint, siginfo_t *, void *))
- #else
- void
- init_signals (struct sigaction *signals, void (*sig_handler)(gint))
- #endif
- {
- struct sigaction sigpipe_act;
- /* Setting up signal handlers */
- /* SIGUSR1 - reopen config file */
- /* SIGUSR2 - worker is ready for accept */
- sigemptyset (&signals->sa_mask);
- sigaddset (&signals->sa_mask, SIGTERM);
- sigaddset (&signals->sa_mask, SIGINT);
- sigaddset (&signals->sa_mask, SIGHUP);
- sigaddset (&signals->sa_mask, SIGCHLD);
- sigaddset (&signals->sa_mask, SIGUSR1);
- sigaddset (&signals->sa_mask, SIGUSR2);
- sigaddset (&signals->sa_mask, SIGALRM);
-
-
- #ifdef HAVE_SA_SIGINFO
- signals->sa_flags = SA_SIGINFO;
- signals->sa_handler = NULL;
- signals->sa_sigaction = sig_handler;
- #else
- signals->sa_handler = sig_handler;
- signals->sa_flags = 0;
- #endif
- sigaction (SIGTERM, signals, NULL);
- sigaction (SIGINT, signals, NULL);
- sigaction (SIGHUP, signals, NULL);
- sigaction (SIGCHLD, signals, NULL);
- sigaction (SIGUSR1, signals, NULL);
- sigaction (SIGUSR2, signals, NULL);
- sigaction (SIGALRM, signals, NULL);
-
- /* Ignore SIGPIPE as we handle write errors manually */
- sigemptyset (&sigpipe_act.sa_mask);
- sigaddset (&sigpipe_act.sa_mask, SIGPIPE);
- sigpipe_act.sa_handler = SIG_IGN;
- sigpipe_act.sa_flags = 0;
- sigaction (SIGPIPE, &sigpipe_act, NULL);
- }
-
- static void
- pass_signal_cb (gpointer key, gpointer value, gpointer ud)
- {
- struct rspamd_worker *cur = value;
- gint signo = GPOINTER_TO_INT (ud);
-
- kill (cur->pid, signo);
- }
-
- void
- pass_signal_worker (GHashTable * workers, gint signo)
- {
- g_hash_table_foreach (workers, pass_signal_cb, GINT_TO_POINTER (signo));
- }
-
- void
- convert_to_lowercase (gchar *str, guint size)
- {
- while (size--) {
- *str = g_ascii_tolower (*str);
- str++;
- }
- }
-
- #ifndef HAVE_SETPROCTITLE
-
- static gchar *title_buffer = 0;
- static size_t title_buffer_size = 0;
- static gchar *title_progname, *title_progname_full;
-
- gint
- setproctitle (const gchar *fmt, ...)
- {
- if (!title_buffer || !title_buffer_size) {
- errno = ENOMEM;
- return -1;
- }
-
- memset (title_buffer, '\0', title_buffer_size);
-
- ssize_t written;
-
- if (fmt) {
- ssize_t written2;
- va_list ap;
-
- written = snprintf (title_buffer, title_buffer_size, "%s: ", title_progname);
- if (written < 0 || (size_t) written >= title_buffer_size)
- return -1;
-
- va_start (ap, fmt);
- written2 = vsnprintf (title_buffer + written, title_buffer_size - written, fmt, ap);
- va_end (ap);
- if (written2 < 0 || (size_t) written2 >= title_buffer_size - written)
- return -1;
- }
- else {
- written = snprintf (title_buffer, title_buffer_size, "%s", title_progname);
- if (written < 0 || (size_t) written >= title_buffer_size)
- return -1;
- }
-
- written = strlen (title_buffer);
- memset (title_buffer + written, '\0', title_buffer_size - written);
-
- return 0;
- }
-
- /*
- It has to be _init function, because __attribute__((constructor))
- functions gets called without arguments.
- */
-
- gint
- init_title (gint argc, gchar *argv[], gchar *envp[])
- {
- #if defined(DARWIN) || defined(SOLARIS)
- /* XXX: try to handle these OSes too */
- return 0;
- #else
- gchar *begin_of_buffer = 0, *end_of_buffer = 0;
- gint i;
-
- for (i = 0; i < argc; ++i) {
- if (!begin_of_buffer)
- begin_of_buffer = argv[i];
- if (!end_of_buffer || end_of_buffer + 1 == argv[i])
- end_of_buffer = argv[i] + strlen (argv[i]);
- }
-
- for (i = 0; envp[i]; ++i) {
- if (!begin_of_buffer)
- begin_of_buffer = envp[i];
- if (!end_of_buffer || end_of_buffer + 1 == envp[i])
- end_of_buffer = envp[i] + strlen (envp[i]);
- }
-
- if (!end_of_buffer)
- return 0;
-
- gchar **new_environ = g_malloc ((i + 1) * sizeof (envp[0]));
-
- if (!new_environ)
- return 0;
-
- for (i = 0; envp[i]; ++i) {
- if (!(new_environ[i] = g_strdup (envp[i])))
- goto cleanup_enomem;
- }
- new_environ[i] = 0;
-
- if (program_invocation_name) {
- title_progname_full = g_strdup (program_invocation_name);
-
- if (!title_progname_full)
- goto cleanup_enomem;
-
- gchar *p = strrchr (title_progname_full, '/');
-
- if (p)
- title_progname = p + 1;
- else
- title_progname = title_progname_full;
-
- program_invocation_name = title_progname_full;
- program_invocation_short_name = title_progname;
- }
-
- environ = new_environ;
- title_buffer = begin_of_buffer;
- title_buffer_size = end_of_buffer - begin_of_buffer;
-
- return 0;
-
- cleanup_enomem:
- for (--i; i >= 0; --i) {
- g_free (new_environ[i]);
- }
- g_free (new_environ);
- return 0;
- #endif
- }
- #endif
-
- #ifndef HAVE_PIDFILE
- extern gchar *__progname;
- static gint _rspamd_pidfile_remove (rspamd_pidfh_t *pfh, gint freeit);
-
- static gint
- rspamd_pidfile_verify (rspamd_pidfh_t *pfh)
- {
- struct stat sb;
-
- if (pfh == NULL || pfh->pf_fd == -1)
- return (-1);
- /*
- * Check remembered descriptor.
- */
- if (fstat (pfh->pf_fd, &sb) == -1)
- return (errno);
- if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino)
- return -1;
- return 0;
- }
-
- static gint
- rspamd_pidfile_read (const gchar *path, pid_t * pidptr)
- {
- gchar buf[16], *endptr;
- gint error, fd, i;
-
- fd = open (path, O_RDONLY);
- if (fd == -1)
- return (errno);
-
- i = read (fd, buf, sizeof (buf) - 1);
- error = errno; /* Remember errno in case close() wants to change it. */
- close (fd);
- if (i == -1)
- return error;
- else if (i == 0)
- return EAGAIN;
- buf[i] = '\0';
-
- *pidptr = strtol (buf, &endptr, 10);
- if (endptr != &buf[i])
- return EINVAL;
-
- return 0;
- }
-
- rspamd_pidfh_t *
- rspamd_pidfile_open (const gchar *path, mode_t mode, pid_t * pidptr)
- {
- rspamd_pidfh_t *pfh;
- struct stat sb;
- gint error, fd, len, count;
- struct timespec rqtp;
-
- pfh = g_malloc (sizeof (*pfh));
- if (pfh == NULL)
- return NULL;
-
- if (path == NULL)
- len = snprintf (pfh->pf_path, sizeof (pfh->pf_path), "/var/run/%s.pid", g_get_prgname ());
- else
- len = snprintf (pfh->pf_path, sizeof (pfh->pf_path), "%s", path);
- if (len >= (gint)sizeof (pfh->pf_path)) {
- g_free (pfh);
- errno = ENAMETOOLONG;
- return NULL;
- }
-
- /*
- * Open the PID file and obtain exclusive lock.
- * We truncate PID file here only to remove old PID immediatelly,
- * PID file will be truncated again in pidfile_write(), so
- * pidfile_write() can be called multiple times.
- */
- fd = open (pfh->pf_path, O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode);
- lock_file (fd, TRUE);
- if (fd == -1) {
- count = 0;
- rqtp.tv_sec = 0;
- rqtp.tv_nsec = 5000000;
- if (errno == EWOULDBLOCK && pidptr != NULL) {
- again:
- errno = rspamd_pidfile_read (pfh->pf_path, pidptr);
- if (errno == 0)
- errno = EEXIST;
- else if (errno == EAGAIN) {
- if (++count <= 3) {
- nanosleep (&rqtp, 0);
- goto again;
- }
- }
- }
- g_free (pfh);
- return NULL;
- }
- /*
- * Remember file information, so in pidfile_write() we are sure we write
- * to the proper descriptor.
- */
- if (fstat (fd, &sb) == -1) {
- error = errno;
- unlink (pfh->pf_path);
- close (fd);
- g_free (pfh);
- errno = error;
- return NULL;
- }
-
- pfh->pf_fd = fd;
- pfh->pf_dev = sb.st_dev;
- pfh->pf_ino = sb.st_ino;
-
- return pfh;
- }
-
- gint
- rspamd_pidfile_write (rspamd_pidfh_t *pfh)
- {
- gchar pidstr[16];
- gint error, fd;
-
- /*
- * Check remembered descriptor, so we don't overwrite some other
- * file if pidfile was closed and descriptor reused.
- */
- errno = rspamd_pidfile_verify (pfh);
- if (errno != 0) {
- /*
- * Don't close descriptor, because we are not sure if it's ours.
- */
- return -1;
- }
- fd = pfh->pf_fd;
-
- /*
- * Truncate PID file, so multiple calls of pidfile_write() are allowed.
- */
- if (ftruncate (fd, 0) == -1) {
- error = errno;
- _rspamd_pidfile_remove (pfh, 0);
- errno = error;
- return -1;
- }
-
- rspamd_snprintf (pidstr, sizeof (pidstr), "%P", getpid ());
- if (pwrite (fd, pidstr, strlen (pidstr), 0) != (ssize_t) strlen (pidstr)) {
- error = errno;
- _rspamd_pidfile_remove (pfh, 0);
- errno = error;
- return -1;
- }
-
- return 0;
- }
-
- gint
- rspamd_pidfile_close (rspamd_pidfh_t *pfh)
- {
- gint error;
-
- error = rspamd_pidfile_verify (pfh);
- if (error != 0) {
- errno = error;
- return -1;
- }
-
- if (close (pfh->pf_fd) == -1)
- error = errno;
- g_free (pfh);
- if (error != 0) {
- errno = error;
- return -1;
- }
- return 0;
- }
-
- static gint
- _rspamd_pidfile_remove (rspamd_pidfh_t *pfh, gint freeit)
- {
- gint error;
-
- error = rspamd_pidfile_verify (pfh);
- if (error != 0) {
- errno = error;
- return -1;
- }
-
- if (unlink (pfh->pf_path) == -1)
- error = errno;
- if (!unlock_file (pfh->pf_fd, FALSE)) {
- if (error == 0)
- error = errno;
- }
- if (close (pfh->pf_fd) == -1) {
- if (error == 0)
- error = errno;
- }
- if (freeit)
- g_free (pfh);
- else
- pfh->pf_fd = -1;
- if (error != 0) {
- errno = error;
- return -1;
- }
- return 0;
- }
-
- gint
- rspamd_pidfile_remove (rspamd_pidfh_t *pfh)
- {
-
- return (_rspamd_pidfile_remove (pfh, 1));
- }
- #endif
-
- /* Replace %r with rcpt value and %f with from value, new string is allocated in pool */
- gchar *
- resolve_stat_filename (memory_pool_t * pool, gchar *pattern, gchar *rcpt, gchar *from)
- {
- gint need_to_format = 0, len = 0;
- gint rcptlen, fromlen;
- gchar *c = pattern, *new, *s;
-
- if (rcpt) {
- rcptlen = strlen (rcpt);
- }
- else {
- rcptlen = 0;
- }
-
- if (from) {
- fromlen = strlen (from);
- }
- else {
- fromlen = 0;
- }
-
- /* Calculate length */
- while (*c++) {
- if (*c == '%' && *(c + 1) == 'r') {
- len += rcptlen;
- c += 2;
- need_to_format = 1;
- continue;
- }
- else if (*c == '%' && *(c + 1) == 'f') {
- len += fromlen;
- c += 2;
- need_to_format = 1;
- continue;
- }
- len++;
- }
-
- /* Do not allocate extra memory if we do not need to format string */
- if (!need_to_format) {
- return pattern;
- }
-
- /* Allocate new string */
- new = memory_pool_alloc (pool, len);
- c = pattern;
- s = new;
-
- /* Format string */
- while (*c++) {
- if (*c == '%' && *(c + 1) == 'r') {
- c += 2;
- memcpy (s, rcpt, rcptlen);
- s += rcptlen;
- continue;
- }
- else if (*c == '%' && *(c + 1) == 'r') {
- c += 2;
- memcpy (s, from, fromlen);
- s += fromlen;
- continue;
- }
- *s++ = *c;
- }
-
- *s = '\0';
-
- return new;
- }
-
- #ifdef HAVE_CLOCK_GETTIME
- const gchar *
- calculate_check_time (struct timeval *tv, struct timespec *begin, gint resolution, guint32 *scan_time)
- #else
- const gchar *
- calculate_check_time (struct timeval *begin, gint resolution, guint32 *scan_time)
- #endif
- {
- double vdiff, diff;
- static gchar res[64];
- static gchar fmt[sizeof ("%.10f ms real, %.10f ms virtual")];
- struct timeval tv_now;
-
- if (gettimeofday (&tv_now, NULL) == -1) {
- msg_warn ("gettimeofday failed: %s", strerror (errno));
- }
- #ifdef HAVE_CLOCK_GETTIME
- struct timespec ts;
-
- diff = (tv_now.tv_sec - tv->tv_sec) * 1000. + /* Seconds */
- (tv_now.tv_usec - tv->tv_usec) / 1000.; /* Microseconds */
- #ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
- clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &ts);
- #elif defined(HAVE_CLOCK_VIRTUAL)
- clock_gettime (CLOCK_VIRTUAL, &ts);
- #else
- clock_gettime (CLOCK_REALTIME, &ts);
- #endif
-
- vdiff = (ts.tv_sec - begin->tv_sec) * 1000. + /* Seconds */
- (ts.tv_nsec - begin->tv_nsec) / 1000000.; /* Nanoseconds */
- #else
- diff = (tv_now.tv_sec - begin->tv_sec) * 1000. + /* Seconds */
- (tv_now.tv_usec - begin->tv_usec) / 1000.; /* Microseconds */
-
- vdiff = diff;
- #endif
-
- *scan_time = diff;
-
- sprintf (fmt, "%%.%dfms real, %%.%dfms virtual", resolution, resolution);
- snprintf (res, sizeof (res), fmt, diff, vdiff);
-
- return (const gchar *)res;
- }
-
- #ifndef g_tolower
- # define g_tolower(x) (((x) >= 'A' && (x) <= 'Z') ? (x) - 'A' + 'a' : (x))
- #endif
-
-
- gboolean
- rspamd_strcase_equal (gconstpointer v, gconstpointer v2)
- {
- if (g_ascii_strcasecmp ((const gchar *)v, (const gchar *)v2) == 0) {
- return TRUE;
- }
-
- return FALSE;
- }
-
-
- guint
- rspamd_strcase_hash (gconstpointer key)
- {
- const gchar *p = key;
- gchar buf[256];
- guint h = 0, i = 0;
-
-
- while (*p != '\0') {
- buf[i] = g_ascii_tolower (*p);
- i++;
- p++;
- if (i == sizeof (buf)) {
- h ^= murmur32_hash (buf, i);
- i = 0;
- }
- }
-
- if (i > 0) {
- h ^= murmur32_hash (buf, i);
- }
-
- return h;
- }
-
- guint
- rspamd_str_hash (gconstpointer key)
- {
- gsize len;
-
- len = strlen ((const gchar *)key);
-
- return murmur32_hash (key, len);
- }
-
- gboolean
- rspamd_str_equal (gconstpointer v, gconstpointer v2)
- {
- return strcmp ((const gchar *)v, (const gchar *)v2) == 0;
- }
-
- gboolean
- fstr_strcase_equal (gconstpointer v, gconstpointer v2)
- {
- const f_str_t *f1 = v, *f2 = v2;
- if (f1->len == f2->len && g_ascii_strncasecmp (f1->begin, f2->begin, f1->len) == 0) {
- return TRUE;
- }
-
- return FALSE;
- }
-
-
- guint
- fstr_strcase_hash (gconstpointer key)
- {
- const f_str_t *f = key;
- const gchar *p;
- guint h = 0, i = 0;
- gchar buf[256];
-
- p = f->begin;
- while (p - f->begin < (gint)f->len) {
- buf[i] = g_ascii_tolower (*p);
- i++;
- p++;
- if (i == sizeof (buf)) {
- h ^= murmur32_hash (buf, i);
- i = 0;
- }
- }
-
- if (i > 0) {
- h ^= murmur32_hash (buf, i);
- }
-
- return h;
- }
-
- void
- gperf_profiler_init (struct config_file *cfg, const gchar *descr)
- {
- #if defined(WITH_GPERF_TOOLS)
- gchar prof_path[PATH_MAX];
-
- if (getenv ("CPUPROFILE")) {
-
- /* disable inherited Profiler enabled in master process */
- ProfilerStop ();
- }
- /* Try to create temp directory for gmon.out and chdir to it */
- if (cfg->profile_path == NULL) {
- cfg->profile_path = g_strdup_printf ("%s/rspamd-profile", cfg->temp_dir);
- }
-
- snprintf (prof_path, sizeof (prof_path), "%s-%s.%d", cfg->profile_path, descr, (gint)getpid ());
- if (ProfilerStart (prof_path)) {
- /* start ITIMER_PROF timer */
- ProfilerRegisterThread ();
- }
- else {
- msg_warn ("cannot start google perftools profiler");
- }
-
- #endif
- }
-
- #ifdef HAVE_FLOCK
- /* Flock version */
- gboolean
- lock_file (gint fd, gboolean async)
- {
- gint flags;
-
- if (async) {
- flags = LOCK_EX | LOCK_NB;
- }
- else {
- flags = LOCK_EX;
- }
-
- if (flock (fd, flags) == -1) {
- if (async && errno == EAGAIN) {
- return FALSE;
- }
- msg_warn ("lock on file failed: %s", strerror (errno));
- return FALSE;
- }
-
- return TRUE;
- }
-
- gboolean
- unlock_file (gint fd, gboolean async)
- {
- gint flags;
-
- if (async) {
- flags = LOCK_UN | LOCK_NB;
- }
- else {
- flags = LOCK_UN;
- }
-
- if (flock (fd, flags) == -1) {
- if (async && errno == EAGAIN) {
- return FALSE;
- }
- msg_warn ("lock on file failed: %s", strerror (errno));
- return FALSE;
- }
-
- return TRUE;
-
- }
- #else /* HAVE_FLOCK */
- /* Fctnl version */
- gboolean
- lock_file (gint fd, gboolean async)
- {
- struct flock fl = {
- .l_type = F_WRLCK,
- .l_whence = SEEK_SET,
- .l_start = 0,
- .l_len = 0
- };
-
- if (fcntl (fd, async ? F_SETLK : F_SETLKW, &fl) == -1) {
- if (async && (errno == EAGAIN || errno == EACCES)) {
- return FALSE;
- }
- msg_warn ("lock on file failed: %s", strerror (errno));
- return FALSE;
- }
-
- return TRUE;
- }
-
- gboolean
- unlock_file (gint fd, gboolean async)
- {
- struct flock fl = {
- .l_type = F_UNLCK,
- .l_whence = SEEK_SET,
- .l_start = 0,
- .l_len = 0
- };
-
- if (fcntl (fd, async ? F_SETLK : F_SETLKW, &fl) == -1) {
- if (async && (errno == EAGAIN || errno == EACCES)) {
- return FALSE;
- }
- msg_warn ("lock on file failed: %s", strerror (errno));
- return FALSE;
- }
-
- return TRUE;
-
- }
- #endif /* HAVE_FLOCK */
-
-
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION < 22))
- void
- g_ptr_array_unref (GPtrArray *array)
- {
- g_ptr_array_free (array, TRUE);
- }
- #endif
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION < 14))
- void
- g_queue_clear (GQueue *queue)
- {
- g_return_if_fail (queue != NULL);
-
- g_list_free (queue->head);
- queue->head = queue->tail = NULL;
- queue->length = 0;
- }
- #endif
-
- gsize
- rspamd_strlcpy (gchar *dst, const gchar *src, gsize siz)
- {
- gchar *d = dst;
- const gchar *s = src;
- gsize n = siz;
-
- /* Copy as many bytes as will fit */
- if (n != 0) {
- while (--n != 0) {
- if ((*d++ = *s++) == '\0') {
- break;
- }
- }
- }
-
- if (n == 0 && siz != 0) {
- *d = '\0';
- }
-
- return (s - src - 1); /* count does not include NUL */
- }
-
- gsize
- rspamd_strlcpy_tolower (gchar *dst, const gchar *src, gsize siz)
- {
- gchar *d = dst;
- const gchar *s = src;
- gsize n = siz;
-
- /* Copy as many bytes as will fit */
- if (n != 0) {
- while (--n != 0) {
- if ((*d++ = g_ascii_tolower (*s++)) == '\0') {
- break;
- }
- }
- }
-
- if (n == 0 && siz != 0) {
- *d = '\0';
- }
-
- return (s - src - 1); /* count does not include NUL */
- }
-
- /* Compare two emails for building emails tree */
- gint
- compare_email_func (gconstpointer a, gconstpointer b)
- {
- const struct uri *u1 = a, *u2 = b;
- gint r;
-
- if (u1->hostlen != u2->hostlen || u1->hostlen == 0) {
- return u1->hostlen - u2->hostlen;
- }
- else {
- if ((r = g_ascii_strncasecmp (u1->host, u2->host, u1->hostlen)) == 0){
- if (u1->userlen != u2->userlen || u1->userlen == 0) {
- return u1->userlen - u2->userlen;
- }
- else {
- return g_ascii_strncasecmp (u1->user, u2->user, u1->userlen);
- }
- }
- else {
- return r;
- }
- }
-
- return 0;
- }
-
- gint
- compare_url_func (gconstpointer a, gconstpointer b)
- {
- const struct uri *u1 = a, *u2 = b;
- int r;
-
- if (u1->hostlen != u2->hostlen || u1->hostlen == 0) {
- return u1->hostlen - u2->hostlen;
- }
- else {
- r = g_ascii_strncasecmp (u1->host, u2->host, u1->hostlen);
- if (r == 0 && u1->is_phished != u2->is_phished) {
- /* Always insert phished urls to the tree */
- return -1;
- }
- }
-
- return r;
- }
-
- /*
- * Find the first occurrence of find in s, ignore case.
- */
- gchar *
- rspamd_strncasestr (const gchar *s, const gchar *find, gint len)
- {
- gchar c, sc;
- gsize mlen;
-
- if ((c = *find++) != 0) {
- c = g_ascii_tolower (c);
- mlen = strlen (find);
- do {
- do {
- if ((sc = *s++) == 0 || len -- == 0)
- return (NULL);
- } while (g_ascii_tolower (sc) != c);
- } while (g_ascii_strncasecmp (s, find, mlen) != 0);
- s--;
- }
- return ((gchar *)s);
- }
-
- /*
- * Try to convert string of length to long
- */
- gboolean
- rspamd_strtol (const gchar *s, gsize len, glong *value)
- {
- const gchar *p = s, *end = s + len;
- gchar c;
- glong v = 0;
- const glong cutoff = G_MAXLONG / 10, cutlim = G_MAXLONG % 10;
- gboolean neg;
-
- /* Case negative values */
- if (*p == '-') {
- neg = TRUE;
- p ++;
- }
- else {
- neg = FALSE;
- }
- /* Some preparations for range errors */
-
- while (p < end) {
- c = *p;
- if (c >= '0' && c <= '9') {
- c -= '0';
- if (v > cutoff || (v == cutoff && c > cutlim)) {
- /* Range error */
- *value = neg ? G_MINLONG : G_MAXLONG;
- return FALSE;
- }
- else {
- v *= 10;
- v += c;
- }
- }
- else {
- return FALSE;
- }
- p ++;
- }
-
- *value = neg ? -(v) : v;
- return TRUE;
- }
-
- /*
- * Try to convert string of length to long
- */
- gboolean
- rspamd_strtoul (const gchar *s, gsize len, gulong *value)
- {
- const gchar *p = s, *end = s + len;
- gchar c;
- gulong v = 0;
- const gulong cutoff = G_MAXULONG / 10, cutlim = G_MAXULONG % 10;
-
- /* Some preparations for range errors */
- while (p < end) {
- c = *p;
- if (c >= '0' && c <= '9') {
- c -= '0';
- if (v > cutoff || (v == cutoff && (guint8)c > cutlim)) {
- /* Range error */
- *value = G_MAXULONG;
- return FALSE;
- }
- else {
- v *= 10;
- v += c;
- }
- }
- else {
- return FALSE;
- }
- p ++;
- }
-
- *value = v;
- return TRUE;
- }
-
- gint
- rspamd_fallocate (gint fd, off_t offset, off_t len)
- {
- #if defined(HAVE_FALLOCATE)
- return fallocate (fd, 0, offset, len);
- #elif defined(HAVE_POSIX_FALLOCATE)
- return posix_fallocate (fd, offset, len);
- #else
- /* Return 0 as nothing can be done on this system */
- return 0;
- #endif
- }
-
-
- /**
- * Create new mutex
- * @return mutex or NULL
- */
- inline rspamd_mutex_t*
- rspamd_mutex_new (void)
- {
- rspamd_mutex_t *new;
-
- new = g_slice_alloc (sizeof (rspamd_mutex_t));
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- g_mutex_init (&new->mtx);
- #else
- g_static_mutex_init (&new->mtx);
- #endif
-
- return new;
- }
-
- /**
- * Lock mutex
- * @param mtx
- */
- inline void
- rspamd_mutex_lock (rspamd_mutex_t *mtx)
- {
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- g_mutex_lock (&mtx->mtx);
- #else
- g_static_mutex_lock (&mtx->mtx);
- #endif
- }
-
- /**
- * Unlock mutex
- * @param mtx
- */
- inline void
- rspamd_mutex_unlock (rspamd_mutex_t *mtx)
- {
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- g_mutex_unlock (&mtx->mtx);
- #else
- g_static_mutex_unlock (&mtx->mtx);
- #endif
- }
-
- void
- rspamd_mutex_free (rspamd_mutex_t *mtx)
- {
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- g_mutex_clear (&mtx->mtx);
- #endif
- g_slice_free1 (sizeof (rspamd_mutex_t), mtx);
- }
-
- /**
- * Create new rwlock
- * @return
- */
- rspamd_rwlock_t*
- rspamd_rwlock_new (void)
- {
- rspamd_rwlock_t *new;
-
- new = g_malloc (sizeof (rspamd_rwlock_t));
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- g_rw_lock_init (&new->rwlock);
- #else
- g_static_rw_lock_init (&new->rwlock);
- #endif
-
- return new;
- }
-
- /**
- * Lock rwlock for writing
- * @param mtx
- */
- inline void
- rspamd_rwlock_writer_lock (rspamd_rwlock_t *mtx)
- {
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- g_rw_lock_writer_lock (&mtx->rwlock);
- #else
- g_static_rw_lock_writer_lock (&mtx->rwlock);
- #endif
- }
-
- /**
- * Lock rwlock for reading
- * @param mtx
- */
- inline void
- rspamd_rwlock_reader_lock (rspamd_rwlock_t *mtx)
- {
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- g_rw_lock_reader_lock (&mtx->rwlock);
- #else
- g_static_rw_lock_reader_lock (&mtx->rwlock);
- #endif
- }
-
- /**
- * Unlock rwlock from writing
- * @param mtx
- */
- inline void
- rspamd_rwlock_writer_unlock (rspamd_rwlock_t *mtx)
- {
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- g_rw_lock_writer_unlock (&mtx->rwlock);
- #else
- g_static_rw_lock_writer_unlock (&mtx->rwlock);
- #endif
- }
-
- /**
- * Unlock rwlock from reading
- * @param mtx
- */
- inline void
- rspamd_rwlock_reader_unlock (rspamd_rwlock_t *mtx)
- {
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- g_rw_lock_reader_unlock (&mtx->rwlock);
- #else
- g_static_rw_lock_reader_unlock (&mtx->rwlock);
- #endif
- }
-
- void
- rspamd_rwlock_free (rspamd_rwlock_t *mtx)
- {
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- g_rw_lock_clear (&mtx->rwlock);
- #endif
- g_slice_free1 (sizeof (rspamd_rwlock_t), mtx);
- }
-
- struct rspamd_thread_data {
- gchar *name;
- gint id;
- GThreadFunc func;
- gpointer data;
- };
-
- static gpointer
- rspamd_thread_func (gpointer ud)
- {
- struct rspamd_thread_data *td = ud;
- sigset_t s_mask;
-
- /* Ignore signals in thread */
- sigemptyset (&s_mask);
- sigaddset (&s_mask, SIGTERM);
- sigaddset (&s_mask, SIGINT);
- sigaddset (&s_mask, SIGHUP);
- sigaddset (&s_mask, SIGCHLD);
- sigaddset (&s_mask, SIGUSR1);
- sigaddset (&s_mask, SIGUSR2);
- sigaddset (&s_mask, SIGALRM);
- sigaddset (&s_mask, SIGPIPE);
-
- sigprocmask (SIG_BLOCK, &s_mask, NULL);
-
- ud = td->func (td->data);
- g_free (td->name);
- g_free (td);
-
- return ud;
- }
-
- /**
- * Create new named thread
- * @param name name pattern
- * @param func function to start
- * @param data data to pass to function
- * @param err error pointer
- * @return new thread object that can be joined
- */
- GThread*
- rspamd_create_thread (const gchar *name, GThreadFunc func, gpointer data, GError **err)
- {
- GThread *new;
- struct rspamd_thread_data *td;
- static gint32 id;
- guint r;
-
- r = strlen (name);
- td = g_malloc (sizeof (struct rspamd_thread_data));
- td->id = ++id;
- td->name = g_malloc (r + sizeof ("4294967296"));
- td->func = func;
- td->data = data;
-
- rspamd_snprintf (td->name, r + sizeof ("4294967296"), "%s-%d", name, id);
- #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- new = g_thread_try_new (td->name, rspamd_thread_func, td, err);
- #else
- new = g_thread_create (rspamd_thread_func, td, TRUE, err);
- #endif
-
- return new;
- }
-
- guint32
- murmur32_hash (const guint8 *in, gsize len)
- {
-
-
- const guint32 c1 = 0xcc9e2d51;
- const guint32 c2 = 0x1b873593;
-
- const int nblocks = len / 4;
- const guint32 *blocks = (const guint32 *)(in);
- const guint8 *tail;
- guint32 h = 0;
- gint i;
- guint32 k;
-
- if (in == NULL || len == 0) {
- return 0;
- }
-
- tail = (const guint8 *)(in + (nblocks * 4));
-
- for (i = 0; i < nblocks; i++) {
- k = blocks[i];
-
- k *= c1;
- k = (k << 15) | (k >> (32 - 15));
- k *= c2;
-
- h ^= k;
- h = (h << 13) | (h >> (32 - 13));
- h = (h * 5) + 0xe6546b64;
- }
-
- k = 0;
- switch (len & 3) {
- case 3:
- k ^= tail[2] << 16;
- case 2:
- k ^= tail[1] << 8;
- case 1:
- k ^= tail[0];
- k *= c1;
- k = (k << 13) | (k >> (32 - 15));
- k *= c2;
- h ^= k;
- };
-
- h ^= len;
-
- h ^= h >> 16;
- h *= 0x85ebca6b;
- h ^= h >> 13;
- h *= 0xc2b2ae35;
- h ^= h >> 16;
-
- return h;
- }
-
- void
- murmur128_hash (const guint8 *in, gsize len, guint64 out[])
- {
- const guint64 c1 = 0x87c37b91114253d5ULL;
- const guint64 c2 = 0x4cf5ad432745937fULL;
- const gint nblocks = len / 16;
- const guint64 *blocks = (const guint64 *)(in);
- const guint8 *tail;
- guint64 h1 = 0;
- guint64 h2 = 0;
- int i;
- guint64 k1, k2;
-
- if (in == NULL || len == 0 || out == NULL) {
- return;
- }
-
- tail = (const guint8 *)(in + (nblocks * 16));
-
- for (i = 0; i < nblocks; i++) {
- k1 = blocks[i*2+0];
- k2 = blocks[i*2+1];
-
- k1 *= c1;
- k1 = (k1 << 31) | (k1 >> (64 - 31));
- k1 *= c2;
- h1 ^= k1;
-
- h1 = (h1 << 27) | (h1 >> (64 - 27));
- h1 += h2;
- h1 = h1*5+0x52dce729;
-
- k2 *= c2;
- k2 = (k2 << 33) | (k2 >> (64 - 33));
- k2 *= c1;
- h2 ^= k2;
-
- h2 = (h2 << 31) | (h2 >> (64 - 31));
- h2 += h1;
- h2 = h2*5+0x38495ab5;
- }
-
- k1 = k2 = 0;
- switch (len & 15) {
- case 15:
- k2 ^= (guint64)(tail[14]) << 48;
- case 14:
- k2 ^= (guint64)(tail[13]) << 40;
- case 13:
- k2 ^= (guint64)(tail[12]) << 32;
- case 12:
- k2 ^= (guint64)(tail[11]) << 24;
- case 11:
- k2 ^= (guint64)(tail[10]) << 16;
- case 10:
- k2 ^= (guint64)(tail[ 9]) << 8;
- case 9:
- k2 ^= (guint64)(tail[ 8]) << 0;
- k2 *= c2;
- k2 = (k2 << 33) | (k2 >> (64 - 33));
- k2 *= c1;
- h2 ^= k2;
-
- case 8:
- k1 ^= (guint64)(tail[ 7]) << 56;
- case 7:
- k1 ^= (guint64)(tail[ 6]) << 48;
- case 6:
- k1 ^= (guint64)(tail[ 5]) << 40;
- case 5:
- k1 ^= (guint64)(tail[ 4]) << 32;
- case 4:
- k1 ^= (guint64)(tail[ 3]) << 24;
- case 3:
- k1 ^= (guint64)(tail[ 2]) << 16;
- case 2:
- k1 ^= (guint64)(tail[ 1]) << 8;
- case 1:
- k1 ^= (guint64)(tail[ 0]) << 0;
- k1 *= c1;
- k1 = (k1 << 31) | (k1 >> (64 - 31));
- k1 *= c2;
- h1 ^= k1;
- };
-
- //----------
- // finalization
-
- h1 ^= len;
- h2 ^= len;
-
- h1 += h2;
- h2 += h1;
-
- h1 ^= h1 >> 33;
- h1 *= 0xff51afd7ed558ccdULL;
- h1 ^= h1 >> 33;
- h1 *= 0xc4ceb9fe1a85ec53ULL;
- h1 ^= h1 >> 33;
-
- h2 ^= h2 >> 33;
- h2 *= 0xff51afd7ed558ccdULL;
- h2 ^= h2 >> 33;
- h2 *= 0xc4ceb9fe1a85ec53ULL;
- h2 ^= h2 >> 33;
-
- h1 += h2;
- h2 += h1;
-
- out[0] = h1;
- out[1] = h2;
- }
-
- struct hash_copy_callback_data {
- gpointer (*key_copy_func)(gconstpointer data, gpointer ud);
- gpointer (*value_copy_func)(gconstpointer data, gpointer ud);
- gpointer ud;
- GHashTable *dst;
- };
-
- static void
- copy_foreach_callback (gpointer key, gpointer value, gpointer ud)
- {
- struct hash_copy_callback_data *cb = ud;
- gpointer nkey, nvalue;
-
- nkey = cb->key_copy_func ? cb->key_copy_func (key, cb->ud) : (gpointer)key;
- nvalue = cb->value_copy_func ? cb->value_copy_func (value, cb->ud) : (gpointer)value;
- g_hash_table_insert (cb->dst, nkey, nvalue);
- }
- /**
- * Deep copy of one hash table to another
- * @param src source hash
- * @param dst destination hash
- * @param key_copy_func function called to copy or modify keys (or NULL)
- * @param value_copy_func function called to copy or modify values (or NULL)
- * @param ud user data for copy functions
- */
- void rspamd_hash_table_copy (GHashTable *src, GHashTable *dst,
- gpointer (*key_copy_func)(gconstpointer data, gpointer ud),
- gpointer (*value_copy_func)(gconstpointer data, gpointer ud),
- gpointer ud)
- {
- struct hash_copy_callback_data cb;
- if (src != NULL && dst != NULL) {
- cb.key_copy_func = key_copy_func;
- cb.value_copy_func = value_copy_func;
- cb.ud = ud;
- cb.dst = dst;
- g_hash_table_foreach (src, copy_foreach_callback, &cb);
- }
- }
-
- /**
- * Utility function to provide mem_pool copy for rspamd_hash_table_copy function
- * @param data string to copy
- * @param ud memory pool to use
- * @return
- */
- gpointer
- rspamd_str_pool_copy (gconstpointer data, gpointer ud)
- {
- memory_pool_t *pool = ud;
-
- return data ? memory_pool_strdup (pool, data) : NULL;
- }
-
- gboolean
- parse_ipmask_v4 (const char *line, struct in_addr *ina, int *mask)
- {
- const char *pos;
- char ip_buf[INET_ADDRSTRLEN + 1], mask_buf[3] = { '\0', '\0', '\0' };
-
- bzero (ip_buf, sizeof (ip_buf));
-
- if ((pos = strchr (line, '/')) != NULL) {
- rspamd_strlcpy (ip_buf, line, MIN ((gsize)(pos - line), sizeof (ip_buf)));
- rspamd_strlcpy (mask_buf, pos + 1, sizeof (mask_buf));
- }
- else {
- rspamd_strlcpy (ip_buf, line, sizeof (ip_buf));
- }
-
- if (!inet_aton (ip_buf, ina)) {
- return FALSE;
- }
-
- if (mask_buf[0] != '\0') {
- /* Also parse mask */
- *mask = (mask_buf[0] - '0') * 10 + mask_buf[1] - '0';
- if (*mask > 32) {
- return FALSE;
- }
- }
- else {
- *mask = 32;
- }
-
- *mask = G_MAXUINT32 << (32 - *mask);
-
- return TRUE;
- }
-
- static volatile sig_atomic_t saved_signo[NSIG];
-
- static
- void read_pass_tmp_sig_handler (int s)
- {
-
- saved_signo[s] = 1;
- }
-
- #ifndef _PATH_TTY
- # define _PATH_TTY "/dev/tty"
- #endif
-
- gint
- rspamd_read_passphrase (gchar *buf, gint size, gint rwflag, gpointer key)
- {
- #ifdef HAVE_PASSPHRASE_H
- gint len = 0;
- gchar pass[BUFSIZ];
-
- if (readpassphrase ("Enter passphrase: ", buf, size, RPP_ECHO_OFF | RPP_REQUIRE_TTY) == NULL) {
- return 0;
- }
-
- return strlen (buf);
- #else
- struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
- struct sigaction savetstp, savettin, savettou, savepipe;
- struct termios term, oterm;
- gint input, output, i;
- gchar *end, *p, ch;
-
- restart:
- if ((input = output = open (_PATH_TTY, O_RDWR)) == -1) {
- errno = ENOTTY;
- return 0;
- }
- if (fcntl (input, F_SETFD, FD_CLOEXEC) == -1) {
- msg_warn ("fcntl failed: %d, '%s'", errno, strerror (errno));
- }
-
- /* Turn echo off */
- if (tcgetattr (input, &oterm) != 0) {
- errno = ENOTTY;
- return 0;
- }
- memcpy(&term, &oterm, sizeof(term));
- term.c_lflag &= ~(ECHO | ECHONL);
- (void)tcsetattr(input, TCSAFLUSH, &term);
- (void)write (output, "Enter passphrase: ", sizeof ("Enter passphrase: ") - 1);
-
- /* Save the current sighandler */
- for (i = 0; i < NSIG; i++) {
- saved_signo[i] = 0;
- }
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- sa.sa_handler = read_pass_tmp_sig_handler;
- (void)sigaction (SIGALRM, &sa, &savealrm);
- (void)sigaction (SIGHUP, &sa, &savehup);
- (void)sigaction (SIGINT, &sa, &saveint);
- (void)sigaction (SIGPIPE, &sa, &savepipe);
- (void)sigaction (SIGQUIT, &sa, &savequit);
- (void)sigaction (SIGTERM, &sa, &saveterm);
- (void)sigaction (SIGTSTP, &sa, &savetstp);
- (void)sigaction (SIGTTIN, &sa, &savettin);
- (void)sigaction (SIGTTOU, &sa, &savettou);
-
- /* Now read a passphrase */
- p = buf;
- end = p + size - 1;
- while (read (input, &ch, 1) == 1 && ch != '\n' && ch != '\r') {
- if (p < end) {
- *p++ = ch;
- }
- }
- *p = '\0';
- (void)write (output, "\n", 1);
-
- /* Restore terminal state */
- if (memcmp (&term, &oterm, sizeof (term)) != 0) {
- while (tcsetattr (input, TCSAFLUSH, &oterm) == -1 &&
- errno == EINTR && !saved_signo[SIGTTOU]);
- }
-
- /* Restore signal handlers */
- (void)sigaction (SIGALRM, &savealrm, NULL);
- (void)sigaction (SIGHUP, &savehup, NULL);
- (void)sigaction (SIGINT, &saveint, NULL);
- (void)sigaction (SIGQUIT, &savequit, NULL);
- (void)sigaction (SIGPIPE, &savepipe, NULL);
- (void)sigaction (SIGTERM, &saveterm, NULL);
- (void)sigaction (SIGTSTP, &savetstp, NULL);
- (void)sigaction (SIGTTIN, &savettin, NULL);
- (void)sigaction (SIGTTOU, &savettou, NULL);
-
- close (input);
-
- /* Send signals pending */
- for (i = 0; i < NSIG; i++) {
- if (saved_signo[i]) {
- kill(getpid(), i);
- switch (i) {
- case SIGTSTP:
- case SIGTTIN:
- case SIGTTOU:
- goto restart;
- }
- }
- }
-
- return p - buf;
- #endif
- }
-
- gboolean
- rspamd_ip_is_valid (void *ptr, int af)
- {
- const struct in_addr ip4_any = { INADDR_ANY }, ip4_none = { INADDR_NONE };
- const struct in6_addr ip6_any = IN6ADDR_ANY_INIT;
-
- gboolean ret = FALSE;
-
- if (G_LIKELY (af == AF_INET)) {
- if (memcmp (ptr, &ip4_any, sizeof (struct in_addr)) != 0 &&
- memcmp (ptr, &ip4_none, sizeof (struct in_addr)) != 0) {
- ret = TRUE;
- }
- }
- else if (G_UNLIKELY (af == AF_INET6)) {
- if (memcmp (ptr, &ip6_any, sizeof (struct in6_addr)) != 0) {
- ret = TRUE;
- }
- }
-
- return ret;
- }
-
- /*
- * GString ucl emitting functions
- */
- static int
- rspamd_gstring_append_character (unsigned char c, size_t len, void *ud)
- {
- GString *buf = ud;
- gsize old_len;
-
- if (len == 1) {
- g_string_append_c (buf, c);
- }
- else {
- if (buf->allocated_len - buf->len <= len) {
- old_len = buf->len;
- g_string_set_size (buf, buf->len + len + 1);
- buf->len = old_len;
- }
- memset (&buf->str[buf->len], c, len);
- buf->len += len;
- }
-
- return 0;
- }
-
- static int
- rspamd_gstring_append_len (const unsigned char *str, size_t len, void *ud)
- {
- GString *buf = ud;
-
- g_string_append_len (buf, str, len);
-
- return 0;
- }
-
- static int
- rspamd_gstring_append_int (int64_t val, void *ud)
- {
- GString *buf = ud;
-
- rspamd_printf_gstring (buf, "%L", (intmax_t)val);
- return 0;
- }
-
- static int
- rspamd_gstring_append_double (double val, void *ud)
- {
- GString *buf = ud;
- const double delta = 0.0000001;
-
- if (val == (double)(int)val) {
- rspamd_printf_gstring (buf, "%.1f", val);
- }
- else if (fabs (val - (double)(int)val) < delta) {
- /* Write at maximum precision */
- rspamd_printf_gstring (buf, "%.*g", DBL_DIG, val);
- }
- else {
- rspamd_printf_gstring (buf, "%f", val);
- }
-
- return 0;
- }
-
- void
- rspamd_ucl_emit_gstring (ucl_object_t *obj, enum ucl_emitter emit_type, GString *target)
- {
- struct ucl_emitter_functions func = {
- .ucl_emitter_append_character = rspamd_gstring_append_character,
- .ucl_emitter_append_len = rspamd_gstring_append_len,
- .ucl_emitter_append_int = rspamd_gstring_append_int,
- .ucl_emitter_append_double = rspamd_gstring_append_double
- };
-
- func.ud = target;
- ucl_object_emit_full (obj, emit_type, &func);
- }
-
- /*
- * vi:ts=4
- */
|