Beispiel #1
0
static bool test_runner_init(bool init)
{
	bool result = TRUE;

	if (init)
	{
		libhydra_init("test_runner");
		libcharon_init("test_runner");
		lib->settings->set_int(lib->settings,
							   "test_runner.filelog.stdout.default", 0);
		charon->load_loggers(charon, NULL, FALSE);

		/* Register TKM specific plugins */
		static plugin_feature_t features[] = {
			PLUGIN_REGISTER(NONCE_GEN, tkm_nonceg_create),
				PLUGIN_PROVIDE(NONCE_GEN),
			PLUGIN_CALLBACK(kernel_ipsec_register, tkm_kernel_ipsec_create),
				PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
		};
		lib->plugins->add_static_features(lib->plugins, "tkm-tests", features,
										  countof(features), TRUE);

		lib->settings->set_int(lib->settings, "%s.dh_mapping.%d", 1,
							   charon->name, MODP_3072_BIT);
		lib->settings->set_int(lib->settings, "%s.dh_mapping.%d", 2,
							   charon->name, MODP_4096_BIT);
		register_dh_mapping();

		plugin_loader_add_plugindirs(BUILDDIR "/src/libstrongswan/plugins",
									 PLUGINS);
		plugin_loader_add_plugindirs(BUILDDIR "/src/libhydra/plugins",
									 PLUGINS);
		plugin_loader_add_plugindirs(BUILDDIR "/src/libcharon/plugins",
									 PLUGINS);
		if (charon->initialize(charon, PLUGINS))
		{
			if (!tkm_initialized)
			{
				if (!tkm_init())
				{
					return FALSE;
				}
				tkm_initialized = true;
			}
			return TRUE;
		}
		result = FALSE;
	}

	destroy_dh_mapping();
	libcharon_deinit();
	libhydra_deinit();
	return result;
}
Beispiel #2
0
static bool test_runner_init(bool init)
{
	if (init)
	{
		libhydra_init();
	}
	else
	{
		lib->processor->set_threads(lib->processor, 0);
		lib->processor->cancel(lib->processor);
		libhydra_deinit();
	}
	return TRUE;
}
Beispiel #3
0
/**
 * Main function, starts the daemon.
 */
int main(int argc, char *argv[])
{
	struct sigaction action;
	struct utsname utsname;
	int group;

	dbg = dbg_stderr;
	atexit(library_deinit);
	if (!library_init(NULL))
	{
		exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
	}
	if (lib->integrity)
	{
		if (!lib->integrity->check_file(lib->integrity, "charon-xpc", argv[0]))
		{
			exit(SS_RC_DAEMON_INTEGRITY);
		}
	}
	atexit(libhydra_deinit);
	if (!libhydra_init("charon-xpc"))
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	atexit(libcharon_deinit);
	if (!libcharon_init("charon-xpc"))
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	for (group = 0; group < DBG_MAX; group++)
	{
		levels[group] = LEVEL_CTRL;
	}
	charon->load_loggers(charon, levels, TRUE);

	lib->settings->set_default_str(lib->settings, "charon-xpc.port", "0");
	lib->settings->set_default_str(lib->settings, "charon-xpc.port_nat_t", "0");
	lib->settings->set_default_str(lib->settings,
								"charon-xpc.close_ike_on_child_failure", "yes");
	if (!charon->initialize(charon,
			lib->settings->get_str(lib->settings, "charon-xpc.load",
				"random nonce pem pkcs1 openssl kernel-pfkey kernel-pfroute "
				"keychain socket-default eap-identity eap-mschapv2 osx-attr")))
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}

	if (uname(&utsname) != 0)
	{
		memset(&utsname, 0, sizeof(utsname));
	}
	DBG1(DBG_DMN, "Starting charon-xpc IKE daemon (strongSwan %s, %s %s, %s)",
		 VERSION, utsname.sysname, utsname.release, utsname.machine);

	/* add handler for SEGV and ILL,
	 * INT, TERM and HUP are handled by sigwait() in run() */
	action.sa_handler = segv_handler;
	action.sa_flags = 0;
	sigemptyset(&action.sa_mask);
	sigaddset(&action.sa_mask, SIGINT);
	sigaddset(&action.sa_mask, SIGTERM);
	sigaddset(&action.sa_mask, SIGHUP);
	sigaction(SIGSEGV, &action, NULL);
	sigaction(SIGILL, &action, NULL);
	sigaction(SIGBUS, &action, NULL);
	action.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &action, NULL);

	pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);

	dispatcher = xpc_dispatch_create();
	if (!dispatcher)
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	atexit(dispatcher_cleanup);

	charon->start(charon);
	return run();
}
Beispiel #4
0
/**
 * Main function, starts the conftest daemon.
 */
int main(int argc, char *argv[])
{
	struct sigaction action;
	int status = 0;
	sigset_t set;
	int sig;
	char *suite_file = "suite.conf", *test_file = NULL;
	file_logger_t *logger;

	if (!library_init(NULL))
	{
		library_deinit();
		return SS_RC_LIBSTRONGSWAN_INTEGRITY;
	}
	if (!libhydra_init("conftest"))
	{
		libhydra_deinit();
		library_deinit();
		return SS_RC_INITIALIZATION_FAILED;
	}
	if (!libcharon_init("conftest"))
	{
		libcharon_deinit();
		libhydra_deinit();
		library_deinit();
		return SS_RC_INITIALIZATION_FAILED;
	}

	INIT(conftest,
		.creds = mem_cred_create(),
		.config = config_create(),
		.hooks = linked_list_create(),
		.loggers = linked_list_create(),
	);
	lib->credmgr->add_set(lib->credmgr, &conftest->creds->set);

	logger = file_logger_create("stdout");
	logger->set_options(logger, NULL, FALSE);
	logger->open(logger, FALSE, FALSE);
	logger->set_level(logger, DBG_ANY, LEVEL_CTRL);
	charon->bus->add_logger(charon->bus, &logger->logger);
	conftest->loggers->insert_last(conftest->loggers, logger);

	atexit(cleanup);

	while (TRUE)
	{
		struct option long_opts[] = {
			{ "help", no_argument, NULL, 'h' },
			{ "version", no_argument, NULL, 'v' },
			{ "suite", required_argument, NULL, 's' },
			{ "test", required_argument, NULL, 't' },
			{ 0,0,0,0 }
		};
		switch (getopt_long(argc, argv, "", long_opts, NULL))
		{
			case EOF:
				break;
			case 'h':
				usage(stdout);
				return 0;
			case 'v':
				printf("strongSwan %s conftest\n", VERSION);
				return 0;
			case 's':
				suite_file = optarg;
				continue;
			case 't':
				test_file = optarg;
				continue;
			default:
				usage(stderr);
				return 1;
		}
		break;
	}

	if (!load_configs(suite_file, test_file))
	{
		return 1;
	}
	load_loggers(logger);

	if (!lib->plugins->load(lib->plugins, NULL,
			conftest->test->get_str(conftest->test, "preload", "")))
	{
		return 1;
	}
	if (!charon->initialize(charon, PLUGINS))
	{
		return 1;
	}
	if (!load_certs(conftest->test, conftest->suite_dir))
	{
		return 1;
	}
	if (!load_keys(conftest->test, conftest->suite_dir))
	{
		return 1;
	}
	load_cdps(conftest->test);
	if (!load_hooks())
	{
		return 1;
	}
	charon->backends->add_backend(charon->backends, &conftest->config->backend);
	conftest->config->load(conftest->config, conftest->test);
	conftest->actions = actions_create();

	/* set up thread specific handlers */
	action.sa_handler = segv_handler;
	action.sa_flags = 0;
	sigemptyset(&action.sa_mask);
	sigaddset(&action.sa_mask, SIGINT);
	sigaddset(&action.sa_mask, SIGTERM);
	sigaddset(&action.sa_mask, SIGHUP);
	sigaction(SIGSEGV, &action, NULL);
	sigaction(SIGILL, &action, NULL);
	sigaction(SIGBUS, &action, NULL);
	action.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &action, NULL);
	pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);

	/* start thread pool */
	charon->start(charon);

	/* handle SIGINT/SIGTERM in main thread */
	sigemptyset(&set);
	sigaddset(&set, SIGINT);
	sigaddset(&set, SIGHUP);
	sigaddset(&set, SIGTERM);
	sigprocmask(SIG_BLOCK, &set, NULL);

	while (sigwait(&set, &sig) == 0)
	{
		switch (sig)
		{
			case SIGINT:
			case SIGTERM:
				fprintf(stderr, "\nshutting down...\n");
				break;
			default:
				continue;
		}
		break;
	}
	return status;
}
Beispiel #5
0
/**
 * Main function, starts the daemon.
 */
