File: | src/sbin/iked/iked.c |
Warning: | line 140, column 2 Value stored to 'argv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: iked.c,v 1.62 2021/12/01 16:42:12 deraadt 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(*__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__attribute__((__noreturn__)) void usage(void); |
42 | |
43 | void parent_shutdown(struct iked *); |
44 | void parent_sig_handler(int, short, void *); |
45 | int parent_dispatch_ca(int, struct privsep_proc *, struct imsg *); |
46 | int parent_dispatch_control(int, struct privsep_proc *, struct imsg *); |
47 | int parent_dispatch_ikev2(int, struct privsep_proc *, struct imsg *); |
48 | int parent_configure(struct iked *); |
49 | |
50 | static struct privsep_proc procs[] = { |
51 | { "ca", PROC_CERT, parent_dispatch_ca, caproc, IKED_CA"/etc/iked/" }, |
52 | { "control", PROC_CONTROL, parent_dispatch_control, control }, |
53 | { "ikev2", PROC_IKEV2, parent_dispatch_ikev2, ikev2 } |
54 | }; |
55 | |
56 | __dead__attribute__((__noreturn__)) void |
57 | usage(void) |
58 | { |
59 | extern char *__progname; |
60 | |
61 | fprintf(stderr(&__sF[2]), "usage: %s [-dnSTtVv] [-D macro=value] " |
62 | "[-f file] [-p udpencap_port] [-s socket]\n", __progname); |
63 | exit(1); |
64 | } |
65 | |
66 | int |
67 | main(int argc, char *argv[]) |
68 | { |
69 | int c; |
70 | int debug = 0, verbose = 0; |
71 | int opts = 0; |
72 | enum natt_mode natt_mode = NATT_DEFAULT; |
73 | in_port_t port = IKED_NATT_PORT4500; |
74 | const char *conffile = IKED_CONFIG"/etc/iked.conf"; |
75 | const char *sock = IKED_SOCKET"/var/run/iked.sock"; |
76 | const char *errstr; |
77 | struct iked *env = NULL((void *)0); |
78 | struct privsep *ps; |
79 | |
80 | log_init(1, LOG_DAEMON(3<<3)); |
81 | |
82 | while ((c = getopt(argc, argv, "6D:df:np:Ss:TtvV")) != -1) { |
83 | switch (c) { |
84 | case '6': |
85 | log_warnx("the -6 option is ignored and will be " |
86 | "removed in the future."); |
87 | break; |
88 | case 'D': |
89 | if (cmdline_symset(optarg) < 0) |
90 | log_warnx("could not parse macro definition %s", |
91 | optarg); |
92 | break; |
93 | case 'd': |
94 | debug++; |
95 | break; |
96 | case 'f': |
97 | conffile = optarg; |
98 | break; |
99 | case 'n': |
100 | debug = 1; |
101 | opts |= IKED_OPT_NOACTION0x00000002; |
102 | break; |
103 | case 'p': |
104 | if (natt_mode == NATT_DISABLE) |
105 | errx(1, "-T and -p are mutually exclusive"); |
106 | port = strtonum(optarg, 1, UINT16_MAX0xffff, &errstr); |
107 | if (errstr != NULL((void *)0)) |
108 | errx(1, "port is %s: %s", errstr, optarg); |
109 | natt_mode = NATT_FORCE; |
110 | break; |
111 | case 'S': |
112 | opts |= IKED_OPT_PASSIVE0x00000004; |
113 | break; |
114 | case 's': |
115 | sock = optarg; |
116 | break; |
117 | case 'T': |
118 | if (natt_mode == NATT_FORCE) |
119 | errx(1, "-T and -t/-p are mutually exclusive"); |
120 | natt_mode = NATT_DISABLE; |
121 | break; |
122 | case 't': |
123 | if (natt_mode == NATT_DISABLE) |
124 | errx(1, "-T and -t are mutually exclusive"); |
125 | natt_mode = NATT_FORCE; |
126 | break; |
127 | case 'v': |
128 | verbose++; |
129 | opts |= IKED_OPT_VERBOSE0x00000001; |
130 | break; |
131 | case 'V': |
132 | fprintf(stderr(&__sF[2]), "OpenIKED %s\n", IKED_VERSION"7.0"); |
133 | return 0; |
134 | default: |
135 | usage(); |
136 | } |
137 | } |
138 | |
139 | argc -= optind; |
140 | argv += optind; |
Value stored to 'argv' is never read | |
141 | if (argc > 0) |
142 | usage(); |
143 | |
144 | if ((env = calloc(1, sizeof(*env))) == NULL((void *)0)) |
145 | fatal("calloc: env"); |
146 | |
147 | env->sc_opts = opts; |
148 | env->sc_nattmode = natt_mode; |
149 | env->sc_nattportsc_static.st_nattport = port; |
150 | |
151 | ps = &env->sc_ps; |
152 | ps->ps_env = env; |
153 | TAILQ_INIT(&ps->ps_rcsocks)do { (&ps->ps_rcsocks)->tqh_first = ((void *)0); (& ps->ps_rcsocks)->tqh_last = &(&ps->ps_rcsocks )->tqh_first; } while (0); |
154 | |
155 | if (strlcpy(env->sc_conffile, conffile, PATH_MAX1024) >= PATH_MAX1024) |
156 | errx(1, "config file exceeds PATH_MAX"); |
157 | |
158 | ca_sslinit(); |
159 | policy_init(env); |
160 | |
161 | /* check for root privileges */ |
162 | if (geteuid()) |
163 | errx(1, "need root privileges"); |
164 | |
165 | if ((ps->ps_pw = getpwnam(IKED_USER"_iked")) == NULL((void *)0)) |
166 | errx(1, "unknown user %s", IKED_USER"_iked"); |
167 | |
168 | /* Configure the control socket */ |
169 | ps->ps_csock.cs_name = sock; |
170 | |
171 | log_init(debug, LOG_DAEMON(3<<3)); |
172 | log_setverbose(verbose); |
173 | |
174 | if (opts & IKED_OPT_NOACTION0x00000002) |
175 | ps->ps_noaction = 1; |
176 | |
177 | if (!debug && daemon(0, 0) == -1) |
178 | err(1, "failed to daemonize"); |
179 | |
180 | group_init(); |
181 | |
182 | ps->ps_ninstances = 1; |
183 | proc_init(ps, procs, nitems(procs)(sizeof((procs)) / sizeof((procs)[0]))); |
184 | |
185 | setproctitle("parent"); |
186 | log_procinit("parent"); |
187 | |
188 | event_init(); |
189 | |
190 | signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps)event_set(&ps->ps_evsigint, 2, 0x08|0x10, parent_sig_handler , ps); |
191 | signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps)event_set(&ps->ps_evsigterm, 15, 0x08|0x10, parent_sig_handler , ps); |
192 | signal_set(&ps->ps_evsigchld, SIGCHLD, parent_sig_handler, ps)event_set(&ps->ps_evsigchld, 20, 0x08|0x10, parent_sig_handler , ps); |
193 | signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps)event_set(&ps->ps_evsighup, 1, 0x08|0x10, parent_sig_handler , ps); |
194 | signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps)event_set(&ps->ps_evsigpipe, 13, 0x08|0x10, parent_sig_handler , ps); |
195 | signal_set(&ps->ps_evsigusr1, SIGUSR1, parent_sig_handler, ps)event_set(&ps->ps_evsigusr1, 30, 0x08|0x10, parent_sig_handler , ps); |
196 | |
197 | signal_add(&ps->ps_evsigint, NULL)event_add(&ps->ps_evsigint, ((void *)0)); |
198 | signal_add(&ps->ps_evsigterm, NULL)event_add(&ps->ps_evsigterm, ((void *)0)); |
199 | signal_add(&ps->ps_evsigchld, NULL)event_add(&ps->ps_evsigchld, ((void *)0)); |
200 | signal_add(&ps->ps_evsighup, NULL)event_add(&ps->ps_evsighup, ((void *)0)); |
201 | signal_add(&ps->ps_evsigpipe, NULL)event_add(&ps->ps_evsigpipe, ((void *)0)); |
202 | signal_add(&ps->ps_evsigusr1, NULL)event_add(&ps->ps_evsigusr1, ((void *)0)); |
203 | |
204 | proc_listen(ps, procs, nitems(procs)(sizeof((procs)) / sizeof((procs)[0]))); |
205 | |
206 | vroute_init(env); |
207 | |
208 | if (parent_configure(env) == -1) |
209 | fatalx("configuration failed"); |
210 | |
211 | event_dispatch(); |
212 | |
213 | log_debug("%d parent exiting", getpid()); |
214 | parent_shutdown(env); |
215 | |
216 | return (0); |
217 | } |
218 | |
219 | int |
220 | parent_configure(struct iked *env) |
221 | { |
222 | struct sockaddr_storage ss; |
223 | |
224 | if (parse_config(env->sc_conffile, env) == -1) { |
225 | proc_kill(&env->sc_ps); |
226 | exit(1); |
227 | } |
228 | |
229 | if (env->sc_opts & IKED_OPT_NOACTION0x00000002) { |
230 | fprintf(stderr(&__sF[2]), "configuration OK\n"); |
231 | proc_kill(&env->sc_ps); |
232 | exit(0); |
233 | } |
234 | |
235 | env->sc_pfkey = -1; |
236 | config_setpfkey(env); |
237 | |
238 | /* Send private and public keys to cert after forking the children */ |
239 | if (config_setkeys(env) == -1) |
240 | fatalx("%s: failed to send keys", __func__); |
241 | config_setreset(env, RESET_CA, PROC_CERT); |
242 | |
243 | /* Now compile the policies and calculate skip steps */ |
244 | config_setcompile(env, PROC_IKEV2); |
245 | |
246 | bzero(&ss, sizeof(ss)); |
247 | ss.ss_family = AF_INET2; |
248 | |
249 | /* see comment on config_setsocket() */ |
250 | if (env->sc_nattmode != NATT_FORCE) |
251 | config_setsocket(env, &ss, htons(IKED_IKE_PORT)(__uint16_t)(__builtin_constant_p(500) ? (__uint16_t)(((__uint16_t )(500) & 0xffU) << 8 | ((__uint16_t)(500) & 0xff00U ) >> 8) : __swap16md(500)), PROC_IKEV2); |
252 | if (env->sc_nattmode != NATT_DISABLE) |
253 | config_setsocket(env, &ss, htons(env->sc_nattport)(__uint16_t)(__builtin_constant_p(env->sc_static.st_nattport ) ? (__uint16_t)(((__uint16_t)(env->sc_static.st_nattport) & 0xffU) << 8 | ((__uint16_t)(env->sc_static.st_nattport ) & 0xff00U) >> 8) : __swap16md(env->sc_static.st_nattport )), PROC_IKEV2); |
254 | |
255 | bzero(&ss, sizeof(ss)); |
256 | ss.ss_family = AF_INET624; |
257 | |
258 | if (env->sc_nattmode != NATT_FORCE) |
259 | config_setsocket(env, &ss, htons(IKED_IKE_PORT)(__uint16_t)(__builtin_constant_p(500) ? (__uint16_t)(((__uint16_t )(500) & 0xffU) << 8 | ((__uint16_t)(500) & 0xff00U ) >> 8) : __swap16md(500)), PROC_IKEV2); |
260 | if (env->sc_nattmode != NATT_DISABLE) |
261 | config_setsocket(env, &ss, htons(env->sc_nattport)(__uint16_t)(__builtin_constant_p(env->sc_static.st_nattport ) ? (__uint16_t)(((__uint16_t)(env->sc_static.st_nattport) & 0xffU) << 8 | ((__uint16_t)(env->sc_static.st_nattport ) & 0xff00U) >> 8) : __swap16md(env->sc_static.st_nattport )), PROC_IKEV2); |
262 | |
263 | /* |
264 | * pledge in the parent process: |
265 | * It has to run fairly late to allow forking the processes and |
266 | * opening the PFKEY socket and the listening UDP sockets (once) |
267 | * that need the bypass ioctls that are never allowed by pledge. |
268 | * |
269 | * Other flags: |
270 | * stdio - for malloc and basic I/O including events. |
271 | * rpath - for reload to open and read the configuration files. |
272 | * proc - run kill to terminate its children safely. |
273 | * dns - for reload and ocsp connect. |
274 | * inet - for ocsp connect. |
275 | * route - for using interfaces in iked.conf (SIOCGIFGMEMB) |
276 | * wroute - for adding and removing addresses (SIOCAIFGMEMB) |
277 | * sendfd - for ocsp sockets. |
278 | */ |
279 | if (pledge("stdio rpath proc dns inet route wroute sendfd", NULL((void *)0)) == -1) |
280 | fatal("pledge"); |
281 | |
282 | config_setstatic(env); |
283 | config_setcoupled(env, env->sc_decoupled ? 0 : 1); |
284 | config_setocsp(env); |
285 | config_setcertpartialchain(env); |
286 | /* Must be last */ |
287 | config_setmode(env, env->sc_passive ? 1 : 0); |
288 | |
289 | return (0); |
290 | } |
291 | |
292 | void |
293 | parent_reload(struct iked *env, int reset, const char *filename) |
294 | { |
295 | /* Switch back to the default config file */ |
296 | if (filename == NULL((void *)0) || *filename == '\0') |
297 | filename = env->sc_conffile; |
298 | |
299 | log_debug("%s: level %d config file %s", __func__, reset, filename); |
300 | |
301 | if (reset == RESET_RELOAD) { |
302 | config_setreset(env, RESET_POLICY, PROC_IKEV2); |
303 | if (config_setkeys(env) == -1) |
304 | fatalx("%s: failed to send keys", __func__); |
305 | config_setreset(env, RESET_CA, PROC_CERT); |
306 | |
307 | if (parse_config(filename, env) == -1) { |
308 | log_debug("%s: failed to load config file %s", |
309 | __func__, filename); |
310 | } |
311 | |
312 | /* Re-compile policies and skip steps */ |
313 | config_setcompile(env, PROC_IKEV2); |
314 | |
315 | config_setstatic(env); |
316 | config_setcoupled(env, env->sc_decoupled ? 0 : 1); |
317 | config_setocsp(env); |
318 | config_setcertpartialchain(env); |
319 | /* Must be last */ |
320 | config_setmode(env, env->sc_passive ? 1 : 0); |
321 | } else { |
322 | config_setreset(env, reset, PROC_IKEV2); |
323 | config_setreset(env, reset, PROC_CERT); |
324 | } |
325 | } |
326 | |
327 | void |
328 | parent_sig_handler(int sig, short event, void *arg) |
329 | { |
330 | struct privsep *ps = arg; |
331 | int die = 0, status, fail, id; |
332 | pid_t pid; |
333 | char *cause; |
334 | |
335 | switch (sig) { |
336 | case SIGHUP1: |
337 | log_info("%s: reload requested with SIGHUP", __func__); |
338 | |
339 | /* |
340 | * This is safe because libevent uses async signal handlers |
341 | * that run in the event loop and not in signal context. |
342 | */ |
343 | parent_reload(ps->ps_env, 0, NULL((void *)0)); |
344 | break; |
345 | case SIGPIPE13: |
346 | log_info("%s: ignoring SIGPIPE", __func__); |
347 | break; |
348 | case SIGUSR130: |
349 | log_info("%s: ignoring SIGUSR1", __func__); |
350 | break; |
351 | case SIGTERM15: |
352 | case SIGINT2: |
353 | die = 1; |
354 | /* FALLTHROUGH */ |
355 | case SIGCHLD20: |
356 | do { |
357 | int len = 0; |
358 | |
359 | pid = waitpid(-1, &status, WNOHANG1); |
360 | if (pid <= 0) |
361 | continue; |
362 | |
363 | fail = 0; |
364 | if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177 ) != 0)) { |
365 | fail = 1; |
366 | len = asprintf(&cause, "terminated; signal %d", |
367 | WTERMSIG(status)(((status) & 0177))); |
368 | } else if (WIFEXITED(status)(((status) & 0177) == 0)) { |
369 | if (WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff) != 0) { |
370 | fail = 1; |
371 | len = asprintf(&cause, |
372 | "exited abnormally"); |
373 | } else |
374 | len = asprintf(&cause, "exited okay"); |
375 | } else |
376 | fatalx("unexpected cause of SIGCHLD"); |
377 | |
378 | if (len == -1) |
379 | fatal("asprintf"); |
380 | |
381 | die = 1; |
382 | |
383 | for (id = 0; id < PROC_MAX; id++) |
384 | if (pid == ps->ps_pid[id]) { |
385 | if (fail) |
386 | log_warnx("lost child: %s %s", |
387 | ps->ps_title[id], cause); |
388 | break; |
389 | } |
390 | |
391 | free(cause); |
392 | } while (pid > 0 || (pid == -1 && errno(*__errno()) == EINTR4)); |
393 | |
394 | if (die) |
395 | parent_shutdown(ps->ps_env); |
396 | break; |
397 | default: |
398 | fatalx("unexpected signal"); |
399 | } |
400 | } |
401 | |
402 | int |
403 | parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg) |
404 | { |
405 | struct iked *env = p->p_ps->ps_env; |
406 | |
407 | switch (imsg->hdr.type) { |
408 | case IMSG_OCSP_FD: |
409 | ocsp_connect(env, imsg); |
410 | break; |
411 | default: |
412 | return (-1); |
413 | } |
414 | |
415 | return (0); |
416 | } |
417 | |
418 | int |
419 | parent_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg) |
420 | { |
421 | struct iked *env = p->p_ps->ps_env; |
422 | int v; |
423 | char *str = NULL((void *)0); |
424 | unsigned int type = imsg->hdr.type; |
425 | |
426 | switch (type) { |
427 | case IMSG_CTL_RESET: |
428 | IMSG_SIZE_CHECK(imsg, &v)do { if (((imsg)->hdr.len - sizeof(struct imsg_hdr)) < sizeof (*&v)) fatalx("bad length imsg received"); } while (0); |
429 | memcpy(&v, imsg->data, sizeof(v)); |
430 | parent_reload(env, v, NULL((void *)0)); |
431 | break; |
432 | case IMSG_CTL_COUPLE: |
433 | case IMSG_CTL_DECOUPLE: |
434 | case IMSG_CTL_ACTIVE: |
435 | case IMSG_CTL_PASSIVE: |
436 | proc_compose(&env->sc_ps, PROC_IKEV2, type, NULL((void *)0), 0); |
437 | break; |
438 | case IMSG_CTL_RELOAD: |
439 | if (IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr)) > 0) |
440 | str = get_string(imsg->data, IMSG_DATA_SIZE(imsg)((imsg)->hdr.len - sizeof(struct imsg_hdr))); |
441 | parent_reload(env, 0, str); |
442 | free(str); |
443 | break; |
444 | case IMSG_CTL_VERBOSE: |
445 | proc_forward_imsg(&env->sc_ps, imsg, PROC_IKEV2, -1); |
446 | proc_forward_imsg(&env->sc_ps, imsg, PROC_CERT, -1); |
447 | |
448 | /* return 1 to let proc.c handle it locally */ |
449 | return (1); |
450 | default: |
451 | return (-1); |
452 | } |
453 | |
454 | return (0); |
455 | } |
456 | |
457 | int |
458 | parent_dispatch_ikev2(int fd, struct privsep_proc *p, struct imsg *imsg) |
459 | { |
460 | struct iked *env = p->p_ps->ps_env; |
461 | |
462 | switch (imsg->hdr.type) { |
463 | case IMSG_IF_ADDADDR: |
464 | case IMSG_IF_DELADDR: |
465 | return (vroute_getaddr(env, imsg)); |
466 | case IMSG_VDNS_ADD: |
467 | case IMSG_VDNS_DEL: |
468 | return (vroute_getdns(env, imsg)); |
469 | case IMSG_VROUTE_ADD: |
470 | case IMSG_VROUTE_DEL: |
471 | return (vroute_getroute(env, imsg)); |
472 | case IMSG_VROUTE_CLONE: |
473 | return (vroute_getcloneroute(env, imsg)); |
474 | default: |
475 | return (-1); |
476 | } |
477 | |
478 | return (0); |
479 | } |
480 | |
481 | void |
482 | parent_shutdown(struct iked *env) |
483 | { |
484 | proc_kill(&env->sc_ps); |
485 | |
486 | vroute_cleanup(env); |
487 | free(env->sc_vroute); |
488 | free(env); |
489 | |
490 | log_warnx("parent terminating"); |
491 | exit(0); |
492 | } |