xref: /openbsd/sbin/isakmpd/isakmpd.c (revision 5b133f3f)
1 /* $OpenBSD: isakmpd.c,v 1.109 2023/03/08 04:43:06 guenther Exp $	 */
2 /* $EOM: isakmpd.c,v 1.54 2000/10/05 09:28:22 niklas Exp $	 */
3 
4 /*
5  * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist.  All rights reserved.
6  * Copyright (c) 1999, 2000 Angelos D. Keromytis.  All rights reserved.
7  * Copyright (c) 1999, 2000, 2001 H�kan Olsson.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * This code was written under funding by Ericsson Radio Systems.
32  */
33 
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42 #include <netdb.h>
43 #include <unistd.h>
44 #include <fcntl.h>
45 #include <paths.h>
46 
47 #include "app.h"
48 #include "conf.h"
49 #include "connection.h"
50 #include "init.h"
51 #include "libcrypto.h"
52 #include "log.h"
53 #include "message.h"
54 #include "monitor.h"
55 #include "nat_traversal.h"
56 #include "sa.h"
57 #include "timer.h"
58 #include "transport.h"
59 #include "udp.h"
60 #include "udp_encap.h"
61 #include "ui.h"
62 #include "util.h"
63 #include "cert.h"
64 
65 #include "policy.h"
66 
67 static void     usage(void);
68 
69 /*
70  * Set if -d is given, currently just for running in the foreground and log
71  * to stderr instead of syslog.
72  */
73 int             debug = 0;
74 
75 /* Set when no policy file shall be used. */
76 int		acquire_only = 0;
77 
78 /* Set when SAs shall be deleted on shutdown. */
79 int		delete_sas = 1;
80 
81 /*
82  * If we receive a SIGHUP signal, this flag gets set to show we need to
83  * reconfigure ASAP.
84  */
85 volatile sig_atomic_t sighupped = 0;
86 
87 /*
88  * If we receive a USR1 signal, this flag gets set to show we need to dump
89  * a report over our internal state ASAP.  The file to report to is settable
90  * via the -R parameter.
91  */
92 volatile sig_atomic_t sigusr1ed = 0;
93 static char    *report_file = "/var/run/isakmpd.report";
94 
95 /*
96  * If we receive a TERM signal, perform a "clean shutdown" of the daemon.
97  * This includes to send DELETE notifications for all our active SAs.
98  * Also on recv of an INT signal (Ctrl-C out of an '-d' session, typically).
99  */
100 volatile sig_atomic_t sigtermed = 0;
101 void            daemon_shutdown_now(int);
102 void		set_slave_signals(void);
103 void		sanitise_stdfd(void);
104 
105 /* The default path of the PID file.  */
106 char	       *pid_file = "/var/run/isakmpd.pid";
107 
108 /* The path of the IKE packet capture log file.  */
109 static char    *pcap_file = 0;
110 
111 static void
usage(void)112 usage(void)
113 {
114 	extern char *__progname;
115 
116 	fprintf(stderr,
117 	    "usage: %s [-46adKLnSTv] [-c config-file] [-D class=level] [-f fifo]\n"
118 	    "          [-i pid-file] [-l packetlog-file] [-N udpencap-port]\n"
119 	    "          [-p listen-port] [-R report-file]\n",
120 	    __progname);
121 	exit(1);
122 }
123 
124 static void
parse_args(int argc,char * argv[])125 parse_args(int argc, char *argv[])
126 {
127 	int             ch;
128 	int             cls, level;
129 	int             do_packetlog = 0;
130 
131 	while ((ch = getopt(argc, argv, "46ac:dD:f:i:KnN:p:Ll:R:STv")) != -1) {
132 		switch (ch) {
133 		case '4':
134 			bind_family |= BIND_FAMILY_INET4;
135 			break;
136 
137 		case '6':
138 			bind_family |= BIND_FAMILY_INET6;
139 			break;
140 
141 		case 'a':
142 			acquire_only = 1;
143 			break;
144 
145 		case 'c':
146 			conf_path = optarg;
147 			break;
148 
149 		case 'd':
150 			debug++;
151 			break;
152 
153 		case 'D':
154 			if (sscanf(optarg, "%d=%d", &cls, &level) != 2) {
155 				if (sscanf(optarg, "A=%d", &level) == 1) {
156 					for (cls = 0; cls < LOG_ENDCLASS;
157 					    cls++)
158 						log_debug_cmd(cls, level);
159 				} else
160 					log_print("parse_args: -D argument "
161 					    "unparseable: %s", optarg);
162 			} else
163 				log_debug_cmd(cls, level);
164 			break;
165 
166 		case 'f':
167 			ui_fifo = optarg;
168 			break;
169 
170 		case 'i':
171 			pid_file = optarg;
172 			break;
173 
174 		case 'K':
175 			ignore_policy++;
176 			break;
177 
178 		case 'n':
179 			app_none++;
180 			break;
181 
182 		case 'N':
183 			udp_encap_default_port = optarg;
184 			break;
185 
186 		case 'p':
187 			udp_default_port = optarg;
188 			break;
189 
190 		case 'l':
191 			pcap_file = optarg;
192 			/* FALLTHROUGH */
193 
194 		case 'L':
195 			do_packetlog++;
196 			break;
197 
198 		case 'R':
199 			report_file = optarg;
200 			break;
201 
202 		case 'S':
203 			delete_sas = 0;
204 			ui_daemon_passive = 1;
205 			break;
206 
207 		case 'T':
208 			disable_nat_t = 1;
209 			break;
210 
211 		case 'v':
212 			verbose_logging = 1;
213 			break;
214 
215 		default:
216 			usage();
217 		}
218 	}
219 	argc -= optind;
220 	argv += optind;
221 
222 	if (argc > 0)
223 		usage();
224 
225 	if (do_packetlog && !pcap_file)
226 		pcap_file = PCAP_FILE_DEFAULT;
227 }
228 
229 static void
sighup(int sig)230 sighup(int sig)
231 {
232 	sighupped = 1;
233 }
234 
235 /* Report internal state on SIGUSR1.  */
236 static void
report(void)237 report(void)
238 {
239 	FILE	*rfp, *old;
240 	mode_t	old_umask;
241 
242 	old_umask = umask(S_IRWXG | S_IRWXO);
243 	rfp = monitor_fopen(report_file, "w");
244 	umask(old_umask);
245 
246 	if (!rfp) {
247 		log_error("report: fopen (\"%s\", \"w\") failed", report_file);
248 		return;
249 	}
250 	/* Divert the log channel to the report file during the report.  */
251 	old = log_current();
252 	log_to(rfp);
253 	ui_report("r");
254 	log_to(old);
255 	fclose(rfp);
256 }
257 
258 static void
sigusr1(int sig)259 sigusr1(int sig)
260 {
261 	sigusr1ed = 1;
262 }
263 
264 static int
phase2_sa_check(struct sa * sa,void * arg)265 phase2_sa_check(struct sa *sa, void *arg)
266 {
267 	return sa->phase == 2;
268 }
269 
270 static int
phase1_sa_check(struct sa * sa,void * arg)271 phase1_sa_check(struct sa *sa, void *arg)
272 {
273 	return sa->phase == 1;
274 }
275 
276 void
set_slave_signals(void)277 set_slave_signals(void)
278 {
279 	int n;
280 
281 	for (n = 1; n < _NSIG; n++)
282 		signal(n, SIG_DFL);
283 
284 	/*
285 	 * Do a clean daemon shutdown on TERM/INT. These signals must be
286 	 * initialized before monitor_init(). INT is only used with '-d'.
287 	 */
288 	signal(SIGTERM, daemon_shutdown_now);
289 	if (debug == 1)		/* i.e '-dd' will skip this.  */
290 		signal(SIGINT, daemon_shutdown_now);
291 
292 	/* Reinitialize on HUP reception.  */
293 	signal(SIGHUP, sighup);
294 
295 	/* Report state on USR1 reception.  */
296 	signal(SIGUSR1, sigusr1);
297 }
298 
299 static void
daemon_shutdown(void)300 daemon_shutdown(void)
301 {
302 	/* Perform a (protocol-wise) clean shutdown of the daemon.  */
303 	struct sa	*sa;
304 
305 	if (sigtermed == 1) {
306 		log_print("isakmpd: shutting down...");
307 
308 		if (delete_sas &&
309 		    strncmp("no", conf_get_str("General", "Delete-SAs"), 2)) {
310 			/*
311 			 * Delete all active SAs.  First IPsec SAs, then
312 			 * ISAKMPD.  Each DELETE is another (outgoing) message.
313 			 */
314 			while ((sa = sa_find(phase2_sa_check, NULL)))
315 				sa_delete(sa, 1);
316 
317 			while ((sa = sa_find(phase1_sa_check, NULL)))
318 				sa_delete(sa, 1);
319 		}
320 
321 		/* We only want to do this once. */
322 		sigtermed++;
323 	}
324 	if (transport_prio_sendqs_empty()) {
325 		/*
326 		 * When the prioritized transport sendq:s are empty, i.e all
327 		 * the DELETE notifications have been sent, we can shutdown.
328 		 */
329 
330 		log_packet_stop();
331 		log_print("isakmpd: exit");
332 		exit(0);
333 	}
334 }
335 
336 /* Called on SIGTERM, SIGINT or by ui_shutdown_daemon().  */
337 void
daemon_shutdown_now(int sig)338 daemon_shutdown_now(int sig)
339 {
340 	sigtermed = 1;
341 }
342 
343 /* Write pid file.  */
344 static void
write_pid_file(void)345 write_pid_file(void)
346 {
347 	FILE	*fp;
348 
349 	unlink(pid_file);
350 
351 	fp = fopen(pid_file, "w");
352 	if (fp != NULL) {
353 		if (fprintf(fp, "%ld\n", (long) getpid()) < 0)
354 			log_error("write_pid_file: failed to write PID to "
355 			    "\"%.100s\"", pid_file);
356 		fclose(fp);
357 	} else
358 		log_fatal("write_pid_file: fopen (\"%.100s\", \"w\") failed",
359 		    pid_file);
360 }
361 
362 void
sanitise_stdfd(void)363 sanitise_stdfd(void)
364 {
365 	int nullfd, dupfd;
366 
367 	if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
368 		fprintf(stderr, "Couldn't open /dev/null: %s\n",
369 		    strerror(errno));
370 		exit(1);
371 	}
372 	while (++dupfd <= STDERR_FILENO) {
373 		/* Only populate closed fds */
374 		if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) {
375 			if (dup2(nullfd, dupfd) == -1) {
376 				fprintf(stderr, "dup2: %s\n", strerror(errno));
377 				exit(1);
378 			}
379 		}
380 	}
381 	if (nullfd > STDERR_FILENO)
382 		close(nullfd);
383 }
384 
385 int
main(int argc,char * argv[])386 main(int argc, char *argv[])
387 {
388 	fd_set         *rfds, *wfds;
389 	int             n, m;
390 	size_t          mask_size;
391 	struct timespec ts, *timeout;
392 
393 	closefrom(STDERR_FILENO + 1);
394 
395 	/*
396 	 * Make sure init() won't alloc fd 0, 1 or 2, as daemon() will close
397 	 * them.
398 	 */
399 	sanitise_stdfd();
400 
401 	/* Log cmd line parsing and initialization errors to stderr.  */
402 	log_to(stderr);
403 	parse_args(argc, argv);
404 	log_init(debug);
405 	log_print("isakmpd: starting");
406 
407 	/* Open protocols and services databases.  */
408 	setprotoent(1);
409 	setservent(1);
410 
411 	/* Open command fifo */
412 	ui_init();
413 
414 	set_slave_signals();
415 	/* Daemonize before forking unpriv'ed child */
416 	if (!debug)
417 		if (daemon(0, 0))
418 			log_fatal("main: daemon (0, 0) failed");
419 
420 	/* Set timezone before priv'separation */
421 	tzset();
422 
423 	write_pid_file();
424 
425 	if (monitor_init(debug)) {
426 		/* The parent, with privileges enters infinite monitor loop. */
427 		monitor_loop(debug);
428 		exit(0);	/* Never reached.  */
429 	}
430 	/* Child process only from this point on, no privileges left.  */
431 
432 	init();
433 
434 	/* If we wanted IKE packet capture to file, initialize it now.  */
435 	if (pcap_file != 0)
436 		log_packet_init(pcap_file);
437 
438 	/* Allocate the file descriptor sets just big enough.  */
439 	n = getdtablesize();
440 	mask_size = howmany(n, NFDBITS) * sizeof(fd_mask);
441 	rfds = malloc(mask_size);
442 	if (!rfds)
443 		log_fatal("main: malloc (%lu) failed",
444 		    (unsigned long)mask_size);
445 	wfds = malloc(mask_size);
446 	if (!wfds)
447 		log_fatal("main: malloc (%lu) failed",
448 		    (unsigned long)mask_size);
449 
450 	monitor_init_done();
451 
452 	while (1) {
453 		/* If someone has sent SIGHUP to us, reconfigure.  */
454 		if (sighupped) {
455 			sighupped = 0;
456 			log_print("SIGHUP received");
457 			reinit();
458 		}
459 		/* and if someone sent SIGUSR1, do a state report.  */
460 		if (sigusr1ed) {
461 			sigusr1ed = 0;
462 			log_print("SIGUSR1 received");
463 			report();
464 		}
465 		/*
466 		 * and if someone set 'sigtermed' (SIGTERM, SIGINT or via the
467 		 * UI), this indicates we should start a controlled shutdown
468 		 * of the daemon.
469 		 *
470 		 * Note: Since _one_ message is sent per iteration of this
471 		 * enclosing while-loop, and we want to send a number of
472 		 * DELETE notifications, we must loop atleast this number of
473 		 * times. The daemon_shutdown() function starts by queueing
474 		 * the DELETEs, all other calls just increments the
475 		 * 'sigtermed' variable until it reaches a "safe" value, and
476 		 * the daemon exits.
477 		 */
478 		if (sigtermed)
479 			daemon_shutdown();
480 
481 		/* Setup the descriptors to look for incoming messages at.  */
482 		bzero(rfds, mask_size);
483 		n = transport_fd_set(rfds);
484 		FD_SET(ui_socket, rfds);
485 		if (ui_socket + 1 > n)
486 			n = ui_socket + 1;
487 
488 		/*
489 		 * XXX Some day we might want to deal with an abstract
490 		 * application class instead, with many instantiations
491 		 * possible.
492 		 */
493 		if (!app_none && app_socket >= 0) {
494 			FD_SET(app_socket, rfds);
495 			if (app_socket + 1 > n)
496 				n = app_socket + 1;
497 		}
498 		/* Setup the descriptors that have pending messages to send. */
499 		bzero(wfds, mask_size);
500 		m = transport_pending_wfd_set(wfds);
501 		if (m > n)
502 			n = m;
503 
504 		/* Find out when the next timed event is.  */
505 		timeout = &ts;
506 		timer_next_event(&timeout);
507 
508 		n = pselect(n, rfds, wfds, NULL, timeout, NULL);
509 		if (n == -1) {
510 			if (errno != EINTR) {
511 				log_error("main: select");
512 
513 				/*
514 				 * In order to give the unexpected error
515 				 * condition time to resolve without letting
516 				 * this process eat up all available CPU
517 				 * we sleep for a short while.
518 				 */
519 				sleep(1);
520 			}
521 		} else if (n) {
522 			transport_handle_messages(rfds);
523 			transport_send_messages(wfds);
524 			if (FD_ISSET(ui_socket, rfds))
525 				ui_handler();
526 			if (!app_none && app_socket >= 0 &&
527 			    FD_ISSET(app_socket, rfds))
528 				app_handler();
529 		}
530 		timer_handle_expirations();
531 	}
532 }
533