xref: /openbsd-src/sbin/iked/iked.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: iked.c,v 1.21 2014/05/08 13:11:16 blambert Exp $	*/
2 
3 /*
4  * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
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 <errno.h>
32 #include <err.h>
33 #include <pwd.h>
34 #include <event.h>
35 
36 #include "iked.h"
37 #include "ikev2.h"
38 
39 __dead void usage(void);
40 
41 void	 parent_shutdown(struct iked *);
42 void	 parent_sig_handler(int, short, void *);
43 int	 parent_dispatch_ikev1(int, struct privsep_proc *, struct imsg *);
44 int	 parent_dispatch_ikev2(int, struct privsep_proc *, struct imsg *);
45 int	 parent_dispatch_ca(int, struct privsep_proc *, struct imsg *);
46 int	 parent_configure(struct iked *);
47 
48 static struct privsep_proc procs[] = {
49 	{ "ikev1",	PROC_IKEV1, parent_dispatch_ikev1, ikev1 },
50 	{ "ikev2",	PROC_IKEV2, parent_dispatch_ikev2, ikev2 },
51 	{ "ca",		PROC_CERT, parent_dispatch_ca, caproc, IKED_CA }
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);
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 	if ((env = calloc(1, sizeof(*env))) == NULL)
115 		fatal("calloc: env");
116 
117 	env->sc_opts = opts;
118 
119 	ps = &env->sc_ps;
120 	ps->ps_env = env;
121 	TAILQ_INIT(&ps->ps_rcsocks);
122 
123 	if ((opts & (IKED_OPT_NONATT|IKED_OPT_NATT)) ==
124 	    (IKED_OPT_NONATT|IKED_OPT_NATT))
125 		errx(1, "conflicting NAT-T options");
126 
127 	if (strlcpy(env->sc_conffile, conffile, MAXPATHLEN) >= MAXPATHLEN)
128 		errx(1, "config file exceeds MAXPATHLEN");
129 
130 	ca_sslinit();
131 	policy_init(env);
132 
133 	/* check for root privileges */
134 	if (geteuid())
135 		errx(1, "need root privileges");
136 
137 	if ((ps->ps_pw =  getpwnam(IKED_USER)) == NULL)
138 		errx(1, "unknown user %s", IKED_USER);
139 
140 	/* Configure the control socket */
141 	ps->ps_csock.cs_name = IKED_SOCKET;
142 
143 	log_init(debug);
144 	log_verbose(verbose);
145 
146 	if (!debug && daemon(0, 0) == -1)
147 		err(1, "failed to daemonize");
148 
149 	group_init();
150 
151 	ps->ps_ninstances = 1;
152 	proc_init(ps, procs, nitems(procs));
153 
154 	setproctitle("parent");
155 
156 	event_init();
157 
158 	signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps);
159 	signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps);
160 	signal_set(&ps->ps_evsigchld, SIGCHLD, parent_sig_handler, ps);
161 	signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps);
162 	signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps);
163 
164 	signal_add(&ps->ps_evsigint, NULL);
165 	signal_add(&ps->ps_evsigterm, NULL);
166 	signal_add(&ps->ps_evsigchld, NULL);
167 	signal_add(&ps->ps_evsighup, NULL);
168 	signal_add(&ps->ps_evsigpipe, NULL);
169 
170 	proc_listen(ps, procs, nitems(procs));
171 
172 	if (parent_configure(env) == -1)
173 		fatalx("configuration failed");
174 
175 	event_dispatch();
176 
177 	log_debug("%d parent exiting", getpid());
178 
179 	return (0);
180 }
181 
182 int
183 parent_configure(struct iked *env)
184 {
185 	struct sockaddr_storage	 ss;
186 
187 	if (parse_config(env->sc_conffile, env) == -1) {
188 		proc_kill(&env->sc_ps);
189 		exit(1);
190 	}
191 
192 	if (env->sc_opts & IKED_OPT_NOACTION) {
193 		fprintf(stderr, "configuration OK\n");
194 		proc_kill(&env->sc_ps);
195 		exit(0);
196 	}
197 
198 	env->sc_pfkey = -1;
199 	config_setpfkey(env, PROC_IKEV2);
200 
201 	/* Now compile the policies and calculate skip steps */
202 	config_setcompile(env, PROC_IKEV1);
203 	config_setcompile(env, PROC_IKEV2);
204 
205 	bzero(&ss, sizeof(ss));
206 	ss.ss_family = AF_INET;
207 
208 	if ((env->sc_opts & IKED_OPT_NATT) == 0)
209 		config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2);
210 	if ((env->sc_opts & IKED_OPT_NONATT) == 0)
211 		config_setsocket(env, &ss, ntohs(IKED_NATT_PORT), PROC_IKEV2);
212 
213 	bzero(&ss, sizeof(ss));
214 	ss.ss_family = AF_INET6;
215 
216 	if ((env->sc_opts & IKED_OPT_NATT) == 0)
217 		config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2);
218 	if ((env->sc_opts & IKED_OPT_NONATT) == 0)
219 		config_setsocket(env, &ss, ntohs(IKED_NATT_PORT), PROC_IKEV2);
220 
221 	config_setcoupled(env, env->sc_decoupled ? 0 : 1);
222 	config_setmode(env, env->sc_passive ? 1 : 0);
223 	config_setocsp(env);
224 
225 	return (0);
226 }
227 
228 void
229 parent_reload(struct iked *env, int reset, const char *filename)
230 {
231 	/* Switch back to the default config file */
232 	if (filename == NULL || *filename == '\0')
233 		filename = env->sc_conffile;
234 
235 	log_debug("%s: level %d config file %s", __func__, reset, filename);
236 
237 	if (reset == RESET_RELOAD) {
238 		config_setreset(env, RESET_POLICY, PROC_IKEV1);
239 		config_setreset(env, RESET_POLICY, PROC_IKEV2);
240 		config_setreset(env, RESET_CA, PROC_CERT);
241 
242 		if (parse_config(filename, env) == -1) {
243 			log_debug("%s: failed to load config file %s",
244 			    __func__, filename);
245 		}
246 
247 		/* Re-compile policies and skip steps */
248 		config_setcompile(env, PROC_IKEV1);
249 		config_setcompile(env, PROC_IKEV2);
250 
251 		config_setcoupled(env, env->sc_decoupled ? 0 : 1);
252 		config_setmode(env, env->sc_passive ? 1 : 0);
253 		config_setocsp(env);
254 	} else {
255 		config_setreset(env, reset, PROC_IKEV1);
256 		config_setreset(env, reset, PROC_IKEV2);
257 		config_setreset(env, reset, PROC_CERT);
258 	}
259 }
260 
261 void
262 parent_sig_handler(int sig, short event, void *arg)
263 {
264 	struct privsep	*ps = arg;
265 	int		 die = 0, status, fail, id;
266 	pid_t		 pid;
267 	char		*cause;
268 
269 	switch (sig) {
270 	case SIGHUP:
271 		log_info("%s: reload requested with SIGHUP", __func__);
272 
273 		/*
274 		 * This is safe because libevent uses async signal handlers
275 		 * that run in the event loop and not in signal context.
276 		 */
277 		parent_reload(ps->ps_env, 0, NULL);
278 		break;
279 	case SIGPIPE:
280 		log_info("%s: ignoring SIGPIPE", __func__);
281 		break;
282 	case SIGTERM:
283 	case SIGINT:
284 		die = 1;
285 		/* FALLTHROUGH */
286 	case SIGCHLD:
287 		do {
288 			pid = waitpid(-1, &status, WNOHANG);
289 			if (pid <= 0)
290 				continue;
291 
292 			fail = 0;
293 			if (WIFSIGNALED(status)) {
294 				fail = 1;
295 				asprintf(&cause, "terminated; signal %d",
296 				    WTERMSIG(status));
297 			} else if (WIFEXITED(status)) {
298 				if (WEXITSTATUS(status) != 0) {
299 					fail = 1;
300 					asprintf(&cause, "exited abnormally");
301 				} else
302 					asprintf(&cause, "exited okay");
303 			} else
304 				fatalx("unexpected cause of SIGCHLD");
305 
306 			die = 1;
307 
308 			for (id = 0; id < PROC_MAX; id++)
309 				if (pid == ps->ps_pid[id]) {
310 					if (fail)
311 						log_warnx("lost child: %s %s",
312 						    ps->ps_title[id], cause);
313 					break;
314 				}
315 
316 			free(cause);
317 		} while (pid > 0 || (pid == -1 && errno == EINTR));
318 
319 		if (die)
320 			parent_shutdown(ps->ps_env);
321 		break;
322 	default:
323 		fatalx("unexpected signal");
324 	}
325 }
326 
327 int
328 parent_dispatch_ikev1(int fd, struct privsep_proc *p, struct imsg *imsg)
329 {
330 	switch (imsg->hdr.type) {
331 	default:
332 		break;
333 	}
334 
335 	return (-1);
336 }
337 
338 int
339 parent_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg)
340 {
341 	switch (imsg->hdr.type) {
342 	default:
343 		break;
344 	}
345 
346 	return (-1);
347 }
348 
349 int
350 parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg)
351 {
352 	struct iked	*env = p->p_ps->ps_env;
353 	int		 v;
354 	char		*str = NULL;
355 	u_int		 type = imsg->hdr.type;
356 
357 	switch (type) {
358 	case IMSG_CTL_RESET:
359 		IMSG_SIZE_CHECK(imsg, &v);
360 		memcpy(&v, imsg->data, sizeof(v));
361 		parent_reload(env, v, NULL);
362 		break;
363 	case IMSG_CTL_COUPLE:
364 	case IMSG_CTL_DECOUPLE:
365 	case IMSG_CTL_ACTIVE:
366 	case IMSG_CTL_PASSIVE:
367 		proc_compose_imsg(&env->sc_ps, PROC_IKEV1, -1,
368 		    type, -1, NULL, 0);
369 		proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1,
370 		    type, -1, NULL, 0);
371 		break;
372 	case IMSG_CTL_RELOAD:
373 		if (IMSG_DATA_SIZE(imsg) > 0)
374 			str = get_string(imsg->data, IMSG_DATA_SIZE(imsg));
375 		parent_reload(env, 0, str);
376 		if (str != NULL)
377 			free(str);
378 		break;
379 	case IMSG_OCSP_FD:
380 		ocsp_connect(env);
381 		break;
382 	default:
383 		return (-1);
384 	}
385 
386 	return (0);
387 }
388 
389 void
390 parent_shutdown(struct iked *env)
391 {
392 	proc_kill(&env->sc_ps);
393 
394 	free(env);
395 
396 	log_warnx("parent terminating");
397 	exit(0);
398 }
399