xref: /openbsd/sbin/iked/iked.c (revision 274d7c50)
1 /*	$OpenBSD: iked.c,v 1.37 2019/05/11 16:30:23 patrick 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 
40 __dead void usage(void);
41 
42 void	 parent_shutdown(struct iked *);
43 void	 parent_sig_handler(int, short, void *);
44 int	 parent_dispatch_ca(int, struct privsep_proc *, struct imsg *);
45 int	 parent_dispatch_control(int, struct privsep_proc *, struct imsg *);
46 int	 parent_configure(struct iked *);
47 
48 static struct privsep_proc procs[] = {
49 	{ "ca",		PROC_CERT,	parent_dispatch_ca, caproc, IKED_CA },
50 	{ "control",	PROC_CONTROL,	parent_dispatch_control, control },
51 	{ "ikev2",	PROC_IKEV2,	NULL, ikev2 }
52 };
53 
54 __dead void
55 usage(void)
56 {
57 	extern char	*__progname;
58 
59 	fprintf(stderr, "usage: %s [-6dnSTtv] [-D macro=value] "
60 	    "[-f file]\n", __progname);
61 	exit(1);
62 }
63 
64 int
65 main(int argc, char *argv[])
66 {
67 	int		 c;
68 	int		 debug = 0, verbose = 0;
69 	int		 opts = 0;
70 	const char	*conffile = IKED_CONFIG;
71 	struct iked	*env = NULL;
72 	struct privsep	*ps;
73 
74 	log_init(1, LOG_DAEMON);
75 
76 	while ((c = getopt(argc, argv, "6dD:nf:vSTt")) != -1) {
77 		switch (c) {
78 		case '6':
79 			opts |= IKED_OPT_NOIPV6BLOCKING;
80 			break;
81 		case 'd':
82 			debug++;
83 			break;
84 		case 'D':
85 			if (cmdline_symset(optarg) < 0)
86 				log_warnx("could not parse macro definition %s",
87 				    optarg);
88 			break;
89 		case 'n':
90 			debug = 1;
91 			opts |= IKED_OPT_NOACTION;
92 			break;
93 		case 'f':
94 			conffile = optarg;
95 			break;
96 		case 'v':
97 			verbose++;
98 			opts |= IKED_OPT_VERBOSE;
99 			break;
100 		case 'S':
101 			opts |= IKED_OPT_PASSIVE;
102 			break;
103 		case 'T':
104 			opts |= IKED_OPT_NONATT;
105 			break;
106 		case 't':
107 			opts |= IKED_OPT_NATT;
108 			break;
109 		default:
110 			usage();
111 		}
112 	}
113 
114 	argc -= optind;
115 	argv += optind;
116 	if (argc > 0)
117 		usage();
118 
119 	if ((env = calloc(1, sizeof(*env))) == NULL)
120 		fatal("calloc: env");
121 
122 	env->sc_opts = opts;
123 
124 	ps = &env->sc_ps;
125 	ps->ps_env = env;
126 	TAILQ_INIT(&ps->ps_rcsocks);
127 
128 	if ((opts & (IKED_OPT_NONATT|IKED_OPT_NATT)) ==
129 	    (IKED_OPT_NONATT|IKED_OPT_NATT))
130 		errx(1, "conflicting NAT-T options");
131 
132 	if (strlcpy(env->sc_conffile, conffile, PATH_MAX) >= PATH_MAX)
133 		errx(1, "config file exceeds PATH_MAX");
134 
135 	ca_sslinit();
136 	policy_init(env);
137 
138 	/* check for root privileges */
139 	if (geteuid())
140 		errx(1, "need root privileges");
141 
142 	if ((ps->ps_pw =  getpwnam(IKED_USER)) == NULL)
143 		errx(1, "unknown user %s", IKED_USER);
144 
145 	/* Configure the control socket */
146 	ps->ps_csock.cs_name = IKED_SOCKET;
147 
148 	log_init(debug, LOG_DAEMON);
149 	log_setverbose(verbose);
150 
151 	if (opts & IKED_OPT_NOACTION)
152 		ps->ps_noaction = 1;
153 
154 	if (!debug && daemon(0, 0) == -1)
155 		err(1, "failed to daemonize");
156 
157 	group_init();
158 
159 	ps->ps_ninstances = 1;
160 	proc_init(ps, procs, nitems(procs));
161 
162 	setproctitle("parent");
163 	log_procinit("parent");
164 
165 	event_init();
166 
167 	signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps);
168 	signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps);
169 	signal_set(&ps->ps_evsigchld, SIGCHLD, parent_sig_handler, ps);
170 	signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps);
171 	signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps);
172 	signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps);
173 
174 	signal_add(&ps->ps_evsigint, NULL);
175 	signal_add(&ps->ps_evsigterm, NULL);
176 	signal_add(&ps->ps_evsigchld, NULL);
177 	signal_add(&ps->ps_evsighup, NULL);
178 	signal_add(&ps->ps_evsigpipe, NULL);
179 	signal_add(&ps->ps_evsigusr1, NULL);
180 
181 	proc_listen(ps, procs, nitems(procs));
182 
183 	if (parent_configure(env) == -1)
184 		fatalx("configuration failed");
185 
186 	event_dispatch();
187 
188 	log_debug("%d parent exiting", getpid());
189 
190 	return (0);
191 }
192 
193 int
194 parent_configure(struct iked *env)
195 {
196 	struct sockaddr_storage	 ss;
197 
198 	if (parse_config(env->sc_conffile, env) == -1) {
199 		proc_kill(&env->sc_ps);
200 		exit(1);
201 	}
202 
203 	if (env->sc_opts & IKED_OPT_NOACTION) {
204 		fprintf(stderr, "configuration OK\n");
205 		proc_kill(&env->sc_ps);
206 		exit(0);
207 	}
208 
209 	env->sc_pfkey = -1;
210 	config_setpfkey(env, PROC_IKEV2);
211 
212 	/* Send private and public keys to cert after forking the children */
213 	if (config_setkeys(env) == -1)
214 		fatalx("%s: failed to send keys", __func__);
215 	config_setreset(env, RESET_CA, PROC_CERT);
216 
217 	/* Now compile the policies and calculate skip steps */
218 	config_setcompile(env, PROC_IKEV2);
219 
220 	bzero(&ss, sizeof(ss));
221 	ss.ss_family = AF_INET;
222 
223 	if ((env->sc_opts & IKED_OPT_NATT) == 0)
224 		config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2);
225 	if ((env->sc_opts & IKED_OPT_NONATT) == 0)
226 		config_setsocket(env, &ss, ntohs(IKED_NATT_PORT), PROC_IKEV2);
227 
228 	bzero(&ss, sizeof(ss));
229 	ss.ss_family = AF_INET6;
230 
231 	if ((env->sc_opts & IKED_OPT_NATT) == 0)
232 		config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2);
233 	if ((env->sc_opts & IKED_OPT_NONATT) == 0)
234 		config_setsocket(env, &ss, ntohs(IKED_NATT_PORT), PROC_IKEV2);
235 
236 	/*
237 	 * pledge in the parent process:
238 	 * It has to run fairly late to allow forking the processes and
239 	 * opening the PFKEY socket and the listening UDP sockets (once)
240 	 * that need the bypass ioctls that are never allowed by pledge.
241 	 *
242 	 * Other flags:
243 	 * stdio - for malloc and basic I/O including events.
244 	 * rpath - for reload to open and read the configuration files.
245 	 * proc - run kill to terminate its children safely.
246 	 * dns - for reload and ocsp connect.
247 	 * inet - for ocsp connect.
248 	 * route - for using interfaces in iked.conf (SIOCGIFGMEMB)
249 	 * sendfd - for ocsp sockets.
250 	 */
251 	if (pledge("stdio rpath proc dns inet route sendfd", NULL) == -1)
252 		fatal("pledge");
253 
254 	config_setmobike(env);
255 	config_setfragmentation(env);
256 	config_setcoupled(env, env->sc_decoupled ? 0 : 1);
257 	config_setmode(env, env->sc_passive ? 1 : 0);
258 	config_setocsp(env);
259 
260 	return (0);
261 }
262 
263 void
264 parent_reload(struct iked *env, int reset, const char *filename)
265 {
266 	/* Switch back to the default config file */
267 	if (filename == NULL || *filename == '\0')
268 		filename = env->sc_conffile;
269 
270 	log_debug("%s: level %d config file %s", __func__, reset, filename);
271 
272 	if (reset == RESET_RELOAD) {
273 		config_setreset(env, RESET_POLICY, PROC_IKEV2);
274 		if (config_setkeys(env) == -1)
275 			fatalx("%s: failed to send keys", __func__);
276 		config_setreset(env, RESET_CA, PROC_CERT);
277 
278 		if (parse_config(filename, env) == -1) {
279 			log_debug("%s: failed to load config file %s",
280 			    __func__, filename);
281 		}
282 
283 		/* Re-compile policies and skip steps */
284 		config_setcompile(env, PROC_IKEV2);
285 
286 		config_setmobike(env);
287 		config_setfragmentation(env);
288 		config_setcoupled(env, env->sc_decoupled ? 0 : 1);
289 		config_setmode(env, env->sc_passive ? 1 : 0);
290 		config_setocsp(env);
291 	} else {
292 		config_setreset(env, reset, PROC_IKEV2);
293 		config_setreset(env, reset, PROC_CERT);
294 	}
295 }
296 
297 void
298 parent_sig_handler(int sig, short event, void *arg)
299 {
300 	struct privsep	*ps = arg;
301 	int		 die = 0, status, fail, id;
302 	pid_t		 pid;
303 	char		*cause;
304 
305 	switch (sig) {
306 	case SIGHUP:
307 		log_info("%s: reload requested with SIGHUP", __func__);
308 
309 		/*
310 		 * This is safe because libevent uses async signal handlers
311 		 * that run in the event loop and not in signal context.
312 		 */
313 		parent_reload(ps->ps_env, 0, NULL);
314 		break;
315 	case SIGPIPE:
316 		log_info("%s: ignoring SIGPIPE", __func__);
317 		break;
318 	case SIGUSR1:
319 		log_info("%s: ignoring SIGUSR1", __func__);
320 		break;
321 	case SIGTERM:
322 	case SIGINT:
323 		die = 1;
324 		/* FALLTHROUGH */
325 	case SIGCHLD:
326 		do {
327 			int len;
328 
329 			pid = waitpid(-1, &status, WNOHANG);
330 			if (pid <= 0)
331 				continue;
332 
333 			fail = 0;
334 			if (WIFSIGNALED(status)) {
335 				fail = 1;
336 				len = asprintf(&cause, "terminated; signal %d",
337 				    WTERMSIG(status));
338 			} else if (WIFEXITED(status)) {
339 				if (WEXITSTATUS(status) != 0) {
340 					fail = 1;
341 					len = asprintf(&cause,
342 					    "exited abnormally");
343 				} else
344 					len = asprintf(&cause, "exited okay");
345 			} else
346 				fatalx("unexpected cause of SIGCHLD");
347 
348 			if (len == -1)
349 				fatal("asprintf");
350 
351 			die = 1;
352 
353 			for (id = 0; id < PROC_MAX; id++)
354 				if (pid == ps->ps_pid[id]) {
355 					if (fail)
356 						log_warnx("lost child: %s %s",
357 						    ps->ps_title[id], cause);
358 					break;
359 				}
360 
361 			free(cause);
362 		} while (pid > 0 || (pid == -1 && errno == EINTR));
363 
364 		if (die)
365 			parent_shutdown(ps->ps_env);
366 		break;
367 	default:
368 		fatalx("unexpected signal");
369 	}
370 }
371 
372 int
373 parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg)
374 {
375 	struct iked	*env = p->p_ps->ps_env;
376 
377 	switch (imsg->hdr.type) {
378 	case IMSG_OCSP_FD:
379 		ocsp_connect(env);
380 		break;
381 	default:
382 		return (-1);
383 	}
384 
385 	return (0);
386 }
387 
388 int
389 parent_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg)
390 {
391 	struct iked	*env = p->p_ps->ps_env;
392 	int		 v;
393 	char		*str = NULL;
394 	unsigned int	 type = imsg->hdr.type;
395 
396 	switch (type) {
397 	case IMSG_CTL_RESET:
398 		IMSG_SIZE_CHECK(imsg, &v);
399 		memcpy(&v, imsg->data, sizeof(v));
400 		parent_reload(env, v, NULL);
401 		break;
402 	case IMSG_CTL_COUPLE:
403 	case IMSG_CTL_DECOUPLE:
404 	case IMSG_CTL_ACTIVE:
405 	case IMSG_CTL_PASSIVE:
406 		proc_compose(&env->sc_ps, PROC_IKEV2, type, NULL, 0);
407 		break;
408 	case IMSG_CTL_RELOAD:
409 		if (IMSG_DATA_SIZE(imsg) > 0)
410 			str = get_string(imsg->data, IMSG_DATA_SIZE(imsg));
411 		parent_reload(env, 0, str);
412 		free(str);
413 		break;
414 	case IMSG_CTL_VERBOSE:
415 		proc_forward_imsg(&env->sc_ps, imsg, PROC_IKEV2, -1);
416 		proc_forward_imsg(&env->sc_ps, imsg, PROC_CERT, -1);
417 
418 		/* return 1 to let proc.c handle it locally */
419 		return (1);
420 	default:
421 		return (-1);
422 	}
423 
424 	return (0);
425 }
426 
427 void
428 parent_shutdown(struct iked *env)
429 {
430 	proc_kill(&env->sc_ps);
431 
432 	free(env);
433 
434 	log_warnx("parent terminating");
435 	exit(0);
436 }
437