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