1/* $Id: main.c,v 1.14.2.3 2005/11/06 17:18:26 monas Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include "config.h" 33 34#include <sys/types.h> 35#include <sys/param.h> 36#include <sys/socket.h> 37#include <sys/stat.h> 38#include <sys/sysctl.h> 39 40#include <netinet/in.h> 41 42#include <stdlib.h> 43#include <stdio.h> 44#include <string.h> 45#include <errno.h> 46#include <limits.h> 47#ifdef HAVE_UNISTD_H 48#include <unistd.h> 49#endif 50#include <paths.h> 51#include <err.h> 52#include <launch.h> 53 54/* 55 * If we're using a debugging malloc library, this may define our 56 * wrapper stubs. 57 */ 58#define RACOON_MAIN_PROGRAM 59#include "gcmalloc.h" 60 61#include "var.h" 62#include "misc.h" 63#include "vmbuf.h" 64#include "plog.h" 65#include "debug.h" 66 67#include "cfparse_proto.h" 68#include "isakmp_var.h" 69#ifdef ENABLE_HYBRID 70#include <resolv.h> 71#include "isakmp.h" 72#include "isakmp_xauth.h" 73#include "isakmp_cfg.h" 74#endif 75#include "remoteconf.h" 76#include "localconf.h" 77#include "session.h" 78#include "oakley.h" 79#include "pfkey.h" 80#include "policy.h" 81#include "crypto_openssl.h" 82#include "vendorid.h" 83 84#include <CoreFoundation/CoreFoundation.h> 85#ifndef TARGET_OS_EMBEDDED 86#include <sandbox.h> 87#endif // !TARGET_OS_EMBEDDED 88#include "power_mgmt.h" 89#include "preferences.h" 90 91//#include "package_version.h" 92 93int f_local = 0; /* local test mode. behave like a wall. */ 94int vflag = 1; /* for print-isakmp.c */ 95static int dump_config = 0; /* dump parsed config file. */ 96static int exec_done = 0; /* we've already been exec'd */ 97 98#ifdef TOP_PACKAGE 99static char version[] = "@(#)" TOP_PACKAGE_STRING " (" TOP_PACKAGE_URL ")"; 100#else /* TOP_PACKAGE */ 101static char version[] = "@(#) racoon / IPsec-tools"; 102#endif /* TOP_PACKAGE */ 103 104int main (int, char **); 105static void usage (void); 106static void parse (int, char **); 107static void restore_params (void); 108static void save_params (void); 109static void saverestore_params (int); 110static void cleanup_pidfile (void); 111#if 0 // <rdar://problem/9286626> 112int launchedbylaunchd (void); 113#endif 114 115pid_t racoon_pid = 0; 116int launchdlaunched = 0; 117int print_pid = 1; /* for racoon only */ 118 119 120void 121usage() 122{ 123 printf("usage: racoon [-BdDFvs%s] %s[-f (file)] [-l (file)] [-p (port)]\n", 124#ifdef INET6 125 "46", 126#else 127 "", 128#endif 129 "" 130 ); 131 printf(" -d: debug level, more -d will generate more debug message.\n"); 132 printf(" -D: started by LaunchD (implies daemon mode).\n"); 133 printf(" -C: dump parsed config file.\n"); 134 printf(" -L: include location in debug messages\n"); 135 printf(" -F: run in foreground, do not become daemon.\n"); 136 printf(" -v: be more verbose\n"); 137 printf(" -s: override enable auto exit\n"); 138#ifdef INET6 139 printf(" -4: IPv4 mode.\n"); 140 printf(" -6: IPv6 mode.\n"); 141#endif 142 printf(" -f: pathname for configuration file.\n"); 143 printf(" -l: pathname for log file.\n"); 144 printf(" -p: port number for isakmp (default: %d).\n", PORT_ISAKMP); 145 printf(" -P: port number for NAT-T (default: %d).\n", PORT_ISAKMP_NATT); 146 exit(1); 147} 148 149int 150main(ac, av) 151 int ac; 152 char **av; 153{ 154 int error; 155#ifndef TARGET_OS_EMBEDDED 156 char *sb_errorbuf = NULL; 157#endif // !TARGET_OS_EMBEDDED 158 159 /* 160 * Check IPSec plist 161 */ 162 prefsinit(); 163 ploginit(); 164 165#ifndef TARGET_OS_EMBEDDED 166 if (sandbox_init("racoon", SANDBOX_NAMED, &sb_errorbuf) == -1) { 167 if (sb_errorbuf) { 168 plog(ASL_LEVEL_ERR, "sandbox_init failed: %s\n", sb_errorbuf); 169 sandbox_free_error(sb_errorbuf); 170 sb_errorbuf = NULL; 171 } else { 172 plog(ASL_LEVEL_ERR, "sandbox_init failed\n"); 173 } 174 } 175#endif // !TARGET_OS_EMBEDDED 176 177 if (geteuid() != 0) { 178 errx(1, "must be root to invoke this program."); 179 /* NOTREACHED*/ 180 } 181 182 /* 183 * Don't let anyone read files I write. Although some files (such as 184 * the PID file) can be other readable, we dare to use the global mask, 185 * because racoon uses fopen(3), which can't specify the permission 186 * at the creation time. 187 */ 188 umask(077); 189 if (umask(077) != 077) { 190 errx(1, "could not set umask"); 191 /* NOTREACHED*/ 192 } 193 194#ifdef HAVE_OPENSSL 195 eay_init(); 196#endif 197 198 initlcconf(); 199 initrmconf(); 200 oakley_dhinit(); 201 compute_vendorids(); 202 203 parse(ac, av); 204 205 plog(ASL_LEVEL_INFO, "***** racoon started: pid=%d started by: %d, launchdlaunched %d\n", getpid(), getppid(), launchdlaunched); 206 plog(ASL_LEVEL_INFO, "%s\n", version); 207#ifdef HAVE_OPENSSL 208 plog(ASL_LEVEL_INFO, "@(#)" 209 "This product linked %s (http://www.openssl.org/)" 210 "\n", eay_version()); 211#endif 212 plog(ASL_LEVEL_INFO, "Reading configuration from \"%s\"\n", 213 lcconf->racoon_conf); 214 215 //%%%%% this sould probably be moved to session() 216 if (pfkey_init() < 0) { 217 errx(1, "failed to initialize pfkey.\n"); 218 /* NOTREACHED*/ 219 } 220 221 /* 222 * in order to prefer the parameters by command line, 223 * saving some parameters before parsing configuration file. 224 */ 225 save_params(); 226 error = cfparse(); 227 if (error != 0) 228 errx(1, "failed to parse configuration file."); 229 restore_params(); 230 231 if (lcconf->logfile_param == NULL && logFileStr[0] == 0) 232 plogresetfile(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]); 233 234#ifdef ENABLE_NATT 235 /* Tell the kernel which port to use for UDP encapsulation */ 236 { 237 int udp_port = PORT_ISAKMP_NATT; 238 if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, &udp_port, sizeof(udp_port)) != 0) 239 errx(1, "couldn't set net.inet.ipsec.esp_port to %d. (%s)", 240 udp_port, strerror(errno)); 241 } 242#endif 243 244 245#ifdef ENABLE_HYBRID 246 if(isakmp_cfg_config.network4 && isakmp_cfg_config.pool_size == 0) 247 if ((error = isakmp_cfg_resize_pool(ISAKMP_CFG_MAX_CNX)) != 0) 248 return error; 249#endif 250 251 if (dump_config) 252 dumprmconf (); 253 254 /* 255 * install SAs from the specified file. If the file is not specified 256 * by the configuration file, racoon will exit. 257 */ 258 259 if (f_foreground) 260 close(0); 261 else { 262 if ( !exec_done && launchdlaunched ){ 263 plog(ASL_LEVEL_INFO, 264 "racoon launched by launchd.\n"); 265 exec_done = 1; 266 if (atexit(cleanup_pidfile) < 0) { 267 plog(ASL_LEVEL_ERR, 268 "cannot register pidfile cleanup"); 269 } 270 }else { 271 272 if (exec_done) { 273 if (atexit(cleanup_pidfile) < 0) { 274 plog(ASL_LEVEL_ERR, 275 "cannot register pidfile cleanup"); 276 } 277 } else { 278 #define MAX_EXEC_ARGS 32 279 280 char *args[MAX_EXEC_ARGS + 2]; /* 2 extra, for '-x' and NULL */ 281 char *env[1] = {0}; 282 int i; 283 284 if (ac > MAX_EXEC_ARGS) { 285 plog(ASL_LEVEL_ERR, 286 "too many arguments.\n"); 287 exit(1); 288 } 289 290 if (daemon(0, 0) < 0) { 291 errx(1, "failed to be daemon. (%s)", 292 strerror(errno)); 293 } 294 295 /* Radar 5129006 - Prevent non-root user from killing racoon 296 * when launched by setuid process 297 */ 298 if (setuid(0)) { 299 plog(ASL_LEVEL_ERR, 300 "cannot set uid.\n"); 301 exit(1); 302 } 303 if (setgid(0)) { 304 plog(ASL_LEVEL_ERR, 305 "cannot set gid.\n"); 306 exit(1); 307 } 308 309 /* setup args to re-exec - for CoreFoundation issues */ 310 args[0] = PATHRACOON; 311 for (i = 1; i < ac; i++) 312 args[i] = *(av + i); 313 args[ac] = "-x"; /* tells racoon its been exec'd */ 314 args[ac+1] = 0; 315 316 execve(PATHRACOON, args, env); 317 plog(ASL_LEVEL_ERR, 318 "failed to exec racoon. (%s)", strerror(errno)); 319 exit(1); 320 } 321 } 322 } 323 324 325 /* start the session */ 326 session(); 327} 328 329#if 0 // <rdar://problem/9286626> 330int 331launchedbylaunchd(){ 332 launch_data_t checkin_response = NULL; 333 334 if ((checkin_response = launch_socket_service_check_in()) == NULL) { 335 plog(LLV_ERROR, LOCATION, NULL, 336 "launch_socket_service_check_in fails.\n"); 337 launchdlaunched = 0; 338 goto done; 339 } 340 if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) { 341 plog(LLV_ERROR, LOCATION, NULL, 342 "launch_data_get_type fails errno %d.\n", launch_data_get_errno(checkin_response)); 343 launchdlaunched = 0; 344 goto done; 345 } 346 launchdlaunched = 1; 347done: 348 /* clean up before we leave */ 349 if ( checkin_response ) 350 launch_data_free(checkin_response); 351 return launchdlaunched; 352} 353#endif 354 355static void 356cleanup_pidfile() 357{ 358 char pid_file[MAXPATHLEN]; 359 pid_t p = getpid(); 360 361 /* if it's not child process, clean everything */ 362 if (racoon_pid == p) { 363 if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) 364 strlcpy(pid_file, _PATH_VARRUN "racoon.pid", sizeof(pid_file)); 365 else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') 366 strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); 367 else { 368 strlcat(pid_file, _PATH_VARRUN, sizeof(pid_file)); 369 strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); 370 } 371 (void) unlink(pid_file); 372 } 373} 374 375 376static void 377parse(ac, av) 378 int ac; 379 char **av; 380{ 381 extern char *optarg; 382 extern int optind; 383 int c; 384#ifdef YYDEBUG 385 extern int yydebug; 386#endif 387 388 pname = strrchr(*av, '/'); 389 if (pname) 390 pname++; 391 else 392 pname = *av; 393 394 while ((c = getopt(ac, av, "dDLFp:P:a:f:l:vsZBCx" 395#ifdef YYDEBUG 396 "y" 397#endif 398#ifdef INET6 399 "46" 400#endif 401 )) != -1) { 402 switch (c) { 403 case 'd': 404 plogsetlevel(ASL_LEVEL_DEBUG); 405 break; 406 case 'D': 407 if (f_foreground) { 408 fprintf(stderr, "-D and -F are mutually exclusive\n"); 409 exit(1); 410 } 411 launchdlaunched = 1; 412 break; 413 case 'L': 414 print_location = 1; 415 break; 416 case 'F': 417 if (launchdlaunched) { 418 fprintf(stderr, "-D and -F are mutually exclusive\n"); 419 exit(1); 420 } 421 printf("Foreground mode.\n"); 422 f_foreground = 1; 423 break; 424 case 'p': 425 lcconf->port_isakmp = atoi(optarg); 426 break; 427 case 'P': 428 lcconf->port_isakmp_natt = atoi(optarg); 429 break; 430 case 'a': 431 fprintf(stderr, "%s: the option is disabled " 432 "in the configuration\n", pname); 433 exit(1); 434 case 'f': 435 lcconf->racoon_conf = optarg; 436 break; 437 case 'l': 438 lcconf->logfile_param = optarg; 439 break; 440 case 'v': 441 vflag++; 442 break; 443 case 's': 444 lcconf->auto_exit_state &= ~LC_AUTOEXITSTATE_CLIENT; /* override default auto exit state */ 445 break; 446 case 'x': 447 exec_done = 1; 448 break; 449 case 'Z': 450 /* 451 * only local test. 452 * To specify -Z option and to choice a appropriate 453 * port number for ISAKMP, you can launch some racoons 454 * on the local host for debug. 455 * pk_sendadd() on initiator side is always failed 456 * even if this flag is used. Because there is same 457 * spi in the SAD which is inserted by pk_sendgetspi() 458 * on responder side. 459 */ 460 printf("Local test mode.\n"); 461 f_local = 1; 462 break; 463#ifdef YYDEBUG 464 case 'y': 465 yydebug = 1; 466 break; 467#endif 468#ifdef INET6 469 case '4': 470 lcconf->default_af = AF_INET; 471 break; 472 case '6': 473 lcconf->default_af = AF_INET6; 474 break; 475#endif 476 case 'C': 477 dump_config++; 478 break; 479 default: 480 usage(); 481 /* NOTREACHED */ 482 } 483 } 484 ac -= optind; 485 av += optind; 486 487 if (ac != 0) { 488 usage(); 489 /* NOTREACHED */ 490 } 491 492 return; 493} 494 495static void 496restore_params() 497{ 498 saverestore_params(1); 499} 500 501static void 502save_params() 503{ 504 saverestore_params(0); 505} 506 507static void 508saverestore_params(f) 509 int f; 510{ 511 static u_int16_t s_port_isakmp; 512 513 /* 0: save, 1: restore */ 514 if (f) { 515 lcconf->port_isakmp = s_port_isakmp; 516 } else { 517 s_port_isakmp = lcconf->port_isakmp; 518 } 519} 520