]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/main.c
7b4f04993d25f7f273351c337beb50ab73c3de6e
[apple/ipsec.git] / ipsec-tools / racoon / main.c
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 "backupsa.h"
83 #include "vendorid.h"
84
85 #include <CoreFoundation/CoreFoundation.h>
86 #include <SystemConfiguration/SystemConfiguration.h>
87 #ifndef TARGET_OS_EMBEDDED
88 #include <sandbox.h>
89 #endif // !TARGET_OS_EMBEDDED
90 #include "power_mgmt.h"
91
92 //#include "package_version.h"
93
94 int f_local = 0; /* local test mode. behave like a wall. */
95 int vflag = 1; /* for print-isakmp.c */
96 static int loading_sa = 0; /* install sa when racoon boots up. */
97 static int dump_config = 0; /* dump parsed config file. */
98 static int exec_done = 0; /* we've already been exec'd */
99
100 #ifdef TOP_PACKAGE
101 static char version[] = "@(#)" TOP_PACKAGE_STRING " (" TOP_PACKAGE_URL ")";
102 #else /* TOP_PACKAGE */
103 static char version[] = "@(#) racoon / IPsec-tools";
104 #endif /* TOP_PACKAGE */
105
106 int main __P((int, char **));
107 static void usage __P((void));
108 static void parse __P((int, char **));
109 static void restore_params __P((void));
110 static void save_params __P((void));
111 static void saverestore_params __P((int));
112 static void cleanup_pidfile __P((void));
113 #if 0 // <rdar://problem/9286626>
114 int launchedbylaunchd __P((void));
115 #endif
116
117 pid_t racoon_pid = 0;
118 int launchdlaunched = 0;
119 int print_pid = 1; /* for racoon only */
120 char logFileStr[MAXPATHLEN+1];
121
122 void
123 usage()
124 {
125 printf("usage: racoon [-BdDFvs%s] %s[-f (file)] [-l (file)] [-p (port)]\n",
126 #ifdef INET6
127 "46",
128 #else
129 "",
130 #endif
131 #ifdef ENABLE_ADMINPORT
132 "[-a (port)] "
133 #else
134 ""
135 #endif
136 );
137 printf(" -B: install SA to the kernel from the file "
138 "specified by the configuration file.\n");
139 printf(" -d: debug level, more -d will generate more debug message.\n");
140 printf(" -D: started by LaunchD (implies daemon mode).\n");
141 printf(" -C: dump parsed config file.\n");
142 printf(" -L: include location in debug messages\n");
143 printf(" -F: run in foreground, do not become daemon.\n");
144 printf(" -v: be more verbose\n");
145 printf(" -s: override enable auto exit\n");
146 #ifdef INET6
147 printf(" -4: IPv4 mode.\n");
148 printf(" -6: IPv6 mode.\n");
149 #endif
150 #ifdef ENABLE_ADMINPORT
151 printf(" -a: port number for admin port.\n");
152 #endif
153 printf(" -f: pathname for configuration file.\n");
154 printf(" -l: pathname for log file.\n");
155 printf(" -p: port number for isakmp (default: %d).\n", PORT_ISAKMP);
156 printf(" -P: port number for NAT-T (default: %d).\n", PORT_ISAKMP_NATT);
157 exit(1);
158 }
159
160 int
161 main(ac, av)
162 int ac;
163 char **av;
164 {
165 int error;
166 #ifndef TARGET_OS_EMBEDDED
167 char *sb_errorbuf = NULL;
168 #endif // !TARGET_OS_EMBEDDED
169
170 #ifndef TARGET_OS_EMBEDDED
171 if (sandbox_init("racoon", SANDBOX_NAMED, &sb_errorbuf) == -1) {
172 if (sb_errorbuf) {
173 syslog(LOG_ERR, "sandbox_init failed: %s\n", sb_errorbuf);
174 sandbox_free_error(sb_errorbuf);
175 sb_errorbuf = NULL;
176 } else {
177 syslog(LOG_ERR, "sandbox_init failed\n");
178 }
179 }
180 #endif // !TARGET_OS_EMBEDDED
181
182 if (geteuid() != 0) {
183 errx(1, "must be root to invoke this program.");
184 /* NOTREACHED*/
185 }
186
187 /*
188 * Don't let anyone read files I write. Although some files (such as
189 * the PID file) can be other readable, we dare to use the global mask,
190 * because racoon uses fopen(3), which can't specify the permission
191 * at the creation time.
192 */
193 umask(077);
194 if (umask(077) != 077) {
195 errx(1, "could not set umask");
196 /* NOTREACHED*/
197 }
198
199 #ifdef DEBUG_RECORD_MALLOCATION
200 DRM_init();
201 #endif
202
203 logFileStr[0] = 0;
204
205 #ifdef HAVE_OPENSSL
206 eay_init();
207 #endif
208
209 initlcconf();
210 initrmconf();
211 oakley_dhinit();
212 compute_vendorids();
213
214 parse(ac, av);
215 plogmtxinit();
216
217 /*
218 * Check IPSec plist
219 */
220 {
221 SCPreferencesRef prefs = NULL;
222 CFPropertyListRef globals;
223 CFStringRef logFileRef;
224 CFNumberRef debugLevelRef;
225
226 int level = 0;
227
228 logFileStr[0] = 0;
229
230 if ((prefs = SCPreferencesCreate(0, CFSTR("racoon"), CFSTR("com.apple.ipsec.plist"))) == NULL)
231 goto skip;
232 globals = SCPreferencesGetValue(prefs, CFSTR("Global"));
233 if (!globals || (CFGetTypeID(globals) != CFDictionaryGetTypeID()))
234 goto skip;
235 debugLevelRef = CFDictionaryGetValue(globals, CFSTR("DebugLevel"));
236 if (!debugLevelRef || (CFGetTypeID(debugLevelRef) != CFNumberGetTypeID()))
237 goto skip;
238 CFNumberGetValue(debugLevelRef, kCFNumberSInt32Type, &level);
239 switch (level)
240 {
241 case 0:
242 loglevel = 5;
243 goto skip;
244 break;
245 case 1:
246 loglevel = 6;
247 break;
248 case 2:
249 loglevel = 7;
250 break;
251 default:
252 break; /* invalid - ignore */
253 }
254
255 logFileRef = CFDictionaryGetValue(globals, CFSTR("DebugLogfile"));
256 if (!logFileRef || (CFGetTypeID(logFileRef) != CFStringGetTypeID())) {
257 goto skip;
258 }
259 CFStringGetCString(logFileRef, logFileStr, MAXPATHLEN, kCFStringEncodingMacRoman);
260 skip:
261 if (prefs)
262 CFRelease(prefs);
263 }
264
265 if (logFileStr[0])
266 plogset(logFileStr);
267 else
268 if (lcconf->logfile_param)
269 plogset(lcconf->logfile_param);
270
271 ploginit();
272
273 plog(LLV_INFO, LOCATION, NULL, "***** racoon started: pid=%d started by: %d, launchdlaunched %d\n", getpid(), getppid(), launchdlaunched);
274 plog(LLV_INFO, LOCATION, NULL, "%s\n", version);
275 #ifdef HAVE_OPENSSL
276 plog(LLV_INFO, LOCATION, NULL, "@(#)"
277 "This product linked %s (http://www.openssl.org/)"
278 "\n", eay_version());
279 #endif
280 plog(LLV_INFO, LOCATION, NULL, "Reading configuration from \"%s\"\n",
281 lcconf->racoon_conf);
282
283 if (pfkey_init() < 0) {
284 errx(1, "something error happened "
285 "while pfkey initializing.");
286 /* NOTREACHED*/
287 }
288
289 #ifdef ENABLE_HYBRID
290 if (isakmp_cfg_init(ISAKMP_CFG_INIT_COLD))
291 errx(1, "could not initialize ISAKMP mode config structures");
292 #endif
293
294 #ifdef HAVE_LIBLDAP
295 if (xauth_ldap_init() != 0)
296 errx(1, "could not initialize libldap");
297 #endif
298
299 /*
300 * in order to prefer the parameters by command line,
301 * saving some parameters before parsing configuration file.
302 */
303 save_params();
304 error = cfparse();
305 if (error != 0)
306 errx(1, "failed to parse configuration file.");
307 restore_params();
308
309 if (lcconf->logfile_param == NULL && logFileStr[0] == 0)
310 plogreset(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]);
311
312 #ifdef ENABLE_NATT
313 /* Tell the kernel which port to use for UDP encapsulation */
314 {
315 int udp_port = PORT_ISAKMP_NATT;
316 if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, &udp_port, sizeof(udp_port)) != 0)
317 errx(1, "couldn't set net.inet.ipsec.esp_port to %d. (%s)",
318 udp_port, strerror(errno));
319 }
320 #endif
321
322 #ifdef HAVE_LIBRADIUS
323 if (xauth_radius_init() != 0) {
324 errx(1, "could not initialize libradius");
325 /* NOTREACHED*/
326 }
327 #endif
328
329 #ifdef ENABLE_HYBRID
330 if(isakmp_cfg_config.network4 && isakmp_cfg_config.pool_size == 0)
331 if ((error = isakmp_cfg_resize_pool(ISAKMP_CFG_MAX_CNX)) != 0)
332 return error;
333 #endif
334
335 if (dump_config)
336 dumprmconf ();
337
338 /*
339 * install SAs from the specified file. If the file is not specified
340 * by the configuration file, racoon will exit.
341 */
342 if (loading_sa && !f_local) {
343 if (backupsa_from_file() != 0)
344 errx(1, "something error happened "
345 "SA recovering.");
346 }
347
348 if (f_foreground)
349 close(0);
350 else {
351 if ( !exec_done && launchdlaunched ){
352 plog(LLV_INFO, LOCATION, NULL,
353 "racoon launched by launchd.\n");
354 exec_done = 1;
355 if (atexit(cleanup_pidfile) < 0) {
356 plog(LLV_ERROR, LOCATION, NULL,
357 "cannot register pidfile cleanup");
358 }
359 }else {
360
361 if (exec_done) {
362 if (atexit(cleanup_pidfile) < 0) {
363 plog(LLV_ERROR, LOCATION, NULL,
364 "cannot register pidfile cleanup");
365 }
366 } else {
367 #define MAX_EXEC_ARGS 32
368
369 char *args[MAX_EXEC_ARGS + 2]; /* 2 extra, for '-x' and NULL */
370 char *env[1] = {0};
371 int i;
372
373 if (ac > MAX_EXEC_ARGS) {
374 plog(LLV_ERROR, LOCATION, NULL,
375 "too many arguments.\n");
376 exit(1);
377 }
378
379 if (daemon(0, 0) < 0) {
380 errx(1, "failed to be daemon. (%s)",
381 strerror(errno));
382 }
383
384 /* Radar 5129006 - Prevent non-root user from killing racoon
385 * when launched by setuid process
386 */
387 if (setuid(0)) {
388 plog(LLV_ERROR, LOCATION, NULL,
389 "cannot set uid.\n");
390 exit(1);
391 }
392 if (setgid(0)) {
393 plog(LLV_ERROR, LOCATION, NULL,
394 "cannot set gid.\n");
395 exit(1);
396 }
397
398 /* setup args to re-exec - for CoreFoundation issues */
399 args[0] = PATHRACOON;
400 for (i = 1; i < ac; i++)
401 args[i] = *(av + i);
402 args[ac] = "-x"; /* tells racoon its been exec'd */
403 args[ac+1] = 0;
404
405 execve(PATHRACOON, args, env);
406 plog(LLV_ERROR, LOCATION, NULL,
407 "failed to exec racoon. (%s)", strerror(errno));
408 exit(1);
409 }
410 }
411 }
412
413 session();
414
415 exit(0);
416 }
417
418 #if 0 // <rdar://problem/9286626>
419 int
420 launchedbylaunchd(){
421 launch_data_t checkin_response = NULL;
422
423 if ((checkin_response = launch_socket_service_check_in()) == NULL) {
424 plog(LLV_ERROR, LOCATION, NULL,
425 "launch_socket_service_check_in fails.\n");
426 launchdlaunched = 0;
427 goto done;
428 }
429 if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) {
430 plog(LLV_ERROR, LOCATION, NULL,
431 "launch_data_get_type fails errno %d.\n", launch_data_get_errno(checkin_response));
432 launchdlaunched = 0;
433 goto done;
434 }
435 launchdlaunched = 1;
436 done:
437 /* clean up before we leave */
438 if ( checkin_response )
439 launch_data_free(checkin_response);
440 return launchdlaunched;
441 }
442 #endif
443
444 static void
445 cleanup_pidfile()
446 {
447 char pid_file[MAXPATHLEN];
448 pid_t p = getpid();
449
450 /* if it's not child process, clean everything */
451 if (racoon_pid == p) {
452 if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL)
453 strlcpy(pid_file, _PATH_VARRUN "racoon.pid", sizeof(pid_file));
454 else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/')
455 strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file));
456 else {
457 strlcat(pid_file, _PATH_VARRUN, sizeof(pid_file));
458 strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file));
459 }
460 (void) unlink(pid_file);
461 }
462 }
463
464
465 static void
466 parse(ac, av)
467 int ac;
468 char **av;
469 {
470 extern char *optarg;
471 extern int optind;
472 int c;
473 #ifdef YYDEBUG
474 extern int yydebug;
475 #endif
476
477 pname = strrchr(*av, '/');
478 if (pname)
479 pname++;
480 else
481 pname = *av;
482
483 #if 0 /* for debugging */
484 loglevel += 2;
485 plogset("/tmp/racoon.log");
486 #endif
487
488 while ((c = getopt(ac, av, "dDLFp:P:a:f:l:vsZBCx"
489 #ifdef YYDEBUG
490 "y"
491 #endif
492 #ifdef INET6
493 "46"
494 #endif
495 )) != -1) {
496 switch (c) {
497 case 'd':
498 loglevel++;
499 break;
500 case 'D':
501 if (f_foreground) {
502 fprintf(stderr, "-D and -F are mutually exclusive\n");
503 exit(1);
504 }
505 launchdlaunched = 1;
506 break;
507 case 'L':
508 print_location = 1;
509 break;
510 case 'F':
511 if (launchdlaunched) {
512 fprintf(stderr, "-D and -F are mutually exclusive\n");
513 exit(1);
514 }
515 printf("Foreground mode.\n");
516 f_foreground = 1;
517 break;
518 case 'p':
519 lcconf->port_isakmp = atoi(optarg);
520 break;
521 case 'P':
522 lcconf->port_isakmp_natt = atoi(optarg);
523 break;
524 case 'a':
525 #ifdef ENABLE_ADMINPORT
526 lcconf->port_admin = atoi(optarg);
527 break;
528 #else
529 fprintf(stderr, "%s: the option is disabled "
530 "in the configuration\n", pname);
531 exit(1);
532 #endif
533 case 'f':
534 lcconf->racoon_conf = optarg;
535 break;
536 case 'l':
537 lcconf->logfile_param = optarg;
538 break;
539 case 'v':
540 vflag++;
541 break;
542 case 's':
543 lcconf->auto_exit_state &= ~LC_AUTOEXITSTATE_CLIENT; /* override default auto exit state */
544 break;
545 case 'x':
546 exec_done = 1;
547 break;
548 case 'Z':
549 /*
550 * only local test.
551 * To specify -Z option and to choice a appropriate
552 * port number for ISAKMP, you can launch some racoons
553 * on the local host for debug.
554 * pk_sendadd() on initiator side is always failed
555 * even if this flag is used. Because there is same
556 * spi in the SAD which is inserted by pk_sendgetspi()
557 * on responder side.
558 */
559 printf("Local test mode.\n");
560 f_local = 1;
561 break;
562 #ifdef YYDEBUG
563 case 'y':
564 yydebug = 1;
565 break;
566 #endif
567 #ifdef INET6
568 case '4':
569 lcconf->default_af = AF_INET;
570 break;
571 case '6':
572 lcconf->default_af = AF_INET6;
573 break;
574 #endif
575 case 'B':
576 loading_sa++;
577 break;
578 case 'C':
579 dump_config++;
580 break;
581 default:
582 usage();
583 /* NOTREACHED */
584 }
585 }
586 ac -= optind;
587 av += optind;
588
589 if (ac != 0) {
590 usage();
591 /* NOTREACHED */
592 }
593
594 return;
595 }
596
597 static void
598 restore_params()
599 {
600 saverestore_params(1);
601 }
602
603 static void
604 save_params()
605 {
606 saverestore_params(0);
607 }
608
609 static void
610 saverestore_params(f)
611 int f;
612 {
613 static u_int16_t s_port_isakmp;
614 #ifdef ENABLE_ADMINPORT
615 static u_int16_t s_port_admin;
616 #endif
617
618 /* 0: save, 1: restore */
619 if (f) {
620 lcconf->port_isakmp = s_port_isakmp;
621 #ifdef ENABLE_ADMINPORT
622 lcconf->port_admin = s_port_admin;
623 #endif
624 } else {
625 s_port_isakmp = lcconf->port_isakmp;
626 #ifdef ENABLE_ADMINPORT
627 s_port_admin = lcconf->port_admin;
628 #endif
629 }
630 }