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