xref: /openbsd/sbin/isakmpd/isakmpd.c (revision d485f761)
1 /*	$OpenBSD: isakmpd.c,v 1.37 2001/10/26 11:37:16 ho Exp $	*/
2 /*	$EOM: isakmpd.c,v 1.54 2000/10/05 09:28:22 niklas Exp $	*/
3 
4 /*
5  * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist.  All rights reserved.
6  * Copyright (c) 1999, 2000 Angelos D. Keromytis.  All rights reserved.
7  * Copyright (c) 1999, 2000, 2001 H�kan Olsson.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by Ericsson Radio Systems.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 /*
36  * This code was written under funding by Ericsson Radio Systems.
37  */
38 
39 #include <errno.h>
40 #include <sys/param.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 
49 #include "sysdep.h"
50 
51 #include "app.h"
52 #include "conf.h"
53 #include "connection.h"
54 #include "init.h"
55 #include "libcrypto.h"
56 #include "log.h"
57 #include "sa.h"
58 #include "timer.h"
59 #include "transport.h"
60 #include "udp.h"
61 #include "ui.h"
62 #include "util.h"
63 #include "cert.h"
64 
65 #ifdef USE_POLICY
66 #include "policy.h"
67 #endif
68 
69 static void usage (void);
70 
71 /*
72  * Set if -d is given, currently just for running in the foreground and log
73  * to stderr instead of syslog.
74  */
75 int debug = 0;
76 
77 /*
78  * If we receive a SIGHUP signal, this flag gets set to show we need to
79  * reconfigure ASAP.
80  */
81 static int sighupped = 0;
82 
83 /*
84  * If we receive a USR1 signal, this flag gets set to show we need to dump
85  * a report over our internal state ASAP.  The file to report to is settable
86  * via the -R parameter.
87  */
88 static int sigusr1ed = 0;
89 static char *report_file = "/var/run/isakmpd.report";
90 
91 /*
92  * If we receive a USR2 signal, this flag gets set to show we need to
93  * rehash our SA soft expiration timers to a uniform distribution.
94  * XXX Perhaps this is a really bad idea?
95  */
96 static int sigusr2ed = 0;
97 
98 /*
99  * If we recieve a TERM signal, perform a "clean shutdown" of the daemon.
100  * This includes to send DELETE notifications for all our active SAs.
101  */
102 static int sigtermed = 0;
103 void daemon_shutdown_now (int);
104 
105 /* The default path of the PID file.  */
106 static char *pid_file = "/var/run/isakmpd.pid";
107 
108 #ifdef USE_DEBUG
109 /* The path of the IKE packet capture log file.  */
110 static char *pcap_file = 0;
111 #endif
112 
113 static void
114 usage (void)
115 {
116   fprintf (stderr,
117 	   "usage: %s [-c config-file] [-d] [-D class=level] [-f fifo]\n"
118 	   "          [-i pid-file] [-n] [-p listen-port] [-P local-port]\n"
119 	   "          [-L] [-l packetlog-file] [-r seed] [-R report-file]\n",
120 	   sysdep_progname ());
121   exit (1);
122 }
123 
124 static void
125 parse_args (int argc, char *argv[])
126 {
127   int ch;
128   char *ep;
129 #ifdef USE_DEBUG
130   int cls, level;
131   int do_packetlog = 0;
132 #endif
133 
134   while ((ch = getopt (argc, argv, "c:dD:f:i:np:P:Ll:r:R:")) != -1) {
135     switch (ch) {
136     case 'c':
137       conf_path = optarg;
138       break;
139 
140     case 'd':
141       debug++;
142       break;
143 
144 #ifdef USE_DEBUG
145     case 'D':
146       if (sscanf (optarg, "%d=%d", &cls, &level) != 2)
147 	{
148 	    if (sscanf (optarg, "A=%d", &level) == 1)
149 	      {
150 		  for (cls = 0; cls < LOG_ENDCLASS; cls++)
151 		    log_debug_cmd (cls, level);
152 	      }
153 	    else
154 	      log_print ("parse_args: -D argument unparseable: %s", optarg);
155 	}
156       else
157 	log_debug_cmd (cls, level);
158       break;
159 #endif /* USE_DEBUG */
160 
161     case 'f':
162       ui_fifo = optarg;
163       break;
164 
165     case 'i':
166       pid_file = optarg;
167       break;
168 
169     case 'n':
170       app_none++;
171       break;
172 
173     case 'p':
174       udp_default_port = optarg;
175       break;
176 
177     case 'P':
178       udp_bind_port = optarg;
179       break;
180 
181 #ifdef USE_DEBUG
182     case 'l':
183       pcap_file = optarg;
184       /* Fallthrough intended.  */
185 
186     case 'L':
187       do_packetlog++;
188       break;
189 #endif /* USE_DEBUG */
190 
191     case 'r':
192       seed = strtoul (optarg, &ep, 0);
193       srandom (seed);
194       if (*ep != '\0')
195 	log_fatal ("parse_args: invalid numeric arg to -r (%s)", optarg);
196       regrand = 1;
197       break;
198 
199     case 'R':
200       report_file = optarg;
201       break;
202 
203     case '?':
204     default:
205       usage ();
206     }
207   }
208   argc -= optind;
209   argv += optind;
210 
211 #ifdef USE_DEBUG
212   if (do_packetlog && !pcap_file)
213     pcap_file = PCAP_FILE_DEFAULT;
214 #endif
215 }
216 
217 /* Reinitialize after a SIGHUP reception.  */
218 static void
219 reinit (void)
220 {
221   log_print ("SIGHUP received, reinitializing daemon.");
222 
223   /*
224    * XXX Remove all(/some?) pending exchange timers? - they may not be
225    *     possible to complete after we've re-read the config file.
226    *     User-initiated SIGHUP's maybe "authorizes" a wait until
227    *     next connection-check.
228    * XXX This means we discard exchange->last_msg, is this really ok?
229    */
230 
231   /* Reinitialize PRNG if we are in deterministic mode.  */
232   if (regrand)
233     srandom (seed);
234 
235   /* Reread config file.  */
236   conf_reinit ();
237 
238   /* Try again to link in libcrypto (good if we started without /usr).  */
239   libcrypto_init ();
240 
241   /* Set timezone */
242   tzset ();
243 
244 #ifdef USE_POLICY
245   /* Reread the policies.  */
246   policy_init ();
247 #endif
248 
249   /* Reinitialize certificates */
250   cert_init ();
251 
252   /* Reinitialize our connection list.  */
253   connection_reinit ();
254 
255   /*
256    * Rescan interfaces.
257    */
258   transport_reinit ();
259 
260   /*
261    * XXX "These" (non-existant) reinitializations should not be done.
262    *   cookie_reinit ();
263    *   ui_reinit ();
264    *   sa_reinit ();
265    */
266 
267   sighupped = 0;
268 }
269 
270 static void
271 sighup (int sig)
272 {
273   sighupped = 1;
274 }
275 
276 /* Report internal state on SIGUSR1.  */
277 static void
278 report (void)
279 {
280   FILE *report, *old;
281   mode_t old_umask;
282 
283   old_umask = umask (S_IRWXG | S_IRWXO);
284   report = fopen (report_file, "w");
285   umask (old_umask);
286 
287   if (!report)
288     {
289       log_error ("fopen (\"%s\", \"w\") failed", report_file);
290       return;
291     }
292 
293   /* Divert the log channel to the report file during the report.  */
294   old = log_current ();
295   log_to (report);
296   ui_report ("r");
297   log_to (old);
298   fclose (report);
299 
300   sigusr1ed = 0;
301 }
302 
303 static void
304 sigusr1 (int sig)
305 {
306   sigusr1ed = 1;
307 }
308 
309 /* Rehash soft expiration timers on SIGUSR2.  */
310 static void
311 rehash_timers (void)
312 {
313 #if 0
314   /* XXX - not yet */
315   log_print ("SIGUSR2 received, rehasing soft expiration timers.");
316 
317   timer_rehash_timers ();
318 #endif
319 
320   sigusr2ed = 0;
321 }
322 
323 static void
324 sigusr2 (int sig)
325 {
326   sigusr2ed = 1;
327 }
328 
329 static int
330 phase2_sa_check (struct sa *sa, void *arg)
331 {
332   return sa->phase == 2;
333 }
334 
335 static void
336 daemon_shutdown (void)
337 {
338   /* Perform a (protocol-wise) clean shutdown of the daemon.  */
339   struct sa *sa;
340 
341   if (sigtermed == 1)
342     {
343       log_print ("isakmpd: shutting down...");
344 
345       /* Delete all active phase 2 SAs.  */
346       while ((sa = sa_find (phase2_sa_check, NULL)))
347 	{
348 	  /* Each DELETE is another (outgoing) message.  */
349 	  sa_delete (sa, 1);
350 	}
351       sigtermed++;
352     }
353   else if (transport_prio_sendqs_empty ())
354     {
355       /*
356        * When the prioritized transport sendq:s are empty, i.e all
357        * the DELETE notifications have been sent, we can shutdown.
358        */
359 
360 #ifdef USE_DEBUG
361       log_packet_stop ();
362 #endif
363       log_print ("isakmpd: exit");
364       exit (0);
365     }
366 }
367 
368 /* called on SIGTERM */
369 void
370 daemon_shutdown_now (int sig)
371 {
372   sigtermed = 1;
373 }
374 
375 /* Write pid file.  */
376 static void
377 write_pid_file (void)
378 {
379   FILE *fp;
380 
381   /* Ignore errors.  */
382   unlink (pid_file);
383 
384   fp = fopen (pid_file, "w");
385   if (fp != NULL)
386     {
387       /* XXX Error checking!  */
388       fprintf (fp, "%d\n", getpid ());
389       fclose (fp);
390     }
391   else
392     log_fatal ("main: fopen (\"%s\", \"w\") failed", pid_file);
393 }
394 
395 int
396 main (int argc, char *argv[])
397 {
398   fd_set *rfds, *wfds;
399   int n, m;
400   size_t mask_size;
401   struct timeval tv, *timeout;
402 
403   parse_args (argc, argv);
404   init ();
405   if (!debug)
406     {
407       if (daemon (0, 0))
408 	log_fatal ("main: daemon (0, 0) failed");
409       /* Switch to syslog.  */
410       log_to (0);
411     }
412 
413   write_pid_file ();
414 
415   /* Reinitialize on HUP reception.  */
416   signal (SIGHUP, sighup);
417 
418   /* Report state on USR1 reception.  */
419   signal (SIGUSR1, sigusr1);
420 
421   /* Rehash soft expiration timers on USR2 reception.  */
422   signal (SIGUSR2, sigusr2);
423 
424   /* Do a clean daemon shutdown on TERM reception.  */
425   signal (SIGTERM, daemon_shutdown_now);
426 
427 #ifdef USE_DEBUG
428   /* If we wanted IKE packet capture to file, initialize it now.  */
429   if (pcap_file != 0)
430     log_packet_init (pcap_file);
431 #endif
432 
433   /* Allocate the file descriptor sets just big enough.  */
434   n = getdtablesize ();
435   mask_size = howmany (n, NFDBITS) * sizeof (fd_mask);
436   rfds = (fd_set *)malloc (mask_size);
437   if (!rfds)
438     log_fatal ("main: malloc (%d) failed", mask_size);
439   wfds = (fd_set *)malloc (mask_size);
440   if (!wfds)
441     log_fatal ("main: malloc (%d) failed", mask_size);
442 
443   while (1)
444     {
445       /* If someone has sent SIGHUP to us, reconfigure.  */
446       if (sighupped)
447 	reinit ();
448 
449       /* and if someone sent SIGUSR1, do a state report.  */
450       if (sigusr1ed)
451 	report ();
452 
453       /* and if someone sent SIGUSR2, do a timer rehash.  */
454       if (sigusr2ed)
455 	rehash_timers ();
456 
457       /*
458        * and if someone set 'sigtermed' (SIGTERM or via the UI), this
459        * indicated we should start a shutdown of the daemon.
460        *
461        * Note: Since _one_ message is sent per iteration of this enclosing
462        * while-loop, and we want to send a number of DELETE notifications,
463        * we must loop atleast this number of times. The daemon_shutdown()
464        * function starts by queueing the DELETEs, all other calls just
465        * increments the 'sigtermed' variable until it reaches a "safe"
466        * value, and the daemon exits.
467        */
468       if (sigtermed)
469 	daemon_shutdown ();
470 
471       /* Setup the descriptors to look for incoming messages at.  */
472       memset (rfds, 0, mask_size);
473       n = transport_fd_set (rfds);
474       FD_SET (ui_socket, rfds);
475       if (ui_socket + 1 > n)
476 	n = ui_socket + 1;
477 
478       /*
479        * XXX Some day we might want to deal with an abstract application
480        * class instead, with many instantiations possible.
481        */
482       if (!app_none && app_socket >= 0)
483 	{
484 	  FD_SET (app_socket, rfds);
485 	  if (app_socket + 1 > n)
486 	    n = app_socket + 1;
487 	}
488 
489       /* Setup the descriptors that have pending messages to send.  */
490       memset (wfds, 0, mask_size);
491       m = transport_pending_wfd_set (wfds);
492       if (m > n)
493 	n = m;
494 
495       /* Find out when the next timed event is.  */
496       timeout = &tv;
497       timer_next_event (&timeout);
498 
499       n = select (n, rfds, wfds, 0, timeout);
500       if (n == -1)
501 	{
502 	  if (errno != EINTR)
503 	    {
504 	      log_error ("select");
505 
506 	      /*
507 	       * In order to give the unexpected error condition time to
508 	       * resolve without letting this process eat up all available CPU
509 	       * we sleep for a short while.
510 	       */
511 	      sleep (1);
512 	    }
513 	}
514       else if (n)
515 	{
516 	  transport_handle_messages (rfds);
517 	  transport_send_messages (wfds);
518 	  if (FD_ISSET (ui_socket, rfds))
519 	    ui_handler ();
520 	  if (!app_none && app_socket >= 0 && FD_ISSET (app_socket, rfds))
521 	    app_handler ();
522 	}
523       timer_handle_expirations ();
524     }
525 }
526