]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/main.c
ipsec-258.1.3.tar.gz
[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 "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
93 int f_local = 0; /* local test mode. behave like a wall. */
94 int vflag = 1; /* for print-isakmp.c */
95 static int dump_config = 0; /* dump parsed config file. */
96 static int exec_done = 0; /* we've already been exec'd */
97
98 #ifdef TOP_PACKAGE
99 static char version[] = "@(#)" TOP_PACKAGE_STRING " (" TOP_PACKAGE_URL ")";
100 #else /* TOP_PACKAGE */
101 static char version[] = "@(#) racoon / IPsec-tools";
102 #endif /* TOP_PACKAGE */
103
104 int main (int, char **);
105 static void usage (void);
106 static void parse (int, char **);
107 static void restore_params (void);
108 static void save_params (void);
109 static void saverestore_params (int);
110 static void cleanup_pidfile (void);
111 #if 0 // <rdar://problem/9286626>
112 int launchedbylaunchd (void);
113 #endif
114
115 pid_t racoon_pid = 0;
116 int launchdlaunched = 0;
117 int print_pid = 1; /* for racoon only */
118
119
120 void
121 usage()
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
149 int
150 main(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>
330 int
331 launchedbylaunchd(){
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;
347 done:
348 /* clean up before we leave */
349 if ( checkin_response )
350 launch_data_free(checkin_response);
351 return launchdlaunched;
352 }
353 #endif
354
355 static void
356 cleanup_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
376 static void
377 parse(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
495 static void
496 restore_params()
497 {
498 saverestore_params(1);
499 }
500
501 static void
502 save_params()
503 {
504 saverestore_params(0);
505 }
506
507 static void
508 saverestore_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 }