1/* $NetBSD: session.c,v 1.7.6.2 2007/08/01 11:52:22 vanhu Exp $ */ 2 3/* $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $ */ 4 5/* 6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "config.h" 35 36#include <sys/types.h> 37#include <sys/param.h> 38#include <sys/time.h> 39#include <sys/socket.h> 40#if HAVE_SYS_WAIT_H 41# include <sys/wait.h> 42#endif 43#ifndef WEXITSTATUS 44# define WEXITSTATUS(s) ((unsigned)(s) >> 8) 45#endif 46#ifndef WIFEXITED 47# define WIFEXITED(s) (((s) & 255) == 0) 48#endif 49 50#ifndef HAVE_NETINET6_IPSEC 51#include <netinet/ipsec.h> 52#else 53#include <netinet6/ipsec.h> 54#endif 55 56#include <stdlib.h> 57#include <stdio.h> 58#include <string.h> 59#include <errno.h> 60#ifdef HAVE_UNISTD_H 61#include <unistd.h> 62#endif 63#include <signal.h> 64#include <sys/stat.h> 65#include <paths.h> 66 67#include <netinet/in.h> 68#include <netinet/ip.h> 69#include <netinet/ip_icmp.h> 70 71#include <resolv.h> 72#include <TargetConditionals.h> 73#include <vproc_priv.h> 74#include <dispatch/dispatch.h> 75 76#include "libpfkey.h" 77 78#include "var.h" 79#include "misc.h" 80#include "vmbuf.h" 81#include "plog.h" 82#include "debug.h" 83#include "plog.h" 84 85#include "schedule.h" 86#include "session.h" 87#include "grabmyaddr.h" 88#include "cfparse_proto.h" 89#include "isakmp_var.h" 90#include "isakmp_xauth.h" 91#include "isakmp_cfg.h" 92#include "oakley.h" 93#include "pfkey.h" 94#include "handler.h" 95#include "localconf.h" 96#include "remoteconf.h" 97#ifdef ENABLE_NATT 98#include "nattraversal.h" 99#endif 100#include "vpn_control_var.h" 101#include "policy.h" 102#include "algorithm.h" /* XXX ??? */ 103 104#include "sainfo.h" 105#include "power_mgmt.h" 106 107 108 109extern pid_t racoon_pid; 110extern int launchdlaunched; 111static void close_session (int); 112static int init_signal (void); 113static int set_signal (int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *)); 114static void check_sigreq (void); 115static void check_flushsa_stub (void *); 116static void check_flushsa (void); 117static void auto_exit_do (void *); 118static int close_sockets (void); 119 120static volatile sig_atomic_t sigreq[NSIG + 1]; 121int terminated = 0; 122 123static int64_t racoon_keepalive = -1; 124 125dispatch_queue_t main_queue; 126 127/* 128 * This is used to (manually) update racoon's launchd keepalive, which is needed because racoon is (mostly) 129 * launched on demand and for <rdar://problem/8768510> requires a keepalive on dirty/failure exits. 130 * The launchd plist can't be used for this because RunOnLoad is required to have keepalive on a failure exit. 131 */ 132int64_t 133launchd_update_racoon_keepalive (Boolean enabled) 134{ 135 if (launchdlaunched) { 136 int64_t val = (__typeof__(val))enabled; 137 /* Set our own KEEPALIVE value */ 138 if (vproc_swap_integer(NULL, 139 VPROC_GSK_BASIC_KEEPALIVE, 140 &val, 141 &racoon_keepalive)) { 142 plog(ASL_LEVEL_ERR, 143 "failed to swap launchd keepalive integer %d\n", enabled); 144 } 145 } 146 return racoon_keepalive; 147} 148 149// 150// Session 151// 152// Initialize listening sockets, timers, vpn control etc., 153// write the PID file and call dispatch_main. 154// 155void 156session(void) 157{ 158 char pid_file[MAXPATHLEN]; 159 FILE *fp; 160 int i; 161 162 main_queue = dispatch_get_main_queue(); 163 164 /* initialize schedular */ 165 sched_init(); 166 167 /* needs to be called after schedular */ 168 if (init_power_mgmt() < 0) { 169 plog(ASL_LEVEL_ERR, 170 "failed to initialize power-mgmt."); 171 exit(1); 172 } 173 174 if (lcconf->autograbaddr == 1) 175 if (pfroute_init()) { 176 plog(ASL_LEVEL_ERR, "failed to initialize route socket.\n"); 177 exit(1); 178 } 179 if (initmyaddr()) { 180 plog(ASL_LEVEL_ERR, "failed to initialize listening addresses.\n"); 181 exit(1); 182 } 183 if (isakmp_init()) { 184 plog(ASL_LEVEL_ERR, "failed to initialize isakmp"); 185 exit(1); 186 } 187#ifdef ENABLE_VPNCONTROL_PORT 188 if (vpncontrol_init()) { 189 plog(ASL_LEVEL_ERR, "failed to initialize vpn control port"); 190 //exit(1); 191 } 192#endif 193 194 if (init_signal()) { 195 plog(ASL_LEVEL_ERR, "failed to initialize signals.\n"); 196 exit(1); 197 } 198 199 for (i = 0; i <= NSIG; i++) 200 sigreq[i] = 0; 201 202 /* write .pid file */ 203 if (!f_foreground) { 204 racoon_pid = getpid(); 205 if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) 206 strlcpy(pid_file, _PATH_VARRUN "racoon.pid", sizeof(pid_file)); 207 else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') 208 strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); 209 else { 210 strlcat(pid_file, _PATH_VARRUN, sizeof(pid_file)); 211 strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); 212 } 213 fp = fopen(pid_file, "w"); 214 if (fp) { 215 if (fchmod(fileno(fp), 216 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { 217 plog(ASL_LEVEL_ERR, "%s", strerror(errno)); 218 fclose(fp); 219 exit(1); 220 } 221 fprintf(fp, "%ld\n", (long)racoon_pid); 222 fclose(fp); 223 } else { 224 plog(ASL_LEVEL_ERR, 225 "cannot open %s", pid_file); 226 } 227 } 228#if !TARGET_OS_EMBEDDED 229 // enable keepalive for recovery (from crashes and bad exits... after init) 230 (void)launchd_update_racoon_keepalive(true); 231#endif // !TARGET_OS_EMBEDDED 232 233 // Off to the races! 234 if (!terminated) { 235 dispatch_main(); 236 } 237 238 exit(1); // should not be reached!!! 239} 240 241 242/* clear all status and exit program. */ 243static void 244close_session(int error) 245{ 246 sched_killall(); 247 cleanup_power_mgmt(); 248 if ( terminated ) 249 ike_session_flush_all_phase2(false); 250 ike_session_flush_all_phase1(false); 251 close_sockets(); 252 253#if !TARGET_OS_EMBEDDED 254 // a clean exit, so disable launchd keepalive 255 (void)launchd_update_racoon_keepalive(false); 256#endif // !TARGET_OS_EMBEDDED 257 258 plog(ASL_LEVEL_INFO, "racoon shutdown\n"); 259 exit(0); 260} 261 262 263/* 264 * waiting the termination of processing until sending DELETE message 265 * for all inbound SA will complete. 266 */ 267static void 268check_flushsa_stub(p) 269 void *p; 270{ 271 check_flushsa(); 272} 273 274static void 275check_flushsa() 276{ 277 vchar_t *buf; 278 struct sadb_msg *msg, *end, *next; 279 struct sadb_sa *sa; 280 caddr_t mhp[SADB_EXT_MAX + 1]; 281 int n; 282 283 buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); 284 if (buf == NULL) { 285 plog(ASL_LEVEL_DEBUG, 286 "pfkey_dump_sadb: returned nothing.\n"); 287 return; 288 } 289 290 msg = ALIGNED_CAST(struct sadb_msg *)buf->v; 291 end = ALIGNED_CAST(struct sadb_msg *)(buf->v + buf->l); 292 293 /* counting SA except of dead one. */ 294 n = 0; 295 while (msg < end) { 296 if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg)) 297 break; 298 next = ALIGNED_CAST(struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len)); // Wcast-align fix (void*) - aligned buffer + multiple of 64 299 if (msg->sadb_msg_type != SADB_DUMP) { 300 msg = next; 301 continue; 302 } 303 304 if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { 305 plog(ASL_LEVEL_ERR, 306 "pfkey_check (%s)\n", ipsec_strerror()); 307 msg = next; 308 continue; 309 } 310 311 sa = ALIGNED_CAST(struct sadb_sa *)(mhp[SADB_EXT_SA]); // Wcast-align fix (void*) - mhp contains pointers to aligned structs 312 if (!sa) { 313 msg = next; 314 continue; 315 } 316 317 if (sa->sadb_sa_state != SADB_SASTATE_DEAD) { 318 n++; 319 msg = next; 320 continue; 321 } 322 323 msg = next; 324 } 325 326 if (buf != NULL) 327 vfree(buf); 328 329 if (n) { 330 sched_new(1, check_flushsa_stub, NULL); 331 return; 332 } 333 334#if !TARGET_OS_EMBEDDED 335 if (lcconf->vt) 336 vproc_transaction_end(NULL, lcconf->vt); 337#endif 338 close_session(0); 339} 340 341void 342auto_exit_do(void *p) 343{ 344 plog(ASL_LEVEL_DEBUG, 345 "performing auto exit\n"); 346 pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); 347 sched_new(1, check_flushsa_stub, NULL); 348 dying(); 349} 350 351void 352check_auto_exit(void) 353{ 354 if (lcconf->auto_exit_sched) { /* exit scheduled? */ 355 if (lcconf->auto_exit_state != LC_AUTOEXITSTATE_ENABLED 356 || vpn_control_connected() /* vpn control connected */ 357 || policies_installed() /* policies installed in kernel */ 358 || !no_remote_configs(FALSE)) { /* remote or anonymous configs */ 359 SCHED_KILL(lcconf->auto_exit_sched); 360 } 361 } else { /* exit not scheduled */ 362 if (lcconf->auto_exit_state == LC_AUTOEXITSTATE_ENABLED 363 && !vpn_control_connected() 364 && !policies_installed() 365 && no_remote_configs(FALSE)) { 366 if (lcconf->auto_exit_delay == 0) { 367 auto_exit_do(NULL); /* immediate exit */ 368 } else { 369 lcconf->auto_exit_sched = sched_new(lcconf->auto_exit_delay, auto_exit_do, NULL); 370 } 371 } 372 } 373} 374 375static int signals[] = { 376 SIGHUP, 377 SIGINT, 378 SIGTERM, 379 SIGUSR1, 380 SIGUSR2, 381 SIGPIPE, 382 0 383}; 384 385 386static void 387check_sigreq() 388{ 389 int sig; 390 391 /* 392 * XXX We are not able to tell if we got 393 * several time the same signal. This is 394 * not a problem for the current code, 395 * but we shall remember this limitation. 396 */ 397 for (sig = 0; sig <= NSIG; sig++) { 398 if (sigreq[sig] == 0) 399 continue; 400 401 sigreq[sig]--; 402 switch(sig) { 403 case 0: 404 return; 405 406 /* Catch up childs, mainly scripts. 407 */ 408 409 case SIGUSR1: 410 case SIGHUP: 411#ifdef ENABLE_HYBRID 412 if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) { 413 plog(ASL_LEVEL_ERR, 414 "ISAKMP mode config structure reset failed, " 415 "not reloading\n"); 416 return; 417 } 418#endif 419 if ( terminated ) 420 break; 421 422 /* 423 * if we got a HUP... try graceful teardown of sessions before we close and reopen sockets... 424 * so that info-deletes notifications can make it to the peer. 425 */ 426 if (sig == SIGHUP) { 427 ike_session_flush_all_phase2(true); 428 ike_session_flush_all_phase1(true); 429 } 430 431 /* Save old configuration, load new one... */ 432 if (cfreparse(sig)) { 433 plog(ASL_LEVEL_ERR, 434 "configuration read failed\n"); 435 exit(1); 436 } 437 if (lcconf->logfile_param == NULL && logFileStr[0] == 0) 438 plogresetfile(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]); 439 440#if TARGET_OS_EMBEDDED 441 if (no_remote_configs(TRUE)) { 442 pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); 443#ifdef ENABLE_FASTQUIT 444 close_session(0); 445#else 446 sched_new(1, check_flushsa_stub, NULL); 447#endif 448 dying(); 449 } 450#endif 451 452 break; 453 454 case SIGINT: 455 case SIGTERM: 456 plog(ASL_LEVEL_INFO, 457 "caught signal %d\n", sig); 458 pfkey_send_flush(lcconf->sock_pfkey, 459 SADB_SATYPE_UNSPEC); 460 if ( sig == SIGTERM ){ 461 terminated = 1; /* in case if it hasn't been set yet */ 462 close_session(0); 463 } 464 else 465 sched_new(1, check_flushsa_stub, NULL); 466 467 dying(); 468 break; 469 470 default: 471 plog(ASL_LEVEL_INFO, 472 "caught signal %d\n", sig); 473 break; 474 } 475 } 476} 477 478 479/* 480 * asynchronous requests will actually dispatched in the 481 * main loop in session(). 482 */ 483RETSIGTYPE 484signal_handler(int sig, siginfo_t *sigi, void *ctx) 485{ 486#if 0 487 plog(ASL_LEVEL_DEBUG, 488 "%s received signal %d from pid %d uid %d\n\n", 489 __FUNCTION__, sig, sigi->si_pid, sigi->si_uid); 490#endif 491 492 /* Do not just set it to 1, because we may miss some signals by just setting 493 * values to 0/1 494 */ 495 sigreq[sig]++; 496 if ( sig == SIGTERM ){ 497 terminated = 1; 498 } 499 dispatch_async(main_queue, 500 ^{ 501 check_sigreq(); 502 }); 503} 504 505 506static int 507init_signal() 508{ 509 int i; 510 511 for (i = 0; signals[i] != 0; i++) { 512 if (set_signal(signals[i], signal_handler) < 0) { 513 plog(ASL_LEVEL_ERR, 514 "failed to set_signal (%s)\n", 515 strerror(errno)); 516 return (1); 517 } 518 } 519 return 0; 520} 521 522static int 523set_signal(int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *)) 524{ 525 struct sigaction sa; 526 527 memset((caddr_t)&sa, 0, sizeof(sa)); 528 sa.sa_sigaction = func; 529 sa.sa_flags = SA_RESTART | SA_SIGINFO; 530 531 if (sigemptyset(&sa.sa_mask) < 0) 532 return -1; 533 534 if (sigaction(sig, &sa, (struct sigaction *)0) < 0) 535 return(-1); 536 537 return 0; 538} 539 540void 541fatal_error(int error) 542{ 543 close_session(error == 0 ? -1 : error); 544} 545 546/* suspend all socket sources except pf_key */ 547void 548dying(void) 549{ 550 if (lcconf->rt_source) 551 dispatch_suspend(lcconf->rt_source); 552 if (lcconf->vpncontrol_source) 553 dispatch_suspend(lcconf->vpncontrol_source); 554 isakmp_suspend_sockets(); 555} 556 557static int 558close_sockets() 559{ 560 pfroute_close(); 561 isakmp_close(); 562 pfkey_close(); 563#ifdef ENABLE_VPNCONTROL_PORT 564 vpncontrol_close(); 565#endif 566 567 return 0; 568} 569 570 571