Return to handler.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ipsec-tools / src / racoon |
1.1 ! misho 1: /* $NetBSD: handler.c,v 1.39 2011/03/14 17:18:12 tteras Exp $ */ ! 2: ! 3: /* Id: handler.c,v 1.28 2006/05/26 12:17:29 manubsd 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/types.h> ! 37: #include <sys/param.h> ! 38: #include <sys/socket.h> ! 39: ! 40: #include <stdlib.h> ! 41: #include <stdio.h> ! 42: #include <string.h> ! 43: #include <time.h> ! 44: #include <errno.h> ! 45: ! 46: #include "var.h" ! 47: #include "misc.h" ! 48: #include "vmbuf.h" ! 49: #include "plog.h" ! 50: #include "sockmisc.h" ! 51: #include "debug.h" ! 52: ! 53: #ifdef ENABLE_HYBRID ! 54: #include <resolv.h> ! 55: #endif ! 56: ! 57: #include "schedule.h" ! 58: #include "grabmyaddr.h" ! 59: #include "algorithm.h" ! 60: #include "crypto_openssl.h" ! 61: #include "policy.h" ! 62: #include "proposal.h" ! 63: #include "isakmp_var.h" ! 64: #include "evt.h" ! 65: #include "isakmp.h" ! 66: #ifdef ENABLE_HYBRID ! 67: #include "isakmp_xauth.h" ! 68: #include "isakmp_cfg.h" ! 69: #endif ! 70: #include "isakmp_inf.h" ! 71: #include "oakley.h" ! 72: #include "remoteconf.h" ! 73: #include "localconf.h" ! 74: #include "handler.h" ! 75: #include "gcmalloc.h" ! 76: #include "nattraversal.h" ! 77: ! 78: #include "sainfo.h" ! 79: ! 80: #ifdef HAVE_GSSAPI ! 81: #include "gssapi.h" ! 82: #endif ! 83: ! 84: static LIST_HEAD(_ph1tree_, ph1handle) ph1tree; ! 85: static LIST_HEAD(_ph2tree_, ph2handle) ph2tree; ! 86: static LIST_HEAD(_ctdtree_, contacted) ctdtree; ! 87: static LIST_HEAD(_rcptree_, recvdpkt) rcptree; ! 88: static struct sched sc_sweep = SCHED_INITIALIZER(); ! 89: ! 90: static void del_recvdpkt __P((struct recvdpkt *)); ! 91: static void rem_recvdpkt __P((struct recvdpkt *)); ! 92: ! 93: /* ! 94: * functions about management of the isakmp status table ! 95: */ ! 96: /* %%% management phase 1 handler */ ! 97: /* ! 98: * search for isakmpsa handler with isakmp index. ! 99: */ ! 100: ! 101: extern caddr_t val2str(const char *, size_t); ! 102: ! 103: /* ! 104: * Enumerate the Phase 1 tree. ! 105: * If enum_func() internally return a non-zero value, this specific ! 106: * error value is returned. 0 is returned if everything went right. ! 107: * ! 108: * Note that it is ok for enum_func() to call insph1(). Those inserted ! 109: * Phase 1 will not interfere with current enumeration process. ! 110: */ ! 111: int ! 112: enumph1(sel, enum_func, enum_arg) ! 113: struct ph1selector *sel; ! 114: int (* enum_func)(struct ph1handle *iph1, void *arg); ! 115: void *enum_arg; ! 116: { ! 117: struct ph1handle *p; ! 118: int ret; ! 119: ! 120: LIST_FOREACH(p, &ph1tree, chain) { ! 121: if (sel != NULL) { ! 122: if (sel->local != NULL && ! 123: cmpsaddr(sel->local, p->local) > CMPSADDR_WILDPORT_MATCH) ! 124: continue; ! 125: ! 126: if (sel->remote != NULL && ! 127: cmpsaddr(sel->remote, p->remote) > CMPSADDR_WILDPORT_MATCH) ! 128: continue; ! 129: } ! 130: ! 131: if ((ret = enum_func(p, enum_arg)) != 0) ! 132: return ret; ! 133: } ! 134: ! 135: return 0; ! 136: } ! 137: ! 138: struct ph1handle * ! 139: getph1byindex(index) ! 140: isakmp_index *index; ! 141: { ! 142: struct ph1handle *p; ! 143: ! 144: LIST_FOREACH(p, &ph1tree, chain) { ! 145: if (p->status >= PHASE1ST_EXPIRED) ! 146: continue; ! 147: if (memcmp(&p->index, index, sizeof(*index)) == 0) ! 148: return p; ! 149: } ! 150: ! 151: return NULL; ! 152: } ! 153: ! 154: ! 155: /* ! 156: * search for isakmp handler by i_ck in index. ! 157: */ ! 158: struct ph1handle * ! 159: getph1byindex0(index) ! 160: isakmp_index *index; ! 161: { ! 162: struct ph1handle *p; ! 163: ! 164: LIST_FOREACH(p, &ph1tree, chain) { ! 165: if (p->status >= PHASE1ST_EXPIRED) ! 166: continue; ! 167: if (memcmp(&p->index, index, sizeof(cookie_t)) == 0) ! 168: return p; ! 169: } ! 170: ! 171: return NULL; ! 172: } ! 173: ! 174: /* ! 175: * search for isakmpsa handler by source and remote address. ! 176: * don't use port number to search because this function search ! 177: * with phase 2's destinaion. ! 178: */ ! 179: struct ph1handle * ! 180: getph1(ph1hint, local, remote, flags) ! 181: struct ph1handle *ph1hint; ! 182: struct sockaddr *local, *remote; ! 183: int flags; ! 184: { ! 185: struct ph1handle *p; ! 186: ! 187: plog(LLV_DEBUG2, LOCATION, NULL, "getph1: start\n"); ! 188: plog(LLV_DEBUG2, LOCATION, NULL, "local: %s\n", saddr2str(local)); ! 189: plog(LLV_DEBUG2, LOCATION, NULL, "remote: %s\n", saddr2str(remote)); ! 190: ! 191: LIST_FOREACH(p, &ph1tree, chain) { ! 192: if (p->status >= PHASE1ST_DYING) ! 193: continue; ! 194: ! 195: plog(LLV_DEBUG2, LOCATION, NULL, "p->local: %s\n", saddr2str(p->local)); ! 196: plog(LLV_DEBUG2, LOCATION, NULL, "p->remote: %s\n", saddr2str(p->remote)); ! 197: ! 198: if ((flags & GETPH1_F_ESTABLISHED) && ! 199: (p->status != PHASE1ST_ESTABLISHED)) { ! 200: plog(LLV_DEBUG2, LOCATION, NULL, ! 201: "status %d, skipping\n", p->status); ! 202: continue; ! 203: } ! 204: ! 205: if (local != NULL && cmpsaddr(local, p->local) == CMPSADDR_MISMATCH) ! 206: continue; ! 207: ! 208: if (remote != NULL && cmpsaddr(remote, p->remote) == CMPSADDR_MISMATCH) ! 209: continue; ! 210: ! 211: if (ph1hint != NULL) { ! 212: if (ph1hint->id && ph1hint->id->l && p->id && p->id->l && ! 213: (ph1hint->id->l != p->id->l || ! 214: memcmp(ph1hint->id->v, p->id->v, p->id->l) != 0)) { ! 215: plog(LLV_DEBUG2, LOCATION, NULL, ! 216: "local identity does match hint\n"); ! 217: continue; ! 218: } ! 219: if (ph1hint->id_p && ph1hint->id_p->l && ! 220: p->id_p && p->id_p->l && ! 221: (ph1hint->id_p->l != p->id_p->l || ! 222: memcmp(ph1hint->id_p->v, p->id_p->v, p->id_p->l) != 0)) { ! 223: plog(LLV_DEBUG2, LOCATION, NULL, ! 224: "remote identity does match hint\n"); ! 225: continue; ! 226: } ! 227: } ! 228: ! 229: plog(LLV_DEBUG2, LOCATION, NULL, "matched\n"); ! 230: return p; ! 231: } ! 232: ! 233: plog(LLV_DEBUG2, LOCATION, NULL, "no match\n"); ! 234: ! 235: return NULL; ! 236: } ! 237: ! 238: int ! 239: resolveph1rmconf(iph1) ! 240: struct ph1handle *iph1; ! 241: { ! 242: struct remoteconf *rmconf; ! 243: ! 244: /* INITIATOR is always expected to know the exact rmconf. */ ! 245: if (iph1->side == INITIATOR) ! 246: return 0; ! 247: ! 248: rmconf = getrmconf_by_ph1(iph1); ! 249: if (rmconf == NULL) ! 250: return -1; ! 251: if (rmconf == RMCONF_ERR_MULTIPLE) ! 252: return 1; ! 253: ! 254: if (iph1->rmconf != NULL) { ! 255: if (rmconf != iph1->rmconf) { ! 256: plog(LLV_ERROR, LOCATION, NULL, ! 257: "unexpected rmconf switch; killing ph1\n"); ! 258: return -1; ! 259: } ! 260: } else { ! 261: iph1->rmconf = rmconf; ! 262: } ! 263: ! 264: return 0; ! 265: } ! 266: ! 267: ! 268: /* ! 269: * move phase2s from old_iph1 to new_iph1 ! 270: */ ! 271: void ! 272: migrate_ph12(old_iph1, new_iph1) ! 273: struct ph1handle *old_iph1, *new_iph1; ! 274: { ! 275: struct ph2handle *p, *next; ! 276: ! 277: /* Relocate phase2s to better phase1s or request a new phase1. */ ! 278: for (p = LIST_FIRST(&old_iph1->ph2tree); p; p = next) { ! 279: next = LIST_NEXT(p, ph1bind); ! 280: ! 281: if (p->status != PHASE2ST_ESTABLISHED) ! 282: continue; ! 283: ! 284: unbindph12(p); ! 285: bindph12(new_iph1, p); ! 286: } ! 287: } ! 288: ! 289: /* ! 290: * the iph1 is new, migrate all phase2s that belong to a dying or dead ph1 ! 291: */ ! 292: void migrate_dying_ph12(iph1) ! 293: struct ph1handle *iph1; ! 294: { ! 295: struct ph1handle *p; ! 296: ! 297: LIST_FOREACH(p, &ph1tree, chain) { ! 298: if (p == iph1) ! 299: continue; ! 300: if (p->status < PHASE1ST_DYING) ! 301: continue; ! 302: ! 303: if (cmpsaddr(iph1->local, p->local) == CMPSADDR_MATCH ! 304: && cmpsaddr(iph1->remote, p->remote) == CMPSADDR_MATCH) ! 305: migrate_ph12(p, iph1); ! 306: } ! 307: } ! 308: ! 309: ! 310: /* ! 311: * dump isakmp-sa ! 312: */ ! 313: vchar_t * ! 314: dumpph1() ! 315: { ! 316: struct ph1handle *iph1; ! 317: struct ph1dump *pd; ! 318: int cnt = 0; ! 319: vchar_t *buf; ! 320: ! 321: /* get length of buffer */ ! 322: LIST_FOREACH(iph1, &ph1tree, chain) ! 323: cnt++; ! 324: ! 325: buf = vmalloc(cnt * sizeof(struct ph1dump)); ! 326: if (buf == NULL) { ! 327: plog(LLV_ERROR, LOCATION, NULL, ! 328: "failed to get buffer\n"); ! 329: return NULL; ! 330: } ! 331: pd = (struct ph1dump *)buf->v; ! 332: ! 333: LIST_FOREACH(iph1, &ph1tree, chain) { ! 334: memcpy(&pd->index, &iph1->index, sizeof(iph1->index)); ! 335: pd->status = iph1->status; ! 336: pd->side = iph1->side; ! 337: memcpy(&pd->remote, iph1->remote, sysdep_sa_len(iph1->remote)); ! 338: memcpy(&pd->local, iph1->local, sysdep_sa_len(iph1->local)); ! 339: pd->version = iph1->version; ! 340: pd->etype = iph1->etype; ! 341: pd->created = iph1->created; ! 342: pd->ph2cnt = iph1->ph2cnt; ! 343: pd++; ! 344: } ! 345: ! 346: return buf; ! 347: } ! 348: ! 349: /* ! 350: * create new isakmp Phase 1 status record to handle isakmp in Phase1 ! 351: */ ! 352: struct ph1handle * ! 353: newph1() ! 354: { ! 355: struct ph1handle *iph1; ! 356: ! 357: /* create new iph1 */ ! 358: iph1 = racoon_calloc(1, sizeof(*iph1)); ! 359: if (iph1 == NULL) ! 360: return NULL; ! 361: ! 362: iph1->status = PHASE1ST_SPAWN; ! 363: ! 364: #ifdef ENABLE_DPD ! 365: iph1->dpd_support = 0; ! 366: iph1->dpd_seq = 0; ! 367: iph1->dpd_fails = 0; ! 368: #endif ! 369: evt_list_init(&iph1->evt_listeners); ! 370: ! 371: return iph1; ! 372: } ! 373: ! 374: /* ! 375: * delete new isakmp Phase 1 status record to handle isakmp in Phase1 ! 376: */ ! 377: void ! 378: delph1(iph1) ! 379: struct ph1handle *iph1; ! 380: { ! 381: if (iph1 == NULL) ! 382: return; ! 383: ! 384: /* SA down shell script hook */ ! 385: script_hook(iph1, SCRIPT_PHASE1_DOWN); ! 386: evt_list_cleanup(&iph1->evt_listeners); ! 387: ! 388: #ifdef ENABLE_NATT ! 389: if (iph1->natt_flags & NAT_KA_QUEUED) ! 390: natt_keepalive_remove (iph1->local, iph1->remote); ! 391: ! 392: if (iph1->natt_options) { ! 393: racoon_free(iph1->natt_options); ! 394: iph1->natt_options = NULL; ! 395: } ! 396: #endif ! 397: ! 398: #ifdef ENABLE_HYBRID ! 399: if (iph1->mode_cfg) ! 400: isakmp_cfg_rmstate(iph1); ! 401: #endif ! 402: ! 403: #ifdef ENABLE_DPD ! 404: sched_cancel(&iph1->dpd_r_u); ! 405: #endif ! 406: sched_cancel(&iph1->sce); ! 407: sched_cancel(&iph1->scr); ! 408: ! 409: if (iph1->remote) { ! 410: racoon_free(iph1->remote); ! 411: iph1->remote = NULL; ! 412: } ! 413: if (iph1->local) { ! 414: racoon_free(iph1->local); ! 415: iph1->local = NULL; ! 416: } ! 417: if (iph1->approval) { ! 418: delisakmpsa(iph1->approval); ! 419: iph1->approval = NULL; ! 420: } ! 421: ! 422: VPTRINIT(iph1->authstr); ! 423: VPTRINIT(iph1->sendbuf); ! 424: VPTRINIT(iph1->dhpriv); ! 425: VPTRINIT(iph1->dhpub); ! 426: VPTRINIT(iph1->dhpub_p); ! 427: VPTRINIT(iph1->dhgxy); ! 428: VPTRINIT(iph1->nonce); ! 429: VPTRINIT(iph1->nonce_p); ! 430: VPTRINIT(iph1->skeyid); ! 431: VPTRINIT(iph1->skeyid_d); ! 432: VPTRINIT(iph1->skeyid_a); ! 433: VPTRINIT(iph1->skeyid_e); ! 434: VPTRINIT(iph1->key); ! 435: VPTRINIT(iph1->hash); ! 436: VPTRINIT(iph1->sig); ! 437: VPTRINIT(iph1->sig_p); ! 438: VPTRINIT(iph1->cert); ! 439: VPTRINIT(iph1->cert_p); ! 440: VPTRINIT(iph1->crl_p); ! 441: VPTRINIT(iph1->cr_p); ! 442: VPTRINIT(iph1->id); ! 443: VPTRINIT(iph1->id_p); ! 444: ! 445: if(iph1->approval != NULL) ! 446: delisakmpsa(iph1->approval); ! 447: ! 448: if (iph1->ivm) { ! 449: oakley_delivm(iph1->ivm); ! 450: iph1->ivm = NULL; ! 451: } ! 452: ! 453: VPTRINIT(iph1->sa); ! 454: VPTRINIT(iph1->sa_ret); ! 455: ! 456: #ifdef HAVE_GSSAPI ! 457: VPTRINIT(iph1->gi_i); ! 458: VPTRINIT(iph1->gi_r); ! 459: ! 460: gssapi_free_state(iph1); ! 461: #endif ! 462: ! 463: racoon_free(iph1); ! 464: } ! 465: ! 466: /* ! 467: * create new isakmp Phase 1 status record to handle isakmp in Phase1 ! 468: */ ! 469: int ! 470: insph1(iph1) ! 471: struct ph1handle *iph1; ! 472: { ! 473: /* validity check */ ! 474: if (iph1->remote == NULL) { ! 475: plog(LLV_ERROR, LOCATION, NULL, ! 476: "invalid isakmp SA handler. no remote address.\n"); ! 477: return -1; ! 478: } ! 479: LIST_INSERT_HEAD(&ph1tree, iph1, chain); ! 480: ! 481: return 0; ! 482: } ! 483: ! 484: void ! 485: remph1(iph1) ! 486: struct ph1handle *iph1; ! 487: { ! 488: LIST_REMOVE(iph1, chain); ! 489: } ! 490: ! 491: /* ! 492: * flush isakmp-sa ! 493: */ ! 494: void ! 495: flushph1() ! 496: { ! 497: struct ph1handle *p, *next; ! 498: ! 499: for (p = LIST_FIRST(&ph1tree); p; p = next) { ! 500: next = LIST_NEXT(p, chain); ! 501: ! 502: /* send delete information */ ! 503: if (p->status >= PHASE1ST_ESTABLISHED) ! 504: isakmp_info_send_d1(p); ! 505: ! 506: remph1(p); ! 507: delph1(p); ! 508: } ! 509: } ! 510: ! 511: void ! 512: initph1tree() ! 513: { ! 514: LIST_INIT(&ph1tree); ! 515: } ! 516: ! 517: int ! 518: ph1_rekey_enabled(iph1) ! 519: struct ph1handle *iph1; ! 520: { ! 521: if (iph1->rmconf == NULL) ! 522: return 0; ! 523: if (iph1->rmconf->rekey == REKEY_FORCE) ! 524: return 1; ! 525: #ifdef ENABLE_DPD ! 526: if (iph1->rmconf->rekey == REKEY_ON && iph1->dpd_support && ! 527: iph1->rmconf->dpd_interval) ! 528: return 1; ! 529: #endif ! 530: return 0; ! 531: } ! 532: ! 533: /* %%% management phase 2 handler */ ! 534: ! 535: int ! 536: enumph2(sel, enum_func, enum_arg) ! 537: struct ph2selector *sel; ! 538: int (*enum_func)(struct ph2handle *ph2, void *arg); ! 539: void *enum_arg; ! 540: { ! 541: struct ph2handle *p; ! 542: int ret; ! 543: ! 544: LIST_FOREACH(p, &ph2tree, chain) { ! 545: if (sel != NULL) { ! 546: if (sel->spid != 0 && sel->spid != p->spid) ! 547: continue; ! 548: ! 549: if (sel->src != NULL && ! 550: cmpsaddr(sel->src, p->src) != CMPSADDR_MATCH) ! 551: continue; ! 552: ! 553: if (sel->dst != NULL && ! 554: cmpsaddr(sel->dst, p->dst) != CMPSADDR_MATCH) ! 555: continue; ! 556: } ! 557: ! 558: if ((ret = enum_func(p, enum_arg)) != 0) ! 559: return ret; ! 560: } ! 561: ! 562: return 0; ! 563: } ! 564: ! 565: /* ! 566: * search ph2handle with sequence number. ! 567: */ ! 568: struct ph2handle * ! 569: getph2byseq(seq) ! 570: u_int32_t seq; ! 571: { ! 572: struct ph2handle *p; ! 573: ! 574: LIST_FOREACH(p, &ph2tree, chain) { ! 575: if (p->seq == seq) ! 576: return p; ! 577: } ! 578: ! 579: return NULL; ! 580: } ! 581: ! 582: /* ! 583: * search ph2handle with message id. ! 584: */ ! 585: struct ph2handle * ! 586: getph2bymsgid(iph1, msgid) ! 587: struct ph1handle *iph1; ! 588: u_int32_t msgid; ! 589: { ! 590: struct ph2handle *p; ! 591: ! 592: LIST_FOREACH(p, &iph1->ph2tree, ph1bind) { ! 593: if (p->msgid == msgid && p->ph1 == iph1) ! 594: return p; ! 595: } ! 596: ! 597: return NULL; ! 598: } ! 599: ! 600: /* Note that src and dst are not the selectors of the SP ! 601: * but the source and destination addresses used for ! 602: * for SA negotiation (best example is tunnel mode SA ! 603: * where src and dst are the endpoints). There is at most ! 604: * a unique match because racoon does not support bundles ! 605: * which makes that there is at most a single established ! 606: * SA for a given spid. One could say that src and dst ! 607: * are in fact useless ... ! 608: */ ! 609: struct ph2handle * ! 610: getph2byid(src, dst, spid) ! 611: struct sockaddr *src, *dst; ! 612: u_int32_t spid; ! 613: { ! 614: struct ph2handle *p; ! 615: ! 616: LIST_FOREACH(p, &ph2tree, chain) { ! 617: if (spid == p->spid && ! 618: cmpsaddr(src, p->src) <= CMPSADDR_WILDPORT_MATCH && ! 619: cmpsaddr(dst, p->dst) <= CMPSADDR_WILDPORT_MATCH){ ! 620: /* Sanity check to detect zombie handlers ! 621: * XXX Sould be done "somewhere" more interesting, ! 622: * because we have lots of getph2byxxxx(), but this one ! 623: * is called by pk_recvacquire(), so is the most important. ! 624: */ ! 625: if(p->status < PHASE2ST_ESTABLISHED && ! 626: p->retry_counter == 0 ! 627: && p->sce.func == NULL && p->scr.func == NULL) { ! 628: plog(LLV_DEBUG, LOCATION, NULL, ! 629: "Zombie ph2 found, expiring it\n"); ! 630: isakmp_ph2expire(p); ! 631: }else ! 632: return p; ! 633: } ! 634: } ! 635: ! 636: return NULL; ! 637: } ! 638: ! 639: struct ph2handle * ! 640: getph2bysaddr(src, dst) ! 641: struct sockaddr *src, *dst; ! 642: { ! 643: struct ph2handle *p; ! 644: ! 645: LIST_FOREACH(p, &ph2tree, chain) { ! 646: if (cmpsaddr(src, p->src) <= CMPSADDR_WILDPORT_MATCH && ! 647: cmpsaddr(dst, p->dst) <= CMPSADDR_WILDPORT_MATCH) ! 648: return p; ! 649: } ! 650: ! 651: return NULL; ! 652: } ! 653: ! 654: /* ! 655: * call by pk_recvexpire(). ! 656: */ ! 657: struct ph2handle * ! 658: getph2bysaidx(src, dst, proto_id, spi) ! 659: struct sockaddr *src, *dst; ! 660: u_int proto_id; ! 661: u_int32_t spi; ! 662: { ! 663: struct ph2handle *iph2; ! 664: struct saproto *pr; ! 665: ! 666: LIST_FOREACH(iph2, &ph2tree, chain) { ! 667: if (iph2->proposal == NULL && iph2->approval == NULL) ! 668: continue; ! 669: if (iph2->approval != NULL) { ! 670: for (pr = iph2->approval->head; pr != NULL; ! 671: pr = pr->next) { ! 672: if (proto_id != pr->proto_id) ! 673: break; ! 674: if (spi == pr->spi || spi == pr->spi_p) ! 675: return iph2; ! 676: } ! 677: } else if (iph2->proposal != NULL) { ! 678: for (pr = iph2->proposal->head; pr != NULL; ! 679: pr = pr->next) { ! 680: if (proto_id != pr->proto_id) ! 681: break; ! 682: if (spi == pr->spi) ! 683: return iph2; ! 684: } ! 685: } ! 686: } ! 687: ! 688: return NULL; ! 689: } ! 690: ! 691: /* ! 692: * create new isakmp Phase 2 status record to handle isakmp in Phase2 ! 693: */ ! 694: struct ph2handle * ! 695: newph2() ! 696: { ! 697: struct ph2handle *iph2 = NULL; ! 698: ! 699: /* create new iph2 */ ! 700: iph2 = racoon_calloc(1, sizeof(*iph2)); ! 701: if (iph2 == NULL) ! 702: return NULL; ! 703: ! 704: iph2->status = PHASE1ST_SPAWN; ! 705: evt_list_init(&iph2->evt_listeners); ! 706: ! 707: return iph2; ! 708: } ! 709: ! 710: /* ! 711: * initialize ph2handle ! 712: * NOTE: don't initialize src/dst. ! 713: * SPI in the proposal is cleared. ! 714: */ ! 715: void ! 716: initph2(iph2) ! 717: struct ph2handle *iph2; ! 718: { ! 719: evt_list_cleanup(&iph2->evt_listeners); ! 720: unbindph12(iph2); ! 721: ! 722: sched_cancel(&iph2->sce); ! 723: sched_cancel(&iph2->scr); ! 724: ! 725: VPTRINIT(iph2->sendbuf); ! 726: VPTRINIT(iph2->msg1); ! 727: ! 728: /* clear spi, keep variables in the proposal */ ! 729: if (iph2->proposal) { ! 730: struct saproto *pr; ! 731: for (pr = iph2->proposal->head; pr != NULL; pr = pr->next) ! 732: pr->spi = 0; ! 733: } ! 734: ! 735: /* clear approval */ ! 736: if (iph2->approval) { ! 737: flushsaprop(iph2->approval); ! 738: iph2->approval = NULL; ! 739: } ! 740: ! 741: /* clear the generated policy */ ! 742: if (iph2->spidx_gen) { ! 743: delsp_bothdir((struct policyindex *)iph2->spidx_gen); ! 744: racoon_free(iph2->spidx_gen); ! 745: iph2->spidx_gen = NULL; ! 746: } ! 747: ! 748: if (iph2->pfsgrp) { ! 749: oakley_dhgrp_free(iph2->pfsgrp); ! 750: iph2->pfsgrp = NULL; ! 751: } ! 752: ! 753: VPTRINIT(iph2->dhpriv); ! 754: VPTRINIT(iph2->dhpub); ! 755: VPTRINIT(iph2->dhpub_p); ! 756: VPTRINIT(iph2->dhgxy); ! 757: VPTRINIT(iph2->id); ! 758: VPTRINIT(iph2->id_p); ! 759: VPTRINIT(iph2->nonce); ! 760: VPTRINIT(iph2->nonce_p); ! 761: VPTRINIT(iph2->sa); ! 762: VPTRINIT(iph2->sa_ret); ! 763: ! 764: if (iph2->ivm) { ! 765: oakley_delivm(iph2->ivm); ! 766: iph2->ivm = NULL; ! 767: } ! 768: ! 769: #ifdef ENABLE_NATT ! 770: if (iph2->natoa_src) { ! 771: racoon_free(iph2->natoa_src); ! 772: iph2->natoa_src = NULL; ! 773: } ! 774: if (iph2->natoa_dst) { ! 775: racoon_free(iph2->natoa_dst); ! 776: iph2->natoa_dst = NULL; ! 777: } ! 778: #endif ! 779: } ! 780: ! 781: /* ! 782: * delete new isakmp Phase 2 status record to handle isakmp in Phase2 ! 783: */ ! 784: void ! 785: delph2(iph2) ! 786: struct ph2handle *iph2; ! 787: { ! 788: initph2(iph2); ! 789: ! 790: if (iph2->src) { ! 791: racoon_free(iph2->src); ! 792: iph2->src = NULL; ! 793: } ! 794: if (iph2->dst) { ! 795: racoon_free(iph2->dst); ! 796: iph2->dst = NULL; ! 797: } ! 798: if (iph2->sa_src) { ! 799: racoon_free(iph2->sa_src); ! 800: iph2->sa_src = NULL; ! 801: } ! 802: if (iph2->sa_dst) { ! 803: racoon_free(iph2->sa_dst); ! 804: iph2->sa_dst = NULL; ! 805: } ! 806: #ifdef ENABLE_NATT ! 807: if (iph2->natoa_src) { ! 808: racoon_free(iph2->natoa_src); ! 809: iph2->natoa_src = NULL; ! 810: } ! 811: if (iph2->natoa_dst) { ! 812: racoon_free(iph2->natoa_dst); ! 813: iph2->natoa_dst = NULL; ! 814: } ! 815: #endif ! 816: ! 817: if (iph2->proposal) { ! 818: flushsaprop(iph2->proposal); ! 819: iph2->proposal = NULL; ! 820: } ! 821: ! 822: racoon_free(iph2); ! 823: } ! 824: ! 825: /* ! 826: * create new isakmp Phase 2 status record to handle isakmp in Phase2 ! 827: */ ! 828: int ! 829: insph2(iph2) ! 830: struct ph2handle *iph2; ! 831: { ! 832: LIST_INSERT_HEAD(&ph2tree, iph2, chain); ! 833: ! 834: return 0; ! 835: } ! 836: ! 837: void ! 838: remph2(iph2) ! 839: struct ph2handle *iph2; ! 840: { ! 841: unbindph12(iph2); ! 842: LIST_REMOVE(iph2, chain); ! 843: } ! 844: ! 845: void ! 846: initph2tree() ! 847: { ! 848: LIST_INIT(&ph2tree); ! 849: } ! 850: ! 851: void ! 852: flushph2() ! 853: { ! 854: struct ph2handle *p, *next; ! 855: ! 856: plog(LLV_DEBUG2, LOCATION, NULL, ! 857: "flushing all ph2 handlers...\n"); ! 858: ! 859: for (p = LIST_FIRST(&ph2tree); p; p = next) { ! 860: next = LIST_NEXT(p, chain); ! 861: ! 862: /* send delete information */ ! 863: if (p->status == PHASE2ST_ESTABLISHED){ ! 864: plog(LLV_DEBUG2, LOCATION, NULL, ! 865: "got a ph2 handler to flush...\n"); ! 866: isakmp_info_send_d2(p); ! 867: }else{ ! 868: plog(LLV_DEBUG2, LOCATION, NULL, ! 869: "skipping ph2 handler (state %d)\n", p->status); ! 870: } ! 871: ! 872: delete_spd(p, 0); ! 873: remph2(p); ! 874: delph2(p); ! 875: } ! 876: } ! 877: ! 878: /* ! 879: * Delete all Phase 2 handlers for this src/dst/proto. This ! 880: * is used during INITIAL-CONTACT processing (so no need to ! 881: * send a message to the peer). ! 882: */ ! 883: void ! 884: deleteallph2(src, dst, proto_id) ! 885: struct sockaddr *src, *dst; ! 886: u_int proto_id; ! 887: { ! 888: struct ph2handle *iph2, *next; ! 889: struct saproto *pr; ! 890: ! 891: for (iph2 = LIST_FIRST(&ph2tree); iph2 != NULL; iph2 = next) { ! 892: next = LIST_NEXT(iph2, chain); ! 893: if (iph2->proposal == NULL && iph2->approval == NULL) ! 894: continue; ! 895: if (iph2->approval != NULL) { ! 896: for (pr = iph2->approval->head; pr != NULL; ! 897: pr = pr->next) { ! 898: if (proto_id == pr->proto_id) ! 899: goto zap_it; ! 900: } ! 901: } else if (iph2->proposal != NULL) { ! 902: for (pr = iph2->proposal->head; pr != NULL; ! 903: pr = pr->next) { ! 904: if (proto_id == pr->proto_id) ! 905: goto zap_it; ! 906: } ! 907: } ! 908: continue; ! 909: zap_it: ! 910: remph2(iph2); ! 911: delph2(iph2); ! 912: } ! 913: } ! 914: ! 915: /* %%% */ ! 916: void ! 917: bindph12(iph1, iph2) ! 918: struct ph1handle *iph1; ! 919: struct ph2handle *iph2; ! 920: { ! 921: unbindph12(iph2); ! 922: ! 923: iph2->ph1 = iph1; ! 924: iph1->ph2cnt++; ! 925: LIST_INSERT_HEAD(&iph1->ph2tree, iph2, ph1bind); ! 926: } ! 927: ! 928: void ! 929: unbindph12(iph2) ! 930: struct ph2handle *iph2; ! 931: { ! 932: if (iph2->ph1 != NULL) { ! 933: LIST_REMOVE(iph2, ph1bind); ! 934: iph2->ph1->ph2cnt--; ! 935: iph2->ph1 = NULL; ! 936: } ! 937: } ! 938: ! 939: /* %%% management contacted list */ ! 940: /* ! 941: * search contacted list. ! 942: */ ! 943: struct contacted * ! 944: getcontacted(remote) ! 945: struct sockaddr *remote; ! 946: { ! 947: struct contacted *p; ! 948: ! 949: LIST_FOREACH(p, &ctdtree, chain) { ! 950: if (cmpsaddr(remote, p->remote) <= CMPSADDR_WILDPORT_MATCH) ! 951: return p; ! 952: } ! 953: ! 954: return NULL; ! 955: } ! 956: ! 957: /* ! 958: * create new isakmp Phase 2 status record to handle isakmp in Phase2 ! 959: */ ! 960: int ! 961: inscontacted(remote) ! 962: struct sockaddr *remote; ! 963: { ! 964: struct contacted *new; ! 965: ! 966: /* create new iph2 */ ! 967: new = racoon_calloc(1, sizeof(*new)); ! 968: if (new == NULL) ! 969: return -1; ! 970: ! 971: new->remote = dupsaddr(remote); ! 972: if (new->remote == NULL) { ! 973: plog(LLV_ERROR, LOCATION, NULL, ! 974: "failed to allocate buffer.\n"); ! 975: racoon_free(new); ! 976: return -1; ! 977: } ! 978: ! 979: LIST_INSERT_HEAD(&ctdtree, new, chain); ! 980: ! 981: return 0; ! 982: } ! 983: ! 984: void ! 985: remcontacted(remote) ! 986: struct sockaddr *remote; ! 987: { ! 988: struct contacted *p; ! 989: ! 990: LIST_FOREACH(p, &ctdtree, chain) { ! 991: if (cmpsaddr(remote, p->remote) <= CMPSADDR_WILDPORT_MATCH) { ! 992: LIST_REMOVE(p, chain); ! 993: racoon_free(p->remote); ! 994: racoon_free(p); ! 995: break; ! 996: } ! 997: } ! 998: } ! 999: ! 1000: void ! 1001: initctdtree() ! 1002: { ! 1003: LIST_INIT(&ctdtree); ! 1004: } ! 1005: ! 1006: /* ! 1007: * check the response has been sent to the peer. when not, simply reply ! 1008: * the buffered packet to the peer. ! 1009: * OUT: ! 1010: * 0: the packet is received at the first time. ! 1011: * 1: the packet was processed before. ! 1012: * 2: the packet was processed before, but the address mismatches. ! 1013: * -1: error happened. ! 1014: */ ! 1015: int ! 1016: check_recvdpkt(remote, local, rbuf) ! 1017: struct sockaddr *remote, *local; ! 1018: vchar_t *rbuf; ! 1019: { ! 1020: vchar_t *hash; ! 1021: struct recvdpkt *r; ! 1022: struct timeval now, diff; ! 1023: int len, s; ! 1024: ! 1025: hash = eay_md5_one(rbuf); ! 1026: if (!hash) { ! 1027: plog(LLV_ERROR, LOCATION, NULL, ! 1028: "failed to allocate buffer.\n"); ! 1029: return -1; ! 1030: } ! 1031: ! 1032: LIST_FOREACH(r, &rcptree, chain) { ! 1033: if (memcmp(hash->v, r->hash->v, r->hash->l) == 0) ! 1034: break; ! 1035: } ! 1036: vfree(hash); ! 1037: ! 1038: /* this is the first time to receive the packet */ ! 1039: if (r == NULL) ! 1040: return 0; ! 1041: ! 1042: /* ! 1043: * the packet was processed before, but the remote address mismatches. ! 1044: */ ! 1045: if (cmpsaddr(remote, r->remote) != CMPSADDR_MATCH) ! 1046: return 2; ! 1047: ! 1048: /* ! 1049: * it should not check the local address because the packet ! 1050: * may arrive at other interface. ! 1051: */ ! 1052: ! 1053: /* check the previous time to send */ ! 1054: sched_get_monotonic_time(&now); ! 1055: timersub(&now, &r->time_send, &diff); ! 1056: if (diff.tv_sec == 0) { ! 1057: plog(LLV_WARNING, LOCATION, NULL, ! 1058: "the packet retransmitted in a short time from %s\n", ! 1059: saddr2str(remote)); ! 1060: /*XXX should it be error ? */ ! 1061: } ! 1062: ! 1063: /* select the socket to be sent */ ! 1064: s = myaddr_getfd(r->local); ! 1065: if (s == -1) ! 1066: return -1; ! 1067: ! 1068: /* resend the packet if needed */ ! 1069: len = sendfromto(s, r->sendbuf->v, r->sendbuf->l, ! 1070: r->local, r->remote, lcconf->count_persend); ! 1071: if (len == -1) { ! 1072: plog(LLV_ERROR, LOCATION, NULL, "sendfromto failed\n"); ! 1073: return -1; ! 1074: } ! 1075: ! 1076: /* check the retry counter */ ! 1077: r->retry_counter--; ! 1078: if (r->retry_counter <= 0) { ! 1079: rem_recvdpkt(r); ! 1080: del_recvdpkt(r); ! 1081: plog(LLV_DEBUG, LOCATION, NULL, ! 1082: "deleted the retransmission packet to %s.\n", ! 1083: saddr2str(remote)); ! 1084: } else ! 1085: r->time_send = now; ! 1086: ! 1087: return 1; ! 1088: } ! 1089: ! 1090: /* ! 1091: * adding a hash of received packet into the received list. ! 1092: */ ! 1093: int ! 1094: add_recvdpkt(remote, local, sbuf, rbuf) ! 1095: struct sockaddr *remote, *local; ! 1096: vchar_t *sbuf, *rbuf; ! 1097: { ! 1098: struct recvdpkt *new = NULL; ! 1099: ! 1100: if (lcconf->retry_counter == 0) { ! 1101: /* no need to add it */ ! 1102: return 0; ! 1103: } ! 1104: ! 1105: new = racoon_calloc(1, sizeof(*new)); ! 1106: if (!new) { ! 1107: plog(LLV_ERROR, LOCATION, NULL, ! 1108: "failed to allocate buffer.\n"); ! 1109: return -1; ! 1110: } ! 1111: ! 1112: new->hash = eay_md5_one(rbuf); ! 1113: if (!new->hash) { ! 1114: plog(LLV_ERROR, LOCATION, NULL, ! 1115: "failed to allocate buffer.\n"); ! 1116: del_recvdpkt(new); ! 1117: return -1; ! 1118: } ! 1119: new->remote = dupsaddr(remote); ! 1120: if (new->remote == NULL) { ! 1121: plog(LLV_ERROR, LOCATION, NULL, ! 1122: "failed to allocate buffer.\n"); ! 1123: del_recvdpkt(new); ! 1124: return -1; ! 1125: } ! 1126: new->local = dupsaddr(local); ! 1127: if (new->local == NULL) { ! 1128: plog(LLV_ERROR, LOCATION, NULL, ! 1129: "failed to allocate buffer.\n"); ! 1130: del_recvdpkt(new); ! 1131: return -1; ! 1132: } ! 1133: new->sendbuf = vdup(sbuf); ! 1134: if (new->sendbuf == NULL) { ! 1135: plog(LLV_ERROR, LOCATION, NULL, ! 1136: "failed to allocate buffer.\n"); ! 1137: del_recvdpkt(new); ! 1138: return -1; ! 1139: } ! 1140: ! 1141: new->retry_counter = lcconf->retry_counter; ! 1142: sched_get_monotonic_time(&new->time_send); ! 1143: ! 1144: LIST_INSERT_HEAD(&rcptree, new, chain); ! 1145: ! 1146: return 0; ! 1147: } ! 1148: ! 1149: void ! 1150: del_recvdpkt(r) ! 1151: struct recvdpkt *r; ! 1152: { ! 1153: if (r->remote) ! 1154: racoon_free(r->remote); ! 1155: if (r->local) ! 1156: racoon_free(r->local); ! 1157: if (r->hash) ! 1158: vfree(r->hash); ! 1159: if (r->sendbuf) ! 1160: vfree(r->sendbuf); ! 1161: racoon_free(r); ! 1162: } ! 1163: ! 1164: void ! 1165: rem_recvdpkt(r) ! 1166: struct recvdpkt *r; ! 1167: { ! 1168: LIST_REMOVE(r, chain); ! 1169: } ! 1170: ! 1171: static void ! 1172: sweep_recvdpkt(dummy) ! 1173: struct sched *dummy; ! 1174: { ! 1175: struct recvdpkt *r, *next; ! 1176: struct timeval now, diff, sweep; ! 1177: ! 1178: sched_get_monotonic_time(&now); ! 1179: ! 1180: /* calculate sweep time; delete entries older than this */ ! 1181: diff.tv_sec = lcconf->retry_counter * lcconf->retry_interval; ! 1182: diff.tv_usec = 0; ! 1183: timersub(&now, &diff, &sweep); ! 1184: ! 1185: for (r = LIST_FIRST(&rcptree); r; r = next) { ! 1186: next = LIST_NEXT(r, chain); ! 1187: ! 1188: if (timercmp(&r->time_send, &sweep, <)) { ! 1189: rem_recvdpkt(r); ! 1190: del_recvdpkt(r); ! 1191: } ! 1192: } ! 1193: ! 1194: sched_schedule(&sc_sweep, diff.tv_sec, sweep_recvdpkt); ! 1195: } ! 1196: ! 1197: void ! 1198: init_recvdpkt() ! 1199: { ! 1200: time_t lt = lcconf->retry_counter * lcconf->retry_interval; ! 1201: ! 1202: LIST_INIT(&rcptree); ! 1203: ! 1204: sched_schedule(&sc_sweep, lt, sweep_recvdpkt); ! 1205: } ! 1206: ! 1207: #ifdef ENABLE_HYBRID ! 1208: /* ! 1209: * Retruns 0 if the address was obtained by ISAKMP mode config, 1 otherwise ! 1210: * This should be in isakmp_cfg.c but ph1tree being private, it must be there ! 1211: */ ! 1212: int ! 1213: exclude_cfg_addr(addr) ! 1214: const struct sockaddr *addr; ! 1215: { ! 1216: struct ph1handle *p; ! 1217: struct sockaddr_in *sin; ! 1218: ! 1219: LIST_FOREACH(p, &ph1tree, chain) { ! 1220: if ((p->mode_cfg != NULL) && ! 1221: (p->mode_cfg->flags & ISAKMP_CFG_GOT_ADDR4) && ! 1222: (addr->sa_family == AF_INET)) { ! 1223: sin = (struct sockaddr_in *)addr; ! 1224: if (sin->sin_addr.s_addr == p->mode_cfg->addr4.s_addr) ! 1225: return 0; ! 1226: } ! 1227: } ! 1228: ! 1229: return 1; ! 1230: } ! 1231: #endif ! 1232: ! 1233: ! 1234: ! 1235: /* ! 1236: * Reload conf code ! 1237: */ ! 1238: static int revalidate_ph2(struct ph2handle *iph2){ ! 1239: struct sainfoalg *alg; ! 1240: int found, check_level; ! 1241: struct sainfo *sainfo; ! 1242: struct saprop *approval; ! 1243: struct ph1handle *iph1; ! 1244: ! 1245: /* ! 1246: * Get the new sainfo using values of the old one ! 1247: */ ! 1248: if (iph2->sainfo != NULL) { ! 1249: iph2->sainfo = getsainfo(iph2->sainfo->idsrc, ! 1250: iph2->sainfo->iddst, iph2->sainfo->id_i, ! 1251: NULL, iph2->sainfo->remoteid); ! 1252: } ! 1253: approval = iph2->approval; ! 1254: sainfo = iph2->sainfo; ! 1255: ! 1256: if (sainfo == NULL) { ! 1257: /* ! 1258: * Sainfo has been removed ! 1259: */ ! 1260: plog(LLV_DEBUG, LOCATION, NULL, ! 1261: "Reload: No sainfo for ph2\n"); ! 1262: return 0; ! 1263: } ! 1264: ! 1265: if (approval == NULL) { ! 1266: /* ! 1267: * XXX why do we have a NULL approval sometimes ??? ! 1268: */ ! 1269: plog(LLV_DEBUG, LOCATION, NULL, ! 1270: "No approval found !\n"); ! 1271: return 0; ! 1272: } ! 1273: ! 1274: /* ! 1275: * Don't care about proposals, should we do something ? ! 1276: * We have to keep iph2->proposal valid at least for initiator, ! 1277: * for pk_sendgetspi() ! 1278: */ ! 1279: ! 1280: plog(LLV_DEBUG, LOCATION, NULL, "active single bundle:\n"); ! 1281: printsaprop0(LLV_DEBUG, approval); ! 1282: ! 1283: /* ! 1284: * Validate approval against sainfo ! 1285: * Note: we must have an updated ph1->rmconf before doing that, ! 1286: * we'll set check_level to EXACT if we don't have a ph1 ! 1287: * XXX try tu find the new remote section to get the new check level ? ! 1288: * XXX lifebyte ! 1289: */ ! 1290: if (iph2->ph1 != NULL) ! 1291: iph1=iph2->ph1; ! 1292: else ! 1293: iph1=getph1byaddr(iph2->src, iph2->dst, 0); ! 1294: ! 1295: if(iph1 != NULL && iph1->rmconf != NULL) { ! 1296: check_level = iph1->rmconf->pcheck_level; ! 1297: } else { ! 1298: if(iph1 != NULL) ! 1299: plog(LLV_DEBUG, LOCATION, NULL, "No phase1 rmconf found !\n"); ! 1300: else ! 1301: plog(LLV_DEBUG, LOCATION, NULL, "No phase1 found !\n"); ! 1302: check_level = PROP_CHECK_EXACT; ! 1303: } ! 1304: ! 1305: switch (check_level) { ! 1306: case PROP_CHECK_OBEY: ! 1307: plog(LLV_DEBUG, LOCATION, NULL, ! 1308: "Reload: OBEY for ph2, ok\n"); ! 1309: return 1; ! 1310: break; ! 1311: ! 1312: case PROP_CHECK_STRICT: ! 1313: /* FALLTHROUGH */ ! 1314: case PROP_CHECK_CLAIM: ! 1315: if (sainfo->lifetime < approval->lifetime) { ! 1316: plog(LLV_DEBUG, LOCATION, NULL, ! 1317: "Reload: lifetime mismatch\n"); ! 1318: return 0; ! 1319: } ! 1320: ! 1321: #if 0 ! 1322: /* Lifebyte is deprecated, just ignore it ! 1323: */ ! 1324: if (sainfo->lifebyte < approval->lifebyte) { ! 1325: plog(LLV_DEBUG, LOCATION, NULL, ! 1326: "Reload: lifebyte mismatch\n"); ! 1327: return 0; ! 1328: } ! 1329: #endif ! 1330: ! 1331: if (sainfo->pfs_group && ! 1332: sainfo->pfs_group != approval->pfs_group) { ! 1333: plog(LLV_DEBUG, LOCATION, NULL, ! 1334: "Reload: PFS group mismatch\n"); ! 1335: return 0; ! 1336: } ! 1337: break; ! 1338: ! 1339: case PROP_CHECK_EXACT: ! 1340: if (sainfo->lifetime != approval->lifetime || ! 1341: #if 0 ! 1342: /* Lifebyte is deprecated, just ignore it ! 1343: */ ! 1344: sainfo->lifebyte != approval->lifebyte || ! 1345: #endif ! 1346: sainfo->pfs_group != iph2->approval->pfs_group) { ! 1347: plog(LLV_DEBUG, LOCATION, NULL, ! 1348: "Reload: lifetime | pfs mismatch\n"); ! 1349: return 0; ! 1350: } ! 1351: break; ! 1352: ! 1353: default: ! 1354: plog(LLV_DEBUG, LOCATION, NULL, ! 1355: "Reload: Shouldn't be here !\n"); ! 1356: return 0; ! 1357: break; ! 1358: } ! 1359: ! 1360: for (alg = sainfo->algs[algclass_ipsec_auth]; alg; alg = alg->next) { ! 1361: if (alg->alg == approval->head->head->authtype) ! 1362: break; ! 1363: } ! 1364: if (alg == NULL) { ! 1365: plog(LLV_DEBUG, LOCATION, NULL, ! 1366: "Reload: alg == NULL (auth)\n"); ! 1367: return 0; ! 1368: } ! 1369: ! 1370: found = 0; ! 1371: for (alg = sainfo->algs[algclass_ipsec_enc]; ! 1372: (found == 0 && alg != NULL); alg = alg->next) { ! 1373: plog(LLV_DEBUG, LOCATION, NULL, ! 1374: "Reload: next ph2 enc alg...\n"); ! 1375: ! 1376: if (alg->alg != approval->head->head->trns_id){ ! 1377: plog(LLV_DEBUG, LOCATION, NULL, ! 1378: "Reload: encmode mismatch (%d / %d)\n", ! 1379: alg->alg, approval->head->head->trns_id); ! 1380: continue; ! 1381: } ! 1382: ! 1383: switch (check_level){ ! 1384: /* PROP_CHECK_STRICT cannot happen here */ ! 1385: case PROP_CHECK_EXACT: ! 1386: if (alg->encklen != approval->head->head->encklen) { ! 1387: plog(LLV_DEBUG, LOCATION, NULL, ! 1388: "Reload: enclen mismatch\n"); ! 1389: continue; ! 1390: } ! 1391: break; ! 1392: ! 1393: case PROP_CHECK_CLAIM: ! 1394: /* FALLTHROUGH */ ! 1395: case PROP_CHECK_STRICT: ! 1396: if (alg->encklen > approval->head->head->encklen) { ! 1397: plog(LLV_DEBUG, LOCATION, NULL, ! 1398: "Reload: enclen mismatch\n"); ! 1399: continue; ! 1400: } ! 1401: break; ! 1402: ! 1403: default: ! 1404: plog(LLV_ERROR, LOCATION, NULL, ! 1405: "unexpected check_level\n"); ! 1406: continue; ! 1407: break; ! 1408: } ! 1409: found = 1; ! 1410: } ! 1411: ! 1412: if (!found){ ! 1413: plog(LLV_DEBUG, LOCATION, NULL, ! 1414: "Reload: No valid enc\n"); ! 1415: return 0; ! 1416: } ! 1417: ! 1418: /* ! 1419: * XXX comp ! 1420: */ ! 1421: plog(LLV_DEBUG, LOCATION, NULL, ! 1422: "Reload: ph2 check ok\n"); ! 1423: ! 1424: return 1; ! 1425: } ! 1426: ! 1427: ! 1428: static void ! 1429: remove_ph2(struct ph2handle *iph2) ! 1430: { ! 1431: u_int32_t spis[2]; ! 1432: ! 1433: if(iph2 == NULL) ! 1434: return; ! 1435: ! 1436: plog(LLV_DEBUG, LOCATION, NULL, ! 1437: "Deleting a Ph2...\n"); ! 1438: ! 1439: if (iph2->status == PHASE2ST_ESTABLISHED) ! 1440: isakmp_info_send_d2(iph2); ! 1441: ! 1442: if(iph2->approval != NULL && iph2->approval->head != NULL){ ! 1443: spis[0]=iph2->approval->head->spi; ! 1444: spis[1]=iph2->approval->head->spi_p; ! 1445: ! 1446: /* purge_ipsec_spi() will do all the work: ! 1447: * - delete SPIs in kernel ! 1448: * - delete generated SPD ! 1449: * - unbind / rem / del ph2 ! 1450: */ ! 1451: purge_ipsec_spi(iph2->dst, iph2->approval->head->proto_id, ! 1452: spis, 2); ! 1453: }else{ ! 1454: remph2(iph2); ! 1455: delph2(iph2); ! 1456: } ! 1457: } ! 1458: ! 1459: static void remove_ph1(struct ph1handle *iph1){ ! 1460: struct ph2handle *iph2, *iph2_next; ! 1461: ! 1462: if(iph1 == NULL) ! 1463: return; ! 1464: ! 1465: plog(LLV_DEBUG, LOCATION, NULL, ! 1466: "Removing PH1...\n"); ! 1467: ! 1468: if (iph1->status == PHASE1ST_ESTABLISHED || ! 1469: iph1->status == PHASE1ST_DYING) { ! 1470: for (iph2 = LIST_FIRST(&iph1->ph2tree); iph2; iph2 = iph2_next) { ! 1471: iph2_next = LIST_NEXT(iph2, ph1bind); ! 1472: remove_ph2(iph2); ! 1473: } ! 1474: isakmp_info_send_d1(iph1); ! 1475: } ! 1476: iph1->status = PHASE1ST_EXPIRED; ! 1477: /* directly call isakmp_ph1delete to avoid as possible a race ! 1478: * condition where we'll try to access iph1->rmconf after it has ! 1479: * freed ! 1480: */ ! 1481: isakmp_ph1delete(iph1); ! 1482: } ! 1483: ! 1484: ! 1485: static int revalidate_ph1tree_rmconf(void) ! 1486: { ! 1487: struct ph1handle *p, *next; ! 1488: struct remoteconf *rmconf; ! 1489: ! 1490: for (p = LIST_FIRST(&ph1tree); p; p = next) { ! 1491: next = LIST_NEXT(p, chain); ! 1492: ! 1493: if (p->status >= PHASE1ST_EXPIRED) ! 1494: continue; ! 1495: if (p->rmconf == NULL) ! 1496: continue; ! 1497: ! 1498: rmconf = getrmconf_by_ph1(p); ! 1499: if (rmconf == NULL || rmconf == RMCONF_ERR_MULTIPLE) ! 1500: remove_ph1(p); ! 1501: else ! 1502: p->rmconf = rmconf; ! 1503: } ! 1504: ! 1505: return 1; ! 1506: } ! 1507: ! 1508: static int revalidate_ph2tree(void){ ! 1509: struct ph2handle *p, *next; ! 1510: ! 1511: for (p = LIST_FIRST(&ph2tree); p; p = next) { ! 1512: next = LIST_NEXT(p, chain); ! 1513: ! 1514: if (p->status == PHASE2ST_EXPIRED) ! 1515: continue; ! 1516: ! 1517: if(!revalidate_ph2(p)){ ! 1518: plog(LLV_DEBUG, LOCATION, NULL, ! 1519: "PH2 not validated, removing it\n"); ! 1520: remove_ph2(p); ! 1521: } ! 1522: } ! 1523: ! 1524: return 1; ! 1525: } ! 1526: ! 1527: int ! 1528: revalidate_ph12(void) ! 1529: { ! 1530: ! 1531: revalidate_ph1tree_rmconf(); ! 1532: revalidate_ph2tree(); ! 1533: ! 1534: return 1; ! 1535: } ! 1536: ! 1537: #ifdef ENABLE_HYBRID ! 1538: struct ph1handle * ! 1539: getph1bylogin(login) ! 1540: char *login; ! 1541: { ! 1542: struct ph1handle *p; ! 1543: ! 1544: LIST_FOREACH(p, &ph1tree, chain) { ! 1545: if (p->mode_cfg == NULL) ! 1546: continue; ! 1547: if (strncmp(p->mode_cfg->login, login, LOGINLEN) == 0) ! 1548: return p; ! 1549: } ! 1550: ! 1551: return NULL; ! 1552: } ! 1553: ! 1554: int ! 1555: purgeph1bylogin(login) ! 1556: char *login; ! 1557: { ! 1558: struct ph1handle *p; ! 1559: int found = 0; ! 1560: ! 1561: LIST_FOREACH(p, &ph1tree, chain) { ! 1562: if (p->mode_cfg == NULL) ! 1563: continue; ! 1564: if (strncmp(p->mode_cfg->login, login, LOGINLEN) == 0) { ! 1565: if (p->status >= PHASE1ST_EXPIRED) ! 1566: continue; ! 1567: ! 1568: if (p->status >= PHASE1ST_ESTABLISHED) ! 1569: isakmp_info_send_d1(p); ! 1570: purge_remote(p); ! 1571: found++; ! 1572: } ! 1573: } ! 1574: ! 1575: return found; ! 1576: } ! 1577: #endif