xref: /openbsd-src/sbin/isakmpd/isakmpd.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /* $OpenBSD: isakmpd.c,v 1.109 2023/03/08 04:43:06 guenther Exp $	 */
2b7bb0eceSniklas /* $EOM: isakmpd.c,v 1.54 2000/10/05 09:28:22 niklas Exp $	 */
32040585eSniklas 
42040585eSniklas /*
542af7185Sniklas  * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist.  All rights reserved.
6bdbf6df3Sniklas  * Copyright (c) 1999, 2000 Angelos D. Keromytis.  All rights reserved.
7867e2181Sho  * Copyright (c) 1999, 2000, 2001 H�kan Olsson.  All rights reserved.
82040585eSniklas  *
92040585eSniklas  * Redistribution and use in source and binary forms, with or without
102040585eSniklas  * modification, are permitted provided that the following conditions
112040585eSniklas  * are met:
122040585eSniklas  * 1. Redistributions of source code must retain the above copyright
132040585eSniklas  *    notice, this list of conditions and the following disclaimer.
142040585eSniklas  * 2. Redistributions in binary form must reproduce the above copyright
152040585eSniklas  *    notice, this list of conditions and the following disclaimer in the
162040585eSniklas  *    documentation and/or other materials provided with the distribution.
172040585eSniklas  *
182040585eSniklas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
192040585eSniklas  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
202040585eSniklas  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
212040585eSniklas  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
222040585eSniklas  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
232040585eSniklas  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
242040585eSniklas  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252040585eSniklas  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262040585eSniklas  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
272040585eSniklas  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282040585eSniklas  */
292040585eSniklas 
302040585eSniklas /*
312040585eSniklas  * This code was written under funding by Ericsson Radio Systems.
322040585eSniklas  */
332040585eSniklas 
34dc4b6c27Sniklas #include <errno.h>
35c3c2e2acSniklas #include <sys/types.h>
36c3c2e2acSniklas #include <sys/stat.h>
372040585eSniklas #include <signal.h>
382040585eSniklas #include <stdio.h>
392040585eSniklas #include <stdlib.h>
402040585eSniklas #include <string.h>
4115537254Shshoexer #include <time.h>
42a9c89582Sho #include <netdb.h>
432040585eSniklas #include <unistd.h>
44f41e756cSho #include <fcntl.h>
45426a6f8cSkrw #include <paths.h>
462040585eSniklas 
472040585eSniklas #include "app.h"
482040585eSniklas #include "conf.h"
4922e84989Sniklas #include "connection.h"
502040585eSniklas #include "init.h"
515fc2ae46Sniklas #include "libcrypto.h"
522040585eSniklas #include "log.h"
53bfb67d4dScloder #include "message.h"
54da35d433Sho #include "monitor.h"
55bfb67d4dScloder #include "nat_traversal.h"
56c6e4dfa3Sho #include "sa.h"
572040585eSniklas #include "timer.h"
582040585eSniklas #include "transport.h"
592040585eSniklas #include "udp.h"
60287d4ce7Shshoexer #include "udp_encap.h"
612040585eSniklas #include "ui.h"
6276fb8883Sniklas #include "util.h"
634144914bSniklas #include "cert.h"
642040585eSniklas 
6528ecb04cSniklas #include "policy.h"
6628ecb04cSniklas 
674c8c122bSho static void     usage(void);
684c8c122bSho 
692040585eSniklas /*
702040585eSniklas  * Set if -d is given, currently just for running in the foreground and log
712040585eSniklas  * to stderr instead of syslog.
722040585eSniklas  */
732040585eSniklas int             debug = 0;
742040585eSniklas 
759a07a765Shshoexer /* Set when no policy file shall be used. */
7639fc3963Shshoexer int		acquire_only = 0;
7739fc3963Shshoexer 
78428bd1b5Shshoexer /* Set when SAs shall be deleted on shutdown. */
7985ead044Shshoexer int		delete_sas = 1;
80428bd1b5Shshoexer 
812040585eSniklas /*
822040585eSniklas  * If we receive a SIGHUP signal, this flag gets set to show we need to
832040585eSniklas  * reconfigure ASAP.
842040585eSniklas  */
853354b35fSho volatile sig_atomic_t sighupped = 0;
862040585eSniklas 
872b81057dSniklas /*
882b81057dSniklas  * If we receive a USR1 signal, this flag gets set to show we need to dump
892b81057dSniklas  * a report over our internal state ASAP.  The file to report to is settable
902b81057dSniklas  * via the -R parameter.
912b81057dSniklas  */
923354b35fSho volatile sig_atomic_t sigusr1ed = 0;
932b81057dSniklas static char    *report_file = "/var/run/isakmpd.report";
942b81057dSniklas 
95c6e4dfa3Sho /*
96e4d25771Stodd  * If we receive a TERM signal, perform a "clean shutdown" of the daemon.
97c6e4dfa3Sho  * This includes to send DELETE notifications for all our active SAs.
98a8478dd3Sho  * Also on recv of an INT signal (Ctrl-C out of an '-d' session, typically).
99c6e4dfa3Sho  */
1003354b35fSho volatile sig_atomic_t sigtermed = 0;
101c6e4dfa3Sho void            daemon_shutdown_now(int);
102b8909177Smoritz void		set_slave_signals(void);
103426a6f8cSkrw void		sanitise_stdfd(void);
104c6e4dfa3Sho 
1055fc2ae46Sniklas /* The default path of the PID file.  */
106e8a27e95Smoritz char	       *pid_file = "/var/run/isakmpd.pid";
1075fc2ae46Sniklas 
108af729d73Sho /* The path of the IKE packet capture log file.  */
109af729d73Sho static char    *pcap_file = 0;
110af729d73Sho 
1112040585eSniklas static void
usage(void)1124c8c122bSho usage(void)
1132040585eSniklas {
11461336936Sderaadt 	extern char *__progname;
11561336936Sderaadt 
1162040585eSniklas 	fprintf(stderr,
117428bd1b5Shshoexer 	    "usage: %s [-46adKLnSTv] [-c config-file] [-D class=level] [-f fifo]\n"
118cadf506fSjmc 	    "          [-i pid-file] [-l packetlog-file] [-N udpencap-port]\n"
119cadf506fSjmc 	    "          [-p listen-port] [-R report-file]\n",
120520d5687Sderaadt 	    __progname);
1212040585eSniklas 	exit(1);
1222040585eSniklas }
1232040585eSniklas 
1242040585eSniklas static void
parse_args(int argc,char * argv[])1252040585eSniklas parse_args(int argc, char *argv[])
1262040585eSniklas {
12751ca15aeSniklas 	int             ch;
12851ca15aeSniklas 	int             cls, level;
129af729d73Sho 	int             do_packetlog = 0;
1302040585eSniklas 
1311ee656d4Sderaadt 	while ((ch = getopt(argc, argv, "46ac:dD:f:i:KnN:p:Ll:R:STv")) != -1) {
1322040585eSniklas 		switch (ch) {
133e2cc3c2eSho 		case '4':
134e2cc3c2eSho 			bind_family |= BIND_FAMILY_INET4;
135e2cc3c2eSho 			break;
136e2cc3c2eSho 
137e2cc3c2eSho 		case '6':
138e2cc3c2eSho 			bind_family |= BIND_FAMILY_INET6;
139e2cc3c2eSho 			break;
140e2cc3c2eSho 
14139fc3963Shshoexer 		case 'a':
1423579491dSderaadt 			acquire_only = 1;
14339fc3963Shshoexer 			break;
14439fc3963Shshoexer 
1452040585eSniklas 		case 'c':
1462040585eSniklas 			conf_path = optarg;
1472040585eSniklas 			break;
14851ca15aeSniklas 
1492040585eSniklas 		case 'd':
1502040585eSniklas 			debug++;
1512040585eSniklas 			break;
15251ca15aeSniklas 
1532040585eSniklas 		case 'D':
154fb9475d6Sderaadt 			if (sscanf(optarg, "%d=%d", &cls, &level) != 2) {
155fb9475d6Sderaadt 				if (sscanf(optarg, "A=%d", &level) == 1) {
15650eea14cSho 					for (cls = 0; cls < LOG_ENDCLASS;
15750eea14cSho 					    cls++)
158b225a241Sniklas 						log_debug_cmd(cls, level);
159fb9475d6Sderaadt 				} else
16012f43dabShshoexer 					log_print("parse_args: -D argument "
16112f43dabShshoexer 					    "unparseable: %s", optarg);
162fb9475d6Sderaadt 			} else
1632040585eSniklas 				log_debug_cmd(cls, level);
1642040585eSniklas 			break;
16551ca15aeSniklas 
1662040585eSniklas 		case 'f':
1672040585eSniklas 			ui_fifo = optarg;
1682040585eSniklas 			break;
16951ca15aeSniklas 
1705fc2ae46Sniklas 		case 'i':
1715fc2ae46Sniklas 			pid_file = optarg;
1725fc2ae46Sniklas 			break;
1735fc2ae46Sniklas 
174b6e0b5cbShshoexer 		case 'K':
175b6e0b5cbShshoexer 			ignore_policy++;
176b6e0b5cbShshoexer 			break;
177b6e0b5cbShshoexer 
1782040585eSniklas 		case 'n':
1792040585eSniklas 			app_none++;
1802040585eSniklas 			break;
18151ca15aeSniklas 
182287d4ce7Shshoexer 		case 'N':
183287d4ce7Shshoexer 			udp_encap_default_port = optarg;
184287d4ce7Shshoexer 			break;
185287d4ce7Shshoexer 
1862040585eSniklas 		case 'p':
187a86dabf6Sho 			udp_default_port = optarg;
1882040585eSniklas 			break;
18951ca15aeSniklas 
190af729d73Sho 		case 'l':
191af729d73Sho 			pcap_file = optarg;
19236d3c850Shshoexer 			/* FALLTHROUGH */
193af729d73Sho 
194af729d73Sho 		case 'L':
195af729d73Sho 			do_packetlog++;
196af729d73Sho 			break;
197af729d73Sho 
1982b81057dSniklas 		case 'R':
1992b81057dSniklas 			report_file = optarg;
2002b81057dSniklas 			break;
20151ca15aeSniklas 
202428bd1b5Shshoexer 		case 'S':
20385ead044Shshoexer 			delete_sas = 0;
20414f1d06aSmpf 			ui_daemon_passive = 1;
205428bd1b5Shshoexer 			break;
206428bd1b5Shshoexer 
207bfb67d4dScloder 		case 'T':
208bfb67d4dScloder 			disable_nat_t = 1;
209bfb67d4dScloder 			break;
210bfb67d4dScloder 
211ce261536Shshoexer 		case 'v':
212ce261536Shshoexer 			verbose_logging = 1;
213ce261536Shshoexer 			break;
214ce261536Shshoexer 
2152040585eSniklas 		default:
2162040585eSniklas 			usage();
2172040585eSniklas 		}
2182040585eSniklas 	}
2192040585eSniklas 	argc -= optind;
2202040585eSniklas 	argv += optind;
221af729d73Sho 
222fde55bc4Spyr 	if (argc > 0)
223fde55bc4Spyr 		usage();
224fde55bc4Spyr 
225af729d73Sho 	if (do_packetlog && !pcap_file)
226af729d73Sho 		pcap_file = PCAP_FILE_DEFAULT;
2272040585eSniklas }
2282040585eSniklas 
2292040585eSniklas static void
sighup(int sig)2302040585eSniklas sighup(int sig)
2312040585eSniklas {
2322040585eSniklas 	sighupped = 1;
2332040585eSniklas }
2342040585eSniklas 
2352b81057dSniklas /* Report internal state on SIGUSR1.  */
2362b81057dSniklas static void
report(void)2372b81057dSniklas report(void)
2382b81057dSniklas {
239605cc57cSho 	FILE	*rfp, *old;
240c3c2e2acSniklas 	mode_t	old_umask;
241c3c2e2acSniklas 
242c3c2e2acSniklas 	old_umask = umask(S_IRWXG | S_IRWXO);
243da35d433Sho 	rfp = monitor_fopen(report_file, "w");
244c3c2e2acSniklas 	umask(old_umask);
2452b81057dSniklas 
246fb9475d6Sderaadt 	if (!rfp) {
247b4caba6dShshoexer 		log_error("report: fopen (\"%s\", \"w\") failed", report_file);
2482b81057dSniklas 		return;
2492b81057dSniklas 	}
2502b81057dSniklas 	/* Divert the log channel to the report file during the report.  */
2512b81057dSniklas 	old = log_current();
252605cc57cSho 	log_to(rfp);
2532b81057dSniklas 	ui_report("r");
2542b81057dSniklas 	log_to(old);
255ea1948caSho 	fclose(rfp);
2562b81057dSniklas }
2572b81057dSniklas 
2582b81057dSniklas static void
sigusr1(int sig)2592b81057dSniklas sigusr1(int sig)
2602b81057dSniklas {
2612b81057dSniklas 	sigusr1ed = 1;
2622b81057dSniklas }
2632b81057dSniklas 
264c6e4dfa3Sho static int
phase2_sa_check(struct sa * sa,void * arg)265c6e4dfa3Sho phase2_sa_check(struct sa *sa, void *arg)
266c6e4dfa3Sho {
267c6e4dfa3Sho 	return sa->phase == 2;
268c6e4dfa3Sho }
269c6e4dfa3Sho 
270723115aaShshoexer static int
phase1_sa_check(struct sa * sa,void * arg)271723115aaShshoexer phase1_sa_check(struct sa *sa, void *arg)
272723115aaShshoexer {
273723115aaShshoexer 	return sa->phase == 1;
274723115aaShshoexer }
275723115aaShshoexer 
276b8909177Smoritz void
set_slave_signals(void)277b8909177Smoritz set_slave_signals(void)
278b8909177Smoritz {
279b8909177Smoritz 	int n;
280b8909177Smoritz 
281b8909177Smoritz 	for (n = 1; n < _NSIG; n++)
282b8909177Smoritz 		signal(n, SIG_DFL);
283b8909177Smoritz 
284b8909177Smoritz 	/*
285b8909177Smoritz 	 * Do a clean daemon shutdown on TERM/INT. These signals must be
286b8909177Smoritz 	 * initialized before monitor_init(). INT is only used with '-d'.
287b8909177Smoritz 	 */
288b8909177Smoritz 	signal(SIGTERM, daemon_shutdown_now);
289b8909177Smoritz 	if (debug == 1)		/* i.e '-dd' will skip this.  */
290b8909177Smoritz 		signal(SIGINT, daemon_shutdown_now);
291b8909177Smoritz 
292b8909177Smoritz 	/* Reinitialize on HUP reception.  */
293b8909177Smoritz 	signal(SIGHUP, sighup);
294b8909177Smoritz 
295b8909177Smoritz 	/* Report state on USR1 reception.  */
296b8909177Smoritz 	signal(SIGUSR1, sigusr1);
297b8909177Smoritz }
298b8909177Smoritz 
299c6e4dfa3Sho static void
daemon_shutdown(void)300c6e4dfa3Sho daemon_shutdown(void)
301c6e4dfa3Sho {
302c6e4dfa3Sho 	/* Perform a (protocol-wise) clean shutdown of the daemon.  */
303c6e4dfa3Sho 	struct sa	*sa;
304c6e4dfa3Sho 
305fb9475d6Sderaadt 	if (sigtermed == 1) {
306c6e4dfa3Sho 		log_print("isakmpd: shutting down...");
307c6e4dfa3Sho 
30885ead044Shshoexer 		if (delete_sas &&
30985ead044Shshoexer 		    strncmp("no", conf_get_str("General", "Delete-SAs"), 2)) {
310723115aaShshoexer 			/*
311428bd1b5Shshoexer 			 * Delete all active SAs.  First IPsec SAs, then
312428bd1b5Shshoexer 			 * ISAKMPD.  Each DELETE is another (outgoing) message.
313723115aaShshoexer 			 */
314723115aaShshoexer 			while ((sa = sa_find(phase2_sa_check, NULL)))
315c6e4dfa3Sho 				sa_delete(sa, 1);
316723115aaShshoexer 
317723115aaShshoexer 			while ((sa = sa_find(phase1_sa_check, NULL)))
318723115aaShshoexer 				sa_delete(sa, 1);
319428bd1b5Shshoexer 		}
320feaa02feShshoexer 
321feaa02feShshoexer 		/* We only want to do this once. */
322867e2181Sho 		sigtermed++;
323c6e4dfa3Sho 	}
324fb9475d6Sderaadt 	if (transport_prio_sendqs_empty()) {
325867e2181Sho 		/*
326867e2181Sho 		 * When the prioritized transport sendq:s are empty, i.e all
327867e2181Sho 		 * the DELETE notifications have been sent, we can shutdown.
328867e2181Sho 		 */
329867e2181Sho 
330c6e4dfa3Sho 		log_packet_stop();
331c6e4dfa3Sho 		log_print("isakmpd: exit");
332c6e4dfa3Sho 		exit(0);
333c6e4dfa3Sho 	}
334c6e4dfa3Sho }
335c6e4dfa3Sho 
336a8478dd3Sho /* Called on SIGTERM, SIGINT or by ui_shutdown_daemon().  */
337c6e4dfa3Sho void
daemon_shutdown_now(int sig)338c6e4dfa3Sho daemon_shutdown_now(int sig)
339c6e4dfa3Sho {
340c6e4dfa3Sho 	sigtermed = 1;
341c6e4dfa3Sho }
342c6e4dfa3Sho 
3435fc2ae46Sniklas /* Write pid file.  */
3445fc2ae46Sniklas static void
write_pid_file(void)3455fc2ae46Sniklas write_pid_file(void)
3465fc2ae46Sniklas {
3475fc2ae46Sniklas 	FILE	*fp;
3485fc2ae46Sniklas 
3495fc2ae46Sniklas 	unlink(pid_file);
3505fc2ae46Sniklas 
351e8a27e95Smoritz 	fp = fopen(pid_file, "w");
352fb9475d6Sderaadt 	if (fp != NULL) {
35370213997Sho 		if (fprintf(fp, "%ld\n", (long) getpid()) < 0)
35412f43dabShshoexer 			log_error("write_pid_file: failed to write PID to "
35512f43dabShshoexer 			    "\"%.100s\"", pid_file);
356ea1948caSho 		fclose(fp);
357fb9475d6Sderaadt 	} else
35812f43dabShshoexer 		log_fatal("write_pid_file: fopen (\"%.100s\", \"w\") failed",
35912f43dabShshoexer 		    pid_file);
3605fc2ae46Sniklas }
3615fc2ae46Sniklas 
362426a6f8cSkrw void
sanitise_stdfd(void)363426a6f8cSkrw sanitise_stdfd(void)
364426a6f8cSkrw {
365426a6f8cSkrw 	int nullfd, dupfd;
366426a6f8cSkrw 
367426a6f8cSkrw 	if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
368426a6f8cSkrw 		fprintf(stderr, "Couldn't open /dev/null: %s\n",
369426a6f8cSkrw 		    strerror(errno));
370426a6f8cSkrw 		exit(1);
371426a6f8cSkrw 	}
372426a6f8cSkrw 	while (++dupfd <= STDERR_FILENO) {
373426a6f8cSkrw 		/* Only populate closed fds */
374426a6f8cSkrw 		if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) {
375426a6f8cSkrw 			if (dup2(nullfd, dupfd) == -1) {
376426a6f8cSkrw 				fprintf(stderr, "dup2: %s\n", strerror(errno));
377426a6f8cSkrw 				exit(1);
378426a6f8cSkrw 			}
379426a6f8cSkrw 		}
380426a6f8cSkrw 	}
381426a6f8cSkrw 	if (nullfd > STDERR_FILENO)
382426a6f8cSkrw 		close(nullfd);
383426a6f8cSkrw }
384426a6f8cSkrw 
3852040585eSniklas int
main(int argc,char * argv[])3862040585eSniklas main(int argc, char *argv[])
3872040585eSniklas {
388783260f4Sniklas 	fd_set         *rfds, *wfds;
3892040585eSniklas 	int             n, m;
390783260f4Sniklas 	size_t          mask_size;
3916ee513e5Sjca 	struct timespec ts, *timeout;
3922040585eSniklas 
39331516eecShshoexer 	closefrom(STDERR_FILENO + 1);
39431516eecShshoexer 
395fb9475d6Sderaadt 	/*
396fb9475d6Sderaadt 	 * Make sure init() won't alloc fd 0, 1 or 2, as daemon() will close
397fb9475d6Sderaadt 	 * them.
398fb9475d6Sderaadt 	 */
399426a6f8cSkrw 	sanitise_stdfd();
400f41e756cSho 
401f41e756cSho 	/* Log cmd line parsing and initialization errors to stderr.  */
40230d6f32eSho 	log_to(stderr);
4032040585eSniklas 	parse_args(argc, argv);
404a8478dd3Sho 	log_init(debug);
405ceac201fSlum 	log_print("isakmpd: starting");
406da35d433Sho 
407a9c89582Sho 	/* Open protocols and services databases.  */
408a9c89582Sho 	setprotoent(1);
409a9c89582Sho 	setservent(1);
410a9c89582Sho 
411a0c57444Shshoexer 	/* Open command fifo */
412a0c57444Shshoexer 	ui_init();
413a0c57444Shshoexer 
414b8909177Smoritz 	set_slave_signals();
41531516eecShshoexer 	/* Daemonize before forking unpriv'ed child */
41631516eecShshoexer 	if (!debug)
41731516eecShshoexer 		if (daemon(0, 0))
41831516eecShshoexer 			log_fatal("main: daemon (0, 0) failed");
41931516eecShshoexer 
42015537254Shshoexer 	/* Set timezone before priv'separation */
42115537254Shshoexer 	tzset();
42215537254Shshoexer 
423e8a27e95Smoritz 	write_pid_file();
424e8a27e95Smoritz 
425db6e54dbSho 	if (monitor_init(debug)) {
42631516eecShshoexer 		/* The parent, with privileges enters infinite monitor loop. */
427da35d433Sho 		monitor_loop(debug);
428da35d433Sho 		exit(0);	/* Never reached.  */
429da35d433Sho 	}
430da35d433Sho 	/* Child process only from this point on, no privileges left.  */
431da35d433Sho 
4322040585eSniklas 	init();
433f41e756cSho 
434af729d73Sho 	/* If we wanted IKE packet capture to file, initialize it now.  */
435af729d73Sho 	if (pcap_file != 0)
436af729d73Sho 		log_packet_init(pcap_file);
437af729d73Sho 
438783260f4Sniklas 	/* Allocate the file descriptor sets just big enough.  */
439783260f4Sniklas 	n = getdtablesize();
440783260f4Sniklas 	mask_size = howmany(n, NFDBITS) * sizeof(fd_mask);
4415ae94ef8Sderaadt 	rfds = malloc(mask_size);
442783260f4Sniklas 	if (!rfds)
44312f43dabShshoexer 		log_fatal("main: malloc (%lu) failed",
44412f43dabShshoexer 		    (unsigned long)mask_size);
4455ae94ef8Sderaadt 	wfds = malloc(mask_size);
446783260f4Sniklas 	if (!wfds)
44712f43dabShshoexer 		log_fatal("main: malloc (%lu) failed",
44812f43dabShshoexer 		    (unsigned long)mask_size);
449783260f4Sniklas 
45031516eecShshoexer 	monitor_init_done();
45131516eecShshoexer 
452fb9475d6Sderaadt 	while (1) {
4532040585eSniklas 		/* If someone has sent SIGHUP to us, reconfigure.  */
454fb9475d6Sderaadt 		if (sighupped) {
455dcd65249Shshoexer 			sighupped = 0;
456b7f5c844Sho 			log_print("SIGHUP received");
4572040585eSniklas 			reinit();
458b7f5c844Sho 		}
4592b81057dSniklas 		/* and if someone sent SIGUSR1, do a state report.  */
460fb9475d6Sderaadt 		if (sigusr1ed) {
461dcd65249Shshoexer 			sigusr1ed = 0;
462b7f5c844Sho 			log_print("SIGUSR1 received");
4632b81057dSniklas 			report();
464b7f5c844Sho 		}
465c6e4dfa3Sho 		/*
46612f43dabShshoexer 		 * and if someone set 'sigtermed' (SIGTERM, SIGINT or via the
46712f43dabShshoexer 		 * UI), this indicates we should start a controlled shutdown
46812f43dabShshoexer 		 * of the daemon.
469c6e4dfa3Sho 		 *
47012f43dabShshoexer 		 * Note: Since _one_ message is sent per iteration of this
47112f43dabShshoexer 		 * enclosing while-loop, and we want to send a number of
47212f43dabShshoexer 		 * DELETE notifications, we must loop atleast this number of
47312f43dabShshoexer 		 * times. The daemon_shutdown() function starts by queueing
47412f43dabShshoexer 		 * the DELETEs, all other calls just increments the
47512f43dabShshoexer 		 * 'sigtermed' variable until it reaches a "safe" value, and
47612f43dabShshoexer 		 * the daemon exits.
477c6e4dfa3Sho 		 */
478c6e4dfa3Sho 		if (sigtermed)
479c6e4dfa3Sho 			daemon_shutdown();
480c6e4dfa3Sho 
4812040585eSniklas 		/* Setup the descriptors to look for incoming messages at.  */
4820dc10397Shshoexer 		bzero(rfds, mask_size);
483783260f4Sniklas 		n = transport_fd_set(rfds);
484783260f4Sniklas 		FD_SET(ui_socket, rfds);
4852040585eSniklas 		if (ui_socket + 1 > n)
4862040585eSniklas 			n = ui_socket + 1;
4872040585eSniklas 
4882040585eSniklas 		/*
48912f43dabShshoexer 		 * XXX Some day we might want to deal with an abstract
49012f43dabShshoexer 		 * application class instead, with many instantiations
49112f43dabShshoexer 		 * possible.
4922040585eSniklas 		 */
493fb9475d6Sderaadt 		if (!app_none && app_socket >= 0) {
494783260f4Sniklas 			FD_SET(app_socket, rfds);
4952040585eSniklas 			if (app_socket + 1 > n)
4962040585eSniklas 				n = app_socket + 1;
4972040585eSniklas 		}
4982040585eSniklas 		/* Setup the descriptors that have pending messages to send. */
4990dc10397Shshoexer 		bzero(wfds, mask_size);
500783260f4Sniklas 		m = transport_pending_wfd_set(wfds);
5012040585eSniklas 		if (m > n)
5022040585eSniklas 			n = m;
5032040585eSniklas 
5042040585eSniklas 		/* Find out when the next timed event is.  */
5056ee513e5Sjca 		timeout = &ts;
5062040585eSniklas 		timer_next_event(&timeout);
5072040585eSniklas 
5086ee513e5Sjca 		n = pselect(n, rfds, wfds, NULL, timeout, NULL);
509fb9475d6Sderaadt 		if (n == -1) {
510fb9475d6Sderaadt 			if (errno != EINTR) {
511b4caba6dShshoexer 				log_error("main: select");
512dc4b6c27Sniklas 
5132040585eSniklas 				/*
514fb9475d6Sderaadt 				 * In order to give the unexpected error
515fb9475d6Sderaadt 				 * condition time to resolve without letting
516fb9475d6Sderaadt 				 * this process eat up all available CPU
517dc4b6c27Sniklas 				 * we sleep for a short while.
5182040585eSniklas 				 */
5192040585eSniklas 				sleep(1);
5202040585eSniklas 			}
521fb9475d6Sderaadt 		} else if (n) {
522783260f4Sniklas 			transport_handle_messages(rfds);
523783260f4Sniklas 			transport_send_messages(wfds);
524783260f4Sniklas 			if (FD_ISSET(ui_socket, rfds))
5252040585eSniklas 				ui_handler();
52612f43dabShshoexer 			if (!app_none && app_socket >= 0 &&
52712f43dabShshoexer 			    FD_ISSET(app_socket, rfds))
5282040585eSniklas 				app_handler();
5292040585eSniklas 		}
5302040585eSniklas 		timer_handle_expirations();
5312040585eSniklas 	}
5322040585eSniklas }
533