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