1/*	$KAME: policy.c,v 1.46 2001/11/16 04:08:10 sakane 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/param.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <sys/queue.h>
38
39#include <netinet/in.h>
40#ifdef HAVE_NETINET6_IPSEC
41#  include <netinet6/ipsec.h>
42#else
43#  include <netinet/ipsec.h>
44#endif
45
46#include <stdlib.h>
47#include <stdio.h>
48#include <string.h>
49#include <errno.h>
50
51#include "var.h"
52#include "misc.h"
53#include "vmbuf.h"
54#include "plog.h"
55#include "sockmisc.h"
56#include "debug.h"
57
58#include "policy.h"
59#include "localconf.h"
60#include "isakmp_var.h"
61#include "isakmp.h"
62#include "oakley.h"
63#include "handler.h"
64#include "strnames.h"
65#include "gcmalloc.h"
66#include "session.h"
67
68static TAILQ_HEAD(_sptree, secpolicy) sptree;
69
70/* perform exact match against security policy table. */
71struct secpolicy *
72getsp(spidx)
73	struct policyindex *spidx;
74{
75	struct secpolicy *p;
76
77	for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
78		if (!cmpspidxstrict(spidx, &p->spidx))
79			return p;
80	}
81
82	return NULL;
83}
84
85/*
86 * perform non-exact match against security policy table, only if this is
87 * transport mode SA negotiation.  for example, 0.0.0.0/0 -> 0.0.0.0/0
88 * entry in policy.txt can be returned when we're negotiating transport
89 * mode SA.  this is how the kernel works.
90 */
91#if 1
92struct secpolicy *
93getsp_r(spidx, iph2)
94	struct policyindex *spidx;
95	phase2_handle_t *iph2;
96{
97	struct secpolicy *p;
98	int mismatched_outer_addr = 0;
99
100	for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
101		if (!cmpspidxwild(spidx, &p->spidx)) {
102			if (spidx->dir != IPSEC_DIR_ANY) {
103				struct ipsecrequest *isr;
104				for (isr = p->req; isr != NULL; isr = isr->next) {
105					if (isr->saidx.mode != IPSEC_MODE_TUNNEL) {
106						plog(ASL_LEVEL_DEBUG, "%s, skipping policy. dir %d, mode %d\n",
107							 __FUNCTION__, spidx->dir, isr->saidx.mode);
108						continue;
109					}
110
111					// for tunnel mode: verify the outer ip addresses match the phase2's addresses
112					if (spidx->dir == IPSEC_DIR_INBOUND) {
113						// TODO: look out for wildcards
114						if (!cmpsaddrwop(iph2->dst, &isr->saidx.src) &&
115							!cmpsaddrwop(iph2->src, &isr->saidx.dst)) {
116							plog(ASL_LEVEL_DEBUG, "%s, inbound policy outer addresses matched Phase 2 addresses\n",
117								 __FUNCTION__);
118							return p;
119						} else {
120							mismatched_outer_addr = 1;
121						}
122					} else if (spidx->dir == IPSEC_DIR_OUTBOUND) {
123						// TODO: look out for wildcards
124						if (!cmpsaddrwop(iph2->src, &isr->saidx.src) &&
125							!cmpsaddrwop(iph2->dst, &isr->saidx.dst)) {
126							plog(ASL_LEVEL_DEBUG, "%s, outbound policy outer addresses matched Phase 2 addresses\n",
127								 __FUNCTION__);
128							return p;
129						} else {
130							mismatched_outer_addr = 1;
131						}
132					} else {
133						mismatched_outer_addr = 1;
134					}
135					if (mismatched_outer_addr) {
136						plog(ASL_LEVEL_DEBUG, "%s, policy outer addresses matched Phase 2 addresses: dir %d\n",
137							 __FUNCTION__, spidx->dir);
138						plog(ASL_LEVEL_DEBUG, "src1: %s\n",
139							 saddr2str((struct sockaddr *)iph2->src));
140						plog(ASL_LEVEL_DEBUG, "src2: %s\n",
141							 saddr2str((struct sockaddr *)&isr->saidx.src));
142						plog(ASL_LEVEL_DEBUG, "dst1: %s\n",
143							 saddr2str((struct sockaddr *)iph2->dst));
144						plog(ASL_LEVEL_DEBUG, "dst2: %s\n",
145							 saddr2str((struct sockaddr *)&isr->saidx.dst));
146					}
147				}
148			}
149			if (!mismatched_outer_addr) {
150				return p;
151			}
152		}
153	}
154
155	return NULL;
156}
157#else
158struct secpolicy *
159getsp_r(spidx, iph2)
160	struct policyindex *spidx;
161	phase2_handle_t *iph2;
162{
163	struct secpolicy *p;
164	u_int8_t prefixlen;
165
166	plog(ASL_LEVEL_DEBUG, "checking for transport mode\n");
167
168	if (spidx->src.ss_family != spidx->dst.ss_family) {
169		plog(ASL_LEVEL_ERR,
170			"address family mismatch, src:%d dst:%d\n",
171				spidx->src.ss_family,
172				spidx->dst.ss_family);
173		return NULL;
174	}
175	switch (spidx->src.ss_family) {
176	case AF_INET:
177		prefixlen = sizeof(struct in_addr) << 3;
178		break;
179#ifdef INET6
180	case AF_INET6:
181		prefixlen = sizeof(struct in6_addr) << 3;
182		break;
183#endif
184	default:
185		plog(ASL_LEVEL_ERR,
186			"invalid family: %d\n", spidx->src.ss_family);
187		return NULL;
188	}
189
190	/* is it transport mode SA negotiation? */
191	plog(ASL_LEVEL_DEBUG, "src1: %s\n",
192		saddr2str(iph2->src));
193	plog(ASL_LEVEL_DEBUG, "src2: %s\n",
194		saddr2str(&spidx->src));
195	if (cmpsaddrwop(iph2->src, &spidx->src)
196	 || spidx->prefs != prefixlen)
197		return NULL;
198
199	plog(ASL_LEVEL_DEBUG, "dst1: %s\n",
200		saddr2str(iph2->dst));
201	plog(ASL_LEVEL_DEBUG, "dst2: %s\n",
202		saddr2str(&spidx->dst));
203	if (cmpsaddrwop(iph2->dst, &spidx->dst)
204	 || spidx->prefd != prefixlen)
205		return NULL;
206
207	plog(ASL_LEVEL_DEBUG, "looks to be transport mode\n");
208
209	for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
210		if (!cmpspidx_wild(spidx, &p->spidx))
211			return p;
212	}
213
214	return NULL;
215}
216#endif
217
218struct secpolicy *
219getspbyspid(spid)
220	u_int32_t spid;
221{
222	struct secpolicy *p;
223
224	for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
225		if (p->id == spid)
226			return p;
227	}
228
229	return NULL;
230}
231
232/*
233 * compare policyindex.
234 * a: subject b: db
235 * OUT:	0:	equal
236 *	1:	not equal
237 */
238int
239cmpspidxstrict(a, b)
240	struct policyindex *a, *b;
241{
242
243	/* XXX don't check direction now, but it's to be checked carefully. */
244	if (a->dir != b->dir
245	 || a->prefs != b->prefs
246	 || a->prefd != b->prefd
247	 || a->ul_proto != b->ul_proto)
248		return 1;
249
250	if (cmpsaddrstrict(&a->src, &b->src))
251		return 1;
252	if (cmpsaddrstrict(&a->dst, &b->dst))
253		return 1;
254
255	return 0;
256}
257
258/*
259 * compare policyindex, with wildcard address/protocol match.
260 * a: subject b: db, can contain wildcard things.
261 * OUT:	0:	equal
262 *	1:	not equal
263 */
264int
265cmpspidxwild(a, b)
266	struct policyindex *a, *b;
267{
268	struct sockaddr_storage sa1, sa2;
269
270	if (!(b->dir == IPSEC_DIR_ANY || a->dir == b->dir))
271		return 1;
272
273	if (!(a->ul_proto == IPSEC_ULPROTO_ANY ||
274	      b->ul_proto == IPSEC_ULPROTO_ANY ||
275	      a->ul_proto == b->ul_proto))
276		return 1;
277
278	if (a->src.ss_family != b->src.ss_family)
279		return 1;
280	if (a->dst.ss_family != b->dst.ss_family)
281		return 1;
282
283	/* compare src address */
284	if (sizeof(sa1) < a->src.ss_len || sizeof(sa2) < b->src.ss_len) {
285		plog(ASL_LEVEL_ERR,
286			"unexpected error: "
287			"src.ss_len:%d dst.ss_len:%d\n",
288			a->src.ss_len, b->src.ss_len);
289		return 1;
290	}
291	mask_sockaddr(&sa1, &a->src, b->prefs);
292	mask_sockaddr(&sa2, &b->src, b->prefs);
293	plog(ASL_LEVEL_DEBUG, "%p masked with /%d: %s\n",
294		a, b->prefs, saddr2str((struct sockaddr *)&sa1));
295	plog(ASL_LEVEL_DEBUG, "%p masked with /%d: %s\n",
296		b, b->prefs, saddr2str((struct sockaddr *)&sa2));
297	if (cmpsaddrwild(&sa1, &sa2))
298		return 1;
299
300	/* compare dst address */
301	if (sizeof(sa1) < a->dst.ss_len || sizeof(sa2) < b->dst.ss_len) {
302		plog(ASL_LEVEL_ERR, "unexpected error\n");
303		exit(1);
304	}
305	mask_sockaddr(&sa1, &a->dst, b->prefd);
306	mask_sockaddr(&sa2, &b->dst, b->prefd);
307	plog(ASL_LEVEL_DEBUG, "%p masked with /%d: %s\n",
308		a, b->prefd, saddr2str((struct sockaddr *)&sa1));
309	plog(ASL_LEVEL_DEBUG, "%p masked with /%d: %s\n",
310		b, b->prefd, saddr2str((struct sockaddr *)&sa2));
311	if (cmpsaddrwild(&sa1, &sa2))
312		return 1;
313
314	return 0;
315}
316
317struct secpolicy *
318newsp()
319{
320	struct secpolicy *new;
321
322	new = racoon_calloc(1, sizeof(*new));
323	if (new == NULL)
324		return NULL;
325
326	return new;
327}
328
329void
330delsp(sp)
331	struct secpolicy *sp;
332{
333	struct ipsecrequest *req = NULL, *next;
334
335	for (req = sp->req; req; req = next) {
336		next = req->next;
337		racoon_free(req);
338	}
339
340	racoon_free(sp);
341}
342
343void
344delsp_bothdir(spidx0)
345	struct policyindex *spidx0;
346{
347	struct policyindex spidx;
348	struct secpolicy *sp;
349	struct sockaddr_storage src, dst;
350	u_int8_t prefs, prefd;
351
352	memcpy(&spidx, spidx0, sizeof(spidx));
353	switch (spidx.dir) {
354	case IPSEC_DIR_INBOUND:
355#ifdef HAVE_POLICY_FWD
356	case IPSEC_DIR_FWD:
357#endif
358		src   = spidx.src;
359		dst   = spidx.dst;
360		prefs = spidx.prefs;
361		prefd = spidx.prefd;
362		break;
363	case IPSEC_DIR_OUTBOUND:
364		src   = spidx.dst;
365		dst   = spidx.src;
366		prefs = spidx.prefd;
367		prefd = spidx.prefs;
368		break;
369	default:
370		return;
371	}
372
373	spidx.src   = src;
374	spidx.dst   = dst;
375	spidx.prefs = prefs;
376	spidx.prefd = prefd;
377	spidx.dir   = IPSEC_DIR_INBOUND;
378
379	sp = getsp(&spidx);
380	if (sp) {
381		remsp(sp);
382		delsp(sp);
383	}
384
385#ifdef HAVE_POLICY_FWD
386	spidx.dir   = IPSEC_DIR_FWD;
387
388	sp = getsp(&spidx);
389	if (sp) {
390		remsp(sp);
391		delsp(sp);
392	}
393#endif
394
395	spidx.src   = dst;
396	spidx.dst   = src;
397	spidx.prefs = prefd;
398	spidx.prefd = prefs;
399	spidx.dir   = IPSEC_DIR_OUTBOUND;
400
401	sp = getsp(&spidx);
402	if (sp) {
403		remsp(sp);
404		delsp(sp);
405	}
406}
407
408void
409inssp(new)
410	struct secpolicy *new;
411{
412#ifdef HAVE_PFKEY_POLICY_PRIORITY
413	struct secpolicy *p;
414
415	TAILQ_FOREACH(p, &sptree, chain) {
416		if (new->spidx.priority < p->spidx.priority) {
417			TAILQ_INSERT_BEFORE(p, new, chain);
418			return;
419		}
420	}
421	if (p == NULL)
422#endif
423	        TAILQ_INSERT_HEAD(&sptree, new, chain);
424
425	check_auto_exit();
426	return;
427}
428
429void
430remsp(sp)
431	struct secpolicy *sp;
432{
433	TAILQ_REMOVE(&sptree, sp, chain);
434	check_auto_exit();
435}
436
437void
438flushsp()
439{
440	struct secpolicy *p, *next;
441
442	for (p = TAILQ_FIRST(&sptree); p; p = next) {
443		next = TAILQ_NEXT(p, chain);
444		remsp(p);
445		delsp(p);
446	}
447}
448
449int
450policies_installed(void)
451{
452	if (TAILQ_EMPTY(&sptree))
453		return 0;
454	else
455		return 1;
456}
457
458void
459initsp()
460{
461	TAILQ_INIT(&sptree);
462}
463
464struct ipsecrequest *
465newipsecreq()
466{
467	struct ipsecrequest *new;
468
469	new = racoon_calloc(1, sizeof(*new));
470	if (new == NULL)
471		return NULL;
472
473	return new;
474}
475
476const char *
477spidx2str(spidx)
478	const struct policyindex *spidx;
479{
480	/* addr/pref[port] addr/pref[port] ul dir act */
481	static char buf[256];
482	char *p, *a, *b;
483	int blen, i;
484
485	blen = sizeof(buf) - 1;
486	p = buf;
487
488	a = saddr2str((const struct sockaddr *)&spidx->src);
489	for (b = a; *b != '\0'; b++)
490		if (*b == '[') {
491			*b = '\0';
492			b++;
493			break;
494		}
495	i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefs, b);
496	if (i < 0 || i >= blen)
497		return NULL;
498	p += i;
499	blen -= i;
500
501	a = saddr2str((const struct sockaddr *)&spidx->dst);
502	for (b = a; *b != '\0'; b++)
503		if (*b == '[') {
504			*b = '\0';
505			b++;
506			break;
507		}
508	i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefd, b);
509	if (i < 0 || i >= blen)
510		return NULL;
511	p += i;
512	blen -= i;
513
514	snprintf(p, blen, "proto=%s dir=%s",
515		s_proto(spidx->ul_proto), s_direction(spidx->dir));
516
517	return buf;
518}
519