int main(int argc, char *argv[])
{
	struct sigaction action;
	struct utsname utsname;
	int group;

	/* handle simple arguments */
	handle_arguments(argc, argv, TRUE);

	dbg = dbg_stderr;
	atexit(library_deinit);
	if (!library_init(NULL, "charon-cmd"))
	{
		exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
	}
	if (lib->integrity)
	{
		if (!lib->integrity->check_file(lib->integrity, "charon-cmd", argv[0]))
		{
			exit(SS_RC_DAEMON_INTEGRITY);
		}
	}
	atexit(libhydra_deinit);
	if (!libhydra_init())
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	atexit(libcharon_deinit);
	if (!libcharon_init())
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	for (group = 0; group < DBG_MAX; group++)
	{
		levels[group] = default_loglevel;
	}
	charon->load_loggers(charon, levels, TRUE);

	if (!lookup_uid_gid())
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0");
	lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0");
	if (!charon->initialize(charon,
			lib->settings->get_str(lib->settings, "charon-cmd.load", PLUGINS)))
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	if (!lib->caps->drop(lib->caps))
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}

	conn = cmd_connection_create();
	atexit(cleanup_conn);
	creds = cmd_creds_create();
	atexit(cleanup_creds);

	/* handle all arguments */
	handle_arguments(argc, argv, FALSE);

	if (uname(&utsname) != 0)
	{
		memset(&utsname, 0, sizeof(utsname));
	}
	DBG1(DBG_DMN, "Starting charon-cmd IKE client (strongSwan %s, %s %s, %s)",
		 VERSION, utsname.sysname, utsname.release, utsname.machine);
	lib->plugins->status(lib->plugins, LEVEL_CTRL);

	/* add handler for SEGV and ILL,
	 * INT, TERM and HUP are handled by sigwait() in run() */
	action.sa_handler = segv_handler;
	action.sa_flags = 0;
	sigemptyset(&action.sa_mask);
	sigaddset(&action.sa_mask, SIGINT);
	sigaddset(&action.sa_mask, SIGTERM);
	sigaddset(&action.sa_mask, SIGHUP);
	sigaddset(&action.sa_mask, SIGUSR1);
	sigaction(SIGSEGV, &action, NULL);
	sigaction(SIGILL, &action, NULL);
	sigaction(SIGBUS, &action, NULL);
	action.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &action, NULL);

	pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);

	/* start daemon with thread-pool */
	charon->start(charon);
	/* wait for signal */
	return run();
}
Beispiel #6
0
/**
 * Main function, starts the daemon.
 */
int main(int argc, char *argv[])
{
	struct sigaction action;
	int group, status = SS_RC_INITIALIZATION_FAILED;
	struct utsname utsname;

	/* logging for library during initialization, as we have no bus yet */
	dbg = dbg_stderr;

	/* initialize library */
	if (!library_init(NULL, "charon"))
	{
		library_deinit();
		exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
	}

	if (lib->integrity &&
		!lib->integrity->check_file(lib->integrity, "charon", argv[0]))
	{
		dbg_stderr(DBG_DMN, 1, "integrity check of charon failed");
		library_deinit();
		exit(SS_RC_DAEMON_INTEGRITY);
	}

	if (!libhydra_init())
	{
		dbg_stderr(DBG_DMN, 1, "initialization failed - aborting charon");
		libhydra_deinit();
		library_deinit();
		exit(SS_RC_INITIALIZATION_FAILED);
	}

	if (!libcharon_init())
	{
		dbg_stderr(DBG_DMN, 1, "initialization failed - aborting charon");
		goto deinit;
	}

	/* use CTRL loglevel for default */
	for (group = 0; group < DBG_MAX; group++)
	{
		levels[group] = LEVEL_CTRL;
	}

	/* handle arguments */
	for (;;)
	{
		struct option long_opts[] = {
			{ "help", no_argument, NULL, 'h' },
			{ "version", no_argument, NULL, 'v' },
			{ "use-syslog", no_argument, NULL, 'l' },
			/* TODO: handle "debug-all" */
			{ "debug-dmn", required_argument, &group, DBG_DMN },
			{ "debug-mgr", required_argument, &group, DBG_MGR },
			{ "debug-ike", required_argument, &group, DBG_IKE },
			{ "debug-chd", required_argument, &group, DBG_CHD },
			{ "debug-job", required_argument, &group, DBG_JOB },
			{ "debug-cfg", required_argument, &group, DBG_CFG },
			{ "debug-knl", required_argument, &group, DBG_KNL },
			{ "debug-net", required_argument, &group, DBG_NET },
			{ "debug-asn", required_argument, &group, DBG_ASN },
			{ "debug-enc", required_argument, &group, DBG_ENC },
			{ "debug-tnc", required_argument, &group, DBG_TNC },
			{ "debug-imc", required_argument, &group, DBG_IMC },
			{ "debug-imv", required_argument, &group, DBG_IMV },
			{ "debug-pts", required_argument, &group, DBG_PTS },
			{ "debug-tls", required_argument, &group, DBG_TLS },
			{ "debug-esp", required_argument, &group, DBG_ESP },
			{ "debug-lib", required_argument, &group, DBG_LIB },
			{ 0,0,0,0 }
		};

		int c = getopt_long(argc, argv, "", long_opts, NULL);
		switch (c)
		{
			case EOF:
				break;
			case 'h':
				usage(NULL);
				status = 0;
				goto deinit;
			case 'v':
				printf("Linux strongSwan %s\n", VERSION);
				status = 0;
				goto deinit;
			case 'l':
				use_syslog = TRUE;
				continue;
			case 0:
				/* option is in group */
				levels[group] = atoi(optarg);
				continue;
			default:
				usage("");
				status = 1;
				goto deinit;
		}
		break;
	}

	if (!lookup_uid_gid())
	{
		dbg_stderr(DBG_DMN, 1, "invalid uid/gid - aborting charon");
		goto deinit;
	}

	charon->load_loggers(charon, levels, !use_syslog);

	if (uname(&utsname) != 0)
	{
		memset(&utsname, 0, sizeof(utsname));
	}
	DBG1(DBG_DMN, "Starting IKE charon daemon (strongSwan "VERSION", %s %s, %s)",
		  utsname.sysname, utsname.release, utsname.machine);
	if (lib->integrity)
	{
		DBG1(DBG_DMN, "integrity tests enabled:");
		DBG1(DBG_DMN, "lib    'libstrongswan': passed file and segment integrity tests");
		DBG1(DBG_DMN, "lib    'libhydra': passed file and segment integrity tests");
		DBG1(DBG_DMN, "lib    'libcharon': passed file and segment integrity tests");
		DBG1(DBG_DMN, "daemon 'charon': passed file integrity test");
	}

	/* initialize daemon */
	if (!charon->initialize(charon,
				lib->settings->get_str(lib->settings, "charon.load", PLUGINS)))
	{
		DBG1(DBG_DMN, "initialization failed - aborting charon");
		goto deinit;
	}
	lib->plugins->status(lib->plugins, LEVEL_CTRL);

	if (check_pidfile())
	{
		DBG1(DBG_DMN, "charon already running (\""PID_FILE"\" exists)");
		goto deinit;
	}

	if (!lib->caps->drop(lib->caps))
	{
		DBG1(DBG_DMN, "capability dropping failed - aborting charon");
		goto deinit;
	}

	/* add handler for SEGV and ILL,
	 * INT, TERM and HUP are handled by sigwaitinfo() in run() */
	action.sa_handler = segv_handler;
	action.sa_flags = 0;
	sigemptyset(&action.sa_mask);
	sigaddset(&action.sa_mask, SIGINT);
	sigaddset(&action.sa_mask, SIGTERM);
	sigaddset(&action.sa_mask, SIGHUP);
	sigaction(SIGSEGV, &action, NULL);
	sigaction(SIGILL, &action, NULL);
	sigaction(SIGBUS, &action, NULL);
	action.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &action, NULL);

	pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);

	/* start daemon (i.e. the threads in the thread-pool) */
	charon->start(charon);

	/* main thread goes to run loop */
	run();

	/* normal termination, cleanup and exit */
	unlink_pidfile();
	status = 0;

deinit:
	libcharon_deinit();
	libhydra_deinit();
	library_deinit();
	return status;
}
Beispiel #7
0
/**
 * Main function, starts TKM backend.
 */
