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#include "power_mgmt.h" 86#include "preferences.h" 87 88//#include "package_version.h" 89 90int f_local = 0; /* local test mode. behave like a wall. */ 91int vflag = 1; /* for print-isakmp.c */ 92static int dump_config = 0; /* dump parsed config file. */ 93static int exec_done = 0; /* we've already been exec'd */ 94 95#ifdef TOP_PACKAGE 96static char version[] = "@(#)" TOP_PACKAGE_STRING " (" TOP_PACKAGE_URL ")"; 97#else /* TOP_PACKAGE */ 98static char version[] = "@(#) racoon / IPsec-tools"; 99#endif /* TOP_PACKAGE */ 100 101int main (int, char **); 102static void usage (void); 103static void parse (int, char **); 104static void restore_params (void); 105static void save_params (void); 106static void saverestore_params (int); 107static void cleanup_pidfile (void); 108#if 0 // <rdar://problem/9286626> 109int launchedbylaunchd (void); 110#endif 111 112pid_t racoon_pid = 0; 113int launchdlaunched = 0; 114int print_pid = 1; /* for racoon only */ 115 116 117void 118usage() 119{ 120 printf("usage: racoon [-BdDFvs%s] %s[-f (file)] [-l (file)] [-p (port)]\n", 121#ifdef INET6 122 "46", 123#else 124 "", 125#endif 126 "" 127 ); 128 printf(" -d: debug level, more -d will generate more debug message.\n"); 129 printf(" -D: started by LaunchD (implies daemon mode).\n"); 130 printf(" -C: dump parsed config file.\n"); 131 printf(" -L: include location in debug messages\n"); 132 printf(" -F: run in foreground, do not become daemon.\n"); 133 printf(" -v: be more verbose\n"); 134 printf(" -s: override enable auto exit\n"); 135#ifdef INET6 136 printf(" -4: IPv4 mode.\n"); 137 printf(" -6: IPv6 mode.\n"); 138#endif 139 printf(" -f: pathname for configuration file.\n"); 140 printf(" -l: pathname for log file.\n"); 141 printf(" -p: port number for isakmp (default: %d).\n", PORT_ISAKMP); 142 printf(" -P: port number for NAT-T (default: %d).\n", PORT_ISAKMP_NATT); 143 exit(1); 144} 145 146int 147main(ac, av) 148 int ac; 149 char **av; 150{ 151 int error; 152 153 /* 154 * Check IPSec plist 155 */ 156 prefsinit(); 157 ploginit(); 158 159 /* 160 * racoon is not sandboxed on Mac OS. 161 * On embedded, racoon is sandboxed with a seatbelt-profiles entitlement. 162 */ 163 164 if (geteuid() != 0) { 165 errx(1, "must be root to invoke this program."); 166 /* NOTREACHED*/ 167 } 168 169 /* 170 * Don't let anyone read files I write. Although some files (such as 171 * the PID file) can be other readable, we dare to use the global mask, 172 * because racoon uses fopen(3), which can't specify the permission 173 * at the creation time. 174 */ 175 umask(077); 176 if (umask(077) != 077) { 177 errx(1, "could not set umask"); 178 /* NOTREACHED*/ 179 } 180 181#ifdef HAVE_OPENSSL 182 eay_init(); 183#endif 184 185 initlcconf(); 186 initrmconf(); 187 oakley_dhinit(); 188 compute_vendorids(); 189 190 parse(ac, av); 191 192 plog(ASL_LEVEL_INFO, "***** racoon started: pid=%d started by: %d, launchdlaunched %d\n", getpid(), getppid(), launchdlaunched); 193 plog(ASL_LEVEL_INFO, "%s\n", version); 194#ifdef HAVE_OPENSSL 195 plog(ASL_LEVEL_INFO, "@(#)" 196 "This product linked %s (http://www.openssl.org/)" 197 "\n", eay_version()); 198#endif 199 plog(ASL_LEVEL_INFO, "Reading configuration from \"%s\"\n", 200 lcconf->racoon_conf); 201 202 //%%%%% this sould probably be moved to session() 203 if (pfkey_init() < 0) { 204 errx(1, "failed to initialize pfkey.\n"); 205 /* NOTREACHED*/ 206 } 207 208 /* 209 * in order to prefer the parameters by command line, 210 * saving some parameters before parsing configuration file. 211 */ 212 save_params(); 213 error = cfparse(); 214 if (error != 0) 215 errx(1, "failed to parse configuration file."); 216 restore_params(); 217 218 if (lcconf->logfile_param == NULL && logFileStr[0] == 0) 219 plogresetfile(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]); 220 221#ifdef ENABLE_NATT 222 /* Tell the kernel which port to use for UDP encapsulation */ 223 { 224 int udp_port = PORT_ISAKMP_NATT; 225 if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, &udp_port, sizeof(udp_port)) != 0) 226 errx(1, "couldn't set net.inet.ipsec.esp_port to %d. (%s)", 227 udp_port, strerror(errno)); 228 } 229#endif 230 231 232#ifdef ENABLE_HYBRID 233 if(isakmp_cfg_config.network4 && isakmp_cfg_config.pool_size == 0) 234 if ((error = isakmp_cfg_resize_pool(ISAKMP_CFG_MAX_CNX)) != 0) 235 return error; 236#endif 237 238 if (dump_config) 239 dumprmconf (); 240 241 /* 242 * install SAs from the specified file. If the file is not specified 243 * by the configuration file, racoon will exit. 244 */ 245 246 if (f_foreground) 247 close(0); 248 else { 249 if ( !exec_done && launchdlaunched ){ 250 plog(ASL_LEVEL_INFO, 251 "racoon launched by launchd.\n"); 252 exec_done = 1; 253 if (atexit(cleanup_pidfile) < 0) { 254 plog(ASL_LEVEL_ERR, 255 "cannot register pidfile cleanup"); 256 } 257 }else { 258 259 if (exec_done) { 260 if (atexit(cleanup_pidfile) < 0) { 261 plog(ASL_LEVEL_ERR, 262 "cannot register pidfile cleanup"); 263 } 264 } else { 265 #define MAX_EXEC_ARGS 32 266 267 char *args[MAX_EXEC_ARGS + 2]; /* 2 extra, for '-x' and NULL */ 268 char *env[1] = {0}; 269 int i; 270 271 if (ac > MAX_EXEC_ARGS) { 272 plog(ASL_LEVEL_ERR, 273 "too many arguments.\n"); 274 exit(1); 275 } 276 277 if (daemon(0, 0) < 0) { 278 errx(1, "failed to be daemon. (%s)", 279 strerror(errno)); 280 } 281 282 /* Radar 5129006 - Prevent non-root user from killing racoon 283 * when launched by setuid process 284 */ 285 if (setuid(0)) { 286 plog(ASL_LEVEL_ERR, 287 "cannot set uid.\n"); 288 exit(1); 289 } 290 if (setgid(0)) { 291 plog(ASL_LEVEL_ERR, 292 "cannot set gid.\n"); 293 exit(1); 294 } 295 296 /* setup args to re-exec - for CoreFoundation issues */ 297 args[0] = PATHRACOON; 298 for (i = 1; i < ac; i++) 299 args[i] = *(av + i); 300 args[ac] = "-x"; /* tells racoon its been exec'd */ 301 args[ac+1] = 0; 302 303 execve(PATHRACOON, args, env); 304 plog(ASL_LEVEL_ERR, 305 "failed to exec racoon. (%s)", strerror(errno)); 306 exit(1); 307 } 308 } 309 } 310 311 312 /* start the session */ 313 session(); 314} 315 316#if 0 // <rdar://problem/9286626> 317int 318launchedbylaunchd(){ 319 launch_data_t checkin_response = NULL; 320 321 if ((checkin_response = launch_socket_service_check_in()) == NULL) { 322 plog(LLV_ERROR, LOCATION, NULL, 323 "launch_socket_service_check_in fails.\n"); 324 launchdlaunched = 0; 325 goto done; 326 } 327 if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) { 328 plog(LLV_ERROR, LOCATION, NULL, 329 "launch_data_get_type fails errno %d.\n", launch_data_get_errno(checkin_response)); 330 launchdlaunched = 0; 331 goto done; 332 } 333 launchdlaunched = 1; 334done: 335 /* clean up before we leave */ 336 if ( checkin_response ) 337 launch_data_free(checkin_response); 338 return launchdlaunched; 339} 340#endif 341 342static void 343cleanup_pidfile() 344{ 345 char pid_file[MAXPATHLEN]; 346 pid_t p = getpid(); 347 348 /* if it's not child process, clean everything */ 349 if (racoon_pid == p) { 350 if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) 351 strlcpy(pid_file, _PATH_VARRUN "racoon.pid", sizeof(pid_file)); 352 else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') 353 strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); 354 else { 355 strlcat(pid_file, _PATH_VARRUN, sizeof(pid_file)); 356 strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); 357 } 358 (void) unlink(pid_file); 359 } 360} 361 362 363static void 364parse(ac, av) 365 int ac; 366 char **av; 367{ 368 extern char *optarg; 369 extern int optind; 370 int c; 371#ifdef YYDEBUG 372 extern int yydebug; 373#endif 374 375 pname = strrchr(*av, '/'); 376 if (pname) 377 pname++; 378 else 379 pname = *av; 380 381 while ((c = getopt(ac, av, "dDLFp:P:a:f:l:vsZBCx" 382#ifdef YYDEBUG 383 "y" 384#endif 385#ifdef INET6 386 "46" 387#endif 388 )) != -1) { 389 switch (c) { 390 case 'd': 391 plogsetlevel(ASL_LEVEL_DEBUG); 392 break; 393 case 'D': 394 if (f_foreground) { 395 fprintf(stderr, "-D and -F are mutually exclusive\n"); 396 exit(1); 397 } 398 launchdlaunched = 1; 399 break; 400 case 'L': 401 print_location = 1; 402 break; 403 case 'F': 404 if (launchdlaunched) { 405 fprintf(stderr, "-D and -F are mutually exclusive\n"); 406 exit(1); 407 } 408 printf("Foreground mode.\n"); 409 f_foreground = 1; 410 break; 411 case 'p': 412 lcconf->port_isakmp = atoi(optarg); 413 break; 414 case 'P': 415 lcconf->port_isakmp_natt = atoi(optarg); 416 break; 417 case 'a': 418 fprintf(stderr, "%s: the option is disabled " 419 "in the configuration\n", pname); 420 exit(1); 421 case 'f': 422 lcconf->racoon_conf = optarg; 423 break; 424 case 'l': 425 lcconf->logfile_param = optarg; 426 break; 427 case 'v': 428 vflag++; 429 break; 430 case 's': 431 lcconf->auto_exit_state &= ~LC_AUTOEXITSTATE_CLIENT; /* override default auto exit state */ 432 break; 433 case 'x': 434 exec_done = 1; 435 break; 436 case 'Z': 437 /* 438 * only local test. 439 * To specify -Z option and to choice a appropriate 440 * port number for ISAKMP, you can launch some racoons 441 * on the local host for debug. 442 * pk_sendadd() on initiator side is always failed 443 * even if this flag is used. Because there is same 444 * spi in the SAD which is inserted by pk_sendgetspi() 445 * on responder side. 446 */ 447 printf("Local test mode.\n"); 448 f_local = 1; 449 break; 450#ifdef YYDEBUG 451 case 'y': 452 yydebug = 1; 453 break; 454#endif 455#ifdef INET6 456 case '4': 457 lcconf->default_af = AF_INET; 458 break; 459 case '6': 460 lcconf->default_af = AF_INET6; 461 break; 462#endif 463 case 'C': 464 dump_config++; 465 break; 466 default: 467 usage(); 468 /* NOTREACHED */ 469 } 470 } 471 ac -= optind; 472 av += optind; 473 474 if (ac != 0) { 475 usage(); 476 /* NOTREACHED */ 477 } 478 479 return; 480} 481 482static void 483restore_params() 484{ 485 saverestore_params(1); 486} 487 488static void 489save_params() 490{ 491 saverestore_params(0); 492} 493 494static void 495saverestore_params(f) 496 int f; 497{ 498 static u_int16_t s_port_isakmp; 499 500 /* 0: save, 1: restore */ 501 if (f) { 502 lcconf->port_isakmp = s_port_isakmp; 503 } else { 504 s_port_isakmp = lcconf->port_isakmp; 505 } 506} 507