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