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