]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/session.c
ipsec-93.15.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / session.c
1 /* $NetBSD: session.c,v 1.7.6.2 2007/08/01 11:52:22 vanhu Exp $ */
2
3 /* $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $ */
4
5 /*
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * 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. Neither the name of the project nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include "config.h"
35
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/time.h>
39 #include <sys/socket.h>
40 #if HAVE_SYS_WAIT_H
41 # include <sys/wait.h>
42 #endif
43 #ifndef WEXITSTATUS
44 # define WEXITSTATUS(s) ((unsigned)(s) >> 8)
45 #endif
46 #ifndef WIFEXITED
47 # define WIFEXITED(s) (((s) & 255) == 0)
48 #endif
49
50 #ifndef HAVE_NETINET6_IPSEC
51 #include <netinet/ipsec.h>
52 #else
53 #include <netinet6/ipsec.h>
54 #endif
55
56 #include <stdlib.h>
57 #include <stdio.h>
58 #include <string.h>
59 #include <errno.h>
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63 #include <signal.h>
64 #include <sys/stat.h>
65 #include <paths.h>
66
67 #include <netinet/in.h>
68 #include <netinet/ip.h>
69 #include <netinet/ip_icmp.h>
70
71 #include <resolv.h>
72 #include <TargetConditionals.h>
73 #if __APPLE__
74 #include <vproc_priv.h>
75 #endif
76
77 #include "libpfkey.h"
78
79 #include "var.h"
80 #include "misc.h"
81 #include "vmbuf.h"
82 #include "plog.h"
83 #include "debug.h"
84
85 #include "schedule.h"
86 #include "session.h"
87 #include "grabmyaddr.h"
88 #include "evt.h"
89 #include "cfparse_proto.h"
90 #include "isakmp_var.h"
91 #include "isakmp_xauth.h"
92 #include "isakmp_cfg.h"
93 #include "admin_var.h"
94 #include "admin.h"
95 #include "privsep.h"
96 #include "oakley.h"
97 #include "pfkey.h"
98 #include "handler.h"
99 #include "localconf.h"
100 #include "remoteconf.h"
101 #include "backupsa.h"
102 #ifdef ENABLE_NATT
103 #include "nattraversal.h"
104 #endif
105 #include "vpn_control_var.h"
106 #include "policy.h"
107 #include "algorithm.h" /* XXX ??? */
108
109 #include "sainfo.h"
110
111
112
113 extern pid_t racoon_pid;
114 extern int launchedbylaunchd(void);
115 static void close_session __P((void));
116 static void check_rtsock __P((void *));
117 static void initfds __P((void));
118 static void init_signal __P((void));
119 static int set_signal __P((int sig, RETSIGTYPE (*func) __P((int))));
120 static void check_sigreq __P((void));
121 static void check_flushsa_stub __P((void *));
122 static void check_flushsa __P((void));
123 static void auto_exit_do __P((void *));
124 static int close_sockets __P((void));
125
126 static fd_set mask0;
127 static fd_set maskdying;
128 static int nfds = 0;
129 static volatile sig_atomic_t sigreq[NSIG + 1];
130 static int dying = 0;
131 static struct sched *check_rtsock_sched = NULL;
132 int terminated = 0;
133
134 static void
135 reinit_socks (void)
136 {
137 isakmp_close();
138 close(lcconf->rtsock);
139 initmyaddr();
140 if (isakmp_open() < 0) {
141 plog(LLV_ERROR2, LOCATION, NULL,
142 "failed to reopen isakmp sockets\n");
143 }
144 initfds();
145 }
146
147 #ifdef __APPLE__
148 static int64_t racoon_keepalive = -1;
149
150 /*
151 * This is used to (manually) update racoon's launchd keepalive, which is needed because racoon is (mostly)
152 * launched on demand and for <rdar://problem/8773022> requires a keepalive on dirty/failure exits.
153 * The launchd plist can't be used for this because RunOnLoad is required to have keepalive on a failure exit.
154 */
155 int64_t
156 launchd_update_racoon_keepalive (Boolean enabled)
157 {
158 if (launchedbylaunchd()) {
159 vproc_t vp = vprocmgr_lookup_vproc("com.apple.racoon");
160 if (vp) {
161 int64_t val = (__typeof__(val))enabled;
162 if (vproc_swap_integer(vp,
163 VPROC_GSK_BASIC_KEEPALIVE,
164 &val,
165 &racoon_keepalive)) {
166 plog(LLV_ERROR2, LOCATION, NULL,
167 "failed to swap launchd keepalive integer %d\n", enabled);
168 }
169 vproc_release(vp);
170 }
171 }
172 return racoon_keepalive;
173 }
174 #endif // __APPLE__
175
176 int
177 session(void)
178 {
179 fd_set rfds;
180 struct timeval *timeout;
181 int error;
182 struct myaddrs *p;
183 char pid_file[MAXPATHLEN];
184 FILE *fp;
185 int i, update_fds;
186
187 /* initialize schedular */
188 sched_init();
189
190 initmyaddr();
191
192 #ifndef __APPLE__
193 if (isakmp_init() < 0) {
194 #else
195 if (isakmp_init(false) < 0) {
196 #endif /* __APPLE__ */
197 plog(LLV_ERROR2, LOCATION, NULL,
198 "failed to initialize isakmp");
199 exit(1);
200 }
201
202 #ifdef ENABLE_ADMINPORT
203 if (admin_init() < 0) {
204 plog(LLV_ERROR2, LOCATION, NULL,
205 "failed to initialize admin port");
206 exit(1);
207 }
208 #endif
209 #ifdef ENABLE_VPNCONTROL_PORT
210 if (vpncontrol_init() < 0) {
211 plog(LLV_ERROR2, LOCATION, NULL,
212 "failed to initialize vpn control port");
213 exit(1);
214 }
215
216 #endif
217
218 init_signal();
219 initfds();
220
221 #ifndef __APPLE__
222 #ifdef ENABLE_NATT
223 natt_keepalive_init ();
224 #endif
225 #endif
226
227 if (privsep_init() != 0) {
228 plog(LLV_ERROR2, LOCATION, NULL,
229 "failed to initialize privsep");
230 exit(1);
231 }
232
233 for (i = 0; i <= NSIG; i++)
234 sigreq[i] = 0;
235
236 /* write .pid file */
237 if (!f_foreground) {
238 racoon_pid = getpid();
239 if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL)
240 strlcpy(pid_file, _PATH_VARRUN "racoon.pid", sizeof(pid_file));
241 else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/')
242 strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file));
243 else {
244 strlcat(pid_file, _PATH_VARRUN, sizeof(pid_file));
245 strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file));
246 }
247 fp = fopen(pid_file, "w");
248 if (fp) {
249 if (fchmod(fileno(fp),
250 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
251 syslog(LOG_ERR, "%s", strerror(errno));
252 fclose(fp);
253 exit(1);
254 }
255 fprintf(fp, "%ld\n", (long)racoon_pid);
256 fclose(fp);
257 } else {
258 plog(LLV_ERROR, LOCATION, NULL,
259 "cannot open %s", pid_file);
260 }
261 }
262
263 #ifdef __APPLE__
264 #if !TARGET_OS_EMBEDDED
265 // enable keepalive for recovery (from crashes and bad exits... after init)
266 (void)launchd_update_racoon_keepalive(true);
267 #endif // !TARGET_OS_EMBEDDED
268 #endif // __APPLE__
269
270 while (1) {
271 if (!TAILQ_EMPTY(&lcconf->saved_msg_queue))
272 pfkey_post_handler();
273 update_fds = 0;
274 /*
275 * asynchronous requests via signal.
276 * make sure to reset sigreq to 0.
277 */
278 check_sigreq();
279
280 /* scheduling */
281 timeout = schedular();
282 // <rdar://problem/7650111> Workaround: make sure timeout is playing nice
283 if (timeout) {
284 if (timeout->tv_usec < 0 || timeout->tv_usec > SELECT_USEC_MAX ) {
285 timeout->tv_sec += ((__typeof__(timeout->tv_sec))timeout->tv_usec)/SELECT_USEC_MAX;
286 timeout->tv_usec %= SELECT_USEC_MAX;
287 }
288 if (timeout->tv_sec > SELECT_SEC_MAX /* tv_sec is unsigned */) {
289 timeout->tv_sec = SELECT_SEC_MAX;
290 }
291 if (!timeout->tv_sec && !timeout->tv_usec) {
292 timeout->tv_sec = 1;
293 }
294 }
295
296 if (dying)
297 rfds = maskdying;
298 else
299 rfds = mask0;
300 error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout);
301 if (error < 0) {
302 switch (errno) {
303 case EINTR:
304 continue;
305 default:
306 plog(LLV_ERROR2, LOCATION, NULL,
307 "failed select (%s) nfds %d\n",
308 strerror(errno), nfds);
309 reinit_socks();
310 update_fds = 0;
311 continue;
312 }
313 /*NOTREACHED*/
314 }
315
316 #ifdef ENABLE_ADMINPORT
317 if ((lcconf->sock_admin != -1) &&
318 (FD_ISSET(lcconf->sock_admin, &rfds)))
319 admin_handler();
320 #endif
321 #ifdef ENABLE_VPNCONTROL_PORT
322 {
323 struct vpnctl_socket_elem *elem;
324 struct vpnctl_socket_elem *t_elem;
325
326 if ((lcconf->sock_vpncontrol != -1) &&
327 (FD_ISSET(lcconf->sock_vpncontrol, &rfds))) {
328 vpncontrol_handler();
329 update_fds = 1; // in case new socket created - update mask
330 }
331 /* The handler may close and remove the list element
332 * so we can't rely on it being valid after calling
333 * the handler.
334 */
335 LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem) {
336 if ((elem->sock != -1) &&
337 (FD_ISSET(elem->sock, &rfds)))
338 if (vpncontrol_comm_handler(elem))
339 update_fds = 1; // socket closed by peer - update mask
340 }
341 }
342 #endif
343
344 for (p = lcconf->myaddrs; p; p = p->next) {
345 if (!p->addr)
346 continue;
347 if (FD_ISSET(p->sock, &rfds))
348 if ((error = isakmp_handler(p->sock)) == -2)
349 break;
350 }
351 if (error == -2) {
352 reinit_socks();
353 update_fds = 0;
354 }
355
356 if (FD_ISSET(lcconf->sock_pfkey, &rfds))
357 pfkey_handler();
358
359 if (lcconf->rtsock >= 0 && FD_ISSET(lcconf->rtsock, &rfds)) {
360 if (update_myaddrs() && lcconf->autograbaddr)
361 if (check_rtsock_sched == NULL) /* only schedule if not already done */
362 check_rtsock_sched = sched_new(5, check_rtsock, NULL);
363 // initfds(); //%%% BUG FIX - not needed here
364 }
365 if (update_fds) {
366 initfds();
367 update_fds = 0;
368 }
369 }
370 }
371
372
373 /* clear all status and exit program. */
374 static void
375 close_session()
376 {
377 if ( terminated )
378 flushph2(false);
379 flushph1(false);
380 close_sockets();
381 backupsa_clean();
382
383 #ifdef __APPLE__
384 #if !TARGET_OS_EMBEDDED
385 // a clean exit, so disable launchd keepalive
386 (void)launchd_update_racoon_keepalive(false);
387 #endif // !TARGET_OS_EMBEDDED
388 #endif // __APPLE__
389
390 plog(LLV_INFO, LOCATION, NULL, "racoon shutdown\n");
391 exit(0);
392 }
393
394 static void
395 check_rtsock(p)
396 void *p;
397 {
398
399 check_rtsock_sched = NULL;
400 grab_myaddrs();
401 isakmp_close_unused();
402
403 autoconf_myaddrsport();
404 isakmp_open();
405
406 /* initialize socket list again */
407 initfds();
408 }
409
410 static void
411 initfds()
412 {
413 struct myaddrs *p;
414
415 nfds = 0;
416
417 FD_ZERO(&mask0);
418 FD_ZERO(&maskdying);
419
420 #ifdef ENABLE_ADMINPORT
421 if (lcconf->sock_admin != -1) {
422 if (lcconf->sock_admin >= FD_SETSIZE) {
423 plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - admin socket\n");
424 exit(1);
425 }
426 FD_SET(lcconf->sock_admin, &mask0);
427 /* XXX should we listen on admin socket when dying ?
428 */
429 #if 0
430 FD_SET(lcconf->sock_admin, &maskdying);
431 #endif
432 nfds = (nfds > lcconf->sock_admin ? nfds : lcconf->sock_admin);
433 }
434 #endif
435 #ifdef ENABLE_VPNCONTROL_PORT
436 {
437 struct vpnctl_socket_elem *elem;
438
439 if (lcconf->sock_vpncontrol != -1) {
440 if (lcconf->sock_vpncontrol >= FD_SETSIZE) {
441 plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - vpncontrol socket\n");
442 exit(1);
443 }
444 FD_SET(lcconf->sock_vpncontrol, &mask0);
445 nfds = (nfds > lcconf->sock_vpncontrol ? nfds : lcconf->sock_vpncontrol);
446 }
447
448 LIST_FOREACH(elem, &lcconf->vpnctl_comm_socks, chain) {
449 if (elem->sock != -1) {
450 if (elem->sock >= FD_SETSIZE) {
451 plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun vpnctl_comm socket\n");
452 exit(1);
453 }
454 FD_SET(elem->sock, &mask0);
455 nfds = (nfds > elem->sock ? nfds : elem->sock);
456 }
457 }
458 }
459 #endif
460
461 if (lcconf->sock_pfkey >= FD_SETSIZE) {
462 plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - pfkey socket\n");
463 exit(1);
464 }
465 FD_SET(lcconf->sock_pfkey, &mask0);
466 FD_SET(lcconf->sock_pfkey, &maskdying);
467 nfds = (nfds > lcconf->sock_pfkey ? nfds : lcconf->sock_pfkey);
468 if (lcconf->rtsock >= 0) {
469 if (lcconf->rtsock >= FD_SETSIZE) {
470 plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - rt socket\n");
471 exit(1);
472 }
473 FD_SET(lcconf->rtsock, &mask0);
474 nfds = (nfds > lcconf->rtsock ? nfds : lcconf->rtsock);
475 }
476
477 for (p = lcconf->myaddrs; p; p = p->next) {
478 if (!p->addr)
479 continue;
480 if (p->sock < 0)
481 continue;
482 if (p->sock >= FD_SETSIZE) {
483 plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - isakmp socket\n");
484 exit(1);
485 }
486 FD_SET(p->sock, &mask0);
487 nfds = (nfds > p->sock ? nfds : p->sock);
488 }
489 nfds++;
490 }
491
492
493 static int signals[] = {
494 SIGHUP,
495 SIGINT,
496 SIGTERM,
497 SIGUSR1,
498 SIGUSR2,
499 SIGCHLD,
500 SIGPIPE,
501 0
502 };
503
504 /*
505 * asynchronous requests will actually dispatched in the
506 * main loop in session().
507 */
508 RETSIGTYPE
509 signal_handler(sig)
510 int sig;
511 {
512 /* Do not just set it to 1, because we may miss some signals by just setting
513 * values to 0/1
514 */
515 sigreq[sig]++;
516 if ( sig == SIGTERM ){
517 terminated = 1;
518 }
519 }
520
521 static void
522 check_sigreq()
523 {
524 int sig;
525
526 /*
527 * XXX We are not able to tell if we got
528 * several time the same signal. This is
529 * not a problem for the current code,
530 * but we shall remember this limitation.
531 */
532 for (sig = 0; sig <= NSIG; sig++) {
533 if (sigreq[sig] == 0)
534 continue;
535
536 sigreq[sig]--;
537 switch(sig) {
538 case 0:
539 return;
540
541 /* Catch up childs, mainly scripts.
542 */
543 case SIGCHLD:
544 {
545 pid_t pid;
546 int s;
547
548 pid = wait(&s);
549 }
550 break;
551
552 #ifdef DEBUG_RECORD_MALLOCATION
553 /*
554 * XXX This operation is signal handler unsafe and may lead to
555 * crashes and security breaches: See Henning Brauer talk at
556 * EuroBSDCon 2005. Do not run in production with this option
557 * enabled.
558 */
559 case SIGUSR2:
560 DRM_dump();
561 break;
562 #endif
563
564 case SIGUSR1:
565 case SIGHUP:
566 #ifdef ENABLE_HYBRID
567 if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) {
568 plog(LLV_ERROR, LOCATION, NULL,
569 "ISAKMP mode config structure reset failed, "
570 "not reloading\n");
571 return;
572 }
573 #endif
574 if ( terminated )
575 break;
576
577 /* Save old configuration, load new one... */
578 isakmp_close();
579 close(lcconf->rtsock);
580 if (cfreparse(sig)) {
581 plog(LLV_ERROR2, LOCATION, NULL,
582 "configuration read failed\n");
583 exit(1);
584 }
585 if (lcconf->logfile_param == NULL)
586 plogreset(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]);
587
588 initmyaddr();
589 isakmp_cleanup();
590 #ifdef __APPLE__
591 isakmp_init(true);
592 #else
593 isakmp_init();
594 #endif /* __APPLE__ */
595 initfds();
596 #if TARGET_OS_EMBEDDED
597 if (no_remote_configs(TRUE)) {
598 EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL);
599 pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
600 #ifdef ENABLE_FASTQUIT
601 close_session();
602 #else
603 sched_new(1, check_flushsa_stub, NULL);
604 #endif
605 dying = 1;
606 }
607 #endif
608 break;
609
610 case SIGINT:
611 case SIGTERM:
612 plog(LLV_INFO, LOCATION, NULL,
613 "caught signal %d\n", sig);
614 EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL);
615 pfkey_send_flush(lcconf->sock_pfkey,
616 SADB_SATYPE_UNSPEC);
617 if ( sig == SIGTERM ){
618 terminated = 1; /* in case if it hasn't been set yet */
619 close_session();
620 }
621 else
622 sched_new(1, check_flushsa_stub, NULL);
623
624 dying = 1;
625 break;
626
627 default:
628 plog(LLV_INFO, LOCATION, NULL,
629 "caught signal %d\n", sig);
630 break;
631 }
632 }
633 }
634
635 /*
636 * waiting the termination of processing until sending DELETE message
637 * for all inbound SA will complete.
638 */
639 static void
640 check_flushsa_stub(p)
641 void *p;
642 {
643
644 check_flushsa();
645 }
646
647 static void
648 check_flushsa()
649 {
650 vchar_t *buf;
651 struct sadb_msg *msg, *end, *next;
652 struct sadb_sa *sa;
653 caddr_t mhp[SADB_EXT_MAX + 1];
654 int n;
655
656 buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC);
657 if (buf == NULL) {
658 plog(LLV_DEBUG, LOCATION, NULL,
659 "pfkey_dump_sadb: returned nothing.\n");
660 return;
661 }
662
663 msg = (struct sadb_msg *)buf->v;
664 end = (struct sadb_msg *)(buf->v + buf->l);
665
666 /* counting SA except of dead one. */
667 n = 0;
668 while (msg < end) {
669 if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg))
670 break;
671 next = (struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len));
672 if (msg->sadb_msg_type != SADB_DUMP) {
673 msg = next;
674 continue;
675 }
676
677 if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
678 plog(LLV_ERROR, LOCATION, NULL,
679 "pfkey_check (%s)\n", ipsec_strerror());
680 msg = next;
681 continue;
682 }
683
684 sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]);
685 if (!sa) {
686 msg = next;
687 continue;
688 }
689
690 if (sa->sadb_sa_state != SADB_SASTATE_DEAD) {
691 n++;
692 msg = next;
693 continue;
694 }
695
696 msg = next;
697 }
698
699 if (buf != NULL)
700 vfree(buf);
701
702 if (n) {
703 sched_new(1, check_flushsa_stub, NULL);
704 return;
705 }
706
707 #if !TARGET_OS_EMBEDDED
708 // abort exit if policies/config/control state is still there
709 if (vpn_control_connected() ||
710 policies_installed() ||
711 !no_remote_configs(FALSE)) {
712 return;
713 }
714 #endif
715
716 close_session();
717 #if !TARGET_OS_EMBEDDED
718 if (lcconf->vt)
719 vproc_transaction_end(NULL, lcconf->vt);
720 #endif
721 }
722
723 void
724 auto_exit_do(void *p)
725 {
726 EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL);
727 plog(LLV_DEBUG, LOCATION, NULL,
728 "performing auto exit\n");
729 pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
730 sched_new(1, check_flushsa_stub, NULL);
731 dying = 1;
732 }
733
734 void
735 check_auto_exit(void)
736 {
737 if (lcconf->auto_exit_sched != NULL) { /* exit scheduled? */
738 if (lcconf->auto_exit_state != LC_AUTOEXITSTATE_ENABLED
739 || vpn_control_connected() /* vpn control connected */
740 || policies_installed() /* policies installed in kernel */
741 || !no_remote_configs(FALSE)) /* remote or anonymous configs */
742 SCHED_KILL(lcconf->auto_exit_sched);
743 } else { /* exit not scheduled */
744 if (lcconf->auto_exit_state == LC_AUTOEXITSTATE_ENABLED
745 && !vpn_control_connected()
746 && !policies_installed()
747 && no_remote_configs(FALSE))
748 if (lcconf->auto_exit_delay == 0)
749 auto_exit_do(NULL); /* immediate exit */
750 else
751 lcconf->auto_exit_sched = sched_new(lcconf->auto_exit_delay, auto_exit_do, NULL);
752 }
753 }
754
755
756 static void
757 init_signal()
758 {
759 int i;
760
761 for (i = 0; signals[i] != 0; i++)
762 if (set_signal(signals[i], signal_handler) < 0) {
763 plog(LLV_ERROR2, LOCATION, NULL,
764 "failed to set_signal (%s)\n",
765 strerror(errno));
766 exit(1);
767 }
768 }
769
770 static int
771 set_signal(sig, func)
772 int sig;
773 RETSIGTYPE (*func) __P((int));
774 {
775 struct sigaction sa;
776
777 memset((caddr_t)&sa, 0, sizeof(sa));
778 sa.sa_handler = func;
779 sa.sa_flags = SA_RESTART;
780
781 if (sigemptyset(&sa.sa_mask) < 0)
782 return -1;
783
784 if (sigaction(sig, &sa, (struct sigaction *)0) < 0)
785 return(-1);
786
787 return 0;
788 }
789
790 static int
791 close_sockets()
792 {
793 isakmp_close();
794 pfkey_close(lcconf->sock_pfkey);
795 #ifdef ENABLE_ADMINPORT
796 (void)admin_close();
797 #endif
798 #ifdef ENABLE_VPNCONTROL_PORT
799 vpncontrol_close();
800 #endif
801 return 0;
802 }
803
804