int main(int argc, char *argv[])
{
	char *dmn_name;
	if (argc > 0 && strlen(argv[0]) > 0)
	{
		dmn_name = basename(argv[0]);
	}
	else
	{
		dmn_name = "charon-tkm";
	}

	/* TKM credential set */
	tkm_cred_t *creds;

	struct sigaction action;
	int status = SS_RC_INITIALIZATION_FAILED;

	/* logging for library during initialization, as we have no bus yet */
	dbg = dbg_syslog;

	/* initialize library */
	if (!library_init(NULL, dmn_name))
	{
		library_deinit();
		exit(status);
	}

	if (!libhydra_init())
	{
		dbg_syslog(DBG_DMN, 1, "initialization failed - aborting %s", dmn_name);
		libhydra_deinit();
		library_deinit();
		exit(status);
	}

	if (!libcharon_init())
	{
		dbg_syslog(DBG_DMN, 1, "initialization failed - aborting %s", dmn_name);
		goto deinit;
	}

	if (!lookup_uid_gid())
	{
		dbg_syslog(DBG_DMN, 1, "invalid uid/gid - aborting %s", dmn_name);
		goto deinit;
	}

	/* make sure we log to the DAEMON facility by default */
	lib->settings->set_int(lib->settings, "%s.syslog.daemon.default",
			lib->settings->get_int(lib->settings, "%s.syslog.daemon.default", 1,
								   dmn_name), dmn_name);
	charon->load_loggers(charon, NULL, FALSE);

	DBG1(DBG_DMN, "Starting charon with TKM backend (strongSwan "VERSION")");

	/* register TKM specific plugins */
	static plugin_feature_t features[] = {
		PLUGIN_REGISTER(NONCE_GEN, tkm_nonceg_create),
			PLUGIN_PROVIDE(NONCE_GEN),
		PLUGIN_REGISTER(PUBKEY, tkm_public_key_load, TRUE),
			PLUGIN_PROVIDE(PUBKEY, KEY_RSA),
			PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA1),
			PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA256),
		PLUGIN_CALLBACK(kernel_ipsec_register, tkm_kernel_ipsec_create),
			PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
	};
	lib->plugins->add_static_features(lib->plugins, "tkm-backend", features,
			countof(features), TRUE);

	if (!register_dh_mapping())
	{
		DBG1(DBG_DMN, "no DH group mapping defined - aborting %s", dmn_name);
		goto deinit;
	}

	/* register TKM keymat variant */
	keymat_register_constructor(IKEV2, (keymat_constructor_t)tkm_keymat_create);

	/* initialize daemon */
	if (!charon->initialize(charon, PLUGINS))
	{
		DBG1(DBG_DMN, "initialization failed - aborting %s", dmn_name);
		goto deinit;
	}
	lib->plugins->status(lib->plugins, LEVEL_CTRL);

	/* set global pidfile name depending on daemon name */
	if (asprintf(&pidfile_name, IPSEC_PIDDIR"/%s.pid", dmn_name) < 0)
	{
		DBG1(DBG_DMN, "unable to set pidfile name - aborting %s", dmn_name);
		goto deinit;
	};

	if (check_pidfile())
	{
		DBG1(DBG_DMN, "%s already running (\"%s\" exists)", dmn_name,
			 pidfile_name);
		goto deinit;
	}

	if (!lib->caps->drop(lib->caps))
	{
		DBG1(DBG_DMN, "capability dropping failed - aborting %s", dmn_name);
		goto deinit;
	}

	/* initialize TKM client */
	if (!tkm_init())
	{
		DBG1(DBG_DMN, "init of TKM client failed - aborting %s", dmn_name);
		goto deinit;
	}

	/* register TKM authorization hook */
	listener = tkm_listener_create();
	charon->bus->add_listener(charon->bus, &listener->listener);

	/* register TKM credential set */
	creds = tkm_cred_create();
	lib->credmgr->add_set(lib->credmgr, (credential_set_t*)creds);

	/* register TKM credential encoder */
	lib->encoding->add_encoder(lib->encoding, tkm_encoder_encode);

	/* add handler for SEGV and ILL,
	 * INT and TERM are handled by sigwait() in run() */
	action.sa_handler = segv_handler;
	action.sa_flags = 0;
	sigemptyset(&action.sa_mask);
	sigaddset(&action.sa_mask, SIGINT);
	sigaddset(&action.sa_mask, SIGTERM);
	sigaction(SIGSEGV, &action, NULL);
	sigaction(SIGILL, &action, NULL);
	sigaction(SIGBUS, &action, NULL);
	action.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &action, NULL);

	pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);

	/* start daemon (i.e. the threads in the thread-pool) */
	charon->start(charon);

	/* main thread goes to run loop */
	run();

	unlink_pidfile();
	status = 0;
	charon->bus->remove_listener(charon->bus, &listener->listener);
	listener->destroy(listener);
	creds->destroy(creds);
	lib->encoding->remove_encoder(lib->encoding, tkm_encoder_encode);

