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#include <NetworkExtension/NEPolicy.h> 108#include <sys/proc_info.h> 109#include <libproc.h> 110 111 112extern pid_t racoon_pid; 113extern int launchdlaunched; 114static void close_session (int); 115static int init_signal (void); 116static int set_signal (int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *)); 117static void check_sigreq (void); 118static void check_flushsa_stub (void *); 119static void check_flushsa (void); 120static void auto_exit_do (void *); 121static int close_sockets (void); 122 123static volatile sig_atomic_t sigreq[NSIG + 1]; 124int terminated = 0; 125 126static int64_t racoon_keepalive = -1; 127 128dispatch_queue_t main_queue; 129 130static NEPolicySessionRef policySession = NULL; 131 132/* 133 * This is used to (manually) update racoon's launchd keepalive, which is needed because racoon is (mostly) 134 * launched on demand and for <rdar://problem/8768510> requires a keepalive on dirty/failure exits. 135 * The launchd plist can't be used for this because RunOnLoad is required to have keepalive on a failure exit. 136 */ 137int64_t 138launchd_update_racoon_keepalive (Boolean enabled) 139{ 140 if (launchdlaunched) { 141 int64_t val = (__typeof__(val))enabled; 142 /* Set our own KEEPALIVE value */ 143 if (vproc_swap_integer(NULL, 144 VPROC_GSK_BASIC_KEEPALIVE, 145 &val, 146 &racoon_keepalive)) { 147 plog(ASL_LEVEL_ERR, 148 "failed to swap launchd keepalive integer %d\n", enabled); 149 } 150 } 151 return racoon_keepalive; 152} 153 154static CFUUIDRef 155copy_racoon_proc_uuid(void) 156{ 157 struct proc_uniqidentifierinfo procu; 158 CFUUIDBytes uuidBytes; 159 int size = 0; 160 161 memset(&procu, 0, sizeof(procu)); 162 size = proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO, 1, &procu, PROC_PIDUNIQIDENTIFIERINFO_SIZE); 163 if (size != PROC_PIDUNIQIDENTIFIERINFO_SIZE) { 164 return (NULL); 165 } 166 167 memcpy(&uuidBytes, procu.p_uuid, sizeof(CFUUIDBytes)); 168 return CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, uuidBytes); 169} 170 171static bool 172policy_session_init(void) 173{ 174 bool success = true; 175 policySession = NEPolicyCreateSession(kCFAllocatorDefault, CFSTR("racoon"), NULL, NULL); 176 if (policySession == NULL) { 177 return false; 178 } 179 180 CFUUIDRef proc_uuid = copy_racoon_proc_uuid(); 181 if (proc_uuid == NULL) { 182 return false; 183 } 184 185 CFMutableArrayRef conditions = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 186 if (conditions) { 187 CFMutableDictionaryRef uuidCondition = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 188 if (uuidCondition) { 189 CFDictionarySetValue(uuidCondition, kNEPolicyConditionType, kNEPolicyValPolicyConditionTypeApplication); 190 CFDictionarySetValue(uuidCondition, kNEPolicyApplicationUUID, proc_uuid); 191 CFArrayAppendValue(conditions, uuidCondition); 192 CFRelease(uuidCondition); 193 } else { 194 success = false; 195 } 196 197 CFMutableDictionaryRef interfacesCondition = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 198 if (interfacesCondition) { 199 CFDictionarySetValue(interfacesCondition, kNEPolicyConditionType, kNEPolicyValPolicyConditionTypeAllInterfaces); 200 CFArrayAppendValue(conditions, interfacesCondition); 201 CFRelease(interfacesCondition); 202 } else { 203 success = false; 204 } 205 } else { 206 success = false; 207 } 208 209 CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 210 if (result) { 211 CFDictionaryAddValue(result, kNEPolicyResult, kNEPolicyValPolicyResultPass); 212 } else { 213 success = false; 214 } 215 216 if (success) { 217 success = (NEPolicyAdd(policySession, 0, conditions, result, NULL) != kNEPolicyIDInvalid); 218 } 219 220 if (result) { 221 CFRelease(result); 222 } 223 if (conditions) { 224 CFRelease(conditions); 225 } 226 if (proc_uuid) { 227 CFRelease(proc_uuid); 228 } 229 230 return (success && NEPolicyApply(policySession)); 231} 232 233// 234// Session 235// 236// Initialize listening sockets, timers, vpn control etc., 237// write the PID file and call dispatch_main. 238// 239void 240session(void) 241{ 242 char pid_file[MAXPATHLEN]; 243 FILE *fp; 244 int i; 245 246 main_queue = dispatch_get_main_queue(); 247 248 /* initialize schedular */ 249 sched_init(); 250 251 /* needs to be called after schedular */ 252 if (init_power_mgmt() < 0) { 253 plog(ASL_LEVEL_ERR, 254 "failed to initialize power-mgmt."); 255 exit(1); 256 } 257 258 if (lcconf->autograbaddr == 1) 259 if (pfroute_init()) { 260 plog(ASL_LEVEL_ERR, "failed to initialize route socket.\n"); 261 exit(1); 262 } 263 264 if (!policy_session_init()) { 265 plog(ASL_LEVEL_ERR, "failed to initialize NEPolicy session.\n"); 266 } 267 268 if (initmyaddr()) { 269 plog(ASL_LEVEL_ERR, "failed to initialize listening addresses.\n"); 270 exit(1); 271 } 272 if (isakmp_init()) { 273 plog(ASL_LEVEL_ERR, "failed to initialize isakmp"); 274 exit(1); 275 } 276#ifdef ENABLE_VPNCONTROL_PORT 277 if (vpncontrol_init()) { 278 plog(ASL_LEVEL_ERR, "failed to initialize vpn control port"); 279 //exit(1); 280 } 281#endif 282 283 if (init_signal()) { 284 plog(ASL_LEVEL_ERR, "failed to initialize signals.\n"); 285 exit(1); 286 } 287 288 for (i = 0; i <= NSIG; i++) 289 sigreq[i] = 0; 290 291 /* write .pid file */ 292 if (!f_foreground) { 293 racoon_pid = getpid(); 294 if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) 295 strlcpy(pid_file, _PATH_VARRUN "racoon.pid", sizeof(pid_file)); 296 else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') 297 strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); 298 else { 299 strlcat(pid_file, _PATH_VARRUN, sizeof(pid_file)); 300 strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); 301 } 302 fp = fopen(pid_file, "w"); 303 if (fp) { 304 if (fchmod(fileno(fp), 305 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { 306 plog(ASL_LEVEL_ERR, "%s", strerror(errno)); 307 fclose(fp); 308 exit(1); 309 } 310 fprintf(fp, "%ld\n", (long)racoon_pid); 311 fclose(fp); 312 } else { 313 plog(ASL_LEVEL_ERR, 314 "cannot open %s", pid_file); 315 } 316 } 317#if !TARGET_OS_EMBEDDED 318 // enable keepalive for recovery (from crashes and bad exits... after init) 319 (void)launchd_update_racoon_keepalive(true); 320#endif // !TARGET_OS_EMBEDDED 321 322 // Off to the races! 323 if (!terminated) { 324 dispatch_main(); 325 } 326 327 exit(1); // should not be reached!!! 328} 329 330 331/* clear all status and exit program. */ 332static void 333close_session(int error) 334{ 335 sched_killall(); 336 cleanup_power_mgmt(); 337 if ( terminated ) 338 ike_session_flush_all_phase2(false); 339 ike_session_flush_all_phase1(false); 340 close_sockets(); 341 342#if !TARGET_OS_EMBEDDED 343 // a clean exit, so disable launchd keepalive 344 (void)launchd_update_racoon_keepalive(false); 345#endif // !TARGET_OS_EMBEDDED 346 347 plog(ASL_LEVEL_INFO, "racoon shutdown\n"); 348 exit(0); 349} 350 351 352/* 353 * waiting the termination of processing until sending DELETE message 354 * for all inbound SA will complete. 355 */ 356static void 357check_flushsa_stub(p) 358 void *p; 359{ 360 check_flushsa(); 361} 362 363static void 364check_flushsa() 365{ 366 vchar_t *buf; 367 struct sadb_msg *msg, *end, *next; 368 struct sadb_sa *sa; 369 caddr_t mhp[SADB_EXT_MAX + 1]; 370 int n; 371 372 buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); 373 if (buf == NULL) { 374 plog(ASL_LEVEL_DEBUG, 375 "pfkey_dump_sadb: returned nothing.\n"); 376 return; 377 } 378 379 msg = ALIGNED_CAST(struct sadb_msg *)buf->v; 380 end = ALIGNED_CAST(struct sadb_msg *)(buf->v + buf->l); 381 382 /* counting SA except of dead one. */ 383 n = 0; 384 while (msg < end) { 385 if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg)) 386 break; 387 next = ALIGNED_CAST(struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len)); // Wcast-align fix (void*) - aligned buffer + multiple of 64 388 if (msg->sadb_msg_type != SADB_DUMP) { 389 msg = next; 390 continue; 391 } 392 393 if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { 394 plog(ASL_LEVEL_ERR, 395 "pfkey_check (%s)\n", ipsec_strerror()); 396 msg = next; 397 continue; 398 } 399 400 sa = ALIGNED_CAST(struct sadb_sa *)(mhp[SADB_EXT_SA]); // Wcast-align fix (void*) - mhp contains pointers to aligned structs 401 if (!sa) { 402 msg = next; 403 continue; 404 } 405 406 if (sa->sadb_sa_state != SADB_SASTATE_DEAD) { 407 n++; 408 msg = next; 409 continue; 410 } 411 412 msg = next; 413 } 414 415 if (buf != NULL) 416 vfree(buf); 417 418 if (n) { 419 sched_new(1, check_flushsa_stub, NULL); 420 return; 421 } 422 423#if !TARGET_OS_EMBEDDED 424 if (lcconf->vt) 425 vproc_transaction_end(NULL, lcconf->vt); 426#endif 427 close_session(0); 428} 429 430void 431auto_exit_do(void *p) 432{ 433 plog(ASL_LEVEL_DEBUG, 434 "performing auto exit\n"); 435#if ENABLE_NO_SA_FLUSH 436 close_session(0); 437#else 438 pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); 439 sched_new(1, check_flushsa_stub, NULL); 440 dying(); 441#endif /* ENABLE_NO_SA_FLUSH */ 442} 443 444void 445check_auto_exit(void) 446{ 447 if (lcconf->auto_exit_sched) { /* exit scheduled? */ 448 if (lcconf->auto_exit_state != LC_AUTOEXITSTATE_ENABLED 449 || vpn_control_connected() /* vpn control connected */ 450 || policies_installed() /* policies installed in kernel */ 451 || !no_remote_configs(FALSE)) { /* remote or anonymous configs */ 452 SCHED_KILL(lcconf->auto_exit_sched); 453 } 454 } else { /* exit not scheduled */ 455 if (lcconf->auto_exit_state == LC_AUTOEXITSTATE_ENABLED 456 && !vpn_control_connected() 457 && !policies_installed() 458 && no_remote_configs(FALSE)) { 459 if (lcconf->auto_exit_delay == 0) { 460 auto_exit_do(NULL); /* immediate exit */ 461 } else { 462 lcconf->auto_exit_sched = sched_new(lcconf->auto_exit_delay, auto_exit_do, NULL); 463 } 464 } 465 } 466} 467 468static int signals[] = { 469 SIGHUP, 470 SIGINT, 471 SIGTERM, 472 SIGUSR1, 473 SIGUSR2, 474 SIGPIPE, 475 0 476}; 477 478 479static void 480check_sigreq() 481{ 482 int sig; 483 484 /* 485 * XXX We are not able to tell if we got 486 * several time the same signal. This is 487 * not a problem for the current code, 488 * but we shall remember this limitation. 489 */ 490 for (sig = 0; sig <= NSIG; sig++) { 491 if (sigreq[sig] == 0) 492 continue; 493 494 sigreq[sig]--; 495 switch(sig) { 496 case 0: 497 return; 498 499 /* Catch up childs, mainly scripts. 500 */ 501 502 case SIGUSR1: 503 case SIGHUP: 504#ifdef ENABLE_HYBRID 505 if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) { 506 plog(ASL_LEVEL_ERR, 507 "ISAKMP mode config structure reset failed, " 508 "not reloading\n"); 509 return; 510 } 511#endif 512 if ( terminated ) 513 break; 514 515 /* 516 * if we got a HUP... try graceful teardown of sessions before we close and reopen sockets... 517 * so that info-deletes notifications can make it to the peer. 518 */ 519 if (sig == SIGHUP) { 520 ike_session_flush_all_phase2(true); 521 ike_session_flush_all_phase1(true); 522 } 523 524 /* Save old configuration, load new one... */ 525 if (cfreparse(sig)) { 526 plog(ASL_LEVEL_ERR, 527 "configuration read failed\n"); 528 exit(1); 529 } 530 if (lcconf->logfile_param == NULL && logFileStr[0] == 0) 531 plogresetfile(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]); 532 533#if TARGET_OS_EMBEDDED 534 if (no_remote_configs(TRUE)) { 535#if ENABLE_NO_SA_FLUSH 536 close_session(0); 537#else 538 pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); 539#ifdef ENABLE_FASTQUIT 540 close_session(0); 541#else 542 sched_new(1, check_flushsa_stub, NULL); 543#endif /* ENABLE_FASTQUIT */ 544 dying(); 545#endif /* ENABLE_NO_SA_FLUSH */ 546 } 547#endif 548 549 break; 550 551 case SIGINT: 552 case SIGTERM: 553 plog(ASL_LEVEL_INFO, 554 "caught signal %d\n", sig); 555#if ENABLE_NO_SA_FLUSH 556 close_session(0); 557#else 558 pfkey_send_flush(lcconf->sock_pfkey, 559 SADB_SATYPE_UNSPEC); 560 if ( sig == SIGTERM ){ 561 terminated = 1; /* in case if it hasn't been set yet */ 562 close_session(0); 563 } 564 else 565 sched_new(1, check_flushsa_stub, NULL); 566 567 dying(); 568#endif /* ENABLE_NO_SA_FLUSH */ 569 break; 570 571 default: 572 plog(ASL_LEVEL_INFO, 573 "caught signal %d\n", sig); 574 break; 575 } 576 } 577} 578 579 580/* 581 * asynchronous requests will actually dispatched in the 582 * main loop in session(). 583 */ 584RETSIGTYPE 585signal_handler(int sig, siginfo_t *sigi, void *ctx) 586{ 587#if 0 588 plog(ASL_LEVEL_DEBUG, 589 "%s received signal %d from pid %d uid %d\n\n", 590 __FUNCTION__, sig, sigi->si_pid, sigi->si_uid); 591#endif 592 593 /* Do not just set it to 1, because we may miss some signals by just setting 594 * values to 0/1 595 */ 596 sigreq[sig]++; 597 if ( sig == SIGTERM ){ 598 terminated = 1; 599 } 600 dispatch_async(main_queue, 601 ^{ 602 check_sigreq(); 603 }); 604} 605 606 607static int 608init_signal() 609{ 610 int i; 611 612 for (i = 0; signals[i] != 0; i++) { 613 if (set_signal(signals[i], signal_handler) < 0) { 614 plog(ASL_LEVEL_ERR, 615 "failed to set_signal (%s)\n", 616 strerror(errno)); 617 return (1); 618 } 619 } 620 return 0; 621} 622 623static int 624set_signal(int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *)) 625{ 626 struct sigaction sa; 627 628 memset((caddr_t)&sa, 0, sizeof(sa)); 629 sa.sa_sigaction = func; 630 sa.sa_flags = SA_RESTART | SA_SIGINFO; 631 632 if (sigemptyset(&sa.sa_mask) < 0) 633 return -1; 634 635 if (sigaction(sig, &sa, (struct sigaction *)0) < 0) 636 return(-1); 637 638 return 0; 639} 640 641void 642fatal_error(int error) 643{ 644 close_session(error == 0 ? -1 : error); 645} 646 647/* suspend all socket sources except pf_key */ 648void 649dying(void) 650{ 651 if (lcconf->rt_source) 652 dispatch_suspend(lcconf->rt_source); 653 if (lcconf->vpncontrol_source) 654 dispatch_suspend(lcconf->vpncontrol_source); 655 isakmp_suspend_sockets(); 656} 657 658static int 659close_sockets() 660{ 661 pfroute_close(); 662 isakmp_close(); 663 pfkey_close(); 664#ifdef ENABLE_VPNCONTROL_PORT 665 vpncontrol_close(); 666#endif 667 668 return 0; 669} 670 671 672