xref: /openbsd/sbin/iked/iked.c (revision cca36db2)
1 /*	$OpenBSD: iked.c,v 1.11 2011/05/09 11:15:18 reyk Exp $	*/
2 /*	$vantronix: iked.c,v 1.22 2010/06/02 14:43:30 reyk Exp $	*/
3 
4 /*
5  * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net>
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/param.h>
21 #include <sys/types.h>
22 #include <sys/queue.h>
23 #include <sys/socket.h>
24 #include <sys/wait.h>
25 #include <sys/uio.h>
26 
27 #include <net/if.h>
28 #include <netinet/in_systm.h>
29 #include <netinet/in.h>
30 #include <netinet/ip.h>
31 #include <netinet/tcp.h>
32 #include <arpa/inet.h>
33 
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <getopt.h>
39 #include <signal.h>
40 #include <errno.h>
41 #include <err.h>
42 #include <pwd.h>
43 #include <event.h>
44 
45 #include "iked.h"
46 #include "ikev2.h"
47 
48 __dead void usage(void);
49 
50 void	 parent_shutdown(struct iked *);
51 void	 parent_sig_handler(int, short, void *);
52 int	 parent_dispatch_ikev1(int, struct privsep_proc *, struct imsg *);
53 int	 parent_dispatch_ikev2(int, struct privsep_proc *, struct imsg *);
54 int	 parent_dispatch_ca(int, struct privsep_proc *, struct imsg *);
55 int	 parent_configure(struct iked *);
56 
57 static struct privsep_proc procs[] = {
58 	{ "ikev1",	PROC_IKEV1, parent_dispatch_ikev1, ikev1 },
59 	{ "ikev2",	PROC_IKEV2, parent_dispatch_ikev2, ikev2 },
60 	{ "ca",		PROC_CERT, parent_dispatch_ca, caproc, IKED_CA }
61 };
62 
63 __dead void
64 usage(void)
65 {
66 	extern char	*__progname;
67 
68 	fprintf(stderr, "usage: %s [-dnSTv] [-D macro=value] "
69 	    "[-f file]\n", __progname);
70 	exit(1);
71 }
72 
73 int
74 main(int argc, char *argv[])
75 {
76 	int		 c;
77 	int		 debug = 0, verbose = 0;
78 	int		 opts = 0;
79 	const char	*conffile = IKED_CONFIG;
80 	struct iked	*env = NULL;
81 	struct privsep	*ps;
82 
83 	log_init(1);
84 
85 	while ((c = getopt(argc, argv, "dD:nf:vST")) != -1) {
86 		switch (c) {
87 		case 'd':
88 			debug++;
89 			break;
90 		case 'D':
91 			if (cmdline_symset(optarg) < 0)
92 				log_warnx("could not parse macro definition %s",
93 				    optarg);
94 			break;
95 		case 'n':
96 			debug = 1;
97 			opts |= IKED_OPT_NOACTION;
98 			break;
99 		case 'f':
100 			conffile = optarg;
101 			break;
102 		case 'v':
103 			verbose++;
104 			opts |= IKED_OPT_VERBOSE;
105 			break;
106 		case 'S':
107 			opts |= IKED_OPT_PASSIVE;
108 			break;
109 		case 'T':
110 			opts |= IKED_OPT_NONATT;
111 			break;
112 		default:
113 			usage();
114 		}
115 	}
116 
117 	argv += optind;
118 	argc -= optind;
119 
120 	if ((env = calloc(1, sizeof(*env))) == NULL)
121 		fatal("calloc: env");
122 
123 	env->sc_opts = opts;
124 
125 	ps = &env->sc_ps;
126 	ps->ps_env = env;
127 
128 	if (strlcpy(env->sc_conffile, conffile, MAXPATHLEN) >= MAXPATHLEN)
129 		errx(1, "config file exceeds MAXPATHLEN");
130 
131 	ca_sslinit();
132 	policy_init(env);
133 
134 	/* check for root privileges */
135 	if (geteuid())
136 		errx(1, "need root privileges");
137 
138 	if ((ps->ps_pw =  getpwnam(IKED_USER)) == NULL)
139 		errx(1, "unknown user %s", IKED_USER);
140 
141 	/* Configure the control socket */
142 	ps->ps_csock.cs_name = IKED_SOCKET;
143 
144 	log_init(debug);
145 	log_verbose(verbose);
146 
147 	if (!debug && daemon(0, 0) == -1)
148 		err(1, "failed to daemonize");
149 
150 	group_init();
151 	proc_init(ps, procs, nitems(procs));
152 
153 	setproctitle("parent");
154 
155 	event_init();
156 
157 	signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps);
158 	signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps);
159 	signal_set(&ps->ps_evsigchld, SIGCHLD, parent_sig_handler, ps);
160 	signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps);
161 	signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps);
162 
163 	signal_add(&ps->ps_evsigint, NULL);
164 	signal_add(&ps->ps_evsigterm, NULL);
165 	signal_add(&ps->ps_evsigchld, NULL);
166 	signal_add(&ps->ps_evsighup, NULL);
167 	signal_add(&ps->ps_evsigpipe, NULL);
168 
169 	proc_config(ps, procs, nitems(procs));
170 
171 	if (parent_configure(env) == -1)
172 		fatalx("configuration failed");
173 
174 	event_dispatch();
175 
176 	log_debug("%d parent exiting", getpid());
177 
178 	return (0);
179 }
180 
181 int
182 parent_configure(struct iked *env)
183 {
184 	struct sockaddr_storage	 ss;
185 
186 	if (parse_config(env->sc_conffile, env) == -1) {
187 		proc_kill(&env->sc_ps);
188 		exit(1);
189 	}
190 
191 	if (env->sc_opts & IKED_OPT_NOACTION) {
192 		fprintf(stderr, "configuration OK\n");
193 		proc_kill(&env->sc_ps);
194 		exit(0);
195 	}
196 
197 	env->sc_pfkey = -1;
198 	config_setpfkey(env, PROC_IKEV2);
199 
200 	/* Now compile the policies and calculate skip steps */
201 	config_setcompile(env, PROC_IKEV1);
202 	config_setcompile(env, PROC_IKEV2);
203 
204 	bzero(&ss, sizeof(ss));
205 	ss.ss_family = AF_INET;
206 
207 	config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2);
208 	config_setsocket(env, &ss, ntohs(IKED_NATT_PORT), PROC_IKEV2);
209 
210 	bzero(&ss, sizeof(ss));
211 	ss.ss_family = AF_INET6;
212 
213 	config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2);
214 	config_setsocket(env, &ss, ntohs(IKED_NATT_PORT), PROC_IKEV2);
215 
216 	config_setcoupled(env, env->sc_decoupled ? 0 : 1);
217 	config_setmode(env, env->sc_passive ? 1 : 0);
218 
219 	return (0);
220 }
221 
222 void
223 parent_reload(struct iked *env, int reset, const char *filename)
224 {
225 	/* Switch back to the default config file */
226 	if (filename == NULL || *filename == '\0')
227 		filename = env->sc_conffile;
228 
229 	log_debug("%s: level %d config file %s", __func__, reset, filename);
230 
231 	if (reset == RESET_RELOAD) {
232 		config_setreset(env, RESET_POLICY, PROC_IKEV1);
233 		config_setreset(env, RESET_POLICY, PROC_IKEV2);
234 		config_setreset(env, RESET_CA, PROC_CERT);
235 
236 		if (parse_config(filename, env) == -1) {
237 			log_debug("%s: failed to load config file %s",
238 			    __func__, filename);
239 		}
240 
241 		/* Re-compile policies and skip steps */
242 		config_setcompile(env, PROC_IKEV1);
243 		config_setcompile(env, PROC_IKEV2);
244 
245 		config_setcoupled(env, env->sc_decoupled ? 0 : 1);
246 		config_setmode(env, env->sc_passive ? 1 : 0);
247 	} else {
248 		config_setreset(env, reset, PROC_IKEV1);
249 		config_setreset(env, reset, PROC_IKEV2);
250 		config_setreset(env, reset, PROC_CERT);
251 	}
252 }
253 
254 void
255 parent_sig_handler(int sig, short event, void *arg)
256 {
257 	struct privsep	*ps = arg;
258 	int		 die = 0, status, fail, id;
259 	pid_t		 pid;
260 	char		*cause;
261 
262 	switch (sig) {
263 	case SIGHUP:
264 		log_info("%s: reload requested with SIGHUP", __func__);
265 
266 		/*
267 		 * This is safe because libevent uses async signal handlers
268 		 * that run in the event loop and not in signal context.
269 		 */
270 		parent_reload(ps->ps_env, 0, NULL);
271 		break;
272 	case SIGPIPE:
273 		log_info("%s: ignoring SIGPIPE", __func__);
274 		break;
275 	case SIGTERM:
276 	case SIGINT:
277 		die = 1;
278 		/* FALLTHROUGH */
279 	case SIGCHLD:
280 		do {
281 			pid = waitpid(-1, &status, WNOHANG);
282 			if (pid <= 0)
283 				continue;
284 
285 			fail = 0;
286 			if (WIFSIGNALED(status)) {
287 				fail = 1;
288 				asprintf(&cause, "terminated; signal %d",
289 				    WTERMSIG(status));
290 			} else if (WIFEXITED(status)) {
291 				if (WEXITSTATUS(status) != 0) {
292 					fail = 1;
293 					asprintf(&cause, "exited abnormally");
294 				} else
295 					asprintf(&cause, "exited okay");
296 			} else
297 				fatalx("unexpected cause of SIGCHLD");
298 
299 			die = 1;
300 
301 			for (id = 0; id < PROC_MAX; id++)
302 				if (pid == ps->ps_pid[id]) {
303 					log_warnx("lost child: %s %s",
304 					    ps->ps_title[id], cause);
305 					break;
306 				}
307 
308 			free(cause);
309 		} while (pid > 0 || (pid == -1 && errno == EINTR));
310 
311 		if (die)
312 			parent_shutdown(ps->ps_env);
313 		break;
314 	default:
315 		fatalx("unexpected signal");
316 	}
317 }
318 
319 int
320 parent_dispatch_ikev1(int fd, struct privsep_proc *p, struct imsg *imsg)
321 {
322 	switch (imsg->hdr.type) {
323 	default:
324 		break;
325 	}
326 
327 	return (-1);
328 }
329 
330 int
331 parent_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg)
332 {
333 	switch (imsg->hdr.type) {
334 	default:
335 		break;
336 	}
337 
338 	return (-1);
339 }
340 
341 int
342 parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg)
343 {
344 	struct iked	*env = p->p_ps->ps_env;
345 	int		 v;
346 	char		*str = NULL;
347 	u_int		 type = imsg->hdr.type;
348 
349 	switch (type) {
350 	case IMSG_CTL_RESET:
351 		IMSG_SIZE_CHECK(imsg, &v);
352 		memcpy(&v, imsg->data, sizeof(v));
353 		parent_reload(env, v, NULL);
354 		break;
355 	case IMSG_CTL_COUPLE:
356 	case IMSG_CTL_DECOUPLE:
357 	case IMSG_CTL_ACTIVE:
358 	case IMSG_CTL_PASSIVE:
359 		proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0);
360 		proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0);
361 		break;
362 	case IMSG_CTL_RELOAD:
363 		if (IMSG_DATA_SIZE(imsg) > 0)
364 			str = get_string(imsg->data, IMSG_DATA_SIZE(imsg));
365 		parent_reload(env, 0, str);
366 		if (str != NULL)
367 			free(str);
368 		break;
369 	default:
370 		return (-1);
371 	}
372 
373 	return (0);
374 }
375 
376 void
377 parent_shutdown(struct iked *env)
378 {
379 	proc_kill(&env->sc_ps);
380 
381 	free(env);
382 
383 	log_warnx("parent terminating");
384 	exit(0);
385 }
386