]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/session.c
ipsec-258.90.2.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 #include <vproc_priv.h>
74 #include <dispatch/dispatch.h>
75
76 #include "libpfkey.h"
77
78 #include "var.h"
79 #include "misc.h"
80 #include "vmbuf.h"
81 #include "plog.h"
82 #include "debug.h"
83 #include "plog.h"
84
85 #include "schedule.h"
86 #include "session.h"
87 #include "grabmyaddr.h"
88 #include "cfparse_proto.h"
89 #include "isakmp_var.h"
90 #include "isakmp_xauth.h"
91 #include "isakmp_cfg.h"
92 #include "oakley.h"
93 #include "pfkey.h"
94 #include "handler.h"
95 #include "localconf.h"
96 #include "remoteconf.h"
97 #ifdef ENABLE_NATT
98 #include "nattraversal.h"
99 #endif
100 #include "vpn_control_var.h"
101 #include "policy.h"
102 #include "algorithm.h" /* XXX ??? */
103
104 #include "sainfo.h"
105 #include "power_mgmt.h"
106
107
108
109 extern pid_t racoon_pid;
110 extern int launchdlaunched;
111 static void close_session (int);
112 static int init_signal (void);
113 static int set_signal (int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *));
114 static void check_sigreq (void);
115 static void check_flushsa_stub (void *);
116 static void check_flushsa (void);
117 static void auto_exit_do (void *);
118 static int close_sockets (void);
119
120 static volatile sig_atomic_t sigreq[NSIG + 1];
121 int terminated = 0;
122
123 static int64_t racoon_keepalive = -1;
124
125 dispatch_queue_t main_queue;
126
127 /*
128 * This is used to (manually) update racoon's launchd keepalive, which is needed because racoon is (mostly)
129 * launched on demand and for <rdar://problem/8768510> requires a keepalive on dirty/failure exits.
130 * The launchd plist can't be used for this because RunOnLoad is required to have keepalive on a failure exit.
131 */
132 int64_t
133 launchd_update_racoon_keepalive (Boolean enabled)
134 {
135 if (launchdlaunched) {
136 int64_t val = (__typeof__(val))enabled;
137 /* Set our own KEEPALIVE value */
138 if (vproc_swap_integer(NULL,
139 VPROC_GSK_BASIC_KEEPALIVE,
140 &val,
141 &racoon_keepalive)) {
142 plog(ASL_LEVEL_ERR,
143 "failed to swap launchd keepalive integer %d\n", enabled);
144 }
145 }
146 return racoon_keepalive;
147 }
148
149 //
150 // Session
151 //
152 // Initialize listening sockets, timers, vpn control etc.,
153 // write the PID file and call dispatch_main.
154 //
155 void
156 session(void)
157 {
158 char pid_file[MAXPATHLEN];
159 FILE *fp;
160 int i;
161
162 main_queue = dispatch_get_main_queue();
163
164 /* initialize schedular */
165 sched_init();
166
167 /* needs to be called after schedular */
168 if (init_power_mgmt() < 0) {
169 plog(ASL_LEVEL_ERR,
170 "failed to initialize power-mgmt.");
171 exit(1);
172 }
173
174 if (lcconf->autograbaddr == 1)
175 if (pfroute_init()) {
176 plog(ASL_LEVEL_ERR, "failed to initialize route socket.\n");
177 exit(1);
178 }
179 if (initmyaddr()) {
180 plog(ASL_LEVEL_ERR, "failed to initialize listening addresses.\n");
181 exit(1);
182 }
183 if (isakmp_init()) {
184 plog(ASL_LEVEL_ERR, "failed to initialize isakmp");
185 exit(1);
186 }
187 #ifdef ENABLE_VPNCONTROL_PORT
188 if (vpncontrol_init()) {
189 plog(ASL_LEVEL_ERR, "failed to initialize vpn control port");
190 //exit(1);
191 }
192 #endif
193
194 if (init_signal()) {
195 plog(ASL_LEVEL_ERR, "failed to initialize signals.\n");
196 exit(1);
197 }
198
199 for (i = 0; i <= NSIG; i++)
200 sigreq[i] = 0;
201
202 /* write .pid file */
203 if (!f_foreground) {
204 racoon_pid = getpid();
205 if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL)
206 strlcpy(pid_file, _PATH_VARRUN "racoon.pid", sizeof(pid_file));
207 else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/')
208 strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file));
209 else {
210 strlcat(pid_file, _PATH_VARRUN, sizeof(pid_file));
211 strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file));
212 }
213 fp = fopen(pid_file, "w");
214 if (fp) {
215 if (fchmod(fileno(fp),
216 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
217 plog(ASL_LEVEL_ERR, "%s", strerror(errno));
218 fclose(fp);
219 exit(1);
220 }
221 fprintf(fp, "%ld\n", (long)racoon_pid);
222 fclose(fp);
223 } else {
224 plog(ASL_LEVEL_ERR,
225 "cannot open %s", pid_file);
226 }
227 }
228 #if !TARGET_OS_EMBEDDED
229 // enable keepalive for recovery (from crashes and bad exits... after init)
230 (void)launchd_update_racoon_keepalive(true);
231 #endif // !TARGET_OS_EMBEDDED
232
233 // Off to the races!
234 if (!terminated) {
235 dispatch_main();
236 }
237
238 exit(1); // should not be reached!!!
239 }
240
241
242 /* clear all status and exit program. */
243 static void
244 close_session(int error)
245 {
246 sched_killall();
247 cleanup_power_mgmt();
248 if ( terminated )
249 ike_session_flush_all_phase2(false);
250 ike_session_flush_all_phase1(false);
251 close_sockets();
252
253 #if !TARGET_OS_EMBEDDED
254 // a clean exit, so disable launchd keepalive
255 (void)launchd_update_racoon_keepalive(false);
256 #endif // !TARGET_OS_EMBEDDED
257
258 plog(ASL_LEVEL_INFO, "racoon shutdown\n");
259 exit(0);
260 }
261
262
263 /*
264 * waiting the termination of processing until sending DELETE message
265 * for all inbound SA will complete.
266 */
267 static void
268 check_flushsa_stub(p)
269 void *p;
270 {
271 check_flushsa();
272 }
273
274 static void
275 check_flushsa()
276 {
277 vchar_t *buf;
278 struct sadb_msg *msg, *end, *next;
279 struct sadb_sa *sa;
280 caddr_t mhp[SADB_EXT_MAX + 1];
281 int n;
282
283 buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC);
284 if (buf == NULL) {
285 plog(ASL_LEVEL_DEBUG,
286 "pfkey_dump_sadb: returned nothing.\n");
287 return;
288 }
289
290 msg = ALIGNED_CAST(struct sadb_msg *)buf->v;
291 end = ALIGNED_CAST(struct sadb_msg *)(buf->v + buf->l);
292
293 /* counting SA except of dead one. */
294 n = 0;
295 while (msg < end) {
296 if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg))
297 break;
298 next = ALIGNED_CAST(struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len)); // Wcast-align fix (void*) - aligned buffer + multiple of 64
299 if (msg->sadb_msg_type != SADB_DUMP) {
300 msg = next;
301 continue;
302 }
303
304 if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
305 plog(ASL_LEVEL_ERR,
306 "pfkey_check (%s)\n", ipsec_strerror());
307 msg = next;
308 continue;
309 }
310
311 sa = ALIGNED_CAST(struct sadb_sa *)(mhp[SADB_EXT_SA]); // Wcast-align fix (void*) - mhp contains pointers to aligned structs
312 if (!sa) {
313 msg = next;
314 continue;
315 }
316
317 if (sa->sadb_sa_state != SADB_SASTATE_DEAD) {
318 n++;
319 msg = next;
320 continue;
321 }
322
323 msg = next;
324 }
325
326 if (buf != NULL)
327 vfree(buf);
328
329 if (n) {
330 sched_new(1, check_flushsa_stub, NULL);
331 return;
332 }
333
334 #if !TARGET_OS_EMBEDDED
335 if (lcconf->vt)
336 vproc_transaction_end(NULL, lcconf->vt);
337 #endif
338 close_session(0);
339 }
340
341 void
342 auto_exit_do(void *p)
343 {
344 plog(ASL_LEVEL_DEBUG,
345 "performing auto exit\n");
346 pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
347 sched_new(1, check_flushsa_stub, NULL);
348 dying();
349 }
350
351 void
352 check_auto_exit(void)
353 {
354 if (lcconf->auto_exit_sched) { /* exit scheduled? */
355 if (lcconf->auto_exit_state != LC_AUTOEXITSTATE_ENABLED
356 || vpn_control_connected() /* vpn control connected */
357 || policies_installed() /* policies installed in kernel */
358 || !no_remote_configs(FALSE)) { /* remote or anonymous configs */
359 SCHED_KILL(lcconf->auto_exit_sched);
360 }
361 } else { /* exit not scheduled */
362 if (lcconf->auto_exit_state == LC_AUTOEXITSTATE_ENABLED
363 && !vpn_control_connected()
364 && !policies_installed()
365 && no_remote_configs(FALSE)) {
366 if (lcconf->auto_exit_delay == 0) {
367 auto_exit_do(NULL); /* immediate exit */
368 } else {
369 lcconf->auto_exit_sched = sched_new(lcconf->auto_exit_delay, auto_exit_do, NULL);
370 }
371 }
372 }
373 }
374
375 static int signals[] = {
376 SIGHUP,
377 SIGINT,
378 SIGTERM,
379 SIGUSR1,
380 SIGUSR2,
381 SIGPIPE,
382 0
383 };
384
385
386 static void
387 check_sigreq()
388 {
389 int sig;
390
391 /*
392 * XXX We are not able to tell if we got
393 * several time the same signal. This is
394 * not a problem for the current code,
395 * but we shall remember this limitation.
396 */
397 for (sig = 0; sig <= NSIG; sig++) {
398 if (sigreq[sig] == 0)
399 continue;
400
401 sigreq[sig]--;
402 switch(sig) {
403 case 0:
404 return;
405
406 /* Catch up childs, mainly scripts.
407 */
408
409 case SIGUSR1:
410 case SIGHUP:
411 #ifdef ENABLE_HYBRID
412 if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) {
413 plog(ASL_LEVEL_ERR,
414 "ISAKMP mode config structure reset failed, "
415 "not reloading\n");
416 return;
417 }
418 #endif
419 if ( terminated )
420 break;
421
422 /*
423 * if we got a HUP... try graceful teardown of sessions before we close and reopen sockets...
424 * so that info-deletes notifications can make it to the peer.
425 */
426 if (sig == SIGHUP) {
427 ike_session_flush_all_phase2(true);
428 ike_session_flush_all_phase1(true);
429 }
430
431 /* Save old configuration, load new one... */
432 if (cfreparse(sig)) {
433 plog(ASL_LEVEL_ERR,
434 "configuration read failed\n");
435 exit(1);
436 }
437 if (lcconf->logfile_param == NULL && logFileStr[0] == 0)
438 plogresetfile(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]);
439
440 #if TARGET_OS_EMBEDDED
441 if (no_remote_configs(TRUE)) {
442 pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
443 #ifdef ENABLE_FASTQUIT
444 close_session(0);
445 #else
446 sched_new(1, check_flushsa_stub, NULL);
447 #endif
448 dying();
449 }
450 #endif
451
452 break;
453
454 case SIGINT:
455 case SIGTERM:
456 plog(ASL_LEVEL_INFO,
457 "caught signal %d\n", sig);
458 pfkey_send_flush(lcconf->sock_pfkey,
459 SADB_SATYPE_UNSPEC);
460 if ( sig == SIGTERM ){
461 terminated = 1; /* in case if it hasn't been set yet */
462 close_session(0);
463 }
464 else
465 sched_new(1, check_flushsa_stub, NULL);
466
467 dying();
468 break;
469
470 default:
471 plog(ASL_LEVEL_INFO,
472 "caught signal %d\n", sig);
473 break;
474 }
475 }
476 }
477
478
479 /*
480 * asynchronous requests will actually dispatched in the
481 * main loop in session().
482 */
483 RETSIGTYPE
484 signal_handler(int sig, siginfo_t *sigi, void *ctx)
485 {
486 #if 0
487 plog(ASL_LEVEL_DEBUG,
488 "%s received signal %d from pid %d uid %d\n\n",
489 __FUNCTION__, sig, sigi->si_pid, sigi->si_uid);
490 #endif
491
492 /* Do not just set it to 1, because we may miss some signals by just setting
493 * values to 0/1
494 */
495 sigreq[sig]++;
496 if ( sig == SIGTERM ){
497 terminated = 1;
498 }
499 dispatch_async(main_queue,
500 ^{
501 check_sigreq();
502 });
503 }
504
505
506 static int
507 init_signal()
508 {
509 int i;
510
511 for (i = 0; signals[i] != 0; i++) {
512 if (set_signal(signals[i], signal_handler) < 0) {
513 plog(ASL_LEVEL_ERR,
514 "failed to set_signal (%s)\n",
515 strerror(errno));
516 return (1);
517 }
518 }
519 return 0;
520 }
521
522 static int
523 set_signal(int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *))
524 {
525 struct sigaction sa;
526
527 memset((caddr_t)&sa, 0, sizeof(sa));
528 sa.sa_sigaction = func;
529 sa.sa_flags = SA_RESTART | SA_SIGINFO;
530
531 if (sigemptyset(&sa.sa_mask) < 0)
532 return -1;
533
534 if (sigaction(sig, &sa, (struct sigaction *)0) < 0)
535 return(-1);
536
537 return 0;
538 }
539
540 void
541 fatal_error(int error)
542 {
543 close_session(error == 0 ? -1 : error);
544 }
545
546 /* suspend all socket sources except pf_key */
547 void
548 dying(void)
549 {
550 if (lcconf->rt_source)
551 dispatch_suspend(lcconf->rt_source);
552 if (lcconf->vpncontrol_source)
553 dispatch_suspend(lcconf->vpncontrol_source);
554 isakmp_suspend_sockets();
555 }
556
557 static int
558 close_sockets()
559 {
560 pfroute_close();
561 isakmp_close();
562 pfkey_close();
563 #ifdef ENABLE_VPNCONTROL_PORT
564 vpncontrol_close();
565 #endif
566
567 return 0;
568 }
569
570