1/*	$OpenBSD: iked.c,v 1.70 2024/02/15 20:10:45 tobhe Exp $	*/
2
3/*
4 * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
5 * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/queue.h>
21#include <sys/socket.h>
22#include <sys/wait.h>
23#include <sys/uio.h>
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <string.h>
29#include <getopt.h>
30#include <signal.h>
31#include <syslog.h>
32#include <errno.h>
33#include <err.h>
34#include <pwd.h>
35#include <event.h>
36
37#include "iked.h"
38#include "ikev2.h"
39#include "version.h"
40
41__dead void usage(void);
42
43void	 parent_shutdown(struct iked *);
44void	 parent_sig_handler(int, short, void *);
45int	 parent_dispatch_ca(int, struct privsep_proc *, struct imsg *);
46int	 parent_dispatch_control(int, struct privsep_proc *, struct imsg *);
47int	 parent_dispatch_ikev2(int, struct privsep_proc *, struct imsg *);
48void	 parent_connected(struct privsep *);
49int	 parent_configure(struct iked *);
50
51struct iked	*iked_env;
52
53static struct privsep_proc procs[] = {
54	{ "ca",		PROC_CERT,	parent_dispatch_ca, caproc, IKED_CA },
55	{ "control",	PROC_CONTROL,	parent_dispatch_control, control },
56	{ "ikev2",	PROC_IKEV2,	parent_dispatch_ikev2, ikev2 }
57};
58
59__dead void
60usage(void)
61{
62	extern char	*__progname;
63
64	fprintf(stderr, "usage: %s [-dnSTtVv] [-D macro=value] "
65	    "[-f file] [-p udpencap_port] [-s socket]\n", __progname);
66	exit(1);
67}
68
69int
70main(int argc, char *argv[])
71{
72	int			 c;
73	int			 debug = 0, verbose = 0;
74	int			 opts = 0;
75	enum natt_mode		 natt_mode = NATT_DEFAULT;
76	in_port_t		 port = IKED_NATT_PORT;
77	const char		*conffile = IKED_CONFIG;
78	const char		*sock = IKED_SOCKET;
79	const char		*errstr, *title = NULL;
80	struct iked		*env = NULL;
81	struct privsep		*ps;
82	enum privsep_procid	 proc_id = PROC_PARENT;
83	int			 proc_instance = 0;
84	int			 argc0 = argc;
85
86	log_init(1, LOG_DAEMON);
87
88	while ((c = getopt(argc, argv, "6D:df:I:nP:p:Ss:TtvV")) != -1) {
89		switch (c) {
90		case '6':
91			log_warnx("the -6 option is ignored and will be "
92			    "removed in the future.");
93			break;
94		case 'D':
95			if (cmdline_symset(optarg) < 0)
96				log_warnx("could not parse macro definition %s",
97				    optarg);
98			break;
99		case 'd':
100			debug++;
101			break;
102		case 'f':
103			conffile = optarg;
104			break;
105		case 'I':
106			proc_instance = strtonum(optarg, 0,
107			    PROC_MAX_INSTANCES, &errstr);
108			if (errstr)
109				fatalx("invalid process instance");
110			break;
111		case 'n':
112			debug = 1;
113			opts |= IKED_OPT_NOACTION;
114			break;
115		case 'P':
116			title = optarg;
117			proc_id = proc_getid(procs, nitems(procs), title);
118			if (proc_id == PROC_MAX)
119				fatalx("invalid process name");
120			break;
121		case 'p':
122			if (natt_mode == NATT_DISABLE)
123				errx(1, "-T and -p are mutually exclusive");
124			port = strtonum(optarg, 1, UINT16_MAX, &errstr);
125			if (errstr != NULL)
126				errx(1, "port is %s: %s", errstr, optarg);
127			natt_mode = NATT_FORCE;
128			break;
129		case 'S':
130			opts |= IKED_OPT_PASSIVE;
131			break;
132		case 's':
133			sock = optarg;
134			break;
135		case 'T':
136			if (natt_mode == NATT_FORCE)
137				errx(1, "-T and -t/-p are mutually exclusive");
138			natt_mode = NATT_DISABLE;
139			break;
140		case 't':
141			if (natt_mode == NATT_DISABLE)
142				errx(1, "-T and -t are mutually exclusive");
143			natt_mode = NATT_FORCE;
144			break;
145		case 'v':
146			verbose++;
147			opts |= IKED_OPT_VERBOSE;
148			break;
149		case 'V':
150			fprintf(stderr, "OpenIKED %s\n", IKED_VERSION);
151			return 0;
152		default:
153			usage();
154		}
155	}
156
157	/* log to stderr until daemonized */
158	log_init(debug ? debug : 1, LOG_DAEMON);
159
160	argc -= optind;
161	if (argc > 0)
162		usage();
163
164	if ((env = calloc(1, sizeof(*env))) == NULL)
165		fatal("calloc: env");
166
167	iked_env = env;
168	env->sc_opts = opts;
169	env->sc_nattmode = natt_mode;
170	env->sc_nattport = port;
171
172	ps = &env->sc_ps;
173	ps->ps_env = env;
174
175	if (strlcpy(env->sc_conffile, conffile, PATH_MAX) >= PATH_MAX)
176		errx(1, "config file exceeds PATH_MAX");
177
178	group_init();
179	policy_init(env);
180
181	/* check for root privileges */
182	if (geteuid())
183		errx(1, "need root privileges");
184
185	if ((ps->ps_pw =  getpwnam(IKED_USER)) == NULL)
186		errx(1, "unknown user %s", IKED_USER);
187
188	/* Configure the control socket */
189	ps->ps_csock.cs_name = sock;
190
191	log_init(debug, LOG_DAEMON);
192	log_setverbose(verbose);
193
194	if (opts & IKED_OPT_NOACTION)
195		ps->ps_noaction = 1;
196
197	ps->ps_instance = proc_instance;
198	if (title != NULL)
199		ps->ps_title[proc_id] = title;
200
201	/* only the parent returns */
202	proc_init(ps, procs, nitems(procs), debug, argc0, argv, proc_id);
203
204	setproctitle("parent");
205	log_procinit("parent");
206
207	event_init();
208
209	signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps);
210	signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps);
211	signal_set(&ps->ps_evsigchld, SIGCHLD, parent_sig_handler, ps);
212	signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps);
213	signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps);
214	signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps);
215
216	signal_add(&ps->ps_evsigint, NULL);
217	signal_add(&ps->ps_evsigterm, NULL);
218	signal_add(&ps->ps_evsigchld, NULL);
219	signal_add(&ps->ps_evsighup, NULL);
220	signal_add(&ps->ps_evsigpipe, NULL);
221	signal_add(&ps->ps_evsigusr1, NULL);
222
223	vroute_init(env);
224
225	proc_connect(ps, parent_connected);
226
227	event_dispatch();
228
229	log_debug("%d parent exiting", getpid());
230	parent_shutdown(env);
231
232	return (0);
233}
234
235void
236parent_connected(struct privsep *ps)
237{
238	struct iked	*env = ps->ps_env;
239
240	if (parent_configure(env) == -1)
241		fatalx("configuration failed");
242}
243
244int
245parent_configure(struct iked *env)
246{
247	struct sockaddr_storage	 ss;
248
249	if (parse_config(env->sc_conffile, env) == -1) {
250		proc_kill(&env->sc_ps);
251		exit(1);
252	}
253
254	if (env->sc_opts & IKED_OPT_NOACTION) {
255		fprintf(stderr, "configuration OK\n");
256		proc_kill(&env->sc_ps);
257		exit(0);
258	}
259
260	env->sc_pfkey = -1;
261	config_setpfkey(env);
262
263	/* Send private and public keys to cert after forking the children */
264	if (config_setkeys(env) == -1)
265		fatalx("%s: failed to send keys", __func__);
266	config_setreset(env, RESET_CA, PROC_CERT);
267
268	/* Now compile the policies and calculate skip steps */
269	config_setcompile(env, PROC_IKEV2);
270
271	bzero(&ss, sizeof(ss));
272	ss.ss_family = AF_INET;
273
274	/* see comment on config_setsocket() */
275	if (env->sc_nattmode != NATT_FORCE)
276		config_setsocket(env, &ss, htons(IKED_IKE_PORT), PROC_IKEV2);
277	if (env->sc_nattmode != NATT_DISABLE)
278		config_setsocket(env, &ss, htons(env->sc_nattport), PROC_IKEV2);
279
280	bzero(&ss, sizeof(ss));
281	ss.ss_family = AF_INET6;
282
283	if (env->sc_nattmode != NATT_FORCE)
284		config_setsocket(env, &ss, htons(IKED_IKE_PORT), PROC_IKEV2);
285	if (env->sc_nattmode != NATT_DISABLE)
286		config_setsocket(env, &ss, htons(env->sc_nattport), PROC_IKEV2);
287
288	/*
289	 * pledge in the parent process:
290	 * It has to run fairly late to allow forking the processes and
291	 * opening the PFKEY socket and the listening UDP sockets (once)
292	 * that need the bypass ioctls that are never allowed by pledge.
293	 *
294	 * Other flags:
295	 * stdio - for malloc and basic I/O including events.
296	 * rpath - for reload to open and read the configuration files.
297	 * proc - run kill to terminate its children safely.
298	 * dns - for reload and ocsp connect.
299	 * inet - for ocsp connect.
300	 * route - for using interfaces in iked.conf (SIOCGIFGMEMB)
301	 * wroute - for adding and removing addresses (SIOCAIFGMEMB)
302	 * sendfd - for ocsp sockets.
303	 */
304	if (pledge("stdio rpath proc dns inet route wroute sendfd", NULL) == -1)
305		fatal("pledge");
306
307	config_setstatic(env);
308	config_setcoupled(env, env->sc_decoupled ? 0 : 1);
309	config_setocsp(env);
310	/* Must be last */
311	config_setmode(env, env->sc_passive ? 1 : 0);
312
313	return (0);
314}
315
316void
317parent_reload(struct iked *env, int reset, const char *filename)
318{
319	/* Switch back to the default config file */
320	if (filename == NULL || *filename == '\0')
321		filename = env->sc_conffile;
322
323	log_debug("%s: level %d config file %s", __func__, reset, filename);
324
325	if (reset == RESET_RELOAD) {
326		config_setreset(env, RESET_POLICY, PROC_IKEV2);
327		if (config_setkeys(env) == -1)
328			fatalx("%s: failed to send keys", __func__);
329		config_setreset(env, RESET_CA, PROC_CERT);
330
331		if (parse_config(filename, env) == -1) {
332			log_debug("%s: failed to load config file %s",
333			    __func__, filename);
334		}
335
336		/* Re-compile policies and skip steps */
337		config_setcompile(env, PROC_IKEV2);
338
339		config_setstatic(env);
340		config_setcoupled(env, env->sc_decoupled ? 0 : 1);
341		config_setocsp(env);
342		/* Must be last */
343		config_setmode(env, env->sc_passive ? 1 : 0);
344	} else {
345		config_setreset(env, reset, PROC_IKEV2);
346		config_setreset(env, reset, PROC_CERT);
347	}
348}
349
350void
351parent_sig_handler(int sig, short event, void *arg)
352{
353	struct privsep	*ps = arg;
354	int		 die = 0, status, fail, id;
355	pid_t		 pid;
356	char		*cause;
357
358	switch (sig) {
359	case SIGHUP:
360		log_info("%s: reload requested with SIGHUP", __func__);
361
362		/*
363		 * This is safe because libevent uses async signal handlers
364		 * that run in the event loop and not in signal context.
365		 */
366		parent_reload(ps->ps_env, 0, NULL);
367		break;
368	case SIGPIPE:
369		log_info("%s: ignoring SIGPIPE", __func__);
370		break;
371	case SIGUSR1:
372		log_info("%s: ignoring SIGUSR1", __func__);
373		break;
374	case SIGTERM:
375	case SIGINT:
376		die = 1;
377		/* FALLTHROUGH */
378	case SIGCHLD:
379		do {
380			int len = 0;
381
382			pid = waitpid(-1, &status, WNOHANG);
383			if (pid <= 0)
384				continue;
385
386			fail = 0;
387			if (WIFSIGNALED(status)) {
388				fail = 1;
389				len = asprintf(&cause, "terminated; signal %d",
390				    WTERMSIG(status));
391			} else if (WIFEXITED(status)) {
392				if (WEXITSTATUS(status) != 0) {
393					fail = 1;
394					len = asprintf(&cause,
395					    "exited abnormally");
396				} else
397					len = asprintf(&cause, "exited okay");
398			} else
399				fatalx("unexpected cause of SIGCHLD");
400
401			if (len == -1)
402				fatal("asprintf");
403
404			die = 1;
405
406			for (id = 0; id < PROC_MAX; id++)
407				if (pid == ps->ps_pid[id]) {
408					if (fail)
409						log_warnx("lost child: %s %s",
410						    ps->ps_title[id], cause);
411					break;
412				}
413
414			free(cause);
415		} while (pid > 0 || (pid == -1 && errno == EINTR));
416
417		if (die)
418			parent_shutdown(ps->ps_env);
419		break;
420	default:
421		fatalx("unexpected signal");
422	}
423}
424
425int
426parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg)
427{
428	struct iked	*env = iked_env;
429
430	switch (imsg->hdr.type) {
431	case IMSG_CTL_ACTIVE:
432	case IMSG_CTL_PASSIVE:
433		proc_forward_imsg(&env->sc_ps, imsg, PROC_IKEV2, -1);
434		break;
435	case IMSG_OCSP_FD:
436		ocsp_connect(env, imsg);
437		break;
438	default:
439		return (-1);
440	}
441
442	return (0);
443}
444
445int
446parent_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg)
447{
448	struct iked	*env = iked_env;
449	int		 v;
450	char		*str = NULL;
451	unsigned int	 type = imsg->hdr.type;
452
453	switch (type) {
454	case IMSG_CTL_RESET:
455		IMSG_SIZE_CHECK(imsg, &v);
456		memcpy(&v, imsg->data, sizeof(v));
457		parent_reload(env, v, NULL);
458		break;
459	case IMSG_CTL_COUPLE:
460	case IMSG_CTL_DECOUPLE:
461	case IMSG_CTL_ACTIVE:
462	case IMSG_CTL_PASSIVE:
463		proc_compose(&env->sc_ps, PROC_IKEV2, type, NULL, 0);
464		break;
465	case IMSG_CTL_RELOAD:
466		if (IMSG_DATA_SIZE(imsg) > 0)
467			str = get_string(imsg->data, IMSG_DATA_SIZE(imsg));
468		parent_reload(env, 0, str);
469		free(str);
470		break;
471	case IMSG_CTL_VERBOSE:
472		proc_forward_imsg(&env->sc_ps, imsg, PROC_IKEV2, -1);
473		proc_forward_imsg(&env->sc_ps, imsg, PROC_CERT, -1);
474
475		/* return 1 to let proc.c handle it locally */
476		return (1);
477	default:
478		return (-1);
479	}
480
481	return (0);
482}
483
484int
485parent_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg)
486{
487	struct iked	*env = iked_env;
488
489	switch (imsg->hdr.type) {
490	case IMSG_IF_ADDADDR:
491	case IMSG_IF_DELADDR:
492		return (vroute_getaddr(env, imsg));
493	case IMSG_VDNS_ADD:
494	case IMSG_VDNS_DEL:
495		return (vroute_getdns(env, imsg));
496	case IMSG_VROUTE_ADD:
497	case IMSG_VROUTE_DEL:
498		return (vroute_getroute(env, imsg));
499	case IMSG_VROUTE_CLONE:
500		return (vroute_getcloneroute(env, imsg));
501	default:
502		return (-1);
503	}
504
505	return (0);
506}
507
508void
509parent_shutdown(struct iked *env)
510{
511	proc_kill(&env->sc_ps);
512
513	vroute_cleanup(env);
514	free(env->sc_vroute);
515	free(env);
516
517	log_warnx("parent terminating");
518	exit(0);
519}
520