1 /* $NetBSD: session.c,v 1.7.6.2 2007/08/01 11:52:22 vanhu Exp $ */
3 /* $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $ */
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
36 #include <sys/types.h>
37 #include <sys/param.h>
39 #include <sys/socket.h>
41 # include <sys/wait.h>
44 # define WEXITSTATUS(s) ((unsigned)(s) >> 8)
47 # define WIFEXITED(s) (((s) & 255) == 0)
50 #ifndef HAVE_NETINET6_IPSEC
51 #include <netinet/ipsec.h>
53 #include <netinet6/ipsec.h>
67 #include <netinet/in.h>
68 #include <netinet/ip.h>
69 #include <netinet/ip_icmp.h>
72 #include <TargetConditionals.h>
73 #include <vproc_priv.h>
74 #include <dispatch/dispatch.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"
95 #include "localconf.h"
96 #include "remoteconf.h"
98 #include "nattraversal.h"
100 #include "vpn_control_var.h"
102 #include "algorithm.h" /* XXX ??? */
105 #include "power_mgmt.h"
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);
120 static volatile sig_atomic_t sigreq
[NSIG
+ 1];
123 static int64_t racoon_keepalive
= -1;
125 dispatch_queue_t main_queue
;
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.
133 launchd_update_racoon_keepalive (Boolean enabled
)
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
,
141 &racoon_keepalive
)) {
143 "failed to swap launchd keepalive integer %d\n", enabled
);
146 return racoon_keepalive
;
152 // Initialize listening sockets, timers, vpn control etc.,
153 // write the PID file and call dispatch_main.
158 char pid_file
[MAXPATHLEN
];
162 main_queue
= dispatch_get_main_queue();
164 /* initialize schedular */
167 /* needs to be called after schedular */
168 if (init_power_mgmt() < 0) {
170 "failed to initialize power-mgmt.");
174 if (lcconf
->autograbaddr
== 1)
175 if (pfroute_init()) {
176 plog(ASL_LEVEL_ERR
, "failed to initialize route socket.\n");
180 plog(ASL_LEVEL_ERR
, "failed to initialize listening addresses.\n");
184 plog(ASL_LEVEL_ERR
, "failed to initialize isakmp");
187 #ifdef ENABLE_VPNCONTROL_PORT
188 if (vpncontrol_init()) {
189 plog(ASL_LEVEL_ERR
, "failed to initialize vpn control port");
195 plog(ASL_LEVEL_ERR
, "failed to initialize signals.\n");
199 for (i
= 0; i
<= NSIG
; i
++)
202 /* write .pid file */
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
));
210 strlcat(pid_file
, _PATH_VARRUN
, sizeof(pid_file
));
211 strlcat(pid_file
, lcconf
->pathinfo
[LC_PATHTYPE_PIDFILE
], sizeof(pid_file
));
213 fp
= fopen(pid_file
, "w");
215 if (fchmod(fileno(fp
),
216 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
) == -1) {
217 plog(ASL_LEVEL_ERR
, "%s", strerror(errno
));
221 fprintf(fp
, "%ld\n", (long)racoon_pid
);
225 "cannot open %s", pid_file
);
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
238 exit(1); // should not be reached!!!
242 /* clear all status and exit program. */
244 close_session(int error
)
247 cleanup_power_mgmt();
249 ike_session_flush_all_phase2(false);
250 ike_session_flush_all_phase1(false);
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
258 plog(ASL_LEVEL_INFO
, "racoon shutdown\n");
264 * waiting the termination of processing until sending DELETE message
265 * for all inbound SA will complete.
268 check_flushsa_stub(p
)
278 struct sadb_msg
*msg
, *end
, *next
;
280 caddr_t mhp
[SADB_EXT_MAX
+ 1];
283 buf
= pfkey_dump_sadb(SADB_SATYPE_UNSPEC
);
285 plog(ASL_LEVEL_DEBUG
,
286 "pfkey_dump_sadb: returned nothing.\n");
290 msg
= ALIGNED_CAST(struct sadb_msg
*)buf
->v
;
291 end
= ALIGNED_CAST(struct sadb_msg
*)(buf
->v
+ buf
->l
);
293 /* counting SA except of dead one. */
296 if (PFKEY_UNUNIT64(msg
->sadb_msg_len
) < sizeof(*msg
))
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
) {
304 if (pfkey_align(msg
, mhp
) || pfkey_check(mhp
)) {
306 "pfkey_check (%s)\n", ipsec_strerror());
311 sa
= ALIGNED_CAST(struct sadb_sa
*)(mhp
[SADB_EXT_SA
]); // Wcast-align fix (void*) - mhp contains pointers to aligned structs
317 if (sa
->sadb_sa_state
!= SADB_SASTATE_DEAD
) {
330 sched_new(1, check_flushsa_stub
, NULL
);
334 #if !TARGET_OS_EMBEDDED
336 vproc_transaction_end(NULL
, lcconf
->vt
);
342 auto_exit_do(void *p
)
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
);
352 check_auto_exit(void)
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
);
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 */
369 lcconf
->auto_exit_sched
= sched_new(lcconf
->auto_exit_delay
, auto_exit_do
, NULL
);
375 static int signals
[] = {
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.
397 for (sig
= 0; sig
<= NSIG
; sig
++) {
398 if (sigreq
[sig
] == 0)
406 /* Catch up childs, mainly scripts.
412 if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM
)) != 0) {
414 "ISAKMP mode config structure reset failed, "
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.
427 ike_session_flush_all_phase2(true);
428 ike_session_flush_all_phase1(true);
431 /* Save old configuration, load new one... */
432 if (cfreparse(sig
)) {
434 "configuration read failed\n");
437 if (lcconf
->logfile_param
== NULL
&& logFileStr
[0] == 0)
438 plogresetfile(lcconf
->pathinfo
[LC_PATHTYPE_LOGFILE
]);
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
446 sched_new(1, check_flushsa_stub
, NULL
);
457 "caught signal %d\n", sig
);
458 pfkey_send_flush(lcconf
->sock_pfkey
,
460 if ( sig
== SIGTERM
){
461 terminated
= 1; /* in case if it hasn't been set yet */
465 sched_new(1, check_flushsa_stub
, NULL
);
472 "caught signal %d\n", sig
);
480 * asynchronous requests will actually dispatched in the
481 * main loop in session().
484 signal_handler(int sig
, siginfo_t
*sigi
, void *ctx
)
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
);
492 /* Do not just set it to 1, because we may miss some signals by just setting
496 if ( sig
== SIGTERM
){
499 dispatch_async(main_queue
,
511 for (i
= 0; signals
[i
] != 0; i
++) {
512 if (set_signal(signals
[i
], signal_handler
) < 0) {
514 "failed to set_signal (%s)\n",
523 set_signal(int sig
, RETSIGTYPE (*func
) (int, siginfo_t
*, void *))
527 memset((caddr_t
)&sa
, 0, sizeof(sa
));
528 sa
.sa_sigaction
= func
;
529 sa
.sa_flags
= SA_RESTART
| SA_SIGINFO
;
531 if (sigemptyset(&sa
.sa_mask
) < 0)
534 if (sigaction(sig
, &sa
, (struct sigaction
*)0) < 0)
541 fatal_error(int error
)
543 close_session(error
== 0 ? -1 : error
);
546 /* suspend all socket sources except pf_key */
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();
563 #ifdef ENABLE_VPNCONTROL_PORT