deinit:
	destroy_dh_mapping();
	libcharon_deinit();
	libhydra_deinit();
	library_deinit();
	tkm_deinit();
	return status;
}
Beispiel #8
0
int main(int argc, char **argv)
{
	bool fork_desired = TRUE;
	bool log_to_stderr_desired = FALSE;
	bool nat_traversal = FALSE;
	bool nat_t_spf = TRUE;  /* support port floating */
	unsigned int keep_alive = 0;
	bool force_keepalive = FALSE;
	char *virtual_private = NULL;
	int lockfd;
#ifdef CAPABILITIES
	cap_t caps;
	int keep[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE };
#endif /* CAPABILITIES */

	/* initialize library and optionsfrom */
	if (!library_init(NULL))
	{
		library_deinit();
		exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
	}
	if (!libhydra_init("pluto"))
	{
		libhydra_deinit();
		library_deinit();
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	if (!pluto_init(argv[0]))
	{
		pluto_deinit();
		libhydra_deinit();
		library_deinit();
		exit(SS_RC_DAEMON_INTEGRITY);
	}
	options = options_create();

	ha_mcast_addr.s_addr = inet_addr(SA_SYNC_MULTICAST);

	/* handle arguments */
	for (;;)
	{
#       define DBG_OFFSET 256
		static const struct option long_opts[] = {
			/* name, has_arg, flag, val */
			{ "help", no_argument, NULL, 'h' },
			{ "version", no_argument, NULL, 'v' },
			{ "optionsfrom", required_argument, NULL, '+' },
			{ "nofork", no_argument, NULL, 'd' },
			{ "stderrlog", no_argument, NULL, 'e' },
			{ "noklips", no_argument, NULL, 'n' },
			{ "nocrsend", no_argument, NULL, 'c' },
			{ "strictcrlpolicy", no_argument, NULL, 'r' },
			{ "crlcheckinterval", required_argument, NULL, 'x'},
			{ "cachecrls", no_argument, NULL, 'C' },
			{ "probe-psk", no_argument, NULL, 'o' },
			{ "uniqueids", no_argument, NULL, 'u' },
			{ "interface", required_argument, NULL, 'i' },
			{ "ha_interface", required_argument, NULL, 'H' },
			{ "ha_multicast", required_argument, NULL, 'M' },
			{ "ha_vips", required_argument, NULL, 'V' },
			{ "ha_seqdiff_in", required_argument, NULL, 'S' },
			{ "ha_seqdiff_out", required_argument, NULL, 'O' },
			{ "ikeport", required_argument, NULL, 'p' },
			{ "ctlbase", required_argument, NULL, 'b' },
			{ "secretsfile", required_argument, NULL, 's' },
			{ "foodgroupsdir", required_argument, NULL, 'f' },
			{ "perpeerlogbase", required_argument, NULL, 'P' },
			{ "perpeerlog", no_argument, NULL, 'l' },
			{ "policygroupsdir", required_argument, NULL, 'f' },
#ifdef USE_LWRES
			{ "lwdnsq", required_argument, NULL, 'a' },
#else /* !USE_LWRES */
			{ "adns", required_argument, NULL, 'a' },
#endif /* !USE_LWRES */
			{ "pkcs11module", required_argument, NULL, 'm' },
			{ "pkcs11keepstate", no_argument, NULL, 'k' },
			{ "pkcs11initargs", required_argument, NULL, 'z' },
			{ "pkcs11proxy", no_argument, NULL, 'y' },
			{ "nat_traversal", no_argument, NULL, '1' },
			{ "keep_alive", required_argument, NULL, '2' },
			{ "force_keepalive", no_argument, NULL, '3' },
			{ "disable_port_floating", no_argument, NULL, '4' },
			{ "debug-natt", no_argument, NULL, '5' },
			{ "virtual_private", required_argument, NULL, '6' },
#ifdef DEBUG
			{ "debug-none", no_argument, NULL, 'N' },
			{ "debug-all", no_argument, NULL, 'A' },
			{ "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET },
			{ "debug-crypt", no_argument, NULL, DBG_CRYPT + DBG_OFFSET },
			{ "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET },
			{ "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET },
			{ "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET },
			{ "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET },
			{ "debug-klips", no_argument, NULL, DBG_KLIPS + DBG_OFFSET },
			{ "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET },
			{ "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET },
			{ "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET },
			{ "debug-ha", no_argument, NULL, DBG_HA + DBG_OFFSET },
			{ "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET },

			{ "impair-delay-adns-key-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_KEY_ANSWER + DBG_OFFSET },
			{ "impair-delay-adns-txt-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_TXT_ANSWER + DBG_OFFSET },
			{ "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET },
			{ "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET },
#endif
			{ 0,0,0,0 }
			};
		/* Note: we don't like the way short options get parsed
		 * by getopt_long, so we simply pass an empty string as
		 * the list.  It could be "hvdenp:l:s:" "NARXPECK".
		 */
		int c = getopt_long(argc, argv, "", long_opts, NULL);

		/* Note: "breaking" from case terminates loop */
		switch (c)
		{
		case EOF:       /* end of flags */
			break;

		case 0: /* long option already handled */
			continue;

		case ':':       /* diagnostic already printed by getopt_long */
		case '?':       /* diagnostic already printed by getopt_long */
			usage("");
			break;   /* not actually reached */

		case 'h':       /* --help */
			usage(NULL);
			break;      /* not actually reached */

		case 'v':       /* --version */
			{
				const char **sp = ipsec_copyright_notice();

				printf("strongSwan "VERSION"%s\n", compile_time_interop_options);
				for (; *sp != NULL; sp++)
					puts(*sp);
			}
			exit_pluto(0);
			break;      /* not actually reached */

		case '+':       /* --optionsfrom <filename> */
			if (!options->from(options, optarg, &argc, &argv, optind))
			{
				exit_pluto(1);
			}
			continue;

		case 'd':       /* --nofork*/
			fork_desired = FALSE;
			continue;

		case 'e':       /* --stderrlog */
			log_to_stderr_desired = TRUE;
			continue;

		case 'n':       /* --noklips */
			no_klips = TRUE;
			continue;

		case 'c':       /* --nocrsend */
			no_cr_send = TRUE;
			continue;

		case 'r':       /* --strictcrlpolicy */
			strict_crl_policy = TRUE;
			continue;

		case 'x':       /* --crlcheckinterval <time>*/
			if (optarg == NULL || !isdigit(optarg[0]))
				usage("missing interval time");

			{
				char *endptr;
				long interval = strtol(optarg, &endptr, 0);

				if (*endptr != '\0' || endptr == optarg
				|| interval <= 0)
					usage("<interval-time> must be a positive number");
				crl_check_interval = interval;
			}
			continue;

		case 'C':       /* --cachecrls */
			cache_crls = TRUE;
			continue;

		case 'o':       /* --probe-psk */
			probe_psk = TRUE;
			continue;

		case 'u':       /* --uniqueids */
			uniqueIDs = TRUE;
			continue;

		case 'i':       /* --interface <ifname> */
			if (!use_interface(optarg))
				usage("too many --interface specifications");
			continue;

		case 'H':       /* --ha_interface <ifname> */
			if (optarg && strcmp(optarg, "none") != 0)
				ha_interface = optarg;
			continue;

		case 'M':	/* --ha_multicast <ip> */
			ha_mcast_addr.s_addr = inet_addr(optarg);
			if (ha_mcast_addr.s_addr == INADDR_NONE ||
				(((unsigned char *) &ha_mcast_addr.s_addr)[0] & 0xF0) != 0xE0)
				ha_mcast_addr.s_addr = inet_addr(SA_SYNC_MULTICAST);
			continue;

		case 'V':	/* --ha_vips <ip addresses> */
			if(add_ha_vips(optarg))
				usage("misconfigured ha_vip addresses");
			continue;

		case 'S':	/* --ha_seqdiff_in <diff> */
			ha_seqdiff_in = strtoul(optarg, NULL, 0);
			continue;

		case 'O':       /* --ha_seqdiff_out <diff> */
			ha_seqdiff_out = strtoul(optarg, NULL, 0);
			continue;

		case 'p':       /* --port <portnumber> */
			if (optarg == NULL || !isdigit(optarg[0]))
				usage("missing port number");

			{
				char *endptr;
				long port = strtol(optarg, &endptr, 0);

				if (*endptr != '\0' || endptr == optarg
				|| port <= 0 || port > 0x10000)
					usage("<port-number> must be a number between 1 and 65535");
				pluto_port = port;
			}
			continue;

		case 'b':       /* --ctlbase <path> */
			if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path)
			, "%s%s", optarg, CTL_SUFFIX) == -1)
				usage("<path>" CTL_SUFFIX " too long for sun_path");
			if (snprintf(info_addr.sun_path, sizeof(info_addr.sun_path)
			, "%s%s", optarg, INFO_SUFFIX) == -1)
				usage("<path>" INFO_SUFFIX " too long for sun_path");
			if (snprintf(pluto_lock, sizeof(pluto_lock)
			, "%s%s", optarg, LOCK_SUFFIX) == -1)
				usage("<path>" LOCK_SUFFIX " must fit");
			continue;

		case 's':       /* --secretsfile <secrets-file> */
			shared_secrets_file = optarg;
			continue;

		case 'f':       /* --policygroupsdir <policygroups-dir> */
			policygroups_dir = optarg;
			continue;

		case 'a':       /* --adns <pathname> */
			pluto_adns_option = optarg;
			continue;

		case 'm':       /* --pkcs11module <pathname> */
			pkcs11_module_path = optarg;
			continue;

		case 'k':       /* --pkcs11keepstate */
			pkcs11_keep_state = TRUE;
			continue;

		case 'y':       /* --pkcs11proxy */
			pkcs11_proxy = TRUE;
			continue;

		case 'z':       /* --pkcs11initargs */
			pkcs11_init_args = optarg;
			continue;

#ifdef DEBUG
		case 'N':       /* --debug-none */
			base_debugging = DBG_NONE;
			continue;

		case 'A':       /* --debug-all */
			base_debugging = DBG_ALL;
			continue;
#endif

		case 'P':       /* --perpeerlogbase */
			base_perpeer_logdir = optarg;
			continue;

		case 'l':
			log_to_perpeer = TRUE;
			continue;

		case '1':       /* --nat_traversal */
			nat_traversal = TRUE;
			continue;
		case '2':       /* --keep_alive */
			keep_alive = atoi(optarg);
			continue;
		case '3':       /* --force_keepalive */
			force_keepalive = TRUE;
			continue;
		case '4':       /* --disable_port_floating */
			nat_t_spf = FALSE;
			continue;
		case '5':       /* --debug-nat_t */
			base_debugging |= DBG_NATT;
			continue;
		case '6':       /* --virtual_private */
			virtual_private = optarg;
			continue;

		default:
#ifdef DEBUG
			if (c >= DBG_OFFSET)
			{
				base_debugging |= c - DBG_OFFSET;
				continue;
			}
#       undef DBG_OFFSET
#endif
			bad_case(c);
		}
		break;
	}
	if (optind != argc)
		usage("unexpected argument");
	reset_debugging();
	lockfd = create_lock();

	/* select between logging methods */

	if (log_to_stderr_desired)
	{
		log_to_syslog = FALSE;
	}
	else
	{
		log_to_stderr = FALSE;
	}

	/* set the logging function of pfkey debugging */
#ifdef DEBUG
	pfkey_debug_func = DBG_log;
#else
	pfkey_debug_func = NULL;
#endif

	/* create control socket.
	 * We must create it before the parent process returns so that
	 * there will be no race condition in using it.  The easiest
	 * place to do this is before the daemon fork.
	 */
	{
		err_t ugh = init_ctl_socket();

		if (ugh != NULL)
		{
			fprintf(stderr, "pluto: %s", ugh);
			exit_pluto(1);
		}
	}

	/* If not suppressed, do daemon fork */

	if (fork_desired)
	{
		{
			pid_t pid = fork();

			if (pid < 0)
			{
				int e = errno;

				fprintf(stderr, "pluto: fork failed (%d %s)\n",
					errno, strerror(e));
				exit_pluto(1);
			}

			if (pid != 0)
			{
				/* parent: die, after filling PID into lock file.
				 * must not use exit_pluto: lock would be removed!
				 */
				exit(fill_lock(lockfd, pid)? 0 : 1);
			}
		}

		if (setsid() < 0)
		{
			int e = errno;

			fprintf(stderr, "setsid() failed in main(). Errno %d: %s\n",
				errno, strerror(e));
			exit_pluto(1);
		}
	}
	else
	{
		/* no daemon fork: we have to fill in lock file */
		(void) fill_lock(lockfd, getpid());
		fprintf(stdout, "Pluto initialized\n");
		fflush(stdout);
	}

	/* Close everything but ctl_fd and (if needed) stderr.
	 * There is some danger that a library that we don't know
	 * about is using some fd that we don't know about.
	 * I guess we'll soon find out.
	 */
	{
		int i;

		for (i = getdtablesize() - 1; i >= 0; i--)  /* Bad hack */
		{
			if ((!log_to_stderr || i != 2) && i != ctl_fd)
				close(i);
		}

		/* make sure that stdin, stdout, stderr are reserved */
		if (open("/dev/null", O_RDONLY) != 0)
			abort();
		if (dup2(0, 1) != 1)
			abort();
		if (!log_to_stderr && dup2(0, 2) != 2)
			abort();
	}

	init_constants();
	init_log("pluto");

	/* Note: some scripts may look for this exact message -- don't change
	 * ipsec barf was one, but it no longer does.
	 */
	plog("Starting IKEv1 pluto daemon (strongSwan "VERSION")%s",
		 compile_time_interop_options);

	if (lib->integrity)
	{
		plog("integrity tests enabled:");
		plog("lib    'libstrongswan': passed file and segment integrity tests");
		plog("lib    'libhydra': passed file and segment integrity tests");
		plog("daemon 'pluto': passed file integrity test");
	}

	/* load plugins, further infrastructure may need it */
	if (!lib->plugins->load(lib->plugins, NULL,
			lib->settings->get_str(lib->settings, "pluto.load", PLUGINS)))
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	print_plugins();

	init_builder();
	if (!init_secret() || !init_crypto())
	{
		plog("initialization failed - aborting pluto");
		exit_pluto(SS_RC_INITIALIZATION_FAILED);
	}
	init_nat_traversal(nat_traversal, keep_alive, force_keepalive, nat_t_spf);
	init_virtual_ip(virtual_private);
	scx_init(pkcs11_module_path, pkcs11_init_args);
	init_states();
	init_demux();
	init_kernel();
	init_adns();
	init_myid();
	fetch_initialize();
	ac_initialize();
	whack_attribute_initialize();

	/* HA System: set sequence number delta and open HA interface */
	if (ha_interface != NULL)
	{
		int version;

		if (kernel_ops->type == KERNEL_TYPE_LINUX
		&& (version = xfrm_aevent_version()) != XFRM_AEVENT_VERSION)
		{
			if (version == 0)
				plog("HA system: XFRM sequence number updates only "
				     "supported with kernel version 2.6.17 and later.");
			else if (version == -1)
				plog("HA system: error reading kernel version. "
				     "Sequence number updates disabled.");
			else
				plog("HA system: Strongswan compiled for wrong kernel "
				     "AEVENT version! Please set XFRM_AEVENT_VERSION "
				     "to %d in src/include/linux/xfrm.h", version);

			ha_seqdiff_in = 0;
			ha_seqdiff_out = 0;
		}
		else
		{
			FILE *etime = fopen("/proc/sys/net/core/xfrm_aevent_etime", "w");
			FILE *rseqth = fopen("/proc/sys/net/core/xfrm_aevent_rseqth", "w");

			if (etime == NULL || rseqth == NULL)
			{
				plog("HA System: no sequence number support in Kernel! "
					"Please use at least kernel 2.6.17.");
				ha_seqdiff_in = 0;
				ha_seqdiff_out = 0;
			}
			else
			{
				/*
				 * Disable etime (otherwise set to a multiple of 100ms,
				 * e.g. 300 for 30 seconds). Using ha_seqdiff_out.
				 */
				fprintf(etime, "0");
				fprintf(rseqth, "%d", ha_seqdiff_out);
			}

			fclose(etime);
			fclose(rseqth);
		}

		if (open_ha_iface() >= 0)
		{
			plog("HA system enabled and listening on interface %s", ha_interface);
			if (access("/var/master", F_OK) == 0)
			{
				plog("Initial HA switch to master mode");
				ha_master = 1;
				event_schedule(EVENT_SA_SYNC_UPDATE, 30, NULL);
			}
		}
		else
		{
			plog("HA system failed to listen on interface %s. "
			     "HA system disabled.", ha_interface);
			ha_interface = NULL;
		}
	}

	/* drop unneeded capabilities and change UID/GID */
	prctl(PR_SET_KEEPCAPS, 1);

#ifdef IPSEC_GROUP
	{
		struct group group, *grp;
	char buf[1024];

		if (getgrnam_r(IPSEC_GROUP, &group, buf, sizeof(buf), &grp) != 0 ||
				grp == NULL || setgid(grp->gr_gid) != 0)
		{
			plog("unable to change daemon group");
			abort();
		}
	}
#endif
#ifdef IPSEC_USER
	{
		struct passwd passwd, *pwp;
	char buf[1024];

		if (getpwnam_r(IPSEC_USER, &passwd, buf, sizeof(buf), &pwp) != 0 ||
				pwp == NULL || setuid(pwp->pw_uid) != 0)
		{
			plog("unable to change daemon user");
			abort();
		}
		}
#endif

#ifdef CAPABILITIES
	caps = cap_init();
	cap_set_flag(caps, CAP_EFFECTIVE, 2, keep, CAP_SET);
	cap_set_flag(caps, CAP_INHERITABLE, 2, keep, CAP_SET);
	cap_set_flag(caps, CAP_PERMITTED, 2, keep, CAP_SET);
	if (cap_set_proc(caps) != 0)
	{
		plog("unable to drop daemon capabilities");
		abort();
	}
	cap_free(caps);
#endif /* CAPABILITIES */

	/* loading X.509 CA certificates */
	load_authcerts("ca", CA_CERT_PATH, X509_CA);
	/* loading X.509 AA certificates */
	load_authcerts("aa", AA_CERT_PATH, X509_AA);
	/* loading X.509 OCSP certificates */
	load_authcerts("ocsp", OCSP_CERT_PATH, X509_OCSP_SIGNER);
	/* loading X.509 CRLs */
	load_crls();
	/* loading attribute certificates (experimental) */
	ac_load_certs();

	daily_log_event();
	call_server();
	return -1;  /* Shouldn't ever reach this */
}
int main(int argc, char **argv)
{
	bool fork_desired = TRUE;
	bool log_to_stderr_desired = FALSE;
	bool nat_traversal = FALSE;
	bool nat_t_spf = TRUE;  /* support port floating */
	unsigned int keep_alive = 0;
	bool force_keepalive = FALSE;
	char *virtual_private = NULL;
	int lockfd;
#ifdef CAPABILITIES
	int keep[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE };
#endif /* CAPABILITIES */

	/* initialize library and optionsfrom */
	if (!library_init(NULL))
	{
		library_deinit();
		exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
	}
	if (!libhydra_init("pluto"))
	{
		libhydra_deinit();
		library_deinit();
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	if (!pluto_init(argv[0]))
	{
		pluto_deinit();
		libhydra_deinit();
		library_deinit();
		exit(SS_RC_DAEMON_INTEGRITY);
	}
	options = options_create();

	/* handle arguments */
	for (;;)
	{
#       define DBG_OFFSET 256
		static const struct option long_opts[] = {
			/* name, has_arg, flag, val */
			{ "help", no_argument, NULL, 'h' },
			{ "version", no_argument, NULL, 'v' },
			{ "optionsfrom", required_argument, NULL, '+' },
			{ "nofork", no_argument, NULL, 'd' },
			{ "stderrlog", no_argument, NULL, 'e' },
			{ "nocrsend", no_argument, NULL, 'c' },
			{ "strictcrlpolicy", no_argument, NULL, 'r' },
			{ "crlcheckinterval", required_argument, NULL, 'x'},
			{ "cachecrls", no_argument, NULL, 'C' },
			{ "uniqueids", no_argument, NULL, 'u' },
      { "disableuniqreqids", no_argument, NULL, 'Z'},			
			{ "interface", required_argument, NULL, 'i' },
			{ "ikeport", required_argument, NULL, 'p' },
			{ "ctlbase", required_argument, NULL, 'b' },
			{ "secretsfile", required_argument, NULL, 's' },
			{ "foodgroupsdir", required_argument, NULL, 'f' },
			{ "perpeerlogbase", required_argument, NULL, 'P' },
			{ "perpeerlog", no_argument, NULL, 'l' },
			{ "policygroupsdir", required_argument, NULL, 'f' },
#ifdef USE_LWRES
			{ "lwdnsq", required_argument, NULL, 'a' },
#else /* !USE_LWRES */
			{ "adns", required_argument, NULL, 'a' },
#endif /* !USE_LWRES */
			{ "pkcs11module", required_argument, NULL, 'm' },
			{ "pkcs11keepstate", no_argument, NULL, 'k' },
			{ "pkcs11initargs", required_argument, NULL, 'z' },
			{ "pkcs11proxy", no_argument, NULL, 'y' },
			{ "nat_traversal", no_argument, NULL, '1' },
			{ "keep_alive", required_argument, NULL, '2' },
			{ "force_keepalive", no_argument, NULL, '3' },
			{ "disable_port_floating", no_argument, NULL, '4' },
			{ "debug-natt", no_argument, NULL, '5' },
			{ "virtual_private", required_argument, NULL, '6' },
#ifdef DEBUG
			{ "debug-none", no_argument, NULL, 'N' },
			{ "debug-all", no_argument, NULL, 'A' },
			{ "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET },
			{ "debug-crypt", no_argument, NULL, DBG_CRYPT + DBG_OFFSET },
			{ "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET },
			{ "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET },
			{ "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET },
			{ "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET },
			{ "debug-klips", no_argument, NULL, DBG_KERNEL + DBG_OFFSET },
			{ "debug-kernel", no_argument, NULL, DBG_KERNEL + DBG_OFFSET },
			{ "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET },
			{ "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET },
			{ "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET },
			{ "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET },

			{ "impair-delay-adns-key-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_KEY_ANSWER + DBG_OFFSET },
			{ "impair-delay-adns-txt-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_TXT_ANSWER + DBG_OFFSET },
			{ "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET },
			{ "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET },
#endif
			{ 0,0,0,0 }
			};
		/* Note: we don't like the way short options get parsed
		 * by getopt_long, so we simply pass an empty string as
		 * the list.  It could be "hvdenp:l:s:" "NARXPECK".
		 */
		int c = getopt_long(argc, argv, "", long_opts, NULL);

		/* Note: "breaking" from case terminates loop */
		switch (c)
		{
		case EOF:       /* end of flags */
			break;

		case 0: /* long option already handled */
			continue;

		case ':':       /* diagnostic already printed by getopt_long */
		case '?':       /* diagnostic already printed by getopt_long */
			usage("");
			break;   /* not actually reached */

		case 'h':       /* --help */
			usage(NULL);
			break;      /* not actually reached */

		case 'v':       /* --version */
			{
				const char **sp = ipsec_copyright_notice();

				printf("strongSwan "VERSION"%s\n", compile_time_interop_options);
				for (; *sp != NULL; sp++)
					puts(*sp);
			}
			exit_pluto(0);
			break;      /* not actually reached */

		case '+':       /* --optionsfrom <filename> */
			if (!options->from(options, optarg, &argc, &argv, optind))
			{
				exit_pluto(1);
			}
			continue;

		case 'd':       /* --nofork*/
			fork_desired = FALSE;
			continue;

		case 'e':       /* --stderrlog */
			log_to_stderr_desired = TRUE;
			continue;

		case 'c':       /* --nocrsend */
			no_cr_send = TRUE;
			continue;

		case 'r':       /* --strictcrlpolicy */
			strict_crl_policy = TRUE;
			continue;

		case 'x':       /* --crlcheckinterval <time>*/
			if (optarg == NULL || !isdigit(optarg[0]))
				usage("missing interval time");

			{
				char *endptr;
				long interval = strtol(optarg, &endptr, 0);

				if (*endptr != '\0' || endptr == optarg
				|| interval <= 0)
					usage("<interval-time> must be a positive number");
				crl_check_interval = interval;
			}
			continue;

		case 'C':       /* --cachecrls */
			cache_crls = TRUE;
			continue;

		case 'u':       /* --uniqueids */
			uniqueIDs = TRUE;
			continue;
	
	  case 'Z':       /* --disableuniqreqids */
	    disable_uniqreqids = TRUE;
	    continue;

		case 'i':       /* --interface <ifname> */
			if (!use_interface(optarg))
				usage("too many --interface specifications");
			continue;

		case 'p':       /* --port <portnumber> */
			if (optarg == NULL || !isdigit(optarg[0]))
				usage("missing port number");

			{
				char *endptr;
				long port = strtol(optarg, &endptr, 0);

				if (*endptr != '\0' || endptr == optarg
				|| port <= 0 || port > 0x10000)
					usage("<port-number> must be a number between 1 and 65535");
				pluto_port = port;
			}
			continue;

		case 'b':       /* --ctlbase <path> */
			if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path)
			, "%s%s", optarg, CTL_SUFFIX) == -1)
				usage("<path>" CTL_SUFFIX " too long for sun_path");
			if (snprintf(info_addr.sun_path, sizeof(info_addr.sun_path)
			, "%s%s", optarg, INFO_SUFFIX) == -1)
				usage("<path>" INFO_SUFFIX " too long for sun_path");
			if (snprintf(pluto_lock, sizeof(pluto_lock)
			, "%s%s", optarg, LOCK_SUFFIX) == -1)
				usage("<path>" LOCK_SUFFIX " must fit");
			continue;

		case 's':       /* --secretsfile <secrets-file> */
			shared_secrets_file = optarg;
			continue;

		case 'f':       /* --policygroupsdir <policygroups-dir> */
			policygroups_dir = optarg;
			continue;

		case 'a':       /* --adns <pathname> */
			pluto_adns_option = optarg;
			continue;

		case 'm':       /* --pkcs11module <pathname> */
			pkcs11_module_path = optarg;
			continue;

		case 'k':       /* --pkcs11keepstate */
			pkcs11_keep_state = TRUE;
			continue;

		case 'y':       /* --pkcs11proxy */
			pkcs11_proxy = TRUE;
			continue;

		case 'z':       /* --pkcs11initargs */
			pkcs11_init_args = optarg;
			continue;

#ifdef DEBUG
		case 'N':       /* --debug-none */
			base_debugging = DBG_NONE;
			continue;

		case 'A':       /* --debug-all */
			base_debugging = DBG_ALL;
			continue;
#endif

		case 'P':       /* --perpeerlogbase */
			base_perpeer_logdir = optarg;
			continue;

		case 'l':
			log_to_perpeer = TRUE;
			continue;

		case '1':       /* --nat_traversal */
			nat_traversal = TRUE;
			continue;
		case '2':       /* --keep_alive */
			keep_alive = atoi(optarg);
			continue;
		case '3':       /* --force_keepalive */
			force_keepalive = TRUE;
			continue;
		case '4':       /* --disable_port_floating */
			nat_t_spf = FALSE;
			continue;
		case '5':       /* --debug-nat_t */
			base_debugging |= DBG_NATT;
			continue;
		case '6':       /* --virtual_private */
			virtual_private = optarg;
			continue;

		default:
#ifdef DEBUG
			if (c >= DBG_OFFSET)
			{
				base_debugging |= c - DBG_OFFSET;
				continue;
			}
#       undef DBG_OFFSET
#endif
			bad_case(c);
		}
		break;
	}
	if (optind != argc)
		usage("unexpected argument");
	reset_debugging();
	lockfd = create_lock();

	/* select between logging methods */

	if (log_to_stderr_desired)
	{
		log_to_syslog = FALSE;
	}
	else
	{
		log_to_stderr = FALSE;
	}

	/* set the logging function of pfkey debugging */
#ifdef DEBUG
	pfkey_debug_func = DBG_log;
#else
	pfkey_debug_func = NULL;
#endif

	/* create control socket.
	 * We must create it before the parent process returns so that
	 * there will be no race condition in using it.  The easiest
	 * place to do this is before the daemon fork.
	 */
	{
		err_t ugh = init_ctl_socket();

		if (ugh != NULL)
		{
			fprintf(stderr, "pluto: %s", ugh);
			exit_pluto(1);
		}
	}

	/* If not suppressed, do daemon fork */

	if (fork_desired)
	{
		{
			pid_t pid = fork();

			if (pid < 0)
			{
				int e = errno;

				fprintf(stderr, "pluto: fork failed (%d %s)\n",
					errno, strerror(e));
				exit_pluto(1);
			}

			if (pid != 0)
			{
				/* parent: die, after filling PID into lock file.
				 * must not use exit_pluto: lock would be removed!
				 */
				exit(fill_lock(lockfd, pid)? 0 : 1);
			}
		}

		if (setsid() < 0)
		{
			int e = errno;

			fprintf(stderr, "setsid() failed in main(). Errno %d: %s\n",
				errno, strerror(e));
			exit_pluto(1);
		}
	}
	else
	{
		/* no daemon fork: we have to fill in lock file */
		(void) fill_lock(lockfd, getpid());
		fprintf(stdout, "Pluto initialized\n");
		fflush(stdout);
	}

	/* Redirect stdin, stdout and stderr to /dev/null
	 */
	{
		int fd;
		if ((fd = open("/dev/null", O_RDWR)) == -1)
			abort();
		if (dup2(fd, 0) != 0)
			abort();
		if (dup2(fd, 1) != 1)
			abort();
		if (!log_to_stderr && dup2(fd, 2) != 2)
			abort();
		close(fd);
	}

	init_constants();
	init_log("pluto");

	/* Note: some scripts may look for this exact message -- don't change
	 * ipsec barf was one, but it no longer does.
	 */
	plog("Starting IKEv1 pluto daemon (strongSwan "VERSION")%s",
		 compile_time_interop_options);

	if (lib->integrity)
	{
		plog("integrity tests enabled:");
		plog("lib    'libstrongswan': passed file and segment integrity tests");
		plog("lib    'libhydra': passed file and segment integrity tests");
		plog("daemon 'pluto': passed file integrity test");
	}

	/* load plugins, further infrastructure may need it */
	if (!lib->plugins->load(lib->plugins, NULL,
			lib->settings->get_str(lib->settings, "pluto.load", PLUGINS)))
	{
		exit(SS_RC_INITIALIZATION_FAILED);
	}
	print_plugins();

	init_builder();
	if (!init_secret() || !init_crypto())
	{
		plog("initialization failed - aborting pluto");
		exit_pluto(SS_RC_INITIALIZATION_FAILED);
	}
	init_nat_traversal(nat_traversal, keep_alive, force_keepalive, nat_t_spf);
	init_virtual_ip(virtual_private);
	scx_init(pkcs11_module_path, pkcs11_init_args);
	init_states();
	init_demux();
	init_kernel();
	init_adns();
	init_myid();
	fetch_initialize();
	ac_initialize();
	whack_attribute_initialize();

	/* drop unneeded capabilities and change UID/GID */
	prctl(PR_SET_KEEPCAPS, 1);

#ifdef IPSEC_GROUP
	{
		struct group group, *grp;
	char buf[1024];

		if (getgrnam_r(IPSEC_GROUP, &group, buf, sizeof(buf), &grp) != 0 ||
				grp == NULL || setgid(grp->gr_gid) != 0)
		{
			plog("unable to change daemon group");
			abort();
		}
	}
#endif
#ifdef IPSEC_USER
	{
		struct passwd passwd, *pwp;
	char buf[1024];

		if (getpwnam_r(IPSEC_USER, &passwd, buf, sizeof(buf), &pwp) != 0 ||
				pwp == NULL || setuid(pwp->pw_uid) != 0)
		{
			plog("unable to change daemon user");
			abort();
		}
		}
#endif

#ifdef CAPABILITIES_LIBCAP
	{
		cap_t caps;
		caps = cap_init();
		cap_set_flag(caps, CAP_EFFECTIVE, countof(keep), keep, CAP_SET);
		cap_set_flag(caps, CAP_INHERITABLE, countof(keep), keep, CAP_SET);
		cap_set_flag(caps, CAP_PERMITTED, countof(keep), keep, CAP_SET);
		if (cap_set_proc(caps) != 0)
		{
			plog("unable to drop daemon capabilities");
			abort();
		}
		cap_free(caps);
	}
#endif /* CAPABILITIES_LIBCAP */
#ifdef CAPABILITIES_NATIVE
	{
		struct __user_cap_data_struct caps = { .effective = 0 };
		struct __user_cap_header_struct header = {
			.version = _LINUX_CAPABILITY_VERSION,
		};
		int i;
		for (i = 0; i < countof(keep); i++)
		{
			caps.effective |= 1 << keep[i];
			caps.permitted |= 1 << keep[i];
			caps.inheritable |= 1 << keep[i];
		}
		if (capset(&header, &caps) != 0)
		{
			plog("unable to drop daemon capabilities");
			abort();
		}
	}
#endif /* CAPABILITIES_NATIVE */

	/* loading X.509 CA certificates */
	load_authcerts("ca", CA_CERT_PATH, X509_CA);
	/* loading X.509 AA certificates */
	load_authcerts("aa", AA_CERT_PATH, X509_AA);
	/* loading X.509 OCSP certificates */
	load_authcerts("ocsp", OCSP_CERT_PATH, X509_OCSP_SIGNER);
	/* loading X.509 CRLs */
	load_crls();
	/* loading attribute certificates (experimental) */
	ac_load_certs();

	lib->processor->set_threads(lib->processor,
			lib->settings->get_int(lib->settings, "pluto.threads",
								   DEFAULT_THREADS));

	daily_log_event();
	call_server();
	return -1;  /* Shouldn't ever reach this */
}

/* leave pluto, with status.
 * Once child is launched, parent must not exit this way because
 * the lock would be released.
 *
 *  0 OK
 *  1 general discomfort
 * 10 lock file exists
 */
void exit_pluto(int status)
{
	lib->processor->set_threads(lib->processor, 0);
	reset_globals();    /* needed because we may be called in odd state */
	free_preshared_secrets();
	free_remembered_public_keys();
	delete_every_connection();
	whack_attribute_finalize(); /* free in-memory pools */
	kernel_finalize();
	fetch_finalize();           /* stop fetching thread */
	free_crl_fetch();           /* free chain of crl fetch requests */
	free_ocsp_fetch();          /* free chain of ocsp fetch requests */
	free_authcerts();           /* free chain of X.509 authority certificates */
	free_crls();                /* free chain of X.509 CRLs */
	free_ca_infos();            /* free chain of X.509 CA information records */
	free_ocsp();                /* free ocsp cache */
	free_ifaces();
	ac_finalize();              /* free X.509 attribute certificates */
	scx_finalize();             /* finalize and unload PKCS #11 module */
	stop_adns();
	free_md_pool();
	free_crypto();
	free_myid();                /* free myids */
	free_events();              /* free remaining events */
	free_vendorid();            /* free all vendor id records */
	free_builder();
	delete_lock();
	options->destroy(options);
	pluto_deinit();
	lib->plugins->unload(lib->plugins);
	libhydra_deinit();
	library_deinit();
	close_log();
	exit(status);
}
Beispiel #10
0
/**
 * Main function, starts NetworkManager backend.
 */
int main(int argc, char *argv[])
{
	struct sigaction action;
	int status = SS_RC_INITIALIZATION_FAILED;

	/* logging for library during initialization, as we have no bus yet */
	dbg = dbg_syslog;

	/* initialize library */
	if (!library_init(NULL))
	{
		library_deinit();
		exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
	}

	if (lib->integrity &&
		!lib->integrity->check_file(lib->integrity, "charon-nm", argv[0]))
	{
		dbg_syslog(DBG_DMN, 1, "integrity check of charon-nm failed");
		library_deinit();
		exit(SS_RC_DAEMON_INTEGRITY);
	}

	if (!libhydra_init("charon-nm"))
	{
		dbg_syslog(DBG_DMN, 1, "initialization failed - aborting charon-nm");
		libhydra_deinit();
		library_deinit();
		exit(SS_RC_INITIALIZATION_FAILED);
	}

	if (!libcharon_init("charon-nm"))
	{
		dbg_syslog(DBG_DMN, 1, "initialization failed - aborting charon-nm");
		goto deinit;
	}

	if (!lookup_uid_gid())
	{
		dbg_syslog(DBG_DMN, 1, "invalid uid/gid - aborting charon-nm");
		goto deinit;
	}

	initialize_logger();

	/* use random ports to avoid conflicts with regular charon */
	lib->settings->set_int(lib->settings, "charon-nm.port", 0);
	lib->settings->set_int(lib->settings, "charon-nm.port_natt_t", 0);

	DBG1(DBG_DMN, "Starting charon NetworkManager backend (strongSwan "VERSION")");
	if (lib->integrity)
	{
		DBG1(DBG_DMN, "integrity tests enabled:");
		DBG1(DBG_DMN, "lib    'libstrongswan': passed file and segment integrity tests");
		DBG1(DBG_DMN, "lib    'libhydra': passed file and segment integrity tests");
		DBG1(DBG_DMN, "lib    'libcharon': passed file and segment integrity tests");
		DBG1(DBG_DMN, "daemon 'charon-nm': passed file integrity test");
	}

	/* register NM backend to be loaded with plugins */
	nm_backend_register();

	/* initialize daemon */
	if (!charon->initialize(charon,
			lib->settings->get_str(lib->settings, "charon-nm.load", PLUGINS)))
	{
		DBG1(DBG_DMN, "initialization failed - aborting charon-nm");
		goto deinit;
	}

	if (!charon->caps->drop(charon->caps))
	{
		DBG1(DBG_DMN, "capability dropping failed - aborting charon-nm");
		goto deinit;
	}

	/* add handler for SEGV and ILL,
	 * INT and TERM are handled by sigwait() in run() */
	action.sa_handler = segv_handler;
	action.sa_flags = 0;
	sigemptyset(&action.sa_mask);
	sigaddset(&action.sa_mask, SIGINT);
	sigaddset(&action.sa_mask, SIGTERM);
	sigaction(SIGSEGV, &action, NULL);
	sigaction(SIGILL, &action, NULL);
	sigaction(SIGBUS, &action, NULL);
	action.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &action, NULL);

	pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);

	/* start daemon (i.e. the threads in the thread-pool) */
	charon->start(charon);

	/* main thread goes to run loop */
	run();

	status = 0;

deinit:
	libcharon_deinit();
	libhydra_deinit();
	library_deinit();
	return status;
}
Beispiel #11
0
int main (int argc, char **argv)
{
	starter_config_t *cfg = NULL;
	starter_config_t *new_cfg;
	starter_conn_t *conn, *conn2;
	starter_ca_t *ca, *ca2;

	struct sigaction action;
	struct stat stb;

	int i;
	int id = 1;
	struct timespec ts;
	unsigned long auto_update = 0;
	time_t last_reload;
	bool no_fork = FALSE;
	bool attach_gdb = FALSE;
	bool load_warning = FALSE;

	library_init(NULL);
	atexit(library_deinit);

	libhydra_init("starter");
	atexit(libhydra_deinit);

	/* parse command line */
	for (i = 1; i < argc; i++)
	{
		if (streq(argv[i], "--debug"))
		{
			current_loglevel = 2;
		}
		else if (streq(argv[i], "--debug-more"))
		{
			current_loglevel = 3;
		}
		else if (streq(argv[i], "--debug-all"))
		{
			current_loglevel = 4;
		}
		else if (streq(argv[i], "--nolog"))
		{
			current_loglevel = 0;
		}
		else if (streq(argv[i], "--nofork"))
		{
			no_fork = TRUE;
		}
		else if (streq(argv[i], "--attach-gdb"))
		{
			no_fork = TRUE;
			attach_gdb = TRUE;
		}
		else if (streq(argv[i], "--auto-update") && i+1 < argc)
		{
			auto_update = atoi(argv[++i]);
			if (!auto_update)
				usage(argv[0]);
		}
		else if (streq(argv[i], "--daemon") && i+1 < argc)
		{
			daemon_name = argv[++i];
		}
		else
		{
			usage(argv[0]);
		}
	}

	if (!set_daemon_name())
	{
		DBG1(DBG_APP, "unable to set daemon name");
		exit(LSB_RC_FAILURE);
	}

	init_log("ipsec_starter");

	DBG1(DBG_APP, "Starting %sSwan "VERSION" IPsec [starter]...",
		lib->settings->get_bool(lib->settings,
			"charon.i_dont_care_about_security_and_use_aggressive_mode_psk",
				FALSE) ? "weak" : "strong");

#ifdef LOAD_WARNING
	load_warning = TRUE;
#endif

	if (lib->settings->get_bool(lib->settings, "starter.load_warning", load_warning))
	{
		if (lib->settings->get_str(lib->settings, "charon.load", NULL))
		{
			DBG1(DBG_APP, "!! Your strongswan.conf contains manual plugin load options for charon.");
			DBG1(DBG_APP, "!! This is recommended for experts only, see");
			DBG1(DBG_APP, "!! http://wiki.strongswan.org/projects/strongswan/wiki/PluginLoad");
		}
	}

	/* verify that we can start */
	if (getuid() != 0)
	{
		DBG1(DBG_APP, "permission denied (must be superuser)");
		cleanup();
		exit(LSB_RC_NOT_ALLOWED);
	}

	if (check_pid(pid_file))
	{
		DBG1(DBG_APP, "%s is already running (%s exists) -- skipping daemon start",
			 daemon_name, pid_file);
	}
	else
	{
		_action_ |= FLAG_ACTION_START_CHARON;
	}
	if (stat(DEV_RANDOM, &stb) != 0)
	{
		DBG1(DBG_APP, "unable to start strongSwan IPsec -- no %s!", DEV_RANDOM);
		cleanup();
		exit(LSB_RC_FAILURE);
	}

	if (stat(DEV_URANDOM, &stb)!= 0)
	{
		DBG1(DBG_APP, "unable to start strongSwan IPsec -- no %s!", DEV_URANDOM);
		cleanup();
		exit(LSB_RC_FAILURE);
	}

	cfg = confread_load(CONFIG_FILE);
	if (cfg == NULL || cfg->err > 0)
	{
		DBG1(DBG_APP, "unable to start strongSwan -- fatal errors in config");
		if (cfg)
		{
			confread_free(cfg);
		}
		cleanup();
		exit(LSB_RC_INVALID_ARGUMENT);
	}

	/* determine if we have a native netkey IPsec stack */
	if (!starter_netkey_init())
	{
		DBG1(DBG_APP, "no netkey IPsec stack detected");
		if (!starter_klips_init())
		{
			DBG1(DBG_APP, "no KLIPS IPsec stack detected");
			DBG1(DBG_APP, "no known IPsec stack detected, ignoring!");
		}
	}

	last_reload = time_monotonic(NULL);

	if (check_pid(starter_pid_file))
	{
		DBG1(DBG_APP, "starter is already running (%s exists) -- no fork done",
			 starter_pid_file);
		confread_free(cfg);
		cleanup();
		exit(LSB_RC_SUCCESS);
	}

#ifdef GENERATE_SELFCERT
	generate_selfcert();
#endif

	/* fork if we're not debugging stuff */
	if (!no_fork)
	{
		log_to_stderr = FALSE;

		switch (fork())
		{
			case 0:
			{
				int fnull;

				close_log();
				closefrom(3);

				fnull = open("/dev/null", O_RDWR);
				if (fnull >= 0)
				{
					dup2(fnull, STDIN_FILENO);
					dup2(fnull, STDOUT_FILENO);
					dup2(fnull, STDERR_FILENO);
					close(fnull);
				}

				setsid();
				init_log("ipsec_starter");
			}
			break;
			case -1:
				DBG1(DBG_APP, "can't fork: %s", strerror(errno));
				break;
			default:
				confread_free(cfg);
				cleanup();
				exit(LSB_RC_SUCCESS);
		}
	}

	/* save pid file in /var/run/starter[.daemon_name].pid */
	{
		FILE *fd = fopen(starter_pid_file, "w");

		if (fd)
		{
			fprintf(fd, "%u\n", getpid());
			fclose(fd);
		}
	}

	/* we handle these signals only in pselect() */
	memset(&action, 0, sizeof(action));
	sigemptyset(&action.sa_mask);
	sigaddset(&action.sa_mask, SIGHUP);
	sigaddset(&action.sa_mask, SIGINT);
	sigaddset(&action.sa_mask, SIGTERM);
	sigaddset(&action.sa_mask, SIGQUIT);
	sigaddset(&action.sa_mask, SIGALRM);
	sigaddset(&action.sa_mask, SIGUSR1);
	pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);

	/* install a handler for fatal signals */
	action.sa_handler = fatal_signal_handler;
	sigaction(SIGSEGV, &action, NULL);
	sigaction(SIGILL, &action, NULL);
	sigaction(SIGBUS, &action, NULL);
	action.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &action, NULL);

	/* install main signal handler */
	action.sa_handler = signal_handler;
	sigaction(SIGHUP, &action, NULL);
	sigaction(SIGINT, &action, NULL);
	sigaction(SIGTERM, &action, NULL);
	sigaction(SIGQUIT, &action, NULL);
	sigaction(SIGALRM, &action, NULL);
	sigaction(SIGUSR1, &action, NULL);
	/* this is not blocked above as we want to receive it asynchronously */
	sigaction(SIGCHLD, &action, NULL);

	/* empty mask for pselect() call below */
	sigemptyset(&action.sa_mask);

	for (;;)
	{
		/*
		 * Stop charon (if started) and exit
		 */
		if (_action_ & FLAG_ACTION_QUIT)
		{
			if (starter_charon_pid())
			{
				starter_stop_charon();
			}
			starter_netkey_cleanup();
			confread_free(cfg);
			unlink(starter_pid_file);
			cleanup();
			DBG1(DBG_APP, "ipsec starter stopped");
			close_log();
			exit(LSB_RC_SUCCESS);
		}

		/*
		 * Delete all connections. Will be added below
		 */
		if (_action_ & FLAG_ACTION_RELOAD)
		{
			if (starter_charon_pid())
			{
				for (conn = cfg->conn_first; conn; conn = conn->next)
				{
					if (conn->state == STATE_ADDED)
					{
						if (starter_charon_pid())
						{
							if (conn->startup == STARTUP_ROUTE)
							{
								starter_stroke_unroute_conn(conn);
							}
							starter_stroke_del_conn(conn);
						}
						conn->state = STATE_TO_ADD;
					}
				}
				for (ca = cfg->ca_first; ca; ca = ca->next)
				{
					if (ca->state == STATE_ADDED)
					{
						if (starter_charon_pid())
						{
							starter_stroke_del_ca(ca);
						}
						ca->state = STATE_TO_ADD;
					}
				}
			}
			_action_ &= ~FLAG_ACTION_RELOAD;
		}

		/*
		 * Update configuration
		 */
		if (_action_ & FLAG_ACTION_UPDATE)
		{
			DBG2(DBG_APP, "Reloading config...");
			new_cfg = confread_load(CONFIG_FILE);

			if (new_cfg && (new_cfg->err == 0))
			{
				/* Switch to new config. New conn will be loaded below */

				/* Look for new connections that are already loaded */
				for (conn = cfg->conn_first; conn; conn = conn->next)
				{
					if (conn->state == STATE_ADDED)
					{
						for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next)
						{
							if (conn2->state == STATE_TO_ADD && starter_cmp_conn(conn, conn2))
							{
								conn->state = STATE_REPLACED;
								conn2->state = STATE_ADDED;
								conn2->id = conn->id;
								break;
							}
						}
					}
				}

				/* Remove conn sections that have become unused */
				for (conn = cfg->conn_first; conn; conn = conn->next)
				{
					if (conn->state == STATE_ADDED)
					{
						if (starter_charon_pid())
						{
							if (conn->startup == STARTUP_ROUTE)
							{
								starter_stroke_unroute_conn(conn);
							}
							starter_stroke_del_conn(conn);
						}
					}
				}

				/* Look for new ca sections that are already loaded */
				for (ca = cfg->ca_first; ca; ca = ca->next)
				{
					if (ca->state == STATE_ADDED)
					{
						for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next)
						{
							if (ca2->state == STATE_TO_ADD && starter_cmp_ca(ca, ca2))
							{
								ca->state = STATE_REPLACED;
								ca2->state = STATE_ADDED;
								break;
							}
						}
					}
				}

				/* Remove ca sections that have become unused */
				for (ca = cfg->ca_first; ca; ca = ca->next)
				{
					if (ca->state == STATE_ADDED)
					{
						if (starter_charon_pid())
						{
							starter_stroke_del_ca(ca);
						}
					}
				}
				confread_free(cfg);
				cfg = new_cfg;
			}
			else
			{
				DBG1(DBG_APP, "can't reload config file due to errors -- keeping old one");
				if (new_cfg)
				{
					confread_free(new_cfg);
				}
			}
			_action_ &= ~FLAG_ACTION_UPDATE;
			last_reload = time_monotonic(NULL);
		}

		/*
		 * Start daemon
		 */
		if (_action_ & FLAG_ACTION_START_CHARON)
		{
			if (cfg->setup.charonstart && !starter_charon_pid())
			{
				DBG2(DBG_APP, "Attempting to start %s...", daemon_name);
				if (starter_start_charon(cfg, no_fork, attach_gdb))
				{
					/* schedule next try */
					alarm(CHARON_RESTART_DELAY);
				}
				starter_stroke_configure(cfg);
			}
			_action_ &= ~FLAG_ACTION_START_CHARON;

			for (ca = cfg->ca_first; ca; ca = ca->next)
			{
				if (ca->state == STATE_ADDED)
				{
					ca->state = STATE_TO_ADD;
				}
			}

			for (conn = cfg->conn_first; conn; conn = conn->next)
			{
				if (conn->state == STATE_ADDED)
				{
					conn->state = STATE_TO_ADD;
				}
			}
		}

		/*
		 * Add stale conn and ca sections
		 */
		if (starter_charon_pid())
		{
			for (ca = cfg->ca_first; ca; ca = ca->next)
			{
				if (ca->state == STATE_TO_ADD)
				{
					if (starter_charon_pid())
					{
						starter_stroke_add_ca(ca);
					}
					ca->state = STATE_ADDED;
				}
			}

			for (conn = cfg->conn_first; conn; conn = conn->next)
			{
				if (conn->state == STATE_TO_ADD)
				{
					if (conn->id == 0)
					{
						/* affect new unique id */
						conn->id = id++;
					}
					if (starter_charon_pid())
					{
						starter_stroke_add_conn(cfg, conn);
					}
					conn->state = STATE_ADDED;

					if (conn->startup == STARTUP_START)
					{
						if (starter_charon_pid())
						{
							starter_stroke_initiate_conn(conn);
						}
					}
					else if (conn->startup == STARTUP_ROUTE)
					{
						if (starter_charon_pid())
						{
							starter_stroke_route_conn(conn);
						}
					}
				}
			}
		}

		/*
		 * If auto_update activated, when to stop select
		 */
		if (auto_update)
		{
			time_t now = time_monotonic(NULL);

			ts.tv_sec = (now < last_reload + auto_update) ?
						(last_reload + auto_update - now) : 0;
			ts.tv_nsec = 0;
		}

		/*
		 * Wait for something to happen
		 */
		if (!_action_ &&
			pselect(0, NULL, NULL, NULL, auto_update ? &ts : NULL,
					&action.sa_mask) == 0)
		{
			/* timeout -> auto_update */
			_action_ |= FLAG_ACTION_UPDATE;
		}
	}
	exit(LSB_RC_SUCCESS);
}