]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/main.c
631b86c9828dbe93b7a5507ff80b27633507ded0
[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 #include "power_mgmt.h"
86 #include "preferences.h"
87
88 //#include "package_version.h"
89
90 int f_local = 0; /* local test mode. behave like a wall. */
91 int vflag = 1; /* for print-isakmp.c */
92 static int dump_config = 0; /* dump parsed config file. */
93 static int exec_done = 0; /* we've already been exec'd */
94
95 #ifdef TOP_PACKAGE
96 static char version[] = "@(#)" TOP_PACKAGE_STRING " (" TOP_PACKAGE_URL ")";
97 #else /* TOP_PACKAGE */
98 static char version[] = "@(#) racoon / IPsec-tools";
99 #endif /* TOP_PACKAGE */
100
101 int main (int, char **);
102 static void usage (void);
103 static void parse (int, char **);
104 static void restore_params (void);
105 static void save_params (void);
106 static void saverestore_params (int);
107 static void cleanup_pidfile (void);
108 #if 0 // <rdar://problem/9286626>
109 int launchedbylaunchd (void);
110 #endif
111
112 pid_t racoon_pid = 0;
113 int launchdlaunched = 0;
114 int print_pid = 1; /* for racoon only */
115
116
117 void
118 usage()
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
146 int
147 main(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>
317 int
318 launchedbylaunchd(){
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;
334 done:
335 /* clean up before we leave */
336 if ( checkin_response )
337 launch_data_free(checkin_response);
338 return launchdlaunched;
339 }
340 #endif
341
342 static void
343 cleanup_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
363 static void
364 parse(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
482 static void
483 restore_params()
484 {
485 saverestore_params(1);
486 }
487
488 static void
489 save_params()
490 {
491 saverestore_params(0);
492 }
493
494 static void
495 saverestore_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 }