File: [local] / src / sbin / isakmpd / isakmpd.c (download)
Revision 1.30, Mon Apr 9 22:09:52 2001 UTC (23 years, 2 months ago) by ho
Branch: MAIN
CVS Tags: OPENBSD_2_9_BASE, OPENBSD_2_9 Changes since 1.29: +4 -4 lines
More style fixes...
|
/* $OpenBSD: isakmpd.c,v 1.30 2001/04/09 22:09:52 ho 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 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Ericsson Radio Systems.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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 <unistd.h>
#include "sysdep.h"
#include "app.h"
#include "conf.h"
#include "connection.h"
#include "init.h"
#include "libcrypto.h"
#include "log.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
/*
* Set if -d is given, currently just for running in the foreground and log
* to stderr instead of syslog.
*/
int debug = 0;
/*
* If we receive a SIGHUP signal, this flag gets set to show we need to
* reconfigure ASAP.
*/
static int 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.
*/
static int sigusr1ed = 0;
static char *report_file = "/var/run/isakmpd.report";
/* 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
/*
* 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?
*/
static int sigusr2ed = 0;
static void
usage ()
{
fprintf (stderr,
"usage: %s [-c config-file] [-d] [-D class=level] [-f fifo]\n"
" [-i pid-file] [-n] [-p listen-port] [-P local-port]\n"
" [-L] [-l packetlog-file] [-r seed] [-R report-file]\n",
sysdep_progname ());
exit (1);
}
static void
parse_args (int argc, char *argv[])
{
int ch;
#ifdef USE_DEBUG
int cls, level;
int do_packetlog = 0;
#endif
while ((ch = getopt (argc, argv, "c:dD:f:i:np:P:Ll:r:R:")) != -1) {
switch (ch) {
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;
case 'n':
app_none++;
break;
case 'p':
udp_default_port = udp_decode_port (optarg);
if (!udp_default_port)
exit (1);
break;
case 'P':
udp_bind_port = udp_decode_port (optarg);
if (!udp_bind_port)
exit (1);
break;
#ifdef USE_DEBUG
case 'l':
pcap_file = optarg;
/* Fallthrough intended. */
case 'L':
do_packetlog++;
break;
#endif /* USE_DEBUG */
case 'r':
srandom (strtoul (optarg, 0, 0));
regrand = 1;
break;
case 'R':
report_file = optarg;
break;
case '?':
default:
usage ();
}
}
argc -= optind;
argv += optind;
#ifdef USE_DEBUG
if (do_packetlog && !pcap_file)
pcap_file = PCAP_FILE_DEFAULT;
#endif
}
/* Reinitialize after a SIGHUP reception. */
static void
reinit (void)
{
log_print ("SIGHUP recieved, reinitializing daemon.");
/*
* XXX Remove all(/some?) pending exchange timers? - they may not be
* possible to complete after we've re-read the config file.
* User-initiated SIGHUP's maybe "authorizes" a wait until
* next connection-check.
* XXX This means we discard exchange->last_msg, is this really ok?
*/
/* Reinitialize PRNG if we are in deterministic mode. */
if (regrand)
srandom (strtoul (optarg, 0, 0));
/* Reread config file. */
conf_reinit ();
/* Try again to link in libcrypto (good if we started without /usr). */
libcrypto_init ();
/* Set timezone */
tzset ();
#ifdef USE_POLICY
/* Reread the policies. */
policy_init ();
#endif
/* Reinitialize certificates */
cert_init ();
/* Reinitialize our connection list. */
connection_reinit ();
/*
* XXX Rescan interfaces.
* transport_reinit ();
* udp_reinit ();
*/
/*
* XXX "These" (non-existant) reinitializations should not be done.
* cookie_reinit ();
* ui_reinit ();
* sa_reinit ();
*/
sighupped = 0;
}
static void
sighup (int sig)
{
sighupped = 1;
}
/* Report internal state on SIGUSR1. */
static void
report (void)
{
FILE *report, *old;
mode_t old_umask;
old_umask = umask (S_IRWXG | S_IRWXO);
report = fopen (report_file, "w");
umask (old_umask);
if (!report)
{
log_error ("fopen (\"%s\", \"w\") failed", report_file);
return;
}
/* Divert the log channel to the report file during the report. */
old = log_current ();
log_to (report);
ui_report ("r");
log_to (old);
fclose (report);
sigusr1ed = 0;
}
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, rehasing soft expiration timers.");
timer_rehash_timers ();
#endif
sigusr2ed = 0;
}
static void
sigusr2 (int sig)
{
sigusr2ed = 1;
}
/* Write pid file. */
static void
write_pid_file (void)
{
FILE *fp;
/* Ignore errors. */
unlink (pid_file);
fp = fopen (pid_file, "w");
if (fp != NULL)
{
/* XXX Error checking! */
fprintf (fp, "%d\n", getpid ());
fclose (fp);
}
else
log_fatal ("main: fopen (\"%s\", \"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;
parse_args (argc, argv);
init ();
if (!debug)
{
if (daemon (0, 0))
log_fatal ("main: daemon (0, 0) failed");
/* Switch to syslog. */
log_to (0);
}
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);
#ifdef 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 (%d) failed", mask_size);
wfds = (fd_set *)malloc (mask_size);
if (!wfds)
log_fatal ("main: malloc (%d) failed", mask_size);
while (1)
{
/* If someone has sent SIGHUP to us, reconfigure. */
if (sighupped)
reinit ();
/* and if someone sent SIGUSR1, do a state report. */
if (sigusr1ed)
report ();
/* and if someone sent SIGUSR2, do a timer rehash. */
if (sigusr2ed)
rehash_timers ();
/* 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 ("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 ();
}
}