Return to policy.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ipsec-tools / src / racoon |
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: }