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