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