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
109extern pid_t racoon_pid;
110extern int launchdlaunched;
111static void close_session (int);
112static int init_signal (void);
113static int set_signal (int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *));
114static void check_sigreq (void);
115static void check_flushsa_stub (void *);
116static void check_flushsa (void);
117static void auto_exit_do (void *);
118static int close_sockets (void);
119
120static volatile sig_atomic_t sigreq[NSIG + 1];
121int terminated = 0;
122
123static int64_t racoon_keepalive = -1;
124
125dispatch_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 */
132int64_t
133launchd_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//
155void
156session(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. */
243static void
244close_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 */
267static void
268check_flushsa_stub(p)
269	void *p;
270{
271	check_flushsa();
272}
273
274static void
275check_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
341void
342auto_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
351void
352check_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
375static int signals[] = {
376	SIGHUP,
377	SIGINT,
378	SIGTERM,
379	SIGUSR1,
380	SIGUSR2,
381	SIGPIPE,
382	0
383};
384
385
386static void
387check_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 */
483RETSIGTYPE
484signal_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
506static int
507init_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
522static int
523set_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
540void
541fatal_error(int error)
542{
543    close_session(error == 0 ? -1 : error);
544}
545
546/* suspend all socket sources except pf_key */
547void
548dying(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
557static int
558close_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
571