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