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