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