Annotation of embedaddon/ipsec-tools/src/racoon/policy.c, revision 1.1
1.1 ! misho 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>