1 /*
2
3 Copyright (C) 1999-2004 IC & S dbmail@ic-s.nl
4 Copyright (c) 2004-2012 NFG Net Facilities Group BV support@nfg.nl
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later
10 version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /*
23 * server.c
24 *
25 */
26
27 #include <libgen.h>
28 #include "dbmail.h"
29 #include "dm_request.h"
30 #include "dm_mempool.h"
31
32 #define THIS_MODULE "server"
33
34
35 volatile sig_atomic_t mainReload = 0;
36
37 // thread data
38 Mempool_T queue_pool;
39 Mempool_T small_pool;
40 GAsyncQueue *queue;
41 GThreadPool *tpool = NULL;
42
43 extern char configFile[PATH_MAX];
44 ServerConfig_T *server_conf;
45 extern DBParam_T db_params;
46
47 static void server_config_load(ServerConfig_T * conf, const char * const service);
48 static int server_set_sighandler(void);
49 static void dm_thread_data_free(gpointer data);
50 void disconnect_all(void);
51
52 struct event_base *evbase = NULL;
53 struct event *sig_int = NULL;
54 struct event *sig_hup = NULL;
55 struct event *sig_term = NULL;
56 struct event *sig_pipe = NULL;
57 struct event *sig_usr = NULL;
58 struct event *heartbeat = NULL;
59
60 SSL_CTX *tls_context;
61
62 FILE *fstdout = NULL;
63 extern FILE *fstderr;
64 FILE *fnull = NULL;
65
66 /* self-pipe
67 */
68 int selfpipe[2];
69 pthread_mutex_t selfpipe_lock;
70
71 /*
72 *
73 * threaded command primitives
74 *
75 * the goal is to make long running tasks (mainly database IO) non-blocking
76 *
77 *
78 */
79
cb_queue_drain(int fd,short what UNUSED,void * arg UNUSED)80 static void cb_queue_drain(int fd, short what UNUSED, void *arg UNUSED)
81 {
82 char buf[1024];
83 event_del(heartbeat);
84 dm_queue_drain();
85 PLOCK(selfpipe_lock);
86 if (read(fd, buf, sizeof(buf))) { /* ignore */ }
87 PUNLOCK(selfpipe_lock);
88 event_add(heartbeat, NULL);
89 }
90
91
dm_queue_heartbeat(void)92 void dm_queue_heartbeat(void)
93 {
94 if (pipe(selfpipe))
95 TRACE(TRACE_EMERG, "self-pipe setup failed");
96
97 UNBLOCK(selfpipe[0]);
98 UNBLOCK(selfpipe[1]);
99
100 pthread_mutex_init(&selfpipe_lock, NULL);
101
102 heartbeat = event_new(evbase, selfpipe[0], EV_READ, cb_queue_drain, NULL);
103 event_add(heartbeat, NULL);
104 }
105
dm_queue_drain(void)106 void dm_queue_drain(void)
107 {
108 gpointer data;
109 do {
110 data = g_async_queue_try_pop(queue);
111 if (data) {
112 dm_thread_data *D = (gpointer)data;
113 if (D->cb_leave) D->cb_leave(data);
114 dm_thread_data_free(data);
115 }
116 } while (data);
117 }
118
119 /*
120 * push a job to the queue
121 *
122 */
123
dm_queue_push(void * cb,void * session,void * data)124 void dm_queue_push(void *cb, void *session, void *data)
125 {
126 dm_thread_data *D;
127 D = mempool_pop(queue_pool, sizeof(*D));
128 D->magic = DM_THREAD_DATA_MAGIC;
129 D->status = 0;
130 D->pool = queue_pool;
131 D->cb_enter = NULL;
132 D->cb_leave = cb;
133 D->session = session;
134 D->data = data;
135
136 g_async_queue_push(queue, (gpointer)D);
137 PLOCK(selfpipe_lock);
138 if (selfpipe[1] > -1) {
139 if (write(selfpipe[1], "Q", 1)) { /* ignore */ }
140 }
141 PUNLOCK(selfpipe_lock);
142 }
143
144 /*
145 * push a job to the thread pool
146 *
147 */
148
dm_thread_data_push(gpointer session,gpointer cb_enter,gpointer cb_leave,gpointer data)149 void dm_thread_data_push(gpointer session, gpointer cb_enter, gpointer cb_leave, gpointer data)
150 {
151 GError *err = NULL;
152 ImapSession *s;
153 dm_thread_data *D;
154
155 assert(session);
156
157 s = (ImapSession *)session;
158
159 /* put a cork on the network IO */
160 ci_cork(s->ci);
161
162 if (s->state == CLIENTSTATE_QUIT_QUEUED)
163 return;
164
165 D = mempool_pop(queue_pool, sizeof(*D));
166 D->magic = DM_THREAD_DATA_MAGIC;
167 D->status = 0;
168 D->pool = queue_pool;
169 D->cb_enter = cb_enter;
170 D->cb_leave = cb_leave;
171 D->session = session;
172 D->data = data;
173
174 // we're not done until we're done
175 D->session->command_state = FALSE;
176
177 TRACE(TRACE_DEBUG,"[%p] [%p]", D, D->session);
178
179 g_thread_pool_push(tpool, D, &err);
180 TRACE(TRACE_INFO, "threads unused %u/%d limits %u/%d queued jobs %d",
181 g_thread_pool_get_num_unused_threads(),
182 g_thread_pool_get_max_unused_threads(),
183 g_thread_pool_get_num_threads(tpool),
184 g_thread_pool_get_max_threads(tpool),
185 g_thread_pool_unprocessed(tpool));
186
187 if (err) TRACE(TRACE_EMERG,"g_thread_pool_push failed [%s]", err->message);
188 }
189
dm_thread_data_free(gpointer data)190 void dm_thread_data_free(gpointer data)
191 {
192 dm_thread_data *D = (dm_thread_data *)data;
193 mempool_push(queue_pool, D, sizeof(dm_thread_data));
194 }
195
196 /*
197 * worker threads can send messages to the client
198 * through the main thread async queue. This data
199 * is written directly to the output event
200 */
dm_thread_data_sendmessage(gpointer data)201 void dm_thread_data_sendmessage(gpointer data)
202 {
203 dm_thread_data *D = (dm_thread_data *)data;
204 ImapSession *session = (ImapSession *)D->session;
205 String_T buf = D->data;
206
207 ci_write(session->ci, "%s", p_string_str(buf));
208
209 p_string_free(buf, TRUE);
210 }
211
212 /*
213 * thread-entry callback
214 *
215 * if a thread in the pool is assigned a job from the queue
216 * this call is used as entry point for the job at hand.
217 */
dm_thread_dispatch(gpointer data,gpointer user_data)218 static void dm_thread_dispatch(gpointer data, gpointer user_data)
219 {
220 TRACE(TRACE_DEBUG,"data[%p], user_data[%p]", data, user_data);
221 dm_thread_data *D = (dm_thread_data *)data;
222 ImapSession *session = (ImapSession *)D->session;
223 if (session->state == CLIENTSTATE_QUIT_QUEUED)
224 return;
225
226 D->cb_enter(D);
227 }
228
229 /*
230 *
231 * basic server setup
232 *
233 */
234
server_setup(ServerConfig_T * conf)235 static int server_setup(ServerConfig_T *conf)
236 {
237 GError *err = NULL;
238 guint tpool_size = db_params.max_db_connections;
239
240 server_set_sighandler();
241
242 small_pool = mempool_open();
243
244 if (! MATCH(conf->service_name,"IMAP"))
245 return 0;
246
247 // Asynchronous message queue for receiving messages
248 // from worker threads in the main thread.
249 //
250 // Only the main thread is allowed to do network IO.
251 // see the libevent docs for the ratio and a work-around.
252 // Dbmail only needs and uses a single eventbase for now.
253 queue = g_async_queue_new();
254
255 queue_pool = mempool_open();
256
257 // Create the thread pool
258 if (! (tpool = g_thread_pool_new((GFunc)dm_thread_dispatch,NULL,tpool_size,TRUE,&err)))
259 TRACE(TRACE_DEBUG,"g_thread_pool creation failed [%s]", err->message);
260
261 assert(evbase);
262
263 return 0;
264 }
265
266 #ifdef DEBUG
_cb_log_event(int UNUSED severity,const char * msg)267 static void _cb_log_event(int UNUSED severity, const char *msg)
268 {
269 TRACE(TRACE_WARNING, "%s", msg);
270 }
271 #endif
272
server_start_cli(ServerConfig_T * conf)273 static int server_start_cli(ServerConfig_T *conf)
274 {
275 server_conf = conf;
276 if (db_connect() != 0) {
277 TRACE(TRACE_ERR, "could not connect to database");
278 return -1;
279 }
280
281 if (auth_connect() != 0) {
282 TRACE(TRACE_ERR, "could not connect to authentication");
283 return -1;
284 }
285 // Disconnect this connection as threads will create their own
286 auth_disconnect();
287
288 srand((int) ((int) time(NULL) + (int) getpid()));
289
290 /* streams are ready, perform handling */
291
292 if (MATCH(conf->service_name,"HTTP")) {
293 TRACE(TRACE_DEBUG,"starting httpd cli server...");
294 } else {
295 Mempool_T pool = mempool_open();
296 client_sock *c = mempool_pop(pool, sizeof(client_sock));
297 c->pool = pool;
298 evthread_use_pthreads();
299 #ifdef DEBUG
300 event_enable_debug_mode();
301 event_set_log_callback(_cb_log_event);
302 #endif
303
304 evbase = event_base_new();
305 if (server_setup(conf)) return -1;
306 conf->ClientHandler(c);
307
308 if (MATCH(conf->service_name, "IMAP"))
309 dm_queue_heartbeat();
310
311 event_base_dispatch(evbase);
312 }
313
314 disconnect_all();
315
316 TRACE(TRACE_INFO, "connections closed");
317 return 0;
318 }
319
320 // PUBLIC
StartCliServer(ServerConfig_T * conf)321 int StartCliServer(ServerConfig_T * conf)
322 {
323 assert(conf);
324 server_start_cli(conf);
325 #ifdef HAVE_SYSTEMD
326 sd_notify(0, "STOPPING=1");
327 #endif
328 return 0;
329 }
330
331 /* Should be called after a HUP to allow for log rotation,
332 * as the filesystem may want to give us new inodes and/or
333 * the user may have changed the log file configs. */
reopen_logs_level(ServerConfig_T * conf,Trace_T level)334 static void reopen_logs_level(ServerConfig_T *conf, Trace_T level)
335 {
336 int serr;
337
338 if (mainReload) {
339 mainReload = 0;
340 TRACE(TRACE_INFO, "reopening log files");
341 }
342
343 if (fstdout) fclose(fstdout);
344 if (fstderr) fclose(fstderr);
345 if (fnull) fclose(fnull);
346
347 SetTraceLevel(conf->service_name);
348 config_get_timeout(conf, conf->service_name);
349
350 if (! (fstdout = freopen(conf->log, "a", stdout))) {
351 serr = errno;
352 TRACE(level, "freopen failed on [%s] [%s]", conf->log, strerror(serr));
353 }
354
355 if (! (fstderr = freopen(conf->error_log, "a", stderr))) {
356 serr = errno;
357 TRACE(level, "freopen failed on [%s] [%s]", conf->error_log, strerror(serr));
358 }
359
360 if (! (fnull = freopen("/dev/null", "r", stdin))) {
361 serr = errno;
362 TRACE(level, "freopen failed on stdin [%s]", strerror(serr));
363 }
364
365 }
366
367 #define reopen_logs(a) reopen_logs_level(a, TRACE_ERR)
368 #define reopen_logs_fatal(a) reopen_logs_level(a, TRACE_EMERG)
369
server_daemonize(ServerConfig_T * conf)370 pid_t server_daemonize(ServerConfig_T *conf)
371 {
372 assert(conf);
373
374 // double-fork
375 if (fork()) exit(0);
376 setsid();
377 if (fork()) exit(0);
378
379 if (chdir("/"))
380 TRACE(TRACE_EMERG, "chdir / failed");
381
382 umask(0077);
383
384 reopen_logs_fatal(conf);
385
386 TRACE(TRACE_DEBUG, "sid: [%d]", getsid(0));
387
388 return getsid(0);
389 }
390
dm_bind_and_listen(int sock,struct sockaddr * saddr,socklen_t len,int backlog,gboolean ssl)391 static int dm_bind_and_listen(int sock, struct sockaddr *saddr, socklen_t len, int backlog, gboolean ssl)
392 {
393 int err, so_reuseaddress = 1;
394 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
395
396 memset(hbuf,0, sizeof(hbuf));
397 memset(sbuf,0, sizeof(sbuf));
398
399 if (getnameinfo(saddr, len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
400 TRACE(TRACE_DEBUG, "could not get numeric hostname");
401 }
402
403 TRACE(TRACE_DEBUG, "creating %s socket [%d] on [%s:%s]", ssl?"ssl":"plain", sock, hbuf, sbuf);
404
405 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddress, sizeof(so_reuseaddress)) == -1) {
406 err = errno;
407 TRACE(TRACE_EMERG, "setsockopt::error [%s]", strerror(err));
408 }
409 /* bind the address */
410 if ((bind(sock, saddr, len)) == -1) {
411 err = errno;
412 TRACE(TRACE_EMERG, "bind::error [%s]", strerror(err));
413 }
414
415 if ((listen(sock, backlog)) == -1) {
416 err = errno;
417 TRACE(TRACE_EMERG, "listen::error [%s]", strerror(err));
418 }
419
420 return 0;
421
422 }
423
create_unix_socket(ServerConfig_T * conf)424 static int create_unix_socket(ServerConfig_T * conf)
425 {
426 int sock;
427 struct sockaddr_un un;
428
429 conf->resolveIP=0;
430
431 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
432 int err = errno;
433 TRACE(TRACE_EMERG, "%s", strerror(err));
434 return -1;
435 }
436
437 /* setup sockaddr_un */
438 memset(&un, 0, sizeof(un));
439 un.sun_family = AF_UNIX;
440 strncpy(un.sun_path,conf->socket, sizeof(un.sun_path)-1);
441
442 TRACE(TRACE_DEBUG, "create socket [%s] backlog [%d]", conf->socket, conf->backlog);
443
444 // any error in dm_bind_and_listen is fatal
445 dm_bind_and_listen(sock, (struct sockaddr *)&un, sizeof(un), conf->backlog, FALSE);
446
447 if (chmod(conf->socket, 02777)) {
448 int serr = errno;
449 TRACE(TRACE_ERR, "chmod [%s] failed: [%s]",
450 conf->socket, strerror(serr));
451 }
452
453 return sock;
454 }
455
create_inet_socket(ServerConfig_T * conf,int i,gboolean ssl)456 static void create_inet_socket(ServerConfig_T *conf, int i, gboolean ssl)
457 {
458 struct addrinfo hints, *res, *res0;
459 int s, error = 0;
460 const char *port;
461
462 if (ssl) {
463 port = conf->ssl_port;
464 } else {
465 port = conf->port;
466 }
467
468 memset(&hints, 0, sizeof(hints));
469 hints.ai_family = PF_UNSPEC;
470 hints.ai_socktype = SOCK_STREAM;
471 hints.ai_flags = AI_PASSIVE;
472 error = getaddrinfo(conf->iplist[i], port, &hints, &res0);
473 if (error) {
474 TRACE(TRACE_ERR, "getaddrinfo error [%d] %s", error, gai_strerror(error));
475 return;
476 /*NOTREACHED*/
477 }
478
479 for (res = res0; res && conf->ssl_socketcount < MAXSOCKETS && conf->socketcount < MAXSOCKETS; res = res->ai_next) {
480 if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
481 TRACE(TRACE_ERR, "could not create a socket of family [%d], socktype[%d], protocol [%d]", res->ai_family, res->ai_socktype, res->ai_protocol);
482 continue;
483 }
484 UNBLOCK(s);
485
486 dm_bind_and_listen(s, res->ai_addr, res->ai_addrlen, conf->backlog, ssl);
487 if (ssl)
488 conf->ssl_listenSockets[conf->ssl_socketcount++] = s;
489 else
490 conf->listenSockets[conf->socketcount++] = s;
491 }
492 freeaddrinfo(res0);
493 }
494
server_close_sockets(ServerConfig_T * conf)495 static void server_close_sockets(ServerConfig_T *conf)
496 {
497 int i;
498 if (conf->evhs) {
499 for (i = 0; i < server_conf->ipcount; i++) {
500 evhttp_free(conf->evhs[i]);
501 }
502 g_free(conf->evhs);
503 } else {
504 for (i = 0; i < conf->socketcount; i++)
505 if (conf->listenSockets[i] > 0)
506 close(conf->listenSockets[i]);
507 conf->socketcount=0;
508
509 for (i = 0; i < conf->ssl_socketcount; i++)
510 if (conf->ssl_listenSockets[i] > 0)
511 close(conf->ssl_listenSockets[i]);
512 conf->ssl_socketcount=0;
513
514 if (strlen(conf->socket))
515 unlink(conf->socket);
516 }
517 }
518
server_exit(void)519 static void server_exit(void)
520 {
521 disconnect_all();
522 server_close_sockets(server_conf);
523 //event_base_free(evbase);
524
525 pthread_mutex_destroy(&selfpipe_lock);
526 if (fstdout) fclose(fstdout);
527 if (fstderr) fclose(fstderr);
528 if (fnull) fclose(fnull);
529 closelog();
530 //mempool_close(&queue_pool);
531 }
532
server_create_sockets(ServerConfig_T * conf)533 static void server_create_sockets(ServerConfig_T * conf)
534 {
535 int i;
536
537 conf->listenSockets = mempool_pop(small_pool, sizeof(int) * MAXSOCKETS);
538 conf->ssl_listenSockets = mempool_pop(small_pool, sizeof(int) * MAXSOCKETS);
539
540 if (strlen(conf->socket))
541 conf->listenSockets[conf->socketcount++] = create_unix_socket(conf);
542
543 tls_load_certs(conf);
544
545 if (conf->ssl)
546 tls_load_ciphers(conf);
547
548 if (strlen(conf->port)) {
549 for (i = 0; i < conf->ipcount; i++) {
550 create_inet_socket(conf, i, FALSE);
551 }
552 }
553
554 if (conf->ssl && strlen(conf->ssl_port)) {
555 for (i = 0; i < conf->ipcount; i++) {
556 create_inet_socket(conf, i, TRUE);
557 }
558 }
559 }
560
561 #ifdef DEBUG
_sock_cb(int sock,short event,void * arg,gboolean ssl)562 static void _sock_cb(int sock, short event, void *arg, gboolean ssl)
563 #else
564 static void _sock_cb(int sock, short UNUSED event, void *arg, gboolean ssl)
565 #endif
566 {
567 Mempool_T pool;
568 client_sock *c;
569 int csock;
570 socklen_t len;
571 struct event *ev = (struct event *)arg;
572
573 #ifdef DEBUG
574 TRACE(TRACE_DEBUG,"%d %s%s%s%s, %p, ssl:%s", sock,
575 (event&EV_TIMEOUT) ? " timeout" : "",
576 (event&EV_READ) ? " read" : "",
577 (event&EV_WRITE) ? " write" : "",
578 (event&EV_SIGNAL) ? " signal" : "",
579 arg, ssl?"Y":"N");
580 #endif
581 /* accept the active fd */
582
583 if (mainReload) {
584 config_read(configFile);
585 reopen_logs(server_conf);
586 }
587
588 if ((csock = accept(sock, NULL, NULL)) < 0) {
589 int serr=errno;
590 switch(serr) {
591 case ECONNABORTED:
592 case EPROTO:
593 case EINTR:
594 case EAGAIN:
595 TRACE(TRACE_DEBUG, "%d:%s", serr, strerror(serr));
596 break;
597 default:
598 TRACE(TRACE_ERR, "%d:%s", serr, strerror(serr));
599 break;
600 }
601 event_add(ev, NULL);
602 return;
603 }
604
605 pool = mempool_open();
606 c = mempool_pop(pool, sizeof(client_sock));
607 c->pool = pool;
608 c->sock = csock;
609 len = sizeof(struct sockaddr);
610 if (getpeername(c->sock, &c->caddr, &len) < 0) {
611 int serr = errno;
612 TRACE(TRACE_INFO, "getpeername::error [%s]", strerror(serr));
613 mempool_push(pool, c, sizeof(client_sock));
614 mempool_close(&pool);
615 close(csock);
616 event_add(ev, NULL);
617 return;
618 }
619
620 if (getsockname(c->sock, &c->saddr, &len) < 0) {
621 int serr = errno;
622 TRACE(TRACE_EMERG, "getsockname::error [%s]", strerror(serr));
623 mempool_push(pool, c, sizeof(client_sock));
624 mempool_close(&pool);
625 close(csock);
626 event_add(ev, NULL);
627 return; // fatal
628 }
629
630 c->caddr_len = len;
631 c->saddr_len = len;
632
633 if (ssl) c->ssl_state = -1; // defer tls setup
634
635 TRACE(TRACE_INFO, "connection accepted");
636
637 /* streams are ready, perform handling */
638 server_conf->ClientHandler((client_sock *)c);
639
640 /* reschedule */
641 event_add(ev, NULL);
642 }
643
server_sock_cb(int sock,short event,void * arg)644 static void server_sock_cb(int sock, short event, void *arg)
645 {
646 _sock_cb(sock, event, arg, FALSE);
647 }
648
server_sock_ssl_cb(int sock,short event,void * arg)649 static void server_sock_ssl_cb(int sock, short event, void *arg)
650 {
651 _sock_cb(sock, event, arg, TRUE);
652 }
653
654
server_sig_cb(int UNUSED fd,short UNUSED event,void * arg)655 void server_sig_cb(int UNUSED fd, short UNUSED event, void *arg)
656 {
657 struct event *ev = arg;
658
659 switch (EVENT_SIGNAL(ev)) {
660 case SIGHUP:
661 mainReload = 1;
662 case SIGPIPE: // ignore
663 break;
664 default:
665 exit(0);
666 break;
667 }
668 }
669
server_set_sighandler(void)670 static int server_set_sighandler(void)
671 {
672 assert(evbase);
673
674 sig_int = evsignal_new(evbase, SIGINT, server_sig_cb, NULL);
675 evsignal_assign(sig_int, evbase, SIGINT, server_sig_cb, sig_int);
676 evsignal_add(sig_int, NULL);
677
678 sig_hup = evsignal_new(evbase, SIGHUP, server_sig_cb, NULL);
679 evsignal_assign(sig_hup, evbase, SIGHUP, server_sig_cb, sig_hup);
680 evsignal_add(sig_hup, NULL);
681
682 sig_term = evsignal_new(evbase, SIGTERM, server_sig_cb, NULL);
683 evsignal_assign(sig_term, evbase, SIGTERM, server_sig_cb, sig_term);
684 evsignal_add(sig_term, NULL);
685
686 sig_pipe = evsignal_new(evbase, SIGPIPE, server_sig_cb, NULL);
687 evsignal_assign(sig_pipe, evbase, SIGPIPE, server_sig_cb, sig_pipe);
688 evsignal_add(sig_pipe, NULL);
689
690 #if MEMDEBUG
691 sig_usr = evsignal_new(evbase, SIGUSR1, server_sig_cb, NULL);
692 evsignal_assign(sig_usr, evbase, SIGUSR1, server_sig_cb, sig_usr);
693 evsignal_add(sig_usr, NULL);
694 #endif
695
696 TRACE(TRACE_INFO, "signal handler placed");
697
698 return 0;
699 }
700
701 //
702 // Public methods
disconnect_all(void)703 void disconnect_all(void)
704 {
705 TRACE(TRACE_INFO, "disconnecting all");
706 db_disconnect();
707 auth_disconnect();
708 g_mime_shutdown();
709 config_free();
710
711 if (tpool) {
712 g_thread_pool_free(tpool, TRUE, TRUE);
713 tpool = NULL;
714 }
715 if (sig_int) {
716 event_free(sig_int);
717 sig_int = NULL;
718 }
719 if (sig_hup) {
720 event_free(sig_hup);
721 sig_hup = NULL;
722 }
723 if (sig_term) {
724 event_free(sig_term);
725 sig_term = NULL;
726 }
727 #if MEMDEBUG
728 if (sig_usr) {
729 free(sig_usr);
730 sig_usr = NULL;
731 }
732 #endif
733 if (sig_pipe) {
734 free(sig_pipe);
735 sig_pipe = NULL;
736 }
737 }
738
server_pidfile(ServerConfig_T * conf)739 static void server_pidfile(ServerConfig_T *conf)
740 {
741 static gboolean configured = FALSE;
742 if (configured) return;
743
744 /* We write the pidFile after daemonize because
745 * we may actually be a child of the original process. */
746 if (! conf->pidFile)
747 conf->pidFile = config_get_pidfile(conf, conf->process_name);
748
749 char *fcopy = strdup(conf->pidFile);
750 char *piddir = dirname(fcopy);
751
752 g_mkdir_with_parents(piddir, 0700);
753 free(fcopy);
754
755 pidfile_create(conf->pidFile, getpid());
756
757 configured = TRUE;
758 }
759
server_run(ServerConfig_T * conf)760 int server_run(ServerConfig_T *conf)
761 {
762 int i;
763 struct event **evsock;
764
765 mainReload = 0;
766
767 assert(conf);
768 reopen_logs(conf);
769
770 TRACE(TRACE_NOTICE, "starting main service loop for [%s]", conf->service_name);
771
772 server_conf = conf;
773 if (db_connect()) {
774 TRACE(TRACE_ERR, "could not connect to database");
775 return -1;
776 }
777
778 if (auth_connect()) {
779 TRACE(TRACE_ERR, "could not connect to authentication");
780 return -1;
781 }
782 srand((int) ((int) time(NULL) + (int) getpid()));
783
784 TRACE(TRACE_NOTICE, "starting main service loop for [%s]", conf->service_name);
785
786 server_conf = conf;
787
788 evthread_use_pthreads();
789 #ifdef DEBUG
790 event_enable_debug_mode();
791 event_set_log_callback(_cb_log_event);
792 #endif
793 evbase = event_base_new();
794
795 if (server_setup(conf))
796 return -1;
797
798 if (strlen(conf->port) || strlen(conf->ssl_port)) {
799
800 if (MATCH(conf->service_name, "HTTP")) {
801 int port = atoi(conf->port);
802 if (! port) {
803 TRACE(TRACE_ERR, "Failed to convert port spec [%s]", conf->port);
804 } else {
805 gboolean http_started = FALSE;
806 conf->evhs = g_new0(struct evhttp *, server_conf->ipcount);
807 for (i = 0; i < server_conf->ipcount; i++) {
808 TRACE(TRACE_DEBUG, "starting HTTP service [%s:%d]", conf->iplist[i], port);
809 conf->evhs[i] = evhttp_new(evbase);
810 if (evhttp_bind_socket(conf->evhs[i], conf->iplist[i], port)) {
811 int serr = errno;
812 TRACE(TRACE_EMERG, "[%s]", strerror(serr));
813 } else {
814 TRACE(TRACE_DEBUG, "started HTTP service [%p]", conf->evhs[i]);
815 evhttp_set_gencb(conf->evhs[i], Request_cb, NULL);
816 http_started = TRUE;
817 }
818 }
819 if (!http_started) {
820 return -1;
821 }
822 }
823 } else {
824 int k, total;
825 server_create_sockets(conf);
826 total = conf->socketcount + conf->ssl_socketcount;
827 evsock = g_new0(struct event *, total);
828 for (i = 0; i < conf->socketcount; i++) {
829 TRACE(TRACE_DEBUG, "Adding event for plain socket [%d] [%d/%d]", conf->listenSockets[i], i+1, total);
830 evsock[i] = event_new(evbase, conf->listenSockets[i], EV_READ, server_sock_cb, NULL);
831 event_assign(evsock[i], evbase, conf->listenSockets[i], EV_READ, server_sock_cb, evsock[i]);
832 event_add(evsock[i], NULL);
833 }
834 for (k = i, i = 0; i < conf->ssl_socketcount; i++, k++) {
835 TRACE(TRACE_DEBUG, "Adding event for ssl socket [%d] [%d/%d]", conf->ssl_listenSockets[i], k+1, total);
836 evsock[k] = event_new(evbase, conf->ssl_listenSockets[i], EV_READ, server_sock_ssl_cb, NULL);
837 event_assign(evsock[k], evbase, conf->ssl_listenSockets[i], EV_READ, server_sock_ssl_cb, evsock[k]);
838 event_add(evsock[k], NULL);
839 }
840 }
841 }
842
843 atexit(server_exit);
844
845 if (drop_privileges(conf->serverUser, conf->serverGroup) < 0)
846 TRACE(TRACE_WARNING, "unable to drop privileges");
847
848 server_pidfile(conf);
849
850 if (MATCH(conf->service_name, "IMAP"))
851 dm_queue_heartbeat();
852 #ifdef HAVE_SYSTEMD
853 sd_notify(0, "READY=1");
854 #endif
855 TRACE(TRACE_DEBUG,"dispatching event loop...");
856
857 event_base_dispatch(evbase);
858
859 return 0;
860 }
861
server_showhelp(const char * name,const char * greeting)862 void server_showhelp(const char *name, const char *greeting) {
863 printf("*** %s ***\n", name);
864
865 printf("%s\n", greeting);
866 printf("See the man page for more info.\n");
867
868 printf("\nCommon options for all DBMail daemons:\n");
869 printf(" -f file specify an alternative config file\n");
870 printf(" -p file specify an alternative runtime pidfile\n");
871 printf(" -n stdin/stdout mode\n");
872 printf(" -D foreground mode\n");
873 printf(" -v verbose logging to syslog and stderr\n");
874 printf(" -V show the version\n");
875 printf(" -h show this help message\n");
876 }
877
878 /* Return values:
879 * -1 just quit
880 * 0 all is well, config is updated
881 * 1 help must be shown, then quit
882 */
883
server_config_free(ServerConfig_T * config)884 static void server_config_free(ServerConfig_T * config)
885 {
886 assert(config);
887
888 g_strfreev(config->iplist);
889 if (small_pool) {
890 mempool_push(small_pool, config->listenSockets, sizeof(int) * MAXSOCKETS);
891 mempool_push(small_pool, config->ssl_listenSockets, sizeof(int) * MAXSOCKETS);
892 }
893
894 config->listenSockets = NULL;
895 config->ssl = FALSE;
896 config->ssl_listenSockets = NULL;
897 config->iplist = NULL;
898
899 memset(config, 0, sizeof(ServerConfig_T));
900 }
901
server_getopt(ServerConfig_T * config,const char * service,int argc,char * argv[])902 int server_getopt(ServerConfig_T *config, const char *service, int argc, char *argv[])
903 {
904 int opt;
905 memset(configFile, 0, sizeof(configFile));
906
907 g_strlcpy(configFile,DEFAULT_CONFIG_FILE, FIELDSIZE-1);
908
909 TRACE(TRACE_DEBUG, "checking command line options");
910
911 /* get command-line options */
912 opterr = 0; /* suppress error message from getopt() */
913 while ((opt = getopt(argc, argv, "vVhqnDf:p:s:")) != -1) {
914 switch (opt) {
915 case 'v':
916 config->log_verbose = 1;
917 break;
918 case 'V':
919 PRINTF_THIS_IS_DBMAIL;
920 return -1;
921 case 'n':
922 config->no_daemonize = 1;
923 break;
924 case 'D':
925 config->no_daemonize = 2;
926 break;
927 case 'h':
928 return 1;
929 case 'p':
930 if (optarg && strlen(optarg) > 0)
931 config->pidFile = g_strdup(optarg);
932 else {
933 fprintf(stderr, "%s: -p requires a filename argument\n\n", argv[0]);
934 return 1;
935 }
936 break;
937 case 'f':
938 if (optarg && strlen(optarg) > 0) {
939 g_strlcpy(configFile, optarg, FIELDSIZE-1);
940 } else {
941 fprintf(stderr, "%s: -f requires a filename argument\n\n", argv[0]);
942 return 1;
943 }
944 break;
945
946 default:
947 fprintf(stderr, "%s: unrecognized option: %s\n\n", argv[0], argv[optind]);
948 return 1;
949 }
950 }
951
952 if (optind < argc) {
953 fprintf(stderr, "%s: unrecognized options: ", argv[0]);
954 while (optind < argc)
955 fprintf(stderr, "%s ", argv[optind++]);
956 fprintf(stderr, "\n\n");
957 return 1;
958 }
959
960 server_config_load(config, service);
961
962 return 0;
963 }
964
server_mainloop(ServerConfig_T * config,const char * servicename)965 int server_mainloop(ServerConfig_T *config, const char *servicename)
966 {
967 strncpy(config->process_name, servicename, FIELDSIZE-1);
968
969 g_mime_init(GMIME_ENABLE_RFC2047_WORKAROUNDS);
970 g_mime_parser_get_type();
971 g_mime_stream_get_type();
972 g_mime_stream_mem_get_type();
973 g_mime_stream_file_get_type();
974 g_mime_stream_buffer_get_type();
975 g_mime_stream_filter_get_type();
976 g_mime_filter_crlf_get_type();
977
978 tls_context = tls_init();
979
980 if (config->no_daemonize == 1) {
981 StartCliServer(config);
982 TRACE(TRACE_INFO, "exiting cli server");
983 return 0;
984 }
985
986 if (! config->no_daemonize)
987 server_daemonize(config);
988
989 /* This is the actual main loop. */
990 server_run(config);
991
992 server_config_free(config);
993 TRACE(TRACE_INFO, "leaving main loop");
994 return 0;
995 }
996
997
server_config_load(ServerConfig_T * config,const char * const service)998 void server_config_load(ServerConfig_T * config, const char * const service)
999 {
1000 Field_T val, val_ssl;
1001
1002 TRACE(TRACE_DEBUG, "reading config [%s]", configFile);
1003 config_free();
1004 config_read(configFile);
1005
1006 GetDBParams();
1007 SetTraceLevel(service);
1008 /* Override SetTraceLevel. */
1009 if (config->log_verbose) {
1010 configure_debug(service,5,5);
1011 }
1012
1013 config_get_value("max_db_connections", service, val);
1014 if (strlen(val) != 0) {
1015 db_params.max_db_connections = (unsigned int) strtol(val, NULL, 10);
1016 if (errno == EINVAL || errno == ERANGE)
1017 TRACE(TRACE_EMERG, "max_db_connnections invalid in config file");
1018 }
1019 TRACE(TRACE_DEBUG, "max_db_connections [%d]", db_params.max_db_connections);
1020
1021 config_get_logfiles(config, service);
1022
1023 config_get_timeout(config, service);
1024
1025 /* SOCKET */
1026 config_get_value("SOCKET", service, val);
1027 if (strlen(val) == 0)
1028 TRACE(TRACE_DEBUG, "no value for SOCKET in config file");
1029 strncpy(config->socket, val, FIELDSIZE-1);
1030 TRACE(TRACE_DEBUG, "socket [%s]", config->socket);
1031
1032 /* read items: PORT */
1033 config_get_value("PORT", service, val);
1034 config_get_value("TLS_PORT", service, val_ssl);
1035
1036 if ((strlen(val) == 0) && (strlen(val_ssl) == 0)) {
1037 TRACE(TRACE_WARNING, "no value for PORT or TLS_PORT in config file. Using defaults");
1038
1039 if (MATCH(service, "IMAP"))
1040 strncpy(config->port, "143", FIELDSIZE-1);
1041 else if (MATCH(service, "POP"))
1042 strncpy(config->port, "110", FIELDSIZE-1);
1043 else if (MATCH(service, "SIEVE"))
1044 strncpy(config->port, "2000", FIELDSIZE-1);
1045 else if (MATCH(service, "HTTP"))
1046 strncpy(config->port, "41380", FIELDSIZE-1);
1047 } else {
1048 strncpy(config->port, val, FIELDSIZE-1);
1049 }
1050
1051 TRACE(TRACE_DEBUG, "binding to PORT [%s]", config->port);
1052
1053 if (strlen(val_ssl) > 0) {
1054 strncpy(config->ssl_port, val_ssl, FIELDSIZE-1);
1055 TRACE(TRACE_DEBUG, "binding to SSL_PORT [%s]", config->ssl_port);
1056 }
1057
1058 /* read items: BINDIP */
1059 config_get_value("BINDIP", service, val);
1060 if (strlen(val) == 0)
1061 strncpy(val, "127.0.0.1", FIELDSIZE-1);
1062
1063 // If there was a SIGHUP, then we're resetting an active config.
1064 g_strfreev(config->iplist);
1065 g_free(config->listenSockets);
1066 // Allowed list separators are ' ' and ','.
1067 config->iplist = g_strsplit_set(val, " ,", 0);
1068 config->ipcount = g_strv_length(config->iplist);
1069 if (config->ipcount < 1)
1070 TRACE(TRACE_EMERG, "no value for BINDIP in config file");
1071
1072 int ip;
1073 for (ip = 0; ip < config->ipcount; ip++) {
1074 // Remove whitespace from each list entry, then log it.
1075 g_strstrip(config->iplist[ip]);
1076 if (config->iplist[ip][0] == '*') {
1077 g_free(config->iplist[ip]);
1078 config->iplist[ip] = g_strdup("0.0.0.0");
1079 }
1080 TRACE(TRACE_DEBUG, "binding to IP [%s]", config->iplist[ip]);
1081 }
1082
1083 /* read items: BACKLOG */
1084 config_get_value("BACKLOG", service, val);
1085 if (strlen(val) == 0) {
1086 TRACE(TRACE_DEBUG, "no value for BACKLOG in config file. Using default value [%d]", BACKLOG);
1087 config->backlog = BACKLOG;
1088 } else if ((config->backlog = atoi(val)) <= 0)
1089 TRACE(TRACE_EMERG, "value for BACKLOG is invalid: [%d]", config->backlog);
1090 TRACE(TRACE_DEBUG, "%s backlog [%d]", service, config->backlog);
1091
1092 /* read items: RESOLVE_IP */
1093 config_get_value("RESOLVE_IP", service, val);
1094 if (strlen(val) == 0)
1095 TRACE(TRACE_DEBUG, "no value for RESOLVE_IP in config file");
1096 config->resolveIP = (strcasecmp(val, "yes") == 0);
1097 TRACE(TRACE_DEBUG, "%sresolving client IP", config->resolveIP ? "" : "not ");
1098
1099 /* read items: service-BEFORE-SMTP */
1100 char *service_before_smtp = g_strconcat(service, "_BEFORE_SMTP", NULL);
1101 config_get_value(service_before_smtp, service, val);
1102 g_free(service_before_smtp);
1103 if (strlen(val) == 0)
1104 TRACE(TRACE_DEBUG, "no value for %s_BEFORE_SMTP in config file", service);
1105 config->service_before_smtp = (strcasecmp(val, "yes") == 0);
1106 TRACE(TRACE_DEBUG, "%s %s-before-SMTP", config->service_before_smtp ? "Enabling" : "Disabling", service);
1107
1108 /* read items: authlog */
1109 config_get_value("authlog", service, val);
1110 if (strlen(val) == 0)
1111 TRACE(TRACE_DEBUG, "no value for AUTHLOG in config file");
1112 config->authlog = (strcasecmp(val, "yes") == 0);
1113 TRACE(TRACE_DEBUG, "%s %s Authentication logging", config->authlog ? "Enabling" : "Disabling", service);
1114
1115 /* read items: EFFECTIVE-USER */
1116 config_get_value("EFFECTIVE_USER", service, val);
1117 if (strlen(val) == 0)
1118 TRACE(TRACE_EMERG, "no value for EFFECTIVE_USER in config file");
1119
1120 strncpy(config->serverUser, val, FIELDSIZE-1);
1121
1122 TRACE(TRACE_DEBUG, "effective user shall be [%s]",
1123 config->serverUser);
1124
1125 /* read items: EFFECTIVE-GROUP */
1126 config_get_value("EFFECTIVE_GROUP", service, val);
1127 if (strlen(val) == 0)
1128 TRACE(TRACE_EMERG, "no value for EFFECTIVE_GROUP in config file");
1129
1130 strncpy(config->serverGroup, val, FIELDSIZE-1);
1131
1132 TRACE(TRACE_DEBUG, "effective group shall be [%s]", config->serverGroup);
1133
1134 /* read items: TLS_CAFILE */
1135 config_get_value("TLS_CAFILE", service, val);
1136 if(strlen(val)) {
1137 strncpy(config->tls_cafile, val, FIELDSIZE-1);
1138 TRACE(TRACE_DEBUG, "CA file is set to [%s]", config->tls_cafile);
1139 }
1140
1141 /* read items: TLS_CERT */
1142 config_get_value("TLS_CERT", service, val);
1143 if(strlen(val)) {
1144 strncpy(config->tls_cert, val, FIELDSIZE-1);
1145 TRACE(TRACE_DEBUG, "Certificate file is set to [%s]", config->tls_cert);
1146 }
1147
1148 /* read items: TLS_KEY */
1149 config_get_value("TLS_KEY", service, val);
1150 if(strlen(val)) {
1151 strncpy(config->tls_key, val, FIELDSIZE-1);
1152 TRACE(TRACE_DEBUG, "Key file is set to [%s]", config->tls_key);
1153 }
1154
1155 /* read items: TLS_CIPHERS */
1156 config_get_value("TLS_CIPHERS", service, val);
1157 if(strlen(val)) {
1158 strncpy(config->tls_ciphers, val, FIELDSIZE-1);
1159 TRACE(TRACE_DEBUG, "Cipher string is set to [%s]", config->tls_ciphers);
1160 }
1161
1162 strncpy(config->service_name, service, FIELDSIZE-1);
1163
1164 }
1165
1166
1167
1168