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