Bug Summary

File:src/sbin/iked/iked.c
Warning:line 140, column 2
Value stored to 'argv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name iked.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/iked/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sbin/iked -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/iked/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/sbin/iked/iked.c
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
43void parent_shutdown(struct iked *);
44void parent_sig_handler(int, short, void *);
45int parent_dispatch_ca(int, struct privsep_proc *, struct imsg *);
46int parent_dispatch_control(int, struct privsep_proc *, struct imsg *);
47int parent_dispatch_ikev2(int, struct privsep_proc *, struct imsg *);
48int parent_configure(struct iked *);
49
50static 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
57usage(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
66int
67main(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
219int
220parent_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
292void
293parent_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
327void
328parent_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
402int
403parent_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
418int
419parent_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
457int
458parent_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
481void
482parent_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}