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#include <NetworkExtension/NEPolicy.h>
108#include <sys/proc_info.h>
109#include <libproc.h>
110
111
112extern pid_t racoon_pid;
113extern int launchdlaunched;
114static void close_session (int);
115static int init_signal (void);
116static int set_signal (int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *));
117static void check_sigreq (void);
118static void check_flushsa_stub (void *);
119static void check_flushsa (void);
120static void auto_exit_do (void *);
121static int close_sockets (void);
122
123static volatile sig_atomic_t sigreq[NSIG + 1];
124int terminated = 0;
125
126static int64_t racoon_keepalive = -1;
127
128dispatch_queue_t main_queue;
129
130static NEPolicySessionRef policySession = NULL;
131
132/*
133 * This is used to (manually) update racoon's launchd keepalive, which is needed because racoon is (mostly)
134 * launched on demand and for <rdar://problem/8768510> requires a keepalive on dirty/failure exits.
135 * The launchd plist can't be used for this because RunOnLoad is required to have keepalive on a failure exit.
136 */
137int64_t
138launchd_update_racoon_keepalive (Boolean enabled)
139{
140	if (launchdlaunched) {
141		int64_t     val = (__typeof__(val))enabled;
142		/* Set our own KEEPALIVE value */
143		if (vproc_swap_integer(NULL,
144							   VPROC_GSK_BASIC_KEEPALIVE,
145							   &val,
146							   &racoon_keepalive)) {
147			plog(ASL_LEVEL_ERR,
148				 "failed to swap launchd keepalive integer %d\n", enabled);
149		}
150	}
151	return racoon_keepalive;
152}
153
154static CFUUIDRef
155copy_racoon_proc_uuid(void)
156{
157	struct proc_uniqidentifierinfo procu;
158	CFUUIDBytes uuidBytes;
159	int size = 0;
160
161	memset(&procu, 0, sizeof(procu));
162	size = proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO, 1, &procu, PROC_PIDUNIQIDENTIFIERINFO_SIZE);
163	if (size != PROC_PIDUNIQIDENTIFIERINFO_SIZE) {
164		return (NULL);
165	}
166
167	memcpy(&uuidBytes, procu.p_uuid, sizeof(CFUUIDBytes));
168	return CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, uuidBytes);
169}
170
171static bool
172policy_session_init(void)
173{
174	bool success = true;
175	policySession = NEPolicyCreateSession(kCFAllocatorDefault, CFSTR("racoon"), NULL, NULL);
176	if (policySession == NULL) {
177		return false;
178	}
179
180	CFUUIDRef proc_uuid = copy_racoon_proc_uuid();
181	if (proc_uuid == NULL) {
182		return false;
183	}
184
185	CFMutableArrayRef conditions = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
186	if (conditions) {
187		CFMutableDictionaryRef uuidCondition = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
188		if (uuidCondition) {
189			CFDictionarySetValue(uuidCondition, kNEPolicyConditionType, kNEPolicyValPolicyConditionTypeApplication);
190			CFDictionarySetValue(uuidCondition, kNEPolicyApplicationUUID, proc_uuid);
191			CFArrayAppendValue(conditions, uuidCondition);
192			CFRelease(uuidCondition);
193		} else {
194			success = false;
195		}
196
197		CFMutableDictionaryRef interfacesCondition = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
198		if (interfacesCondition) {
199			CFDictionarySetValue(interfacesCondition, kNEPolicyConditionType, kNEPolicyValPolicyConditionTypeAllInterfaces);
200			CFArrayAppendValue(conditions, interfacesCondition);
201			CFRelease(interfacesCondition);
202		} else {
203			success = false;
204		}
205	} else {
206		success = false;
207	}
208
209	CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
210	if (result) {
211		CFDictionaryAddValue(result, kNEPolicyResult, kNEPolicyValPolicyResultPass);
212	} else {
213		success = false;
214	}
215
216	if (success) {
217		success = (NEPolicyAdd(policySession, 0, conditions, result, NULL) != kNEPolicyIDInvalid);
218	}
219
220	if (result) {
221		CFRelease(result);
222	}
223	if (conditions) {
224		CFRelease(conditions);
225	}
226	if (proc_uuid) {
227		CFRelease(proc_uuid);
228	}
229
230	return (success && NEPolicyApply(policySession));
231}
232
233//
234// Session
235//
236// Initialize listening sockets, timers, vpn control etc.,
237// write the PID file and call dispatch_main.
238//
239void
240session(void)
241{
242	char pid_file[MAXPATHLEN];
243	FILE *fp;
244	int i;
245
246    main_queue = dispatch_get_main_queue();
247
248	/* initialize schedular */
249	sched_init();
250
251	/* needs to be called after schedular */
252	if (init_power_mgmt() < 0) {
253        plog(ASL_LEVEL_ERR,
254             "failed to initialize power-mgmt.");
255		exit(1);
256	}
257
258    if (lcconf->autograbaddr == 1)
259        if (pfroute_init()) {
260            plog(ASL_LEVEL_ERR, "failed to initialize route socket.\n");
261            exit(1);
262        }
263
264	if (!policy_session_init()) {
265		plog(ASL_LEVEL_ERR, "failed to initialize NEPolicy session.\n");
266	}
267
268    if (initmyaddr()) {
269        plog(ASL_LEVEL_ERR, "failed to initialize listening addresses.\n");
270        exit(1);
271    }
272	if (isakmp_init()) {
273		plog(ASL_LEVEL_ERR, "failed to initialize isakmp");
274		exit(1);
275	}
276#ifdef ENABLE_VPNCONTROL_PORT
277	if (vpncontrol_init()) {
278		plog(ASL_LEVEL_ERR, "failed to initialize vpn control port");
279		//exit(1);
280	}
281#endif
282
283	if (init_signal()) {
284        plog(ASL_LEVEL_ERR, "failed to initialize signals.\n");
285		exit(1);
286    }
287
288	for (i = 0; i <= NSIG; i++)
289		sigreq[i] = 0;
290
291	/* write .pid file */
292	if (!f_foreground) {
293		racoon_pid = getpid();
294		if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL)
295			strlcpy(pid_file, _PATH_VARRUN "racoon.pid", sizeof(pid_file));
296		else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/')
297			strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file));
298		else {
299			strlcat(pid_file, _PATH_VARRUN, sizeof(pid_file));
300			strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file));
301		}
302		fp = fopen(pid_file, "w");
303		if (fp) {
304			if (fchmod(fileno(fp),
305				S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
306				plog(ASL_LEVEL_ERR, "%s", strerror(errno));
307				fclose(fp);
308				exit(1);
309			}
310			fprintf(fp, "%ld\n", (long)racoon_pid);
311			fclose(fp);
312		} else {
313			plog(ASL_LEVEL_ERR,
314				"cannot open %s", pid_file);
315		}
316	}
317#if !TARGET_OS_EMBEDDED
318	// enable keepalive for recovery (from crashes and bad exits... after init)
319	(void)launchd_update_racoon_keepalive(true);
320#endif // !TARGET_OS_EMBEDDED
321
322    // Off to the races!
323    if (!terminated) {
324        dispatch_main();
325    }
326
327    exit(1);    // should not be reached!!!
328}
329
330
331/* clear all status and exit program. */
332static void
333close_session(int error)
334{
335    sched_killall();
336    cleanup_power_mgmt();
337	if ( terminated )
338		ike_session_flush_all_phase2(false);
339	ike_session_flush_all_phase1(false);
340	close_sockets();
341
342#if !TARGET_OS_EMBEDDED
343	// a clean exit, so disable launchd keepalive
344	(void)launchd_update_racoon_keepalive(false);
345#endif // !TARGET_OS_EMBEDDED
346
347	plog(ASL_LEVEL_INFO, "racoon shutdown\n");
348	exit(0);
349}
350
351
352/*
353 * waiting the termination of processing until sending DELETE message
354 * for all inbound SA will complete.
355 */
356static void
357check_flushsa_stub(p)
358	void *p;
359{
360	check_flushsa();
361}
362
363static void
364check_flushsa()
365{
366	vchar_t *buf;
367	struct sadb_msg *msg, *end, *next;
368	struct sadb_sa *sa;
369	caddr_t mhp[SADB_EXT_MAX + 1];
370	int n;
371
372	buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC);
373	if (buf == NULL) {
374		plog(ASL_LEVEL_DEBUG,
375		    "pfkey_dump_sadb: returned nothing.\n");
376		return;
377	}
378
379	msg = ALIGNED_CAST(struct sadb_msg *)buf->v;
380	end = ALIGNED_CAST(struct sadb_msg *)(buf->v + buf->l);
381
382	/* counting SA except of dead one. */
383	n = 0;
384	while (msg < end) {
385		if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg))
386			break;
387		next = ALIGNED_CAST(struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len));    // Wcast-align fix (void*) - aligned buffer + multiple of 64
388		if (msg->sadb_msg_type != SADB_DUMP) {
389			msg = next;
390			continue;
391		}
392
393		if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
394			plog(ASL_LEVEL_ERR,
395				"pfkey_check (%s)\n", ipsec_strerror());
396			msg = next;
397			continue;
398		}
399
400		sa = ALIGNED_CAST(struct sadb_sa *)(mhp[SADB_EXT_SA]);       // Wcast-align fix (void*) - mhp contains pointers to aligned structs
401		if (!sa) {
402			msg = next;
403			continue;
404		}
405
406		if (sa->sadb_sa_state != SADB_SASTATE_DEAD) {
407			n++;
408			msg = next;
409			continue;
410		}
411
412		msg = next;
413	}
414
415	if (buf != NULL)
416		vfree(buf);
417
418	if (n) {
419		sched_new(1, check_flushsa_stub, NULL);
420		return;
421	}
422
423#if !TARGET_OS_EMBEDDED
424	if (lcconf->vt)
425		vproc_transaction_end(NULL, lcconf->vt);
426#endif
427    close_session(0);
428}
429
430void
431auto_exit_do(void *p)
432{
433	plog(ASL_LEVEL_DEBUG,
434				"performing auto exit\n");
435#if ENABLE_NO_SA_FLUSH
436	close_session(0);
437#else
438	pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
439	sched_new(1, check_flushsa_stub, NULL);
440	dying();
441#endif /* ENABLE_NO_SA_FLUSH */
442}
443
444void
445check_auto_exit(void)
446{
447	if (lcconf->auto_exit_sched) {	/* exit scheduled? */
448		if (lcconf->auto_exit_state != LC_AUTOEXITSTATE_ENABLED
449			|| vpn_control_connected()          /* vpn control connected */
450			|| policies_installed()             /* policies installed in kernel */
451			|| !no_remote_configs(FALSE))	{	/* remote or anonymous configs */
452			SCHED_KILL(lcconf->auto_exit_sched);
453        }
454	} else {								/* exit not scheduled */
455		if (lcconf->auto_exit_state == LC_AUTOEXITSTATE_ENABLED
456			&& !vpn_control_connected()
457			&& !policies_installed()
458			&& no_remote_configs(FALSE)) {
459            if (lcconf->auto_exit_delay == 0) {
460                auto_exit_do(NULL);		/* immediate exit */
461            } else {
462                lcconf->auto_exit_sched = sched_new(lcconf->auto_exit_delay, auto_exit_do, NULL);
463            }
464        }
465	}
466}
467
468static int signals[] = {
469	SIGHUP,
470	SIGINT,
471	SIGTERM,
472	SIGUSR1,
473	SIGUSR2,
474	SIGPIPE,
475	0
476};
477
478
479static void
480check_sigreq()
481{
482	int sig;
483
484	/*
485	 * XXX We are not able to tell if we got
486	 * several time the same signal. This is
487	 * not a problem for the current code,
488	 * but we shall remember this limitation.
489	 */
490	for (sig = 0; sig <= NSIG; sig++) {
491		if (sigreq[sig] == 0)
492			continue;
493
494		sigreq[sig]--;
495		switch(sig) {
496            case 0:
497                return;
498
499                /* Catch up childs, mainly scripts.
500                 */
501
502            case SIGUSR1:
503            case SIGHUP:
504#ifdef ENABLE_HYBRID
505                if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) {
506                    plog(ASL_LEVEL_ERR,
507                         "ISAKMP mode config structure reset failed, "
508                         "not reloading\n");
509                    return;
510                }
511#endif
512                if ( terminated )
513                    break;
514
515                /*
516                 * if we got a HUP... try graceful teardown of sessions before we close and reopen sockets...
517                 * so that info-deletes notifications can make it to the peer.
518                 */
519                if (sig == SIGHUP) {
520                    ike_session_flush_all_phase2(true);
521                    ike_session_flush_all_phase1(true);
522                }
523
524                /* Save old configuration, load new one...  */
525                if (cfreparse(sig)) {
526                    plog(ASL_LEVEL_ERR,
527                         "configuration read failed\n");
528                    exit(1);
529                }
530                if (lcconf->logfile_param == NULL && logFileStr[0] == 0)
531                    plogresetfile(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]);
532
533#if TARGET_OS_EMBEDDED
534                if (no_remote_configs(TRUE)) {
535#if ENABLE_NO_SA_FLUSH
536                    close_session(0);
537#else
538                    pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
539#ifdef ENABLE_FASTQUIT
540                    close_session(0);
541#else
542                    sched_new(1, check_flushsa_stub, NULL);
543#endif /* ENABLE_FASTQUIT */
544                    dying();
545#endif /* ENABLE_NO_SA_FLUSH */
546                }
547#endif
548
549                break;
550
551            case SIGINT:
552            case SIGTERM:
553                plog(ASL_LEVEL_INFO,
554                     "caught signal %d\n", sig);
555#if ENABLE_NO_SA_FLUSH
556                close_session(0);
557#else
558                pfkey_send_flush(lcconf->sock_pfkey,
559                                 SADB_SATYPE_UNSPEC);
560                if ( sig == SIGTERM ){
561                    terminated = 1;			/* in case if it hasn't been set yet */
562                    close_session(0);
563                }
564                else
565                    sched_new(1, check_flushsa_stub, NULL);
566
567				dying();
568#endif /* ENABLE_NO_SA_FLUSH */
569                break;
570
571            default:
572                plog(ASL_LEVEL_INFO,
573                     "caught signal %d\n", sig);
574                break;
575		}
576	}
577}
578
579
580/*
581 * asynchronous requests will actually dispatched in the
582 * main loop in session().
583 */
584RETSIGTYPE
585signal_handler(int sig, siginfo_t *sigi, void *ctx)
586{
587#if 0
588    plog(ASL_LEVEL_DEBUG,
589         "%s received signal %d from pid %d uid %d\n\n",
590         __FUNCTION__, sig, sigi->si_pid, sigi->si_uid);
591#endif
592
593    /* Do not just set it to 1, because we may miss some signals by just setting
594     * values to 0/1
595     */
596    sigreq[sig]++;
597    if ( sig == SIGTERM ){
598        terminated = 1;
599    }
600    dispatch_async(main_queue,
601                   ^{
602                        check_sigreq();
603                   });
604}
605
606
607static int
608init_signal()
609{
610	int i;
611
612	for (i = 0; signals[i] != 0; i++) {
613		if (set_signal(signals[i], signal_handler) < 0) {
614			plog(ASL_LEVEL_ERR,
615				"failed to set_signal (%s)\n",
616				strerror(errno));
617			return (1);
618		}
619    }
620    return 0;
621}
622
623static int
624set_signal(int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *))
625{
626	struct sigaction sa;
627
628	memset((caddr_t)&sa, 0, sizeof(sa));
629    sa.sa_sigaction = func;
630	sa.sa_flags = SA_RESTART | SA_SIGINFO;
631
632	if (sigemptyset(&sa.sa_mask) < 0)
633		return -1;
634
635	if (sigaction(sig, &sa, (struct sigaction *)0) < 0)
636		return(-1);
637
638	return 0;
639}
640
641void
642fatal_error(int error)
643{
644    close_session(error == 0 ? -1 : error);
645}
646
647/* suspend all socket sources except pf_key */
648void
649dying(void)
650{
651    if (lcconf->rt_source)
652        dispatch_suspend(lcconf->rt_source);
653    if (lcconf->vpncontrol_source)
654        dispatch_suspend(lcconf->vpncontrol_source);
655    isakmp_suspend_sockets();
656}
657
658static int
659close_sockets()
660{
661    pfroute_close();
662	isakmp_close();
663	pfkey_close();
664#ifdef ENABLE_VPNCONTROL_PORT
665	vpncontrol_close();
666#endif
667
668	return 0;
669}
670
671
672