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