GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/iked/iked.c Lines: 0 191 0.0 %
Date: 2017-11-13 Branches: 0 107 0.0 %

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