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