summaryrefslogtreecommitdiff
path: root/keyexchange/isakmpd-20041012/isakmpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyexchange/isakmpd-20041012/isakmpd.c')
-rw-r--r--keyexchange/isakmpd-20041012/isakmpd.c543
1 files changed, 543 insertions, 0 deletions
diff --git a/keyexchange/isakmpd-20041012/isakmpd.c b/keyexchange/isakmpd-20041012/isakmpd.c
new file mode 100644
index 0000000..8675201
--- /dev/null
+++ b/keyexchange/isakmpd-20041012/isakmpd.c
@@ -0,0 +1,543 @@
+/* $OpenBSD: isakmpd.c,v 1.68 2004/09/17 14:54:09 hshoexer Exp $ */
+/* $EOM: isakmpd.c,v 1.54 2000/10/05 09:28:22 niklas Exp $ */
+
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 1999, 2000, 2001 Håkan Olsson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "sysdep.h"
+
+#include "app.h"
+#include "conf.h"
+#include "connection.h"
+#include "init.h"
+#include "libcrypto.h"
+#include "log.h"
+#include "monitor.h"
+#include "sa.h"
+#include "timer.h"
+#include "transport.h"
+#include "udp.h"
+#include "ui.h"
+#include "util.h"
+#include "cert.h"
+
+#ifdef USE_POLICY
+#include "policy.h"
+#endif
+
+static void usage(void);
+
+/*
+ * Set if -d is given, currently just for running in the foreground and log
+ * to stderr instead of syslog.
+ */
+int debug = 0;
+
+/* Set when no policy file is found. */
+int acquire_only = 0;
+
+/*
+ * If we receive a SIGHUP signal, this flag gets set to show we need to
+ * reconfigure ASAP.
+ */
+volatile sig_atomic_t sighupped = 0;
+
+/*
+ * If we receive a USR1 signal, this flag gets set to show we need to dump
+ * a report over our internal state ASAP. The file to report to is settable
+ * via the -R parameter.
+ */
+volatile sig_atomic_t sigusr1ed = 0;
+static char *report_file = "/var/run/isakmpd.report";
+
+/*
+ * If we receive a USR2 signal, this flag gets set to show we need to
+ * rehash our SA soft expiration timers to a uniform distribution.
+ * XXX Perhaps this is a really bad idea?
+ */
+volatile sig_atomic_t sigusr2ed = 0;
+
+/*
+ * If we receive a TERM signal, perform a "clean shutdown" of the daemon.
+ * This includes to send DELETE notifications for all our active SAs.
+ * Also on recv of an INT signal (Ctrl-C out of an '-d' session, typically).
+ */
+volatile sig_atomic_t sigtermed = 0;
+void daemon_shutdown_now(int);
+
+/* The default path of the PID file. */
+static char *pid_file = "/var/run/isakmpd.pid";
+
+#ifdef USE_DEBUG
+/* The path of the IKE packet capture log file. */
+static char *pcap_file = 0;
+#endif
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-4] [-6] [-a] [-c config-file] [-d] [-D class=level]\n"
+ " [-f fifo] [-i pid-file] [-K] [-n] [-p listen-port]\n"
+ " [-P local-port] [-L] [-l packetlog-file] [-r seed]\n"
+ " [-R report-file] [-v]\n",
+ sysdep_progname());
+ exit(1);
+}
+
+static void
+parse_args(int argc, char *argv[])
+{
+ int ch;
+ char *ep;
+#ifdef USE_DEBUG
+ int cls, level;
+ int do_packetlog = 0;
+#endif
+
+ while ((ch = getopt(argc, argv, "46ac:dD:f:i:Knp:P:Ll:r:R:v")) != -1) {
+ switch (ch) {
+ case '4':
+ bind_family |= BIND_FAMILY_INET4;
+ break;
+
+ case '6':
+ bind_family |= BIND_FAMILY_INET6;
+ break;
+
+ case 'a':
+ acquire_only++;
+ break;
+
+ case 'c':
+ conf_path = optarg;
+ break;
+
+ case 'd':
+ debug++;
+ break;
+
+#ifdef USE_DEBUG
+ case 'D':
+ if (sscanf(optarg, "%d=%d", &cls, &level) != 2) {
+ if (sscanf(optarg, "A=%d", &level) == 1) {
+ for (cls = 0; cls < LOG_ENDCLASS;
+ cls++)
+ log_debug_cmd(cls, level);
+ } else
+ log_print("parse_args: -D argument "
+ "unparseable: %s", optarg);
+ } else
+ log_debug_cmd(cls, level);
+ break;
+#endif /* USE_DEBUG */
+
+ case 'f':
+ ui_fifo = optarg;
+ break;
+
+ case 'i':
+ pid_file = optarg;
+ break;
+
+#ifdef USE_POLICY
+ case 'K':
+ ignore_policy++;
+ break;
+#endif
+
+ case 'n':
+ app_none++;
+ break;
+
+ case 'p':
+ udp_default_port = optarg;
+ break;
+
+ case 'P':
+ udp_bind_port = optarg;
+ break;
+
+#ifdef USE_DEBUG
+ case 'l':
+ pcap_file = optarg;
+ /* Fallthrough intended. */
+
+ case 'L':
+ do_packetlog++;
+ break;
+#endif /* USE_DEBUG */
+
+ case 'r':
+ seed = strtoul(optarg, &ep, 0);
+ srandom(seed);
+ if (*ep != '\0')
+ log_fatal("parse_args: invalid numeric arg "
+ "to -r (%s)", optarg);
+ regrand = 1;
+ break;
+
+ case 'R':
+ report_file = optarg;
+ break;
+
+ case 'v':
+ verbose_logging = 1;
+ break;
+
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef USE_DEBUG
+ if (do_packetlog && !pcap_file)
+ pcap_file = PCAP_FILE_DEFAULT;
+#endif
+}
+
+static void
+sighup(int sig)
+{
+ sighupped = 1;
+}
+
+/* Report internal state on SIGUSR1. */
+static void
+report(void)
+{
+ FILE *rfp, *old;
+ mode_t old_umask;
+
+ old_umask = umask(S_IRWXG | S_IRWXO);
+ rfp = monitor_fopen(report_file, "w");
+ umask(old_umask);
+
+ if (!rfp) {
+ log_error("report: fopen (\"%s\", \"w\") failed", report_file);
+ return;
+ }
+ /* Divert the log channel to the report file during the report. */
+ old = log_current();
+ log_to(rfp);
+ ui_report("r");
+ log_to(old);
+ fclose(rfp);
+}
+
+static void
+sigusr1(int sig)
+{
+ sigusr1ed = 1;
+}
+
+/* Rehash soft expiration timers on SIGUSR2. */
+static void
+rehash_timers(void)
+{
+#if 0
+ /* XXX - not yet */
+ log_print("SIGUSR2 received, rehashing soft expiration timers.");
+
+ timer_rehash_timers();
+#endif
+}
+
+static void
+sigusr2(int sig)
+{
+ sigusr2ed = 1;
+}
+
+static int
+phase2_sa_check(struct sa *sa, void *arg)
+{
+ return sa->phase == 2;
+}
+
+static void
+daemon_shutdown(void)
+{
+ /* Perform a (protocol-wise) clean shutdown of the daemon. */
+ struct sa *sa;
+
+ if (sigtermed == 1) {
+ log_print("isakmpd: shutting down...");
+
+ /* Delete all active phase 2 SAs. */
+ while ((sa = sa_find(phase2_sa_check, NULL))) {
+ /* Each DELETE is another (outgoing) message. */
+ sa_delete(sa, 1);
+ }
+ sigtermed++;
+ }
+ if (transport_prio_sendqs_empty()) {
+ /*
+ * When the prioritized transport sendq:s are empty, i.e all
+ * the DELETE notifications have been sent, we can shutdown.
+ */
+
+#ifdef USE_DEBUG
+ log_packet_stop();
+#endif
+ /* Remove FIFO and pid files. */
+ unlink(ui_fifo);
+ unlink(pid_file);
+ log_print("isakmpd: exit");
+ exit(0);
+ }
+}
+
+/* Called on SIGTERM, SIGINT or by ui_shutdown_daemon(). */
+void
+daemon_shutdown_now(int sig)
+{
+ sigtermed = 1;
+}
+
+/* Write pid file. */
+static void
+write_pid_file(void)
+{
+ FILE *fp;
+
+ /* Ignore errors. This will fail with USE_PRIVSEP. */
+ unlink(pid_file);
+
+ fp = monitor_fopen(pid_file, "w");
+ if (fp != NULL) {
+ if (fprintf(fp, "%ld\n", (long) getpid()) < 0)
+ log_error("write_pid_file: failed to write PID to "
+ "\"%.100s\"", pid_file);
+ fclose(fp);
+ } else
+ log_fatal("write_pid_file: fopen (\"%.100s\", \"w\") failed",
+ pid_file);
+}
+
+int
+main(int argc, char *argv[])
+{
+ fd_set *rfds, *wfds;
+ int n, m;
+ size_t mask_size;
+ struct timeval tv, *timeout;
+
+#if defined (HAVE_CLOSEFROM) && (!defined (OpenBSD) || (OpenBSD >= 200405))
+ closefrom(STDERR_FILENO + 1);
+#else
+ m = getdtablesize();
+ for (n = STDERR_FILENO + 1; n < m; n++)
+ (void) close(n);
+#endif
+
+ /*
+ * Make sure init() won't alloc fd 0, 1 or 2, as daemon() will close
+ * them.
+ */
+ for (n = 0; n <= 2; n++)
+ if (fcntl(n, F_GETFL, 0) == -1 && errno == EBADF)
+ (void) open("/dev/null", n ? O_WRONLY : O_RDONLY, 0);
+
+ for (n = 1; n < _NSIG; n++)
+ signal(n, SIG_DFL);
+
+ /* Log cmd line parsing and initialization errors to stderr. */
+ log_to(stderr);
+ parse_args(argc, argv);
+ log_init(debug);
+
+ /* Open protocols and services databases. */
+ setprotoent(1);
+ setservent(1);
+
+ /*
+ * Do a clean daemon shutdown on TERM/INT. These signals must be
+ * initialized before monitor_init(). INT is only used with '-d'.
+ */
+ signal(SIGTERM, daemon_shutdown_now);
+ if (debug == 1) /* i.e '-dd' will skip this. */
+ signal(SIGINT, daemon_shutdown_now);
+
+ /* Daemonize before forking unpriv'ed child */
+ if (!debug)
+ if (daemon(0, 0))
+ log_fatal("main: daemon (0, 0) failed");
+
+ /* Set timezone before priv'separation */
+ tzset();
+
+#if defined (USE_PRIVSEP)
+ if (monitor_init(debug)) {
+ /* The parent, with privileges enters infinite monitor loop. */
+ monitor_loop(debug);
+ exit(0); /* Never reached. */
+ }
+ /* Child process only from this point on, no privileges left. */
+#endif
+
+ init();
+
+ write_pid_file();
+
+ /* Reinitialize on HUP reception. */
+ signal(SIGHUP, sighup);
+
+ /* Report state on USR1 reception. */
+ signal(SIGUSR1, sigusr1);
+
+ /* Rehash soft expiration timers on USR2 reception. */
+ signal(SIGUSR2, sigusr2);
+
+#if defined (USE_DEBUG)
+ /* If we wanted IKE packet capture to file, initialize it now. */
+ if (pcap_file != 0)
+ log_packet_init(pcap_file);
+#endif
+
+ /* Allocate the file descriptor sets just big enough. */
+ n = getdtablesize();
+ mask_size = howmany(n, NFDBITS) * sizeof(fd_mask);
+ rfds = (fd_set *) malloc(mask_size);
+ if (!rfds)
+ log_fatal("main: malloc (%lu) failed",
+ (unsigned long)mask_size);
+ wfds = (fd_set *) malloc(mask_size);
+ if (!wfds)
+ log_fatal("main: malloc (%lu) failed",
+ (unsigned long)mask_size);
+
+#if defined (USE_PRIVSEP)
+ monitor_init_done();
+#endif
+
+ while (1) {
+ /* If someone has sent SIGHUP to us, reconfigure. */
+ if (sighupped) {
+ sighupped = 0;
+ log_print("SIGHUP received");
+ reinit();
+ }
+ /* and if someone sent SIGUSR1, do a state report. */
+ if (sigusr1ed) {
+ sigusr1ed = 0;
+ log_print("SIGUSR1 received");
+ report();
+ }
+ /* and if someone sent SIGUSR2, do a timer rehash. */
+ if (sigusr2ed) {
+ sigusr2ed = 0;
+ log_print("SIGUSR2 received");
+ rehash_timers();
+ }
+ /*
+ * and if someone set 'sigtermed' (SIGTERM, SIGINT or via the
+ * UI), this indicates we should start a controlled shutdown
+ * of the daemon.
+ *
+ * Note: Since _one_ message is sent per iteration of this
+ * enclosing while-loop, and we want to send a number of
+ * DELETE notifications, we must loop atleast this number of
+ * times. The daemon_shutdown() function starts by queueing
+ * the DELETEs, all other calls just increments the
+ * 'sigtermed' variable until it reaches a "safe" value, and
+ * the daemon exits.
+ */
+ if (sigtermed)
+ daemon_shutdown();
+
+ /* Setup the descriptors to look for incoming messages at. */
+ memset(rfds, 0, mask_size);
+ n = transport_fd_set(rfds);
+ FD_SET(ui_socket, rfds);
+ if (ui_socket + 1 > n)
+ n = ui_socket + 1;
+
+ /*
+ * XXX Some day we might want to deal with an abstract
+ * application class instead, with many instantiations
+ * possible.
+ */
+ if (!app_none && app_socket >= 0) {
+ FD_SET(app_socket, rfds);
+ if (app_socket + 1 > n)
+ n = app_socket + 1;
+ }
+ /* Setup the descriptors that have pending messages to send. */
+ memset(wfds, 0, mask_size);
+ m = transport_pending_wfd_set(wfds);
+ if (m > n)
+ n = m;
+
+ /* Find out when the next timed event is. */
+ timeout = &tv;
+ timer_next_event(&timeout);
+
+ n = select(n, rfds, wfds, 0, timeout);
+ if (n == -1) {
+ if (errno != EINTR) {
+ log_error("main: select");
+
+ /*
+ * In order to give the unexpected error
+ * condition time to resolve without letting
+ * this process eat up all available CPU
+ * we sleep for a short while.
+ */
+ sleep(1);
+ }
+ } else if (n) {
+ transport_handle_messages(rfds);
+ transport_send_messages(wfds);
+ if (FD_ISSET(ui_socket, rfds))
+ ui_handler();
+ if (!app_none && app_socket >= 0 &&
+ FD_ISSET(app_socket, rfds))
+ app_handler();
+ }
+ timer_handle_expirations();
+ }
+}