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