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