1 /* $Id: handler.c,v 1.16 2008/02/07 10:12:27 mk Exp $ */
   2 
   3 /*
   4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
   5  * All rights reserved.
   6  * 
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  * 2. Redistributions in binary form must reproduce the above copyright
  13  *    notice, this list of conditions and the following disclaimer in the
  14  *    documentation and/or other materials provided with the distribution.
  15  * 3. Neither the name of the project nor the names of its contributors
  16  *    may be used to endorse or promote products derived from this software
  17  *    without specific prior written permission.
  18  * 
  19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
  23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29  * SUCH DAMAGE.
  30  */
  31 
  32 #include "config.h"
  33 
  34 #include <sys/types.h>
  35 #include <sys/param.h>
  36 #include <sys/socket.h>
  37 
  38 #include <netinet/in.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 "racoon.h"
  47 
  48 #include "var.h"
  49 /* #include "misc.h" */
  50 /* #include "vmbuf.h" */
  51 #include "plog.h"
  52 #include "sockmisc.h"
  53 #include "debug.h"
  54 
  55 #ifdef ENABLE_HYBRID
  56 #include <resolv.h>
  57 #endif
  58 
  59 /* #include "schedule.h" */
  60 /* #include "grabmyaddr.h" */
  61 #include "algorithm.h"
  62 #include "crypto_impl.h"
  63 /* #include "policy.h" */
  64 #include "proposal.h"
  65 #include "isakmp.h"
  66 #include "isakmp_var.h"
  67 #include "ipsec_doi.h"
  68 #include "evt.h"
  69 #ifdef ENABLE_HYBRID
  70 #include "isakmp_xauth.h"  
  71 #include "isakmp_cfg.h"
  72 #endif
  73 #include "isakmp_inf.h"
  74 #include "oakley.h"
  75 #include "isakmp_impl.h"
  76 #include "ikev1_impl.h"
  77 #include "ike_conf.h"
  78 #include "remoteconf.h"
  79 /* #include "localconf.h" */
  80 #include "handler.h"
  81 #include "gcmalloc.h"
  82 #include "ikev1_natt.h"
  83 
  84 /* #include "sainfo.h" */
  85 
  86 #ifdef HAVE_GSSAPI
  87 #include "gssapi.h"
  88 #endif
  89 
  90 static LIST_HEAD(_ph1tree_, ph1handle) ph1tree;
  91 static LIST_HEAD(_ph2tree_, ph2handle) ph2tree;
  92 static LIST_HEAD(_ctdtree_, contacted) ctdtree;
  93 static LIST_HEAD(_rcptree_, recvdpkt) rcptree;
  94 
  95 static void del_recvdpkt (struct recvdpkt *);
  96 static void rem_recvdpkt (struct recvdpkt *);
  97 static void sweep_recvdpkt (void *);
  98 
  99 /*
 100  * functions about management of the isakmp status table
 101  */
 102 /* %%% management phase 1 handler */
 103 /*
 104  * search for isakmpsa handler with isakmp index.
 105  */
 106 
 107 extern caddr_t val2str(const char *, size_t);
 108 
 109 struct ph1handle *
 110 getph1byindex(isakmp_index_t *index)
 111 {
 112         struct ph1handle *p;
 113 
 114         LIST_FOREACH(p, &ph1tree, chain) {
 115                 if (p->status == PHASE1ST_EXPIRED)
 116                         continue;
 117                 if (memcmp(&p->index, index, sizeof(*index)) == 0)
 118                         return p;
 119         }
 120 
 121         return NULL;
 122 }
 123 
 124 
 125 /*
 126  * search for isakmp handler by i_ck in index.
 127  */
 128 struct ph1handle *
 129 getph1byindex0(isakmp_index_t *index)
 130 {
 131         struct ph1handle *p;
 132 
 133         LIST_FOREACH(p, &ph1tree, chain) {
 134                 if (p->status == PHASE1ST_EXPIRED)
 135                         continue;
 136                 if (memcmp(&p->index, index, sizeof(isakmp_cookie_t)) == 0)
 137                         return p;
 138         }
 139 
 140         return NULL;
 141 }
 142 
 143 /*
 144  * search for isakmpsa handler by source and remote address.
 145  * don't use port number to search because this function search
 146  * with phase 2's destinaion.
 147  */
 148 struct ph1handle *
 149 getph1byaddr(struct sockaddr *local, struct sockaddr *remote)
 150 {
 151         struct ph1handle *p;
 152 
 153         LIST_FOREACH(p, &ph1tree, chain) {
 154                 if (p->status == PHASE1ST_EXPIRED)
 155                         continue;
 156                 if (CMPSADDR(local, p->local) == 0
 157                  && CMPSADDR(remote, p->remote) == 0)
 158                         return p;
 159         }
 160 
 161         return NULL;
 162 }
 163 
 164 struct ph1handle *
 165 getph1byaddrwop(struct sockaddr *local, struct sockaddr *remote)
 166 {
 167         struct ph1handle *p;
 168 
 169         LIST_FOREACH(p, &ph1tree, chain) {
 170                 if (p->status == PHASE1ST_EXPIRED)
 171                         continue;
 172                 if (rcs_cmpsa_wop(local, p->local) == 0
 173                  && rcs_cmpsa_wop(remote, p->remote) == 0)
 174                         return p;
 175         }
 176 
 177         return NULL;
 178 }
 179 
 180 /*
 181  * search for isakmpsa handler by remote address.
 182  * don't use port number to search because this function search
 183  * with phase 2's destinaion.
 184  */
 185 struct ph1handle *
 186 getph1bydstaddrwop(struct sockaddr *remote)
 187 {
 188         struct ph1handle *p;
 189 
 190         LIST_FOREACH(p, &ph1tree, chain) {
 191                 if (p->status == PHASE1ST_EXPIRED)
 192                         continue;
 193                 if (rcs_cmpsa_wop(remote, p->remote) == 0)
 194                         return p;
 195         }
 196 
 197         return NULL;
 198 }
 199 
 200 /*
 201  * dump isakmp-sa
 202  */
 203 rc_vchar_t *
 204 dumpph1(void)
 205 {
 206         struct ph1handle *iph1;
 207         struct ph1dump *pd;
 208         int cnt = 0;
 209         rc_vchar_t *buf;
 210 
 211         /* get length of buffer */
 212         LIST_FOREACH(iph1, &ph1tree, chain)
 213                 cnt++;
 214 
 215         buf = rc_vmalloc(cnt * sizeof(struct ph1dump));
 216         if (buf == NULL) {
 217                 plog(PLOG_INTERR, PLOGLOC, NULL,
 218                         "failed to get buffer\n");
 219                 return NULL;
 220         }
 221         pd = (struct ph1dump *)buf->v;
 222 
 223         LIST_FOREACH(iph1, &ph1tree, chain) {
 224                 memcpy(&pd->index, &iph1->index, sizeof(iph1->index));
 225                 pd->status = iph1->status;
 226                 pd->side = iph1->side;
 227                 memcpy(&pd->remote, iph1->remote, sysdep_sa_len(iph1->remote));
 228                 memcpy(&pd->local, iph1->local, sysdep_sa_len(iph1->local));
 229                 pd->version = iph1->version;
 230                 pd->etype = iph1->etype;
 231                 pd->created = iph1->created;
 232                 pd->ph2cnt = iph1->ph2cnt;
 233                 pd++;
 234         }
 235 
 236         return buf;
 237 }
 238 
 239 /*
 240  * create new isakmp Phase 1 status record to handle isakmp in Phase1
 241  */
 242 struct ph1handle *
 243 newph1(void)
 244 {
 245         struct ph1handle *iph1;
 246 
 247         /* create new iph1 */
 248         iph1 = racoon_calloc(1, sizeof(*iph1));
 249         if (iph1 == NULL)
 250                 return NULL;
 251 
 252         iph1->status = PHASE1ST_SPAWN;
 253 
 254         iph1->dpd_support = 0;
 255         iph1->dpd_lastack = 0;
 256         iph1->dpd_seq = 0;
 257         iph1->dpd_fails = 0;
 258         iph1->dpd_r_u = NULL;
 259 
 260         return iph1;
 261 }
 262 
 263 /*
 264  * delete new isakmp Phase 1 status record to handle isakmp in Phase1
 265  */
 266 void
 267 delph1(struct ph1handle *iph1)
 268 {
 269         if (iph1 == NULL)
 270                 return;
 271 
 272         /* SA down shell script hook */
 273         ikev1_script_hook(iph1, SCRIPT_PHASE1_DOWN);
 274 
 275         EVT_PUSH(iph1->local, iph1->remote, EVTT_PHASE1_DOWN, NULL);
 276 
 277 #ifdef ENABLE_NATT
 278 #ifndef sun     /* XXX KEBE SAYS kernel does this in OpenSolaris */
 279         if (iph1->natt_flags & NAT_KA_QUEUED)
 280                 natt_keepalive_remove (iph1->local, iph1->remote);
 281 #endif
 282 
 283         if (iph1->natt_options) {
 284                 racoon_free(iph1->natt_options);
 285                 iph1->natt_options = NULL;
 286         }
 287 #endif
 288 
 289         if (iph1->dpd_r_u != NULL)
 290                 SCHED_KILL(iph1->dpd_r_u);
 291 
 292         if (iph1->remote) {
 293                 racoon_free(iph1->remote);
 294                 iph1->remote = NULL;
 295         }
 296         if (iph1->local) {
 297                 racoon_free(iph1->local);
 298                 iph1->local = NULL;
 299         }
 300 
 301         if (iph1->approval) {
 302                 delisakmpsa(iph1->approval);
 303                 iph1->approval = NULL;
 304         }
 305 
 306 #ifdef ENABLE_HYBRID
 307         if (iph1->mode_cfg)
 308                 isakmp_cfg_rmstate(iph1);
 309 #endif
 310 
 311         VPTRINIT(iph1->authstr);
 312 
 313         sched_scrub_param(iph1);
 314         iph1->sce = NULL;
 315         iph1->scr = NULL;
 316 
 317         VPTRINIT(iph1->sendbuf);
 318 
 319         VPTRINIT(iph1->dhpriv);
 320         VPTRINIT(iph1->dhpub);
 321         VPTRINIT(iph1->dhpub_p);
 322         VPTRINIT(iph1->dhgxy);
 323         VPTRINIT(iph1->nonce);
 324         VPTRINIT(iph1->nonce_p);
 325         VPTRINIT(iph1->skeyid);
 326         VPTRINIT(iph1->skeyid_d);
 327         VPTRINIT(iph1->skeyid_a);
 328         VPTRINIT(iph1->skeyid_e);
 329         VPTRINIT(iph1->key);
 330         VPTRINIT(iph1->hash);
 331         VPTRINIT(iph1->sig);
 332         VPTRINIT(iph1->sig_p);
 333         oakley_delcert(iph1->cert);
 334         iph1->cert = NULL;
 335         oakley_delcert(iph1->cert_p);
 336         iph1->cert_p = NULL;
 337         oakley_delcert(iph1->crl_p);
 338         iph1->crl_p = NULL;
 339         oakley_delcert(iph1->cr_p);
 340         iph1->cr_p = NULL;
 341         VPTRINIT(iph1->id);
 342         VPTRINIT(iph1->id_p);
 343 
 344         if (iph1->approval)
 345                 delisakmpsa(iph1->approval);
 346 
 347         if (iph1->ivm) {
 348                 oakley_delivm(iph1->ivm);
 349                 iph1->ivm = NULL;
 350         }
 351 
 352         VPTRINIT(iph1->sa);
 353         VPTRINIT(iph1->sa_ret);
 354 
 355 #ifdef HAVE_GSSAPI
 356         VPTRINIT(iph1->gi_i);
 357         VPTRINIT(iph1->gi_r);
 358 
 359         gssapi_free_state(iph1);
 360 #endif
 361 
 362         racoon_free(iph1);
 363 }
 364 
 365 /*
 366  * create new isakmp Phase 1 status record to handle isakmp in Phase1
 367  */
 368 int
 369 insph1(struct ph1handle *iph1)
 370 {
 371         /* validity check */
 372         if (iph1->remote == NULL) {
 373                 plog(PLOG_INTERR, PLOGLOC, NULL,
 374                         "invalid isakmp SA handler. no remote address.\n");
 375                 return -1;
 376         }
 377         LIST_INSERT_HEAD(&ph1tree, iph1, chain);
 378 
 379         return 0;
 380 }
 381 
 382 void
 383 remph1(struct ph1handle *iph1)
 384 {
 385         LIST_REMOVE(iph1, chain);
 386 }
 387 
 388 /*
 389  * flush isakmp-sa
 390  */
 391 void
 392 flushph1(void)
 393 {
 394         struct ph1handle *p, *next;
 395 
 396         for (p = LIST_FIRST(&ph1tree); p; p = next) {
 397                 next = LIST_NEXT(p, chain);
 398 
 399                 /* send delete information */
 400                 if (p->status == PHASE1ST_ESTABLISHED) 
 401                         isakmp_info_send_d1(p);
 402 
 403                 remph1(p);
 404                 delph1(p);
 405         }
 406 }
 407 
 408 void
 409 initph1tree(void)
 410 {
 411         LIST_INIT(&ph1tree);
 412 }
 413 
 414 /* %%% management phase 2 handler */
 415 #if 0
 416 /*
 417  * search ph2handle with policy id.
 418  */
 419 struct ph2handle *
 420 getph2byspid(uint32_t spid)
 421 {
 422         struct ph2handle *p;
 423 
 424         LIST_FOREACH(p, &ph2tree, chain) {
 425                 /*
 426                  * there are ph2handle independent on policy
 427                  * such like informational exchange.
 428                  */
 429                 if (p->spid == spid)
 430                         return p;
 431         }
 432 
 433         return NULL;
 434 }
 435 #endif
 436 
 437 /*
 438  * search ph2handle with sequence number.
 439  */
 440 struct ph2handle *
 441 getph2byseq(uint32_t seq)
 442 {
 443         struct ph2handle *p;
 444 
 445         LIST_FOREACH(p, &ph2tree, chain) {
 446                 if (p->seq == seq)
 447                         return p;
 448         }
 449 
 450         return NULL;
 451 }
 452 
 453 /*
 454  * search ph2handle with message id.
 455  */
 456 struct ph2handle *
 457 getph2bymsgid(struct ph1handle *iph1, uint32_t msgid)
 458 {
 459         struct ph2handle *p;
 460 
 461         LIST_FOREACH(p, &ph2tree, chain) {
 462                 if (p->msgid == msgid)
 463                         return p;
 464         }
 465 
 466         return NULL;
 467 }
 468 
 469 struct ph2handle *
 470 getph2byselector(struct sockaddr *src, struct sockaddr *dst, struct rcf_selector *selector)
 471 {
 472         struct ph2handle *p;
 473 
 474         LIST_FOREACH(p, &ph2tree, chain) {
 475 #ifdef sun
 476                 if ((p->selector->sl_index == selector->sl_index ||
 477                     rc_vmemcmp(p->selector->sl_index,
 478                         selector->sl_index) == 0) &&
 479 #else
 480                 if (rc_vmemcmp(p->selector->sl_index, selector->sl_index)
 481                         == 0 &&
 482 #endif
 483                     CMPSADDR(src, p->src) == 0 &&
 484                     CMPSADDR(dst, p->dst) == 0)
 485                         return p;
 486         }
 487 
 488         return NULL;
 489 }
 490 
 491 struct ph2handle *
 492 getph2bysaddr(struct sockaddr *src, struct sockaddr *dst)
 493 {
 494         struct ph2handle *p;
 495 
 496         LIST_FOREACH(p, &ph2tree, chain) {
 497                 if (rcs_cmpsa(src, p->src) == 0 &&
 498                     rcs_cmpsa(dst, p->dst) == 0)
 499                         return p;
 500         }
 501 
 502         return NULL;
 503 }
 504 
 505 /*
 506  * call by pk_recvexpire().
 507  */
 508 struct ph2handle *
 509 getph2bysaidx(struct sockaddr *src, struct sockaddr *dst, unsigned int proto_id, uint32_t spi)
 510 {
 511         struct ph2handle *iph2;
 512         struct saproto *pr;
 513 
 514         LIST_FOREACH(iph2, &ph2tree, chain) {
 515                 if (iph2->proposal == NULL && iph2->approval == NULL)
 516                         continue;
 517                 if (iph2->approval != NULL) {
 518                         for (pr = iph2->approval->head; pr != NULL;
 519                              pr = pr->next) {
 520                                 if (proto_id != pr->proto_id)
 521                                         break;
 522                                 if (spi == pr->spi || spi == pr->spi_p)
 523                                         return iph2;
 524                         }
 525                 } else if (iph2->proposal != NULL) {
 526                         for (pr = iph2->proposal->head; pr != NULL;
 527                              pr = pr->next) {
 528                                 if (proto_id != pr->proto_id)
 529                                         break;
 530                                 if (spi == pr->spi)
 531                                         return iph2;
 532                         }
 533                 }
 534         }
 535 
 536         return NULL;
 537 }
 538 
 539 /*
 540  * create new isakmp Phase 2 status record to handle isakmp in Phase2
 541  */
 542 struct ph2handle *
 543 newph2(void)
 544 {
 545         struct ph2handle *iph2 = NULL;
 546 
 547         /* create new iph2 */
 548         iph2 = racoon_calloc(1, sizeof(*iph2));
 549         if (iph2 == NULL)
 550                 return NULL;
 551 
 552         iph2->status = PHASE1ST_SPAWN;
 553 
 554         return iph2;
 555 }
 556 
 557 /*
 558  * initialize ph2handle
 559  * NOTE: don't initialize src/dst.
 560  *       SPI in the proposal is cleared.
 561  */
 562 void
 563 initph2(struct ph2handle *iph2)
 564 {
 565         sched_scrub_param(iph2);
 566         iph2->sce = NULL;
 567         iph2->scr = NULL;
 568 
 569         VPTRINIT(iph2->sendbuf);
 570         VPTRINIT(iph2->msg1);
 571 
 572         /* clear spi, keep variables in the proposal */
 573         if (iph2->proposal) {
 574                 struct saproto *pr;
 575                 for (pr = iph2->proposal->head; pr != NULL; pr = pr->next)
 576                         pr->spi = 0;
 577         }
 578 
 579         /* clear approval */
 580         if (iph2->approval) {
 581                 flushsaprop(iph2->approval);
 582                 iph2->approval = NULL;
 583         }
 584 
 585 #ifdef notyet
 586         /* clear the generated policy */
 587         if (iph2->spidx_gen) {
 588                 delsp_bothdir((struct policyindex *)iph2->spidx_gen);
 589                 racoon_free(iph2->spidx_gen);
 590                 iph2->spidx_gen = NULL;
 591         }
 592 #endif
 593 
 594         if (iph2->pfsgrp) {
 595                 oakley_dhgrp_free(iph2->pfsgrp);
 596                 iph2->pfsgrp = NULL;
 597         }
 598 
 599         VPTRINIT(iph2->dhpriv);
 600         VPTRINIT(iph2->dhpub);
 601         VPTRINIT(iph2->dhpub_p);
 602         VPTRINIT(iph2->dhgxy);
 603         VPTRINIT(iph2->id);
 604         VPTRINIT(iph2->id_p);
 605         VPTRINIT(iph2->nonce);
 606         VPTRINIT(iph2->nonce_p);
 607         VPTRINIT(iph2->sa);
 608         VPTRINIT(iph2->sa_ret);
 609 
 610         if (iph2->ivm) {
 611                 oakley_delivm(iph2->ivm);
 612                 iph2->ivm = NULL;
 613         }
 614 }
 615 
 616 /*
 617  * delete new isakmp Phase 2 status record to handle isakmp in Phase2
 618  */
 619 void
 620 delph2(struct ph2handle *iph2)
 621 {
 622         initph2(iph2);
 623 
 624         if (iph2->src) {
 625                 racoon_free(iph2->src);
 626                 iph2->src = NULL;
 627         }
 628         if (iph2->dst) {
 629                 racoon_free(iph2->dst);
 630                 iph2->dst = NULL;
 631         }
 632         if (iph2->src_id) {
 633               racoon_free(iph2->src_id);
 634               iph2->src_id = NULL;
 635         }
 636         if (iph2->dst_id) {
 637               racoon_free(iph2->dst_id);
 638               iph2->dst_id = NULL;
 639         }
 640 #ifdef ENABLE_NATT
 641         if (iph2->natoa_src) {
 642                 racoon_free(iph2->natoa_src);
 643                 iph2->natoa_src = NULL;
 644         }
 645         if (iph2->natoa_dst) {
 646                 racoon_free(iph2->natoa_dst);
 647                 iph2->natoa_dst = NULL;
 648         }
 649 #endif
 650 
 651         if (iph2->proposal) {
 652                 flushsaprop(iph2->proposal);
 653                 iph2->proposal = NULL;
 654         }
 655 
 656         sadb_request_finish(&iph2->sadb_request);
 657 
 658         racoon_free(iph2);
 659 }
 660 
 661 /*
 662  * create new isakmp Phase 2 status record to handle isakmp in Phase2
 663  */
 664 int
 665 insph2(struct ph2handle *iph2)
 666 {
 667         LIST_INSERT_HEAD(&ph2tree, iph2, chain);
 668 
 669         return 0;
 670 }
 671 
 672 void
 673 remph2(struct ph2handle *iph2)
 674 {
 675         LIST_REMOVE(iph2, chain);
 676 }
 677 
 678 void
 679 destroy_ph2(struct ph2handle *iph2)
 680 {
 681         /* delete_spd(iph2); */
 682         unbindph12(iph2);
 683         remph2(iph2);
 684         delph2(iph2);
 685 }
 686 
 687 
 688 void
 689 initph2tree(void)
 690 {
 691         LIST_INIT(&ph2tree);
 692 }
 693 
 694 void
 695 flushph2(void)
 696 {
 697         struct ph2handle *p, *next;
 698 
 699         for (p = LIST_FIRST(&ph2tree); p; p = next) {
 700                 next = LIST_NEXT(p, chain);
 701 
 702                 /* send delete information */
 703                 if (p->status == PHASE2ST_ESTABLISHED) 
 704                         isakmp_info_send_d2(p);
 705 
 706                 destroy_ph2(p);
 707         }
 708 }
 709 
 710 /*
 711  * Delete all Phase 2 handlers for this src/dst/proto.  This
 712  * is used during INITIAL-CONTACT processing (so no need to
 713  * send a message to the peer).
 714  */
 715 void
 716 deleteallph2(struct sockaddr *src, struct sockaddr *dst, unsigned int proto_id)
 717 {
 718         struct ph2handle *iph2, *next;
 719         struct saproto *pr;
 720 
 721         for (iph2 = LIST_FIRST(&ph2tree); iph2 != NULL; iph2 = next) {
 722                 next = LIST_NEXT(iph2, chain);
 723                 if (iph2->proposal == NULL && iph2->approval == NULL)
 724                         continue;
 725                 if (iph2->approval != NULL) {
 726                         for (pr = iph2->approval->head; pr != NULL;
 727                              pr = pr->next) {
 728                                 if (proto_id == pr->proto_id)
 729                                         goto zap_it;
 730                         }
 731                 } else if (iph2->proposal != NULL) {
 732                         for (pr = iph2->proposal->head; pr != NULL;
 733                              pr = pr->next) {
 734                                 if (proto_id == pr->proto_id)
 735                                         goto zap_it;
 736                         }
 737                 }
 738                 continue;
 739  zap_it:
 740                 unbindph12(iph2);
 741                 remph2(iph2);
 742                 delph2(iph2);
 743         }
 744 }
 745 
 746 /* %%% */
 747 void
 748 bindph12(struct ph1handle *iph1, struct ph2handle *iph2)
 749 {
 750         iph2->ph1 = iph1;
 751         LIST_INSERT_HEAD(&iph1->ph2tree, iph2, ph1bind);
 752 }
 753 
 754 void
 755 unbindph12(struct ph2handle *iph2)
 756 {
 757         if (iph2->ph1 != NULL) {
 758                 iph2->ph1 = NULL;
 759                 LIST_REMOVE(iph2, ph1bind);
 760         }
 761 }
 762 
 763 /* %%% management contacted list */
 764 /*
 765  * search contacted list.
 766  */
 767 struct contacted *
 768 getcontacted(struct sockaddr *remote)
 769 {
 770         struct contacted *p;
 771 
 772         LIST_FOREACH(p, &ctdtree, chain) {
 773                 if (rcs_cmpsa(remote, p->remote) == 0)
 774                         return p;
 775         }
 776 
 777         return NULL;
 778 }
 779 
 780 /*
 781  * create new isakmp Phase 2 status record to handle isakmp in Phase2
 782  */
 783 int
 784 inscontacted(struct sockaddr *remote)
 785 {
 786         struct contacted *new;
 787 
 788         /* create new iph2 */
 789         new = racoon_calloc(1, sizeof(*new));
 790         if (new == NULL)
 791                 return -1;
 792 
 793         new->remote = rcs_sadup(remote);
 794         if (!new->remote) {
 795                 racoon_free(new);
 796                 return -1;
 797         }
 798 
 799         LIST_INSERT_HEAD(&ctdtree, new, chain);
 800 
 801         return 0;
 802 }
 803 
 804 void
 805 initctdtree(void)
 806 {
 807         LIST_INIT(&ctdtree);
 808 }
 809 
 810 /*
 811  * check the response has been sent to the peer.  when not, simply reply
 812  * the buffered packet to the peer.
 813  * OUT:
 814  *       0:     the packet is received at the first time.
 815  *       1:     the packet was processed before.
 816  *       2:     the packet was processed before, but the address mismatches.
 817  *      -1:     error happened.
 818  */
 819 int
 820 check_recvdpkt(struct sockaddr *remote, struct sockaddr *local, rc_vchar_t *rbuf)
 821 {
 822         rc_vchar_t *hash;
 823         struct recvdpkt *r;
 824         time_t t;
 825         int len, s;
 826 
 827         /* set current time */
 828         t = time(NULL);
 829 
 830         hash = eay_md5_one(rbuf);
 831         if (!hash) {
 832                 plog(PLOG_INTERR, PLOGLOC, NULL,
 833                         "failed to allocate buffer.\n");
 834                 return -1;
 835         }
 836 
 837         LIST_FOREACH(r, &rcptree, chain) {
 838                 if (memcmp(hash->v, r->hash->v, r->hash->l) == 0)
 839                         break;
 840         }
 841         rc_vfree(hash);
 842 
 843         /* this is the first time to receive the packet */
 844         if (r == NULL)
 845                 return 0;
 846 
 847         /*
 848          * the packet was processed before, but the remote address mismatches.
 849          */
 850         if (rcs_cmpsa(remote, r->remote) != 0)
 851                 return 2;
 852 
 853         /*
 854          * it should not check the local address because the packet
 855          * may arrive at other interface.
 856          */
 857 
 858         /* check the previous time to send */
 859         if (t - r->time_send < 1) {
 860                 plog(PLOG_PROTOWARN, PLOGLOC, NULL,
 861                         "the packet retransmitted in a short time from %s\n",
 862                      rcs_sa2str(remote));
 863                 /*XXX should it be error ? */
 864         }
 865 
 866         /* select the socket to be sent */
 867         s = getsockmyaddr(r->local);
 868         if (s == -1)
 869                 return -1;
 870 
 871         /* resend the packet if needed */
 872         len = sendfromto(s, r->sendbuf->v, r->sendbuf->l,
 873                          r->local, r->remote, 1 /* lcconf->count_persend */);
 874         if (len == -1) {
 875                 plog(PLOG_INTERR, PLOGLOC, NULL, "sendfromto failed\n");
 876                 return -1;
 877         }
 878 
 879         /* check the retry counter */
 880         r->retry_counter--;
 881         if (r->retry_counter <= 0) {
 882                 rem_recvdpkt(r);
 883                 del_recvdpkt(r);
 884                 plog(PLOG_DEBUG, PLOGLOC, NULL,
 885                         "deleted the retransmission packet to %s.\n",
 886                      rcs_sa2str(remote));
 887         } else
 888                 r->time_send = t;
 889 
 890         return 1;
 891 }
 892 
 893 /*
 894  * adding a hash of received packet into the received list.
 895  */
 896 int
 897 add_recvdpkt(struct sockaddr *remote, struct sockaddr *local, 
 898              rc_vchar_t *sbuf, rc_vchar_t *rbuf, struct rcf_remote *conf)
 899 {
 900         struct recvdpkt *new = NULL;
 901         int lifetime;
 902 
 903         lifetime = ikev1_max_retry_to_send(conf) * ikev1_interval_to_send(conf);
 904         if (lifetime == 0) {
 905                 /* no need to add it */
 906                 return 0;
 907         }
 908 
 909         new = racoon_calloc(1, sizeof(*new));
 910         if (!new) {
 911                 plog(PLOG_INTERR, PLOGLOC, NULL,
 912                         "failed to allocate buffer.\n");
 913                 return -1;
 914         }
 915 
 916         new->hash = eay_md5_one(rbuf);
 917         if (!new->hash) {
 918                 plog(PLOG_INTERR, PLOGLOC, NULL,
 919                         "failed to allocate buffer.\n");
 920                 del_recvdpkt(new);
 921                 return -1;
 922         }
 923         new->remote = rcs_sadup(remote);
 924         if (new->remote == NULL) {
 925                 plog(PLOG_INTERR, PLOGLOC, NULL,
 926                         "failed to allocate buffer.\n");
 927                 del_recvdpkt(new);
 928                 return -1;
 929         }
 930         new->local = rcs_sadup(local);
 931         if (new->local == NULL) {
 932                 plog(PLOG_INTERR, PLOGLOC, NULL,
 933                         "failed to allocate buffer.\n");
 934                 del_recvdpkt(new);
 935                 return -1;
 936         }
 937         new->sendbuf = rc_vdup(sbuf);
 938         if (new->sendbuf == NULL) {
 939                 plog(PLOG_INTERR, PLOGLOC, NULL,
 940                         "failed to allocate buffer.\n");
 941                 del_recvdpkt(new);
 942                 return -1;
 943         }
 944 
 945         new->lifetime = lifetime;
 946         new->time_send = 0;
 947         new->created = time(NULL);
 948 
 949         LIST_INSERT_HEAD(&rcptree, new, chain);
 950 
 951         return 0;
 952 }
 953 
 954 void
 955 del_recvdpkt(struct recvdpkt *r)
 956 {
 957         if (r->remote)
 958                 racoon_free(r->remote);
 959         if (r->local)
 960                 racoon_free(r->local);
 961         if (r->hash)
 962                 rc_vfree(r->hash);
 963         if (r->sendbuf)
 964                 rc_vfree(r->sendbuf);
 965         racoon_free(r);
 966 }
 967 
 968 void
 969 rem_recvdpkt(struct recvdpkt *r)
 970 {
 971         LIST_REMOVE(r, chain);
 972 }
 973 
 974 int ikev1_recvdpkt_sweep_interval = 5; /* ??? */
 975 
 976 void
 977 sweep_recvdpkt(void *dummy)
 978 {
 979         struct recvdpkt *r, *next;
 980         time_t t;
 981 
 982         /* set current time */
 983         t = time(NULL);
 984 
 985         for (r = LIST_FIRST(&rcptree); r; r = next) {
 986                 next = LIST_NEXT(r, chain);
 987 
 988                 if (t > r->created + r->lifetime) {
 989                         rem_recvdpkt(r);
 990                         del_recvdpkt(r);
 991                 }
 992         }
 993 
 994         sched_new(ikev1_recvdpkt_sweep_interval, sweep_recvdpkt, NULL);
 995 }
 996 
 997 void
 998 init_recvdpkt(void)
 999 {
1000         LIST_INIT(&rcptree);
1001 
1002         sched_new(ikev1_recvdpkt_sweep_interval, sweep_recvdpkt, NULL);
1003 }
1004 
1005 #ifdef ENABLE_HYBRID
1006 /* 
1007  * Retruns 0 if the address was obtained by ISAKMP mode config, 1 otherwise
1008  * This should be in isakmp_cfg.c but ph1tree being private, it must be there
1009  */
1010 int
1011 exclude_cfg_addr(const struct sockaddr *addr)
1012 {
1013         struct ph1handle *p;
1014         struct sockaddr_in *sin;
1015 
1016         LIST_FOREACH(p, &ph1tree, chain) {
1017                 if ((p->mode_cfg != NULL) &&
1018                     (p->mode_cfg->flags & ISAKMP_CFG_GOT_ADDR4) &&
1019                     (addr->sa_family == AF_INET)) {
1020                         sin = (struct sockaddr_in *)addr;
1021                         if (sin->sin_addr.s_addr == p->mode_cfg->addr4.s_addr)
1022                                 return 0;
1023                 }
1024         }
1025 
1026         return 1;
1027 }
1028 #endif
1029 
1030 
1031 
1032 #if 0
1033 /* 
1034  * Reload conf code
1035  */
1036 static int revalidate_ph2(struct ph2handle *iph2){
1037         struct sainfoalg *alg;
1038         int found, check_level;
1039         struct sainfo *sainfo;
1040         struct saprop *approval;
1041 
1042         /* 
1043          * Get the new sainfo using values of the old one
1044          */
1045         iph2->sainfo = getsainfo(iph2->sainfo->idsrc, 
1046             iph2->sainfo->iddst, iph2->sainfo->id_i);
1047         approval = iph2->approval;
1048         sainfo = iph2->sainfo;
1049 
1050         if (sainfo == NULL) {
1051                 /* 
1052                  * Sainfo has been removed
1053                  */
1054                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1055                          "Reload: No sainfo for ph2\n");
1056                 return 0;
1057         }
1058 
1059         if (approval == NULL) {
1060                 /*
1061                  * XXX why do we have a NULL approval sometimes ???
1062                  */
1063                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1064                          "No approval found !\n");
1065                 return 0;
1066         }       
1067 
1068         /*
1069          * Don't care about proposals, should we do something ?
1070          * We have to keep iph2->proposal valid at least for initiator,
1071          * for pk_sendgetspi()
1072          */
1073 
1074         plog(PLOG_DEBUG, PLOGLOC, NULL, "active single bundle:\n");
1075         printsaprop0(PLOG_DEBUG, approval);
1076 
1077         /*
1078          * Validate approval against sainfo
1079          * Note: we must have an updated ph1->rmconf before doing that,
1080          * we'll set check_level to EXACT if we don't have a ph1
1081          * XXX try tu find the new remote section to get the new check level ?
1082          * XXX lifebyte
1083          */
1084         if (iph2->ph1 != NULL && iph2->ph1->rmconf != NULL) {
1085                 check_level = ikev1_proposal_check(iph2->ph1->rmconf);
1086         } else {
1087                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1088                          "No phase1 rmconf found !\n");
1089                 check_level = RCT_PCT_EXACT;
1090         }
1091 
1092         switch (check_level) {
1093         case RCT_PCT_OBEY:
1094                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1095                          "Reload: OBEY for ph2, ok\n");
1096                 return 1;
1097                 break;
1098 
1099         case RCT_PCT_STRICT:
1100                 /* FALLTHROUGH */
1101         case RCT_PCT_CLAIM:
1102                 if (sainfo->lifetime < approval->lifetime) {
1103                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1104                                  "Reload: lifetime mismatch\n");
1105                         return 0;
1106                 }
1107 
1108                 if (sainfo->lifebyte < approval->lifebyte) {
1109                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1110                                  "Reload: lifebyte mismatch\n");
1111                         return 0;
1112                 }
1113 
1114                 if (sainfo->pfs_group &&
1115                    sainfo->pfs_group != approval->pfs_group) {
1116                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1117                                  "Reload: PFS group mismatch\n");
1118                         return 0;
1119                 }
1120                 break;
1121 
1122         case RCT_PCT_EXACT:
1123                 if (sainfo->lifetime != approval->lifetime ||
1124                     sainfo->lifebyte != approval->lifebyte ||
1125                     sainfo->pfs_group != iph2->approval->pfs_group) {
1126                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1127                             "Reload: lifetime | pfs mismatch\n");
1128                         return 0;
1129                 }
1130                 break;
1131 
1132         default:
1133                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1134                          "Reload: Shouldn't be here !\n");
1135                 return 0;
1136                 break;
1137         }
1138 
1139         for (alg = sainfo->algs[algclass_ipsec_auth]; alg; alg = alg->next) {
1140                 if (alg->alg == approval->head->head->authtype)
1141                         break;
1142         }
1143         if (alg == NULL) {
1144                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1145                          "Reload: alg == NULL (auth)\n");
1146                 return 0;
1147         }
1148 
1149         found = 0;
1150         for (alg = sainfo->algs[algclass_ipsec_enc]; 
1151             (found == 0 && alg != NULL); alg = alg->next) {
1152                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1153                          "Reload: next ph2 enc alg...\n");
1154 
1155                 if (alg->alg != approval->head->head->trns_id){
1156                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1157                                  "Reload: encmode mismatch (%d / %d)\n",
1158                                  alg->alg, approval->head->head->trns_id);
1159                         continue;
1160                 }
1161 
1162                 switch (check_level){
1163                 /* RCT_PCT_STRICT cannot happen here */
1164                 case RCT_PCT_EXACT:
1165                         if (alg->encklen != approval->head->head->encklen) {
1166                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1167                                          "Reload: enclen mismatch\n");
1168                                 continue;
1169                         }
1170                         break;
1171 
1172                 case RCT_PCT_CLAIM:
1173                         /* FALLTHROUGH */
1174                 case RCT_PCT_STRICT:
1175                         if (alg->encklen > approval->head->head->encklen) {
1176                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1177                                          "Reload: enclen mismatch\n");
1178                                 continue;
1179                         }
1180                         break;
1181 
1182                 default:
1183                         plog(PLOG_INTERR, PLOGLOC, NULL, 
1184                             "unexpected check_level\n");
1185                         continue;
1186                         break;
1187                 }
1188                 found = 1;
1189         }
1190 
1191         if (!found){
1192                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1193                          "Reload: No valid enc\n");
1194                 return 0;
1195         }
1196 
1197         /*
1198          * XXX comp
1199          */
1200         plog(PLOG_DEBUG, PLOGLOC, NULL,
1201                  "Reload: ph2 check ok\n");
1202 
1203         return 1;
1204 }
1205 #endif
1206 
1207 
1208 #ifdef notyet
1209 static void 
1210 remove_ph2(struct ph2handle *iph2)
1211 {
1212         uint32_t spis[2];
1213 
1214         if(iph2 == NULL)
1215                 return;
1216 
1217         plog(PLOG_DEBUG, PLOGLOC, NULL,
1218                  "Deleting a Ph2...\n");
1219 
1220         if (iph2->status == PHASE2ST_ESTABLISHED)
1221                 isakmp_info_send_d2(iph2);
1222 
1223         if(iph2->approval != NULL && iph2->approval->head != NULL){
1224                 spis[0]=iph2->approval->head->spi;
1225                 spis[1]=iph2->approval->head->spi_p;
1226 
1227                 /* purge_ipsec_spi() will do all the work:
1228                  * - delete SPIs in kernel
1229                  * - delete generated SPD
1230                  * - unbind / rem / del ph2
1231                  */
1232                 purge_ipsec_spi(iph2->ph1, iph2->dst, iph2->approval->head->proto_id,
1233                                                 spis, 2);
1234         }else{
1235                 unbindph12(iph2);
1236                 remph2(iph2);
1237                 delph2(iph2);
1238         }
1239 }
1240 
1241 static void 
1242 remove_ph1(struct ph1handle *iph1)
1243 {
1244         struct ph2handle *iph2, *iph2_next;
1245 
1246         if(iph1 == NULL)
1247                 return;
1248 
1249         plog(PLOG_DEBUG, PLOGLOC, NULL,
1250                  "Removing PH1...\n");
1251 
1252         if (iph1->status == PHASE1ST_ESTABLISHED){
1253                 for (iph2 = LIST_FIRST(&iph1->ph2tree); iph2; iph2 = iph2_next) {
1254                         iph2_next = LIST_NEXT(iph2, chain);
1255                         remove_ph2(iph2);
1256                 }
1257                 isakmp_info_send_d1(iph1);
1258         }
1259         iph1->status = PHASE1ST_EXPIRED;
1260         iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
1261 }
1262 
1263 
1264 static int 
1265 revalidate_ph1tree_rmconf(void)
1266 {
1267         struct ph1handle *p, *next;
1268         struct rcf_remote *newrmconf;
1269 
1270         for (p = LIST_FIRST(&ph1tree); p; p = next) {
1271                 next = LIST_NEXT(p, chain);
1272 
1273                 if (p->status == PHASE1ST_EXPIRED)
1274                         continue;
1275 
1276                 newrmconf=getrmconf(p->remote);
1277                 if(newrmconf == NULL){
1278                         p->rmconf = NULL;
1279                         remove_ph1(p);
1280                 }else{
1281                         /* Do not free old rmconf, it is just a pointer to an entry in rmtree
1282                          */
1283                         p->rmconf=newrmconf;
1284                         if(p->approval != NULL){
1285                                 struct isakmpsa *tmpsa;
1286 
1287                                 tmpsa=dupisakmpsa(p->approval);
1288                                 if(tmpsa != NULL){
1289                                         delisakmpsa(p->approval);
1290                                         p->approval=tmpsa;
1291                                         p->approval->rmconf=newrmconf;
1292                                 }
1293                         }
1294                 }
1295         }
1296 
1297         return 1;
1298 }
1299 
1300 
1301 /* rmconf is already updated here
1302  */
1303 static int 
1304 revalidate_ph1(struct ph1handle *iph1)
1305 {
1306         rc_type exchange_mode;
1307         struct isakmpsa *p, *approval;
1308         struct etypes *e;
1309 
1310         if(iph1 == NULL ||
1311            iph1->approval == NULL ||
1312                 iph1->rmconf == NULL)
1313                 return 0;
1314 
1315         approval=iph1->approval;
1316         for (p=iph1->rmconf->proposal; p != NULL; p=p->next){
1317                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1318                          "Reload: Trying next proposal...\n");
1319 
1320                 if(approval->authmethod != p->authmethod){
1321                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1322                                  "Reload: Authmethod mismatch\n");
1323                         continue;
1324                 }
1325 
1326                 if(approval->enctype != p->enctype){
1327                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1328                                  "Reload: enctype mismatch\n");
1329                         continue;
1330                 }
1331 
1332                 switch (iph1->rmconf->pcheck_level) {
1333                 case RCT_PCT_OBEY:
1334                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1335                                  "Reload: OBEY pcheck level, ok...\n");
1336                         return 1;
1337                         break;
1338 
1339                 case RCT_PCT_CLAIM:
1340                         /* FALLTHROUGH */
1341                 case RCT_PCT_STRICT:
1342                         if (approval->encklen < p->encklen) {
1343                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1344                                          "Reload: encklen mismatch\n");
1345                                 continue;
1346                         }
1347 
1348                         if (approval->lifetime > p->lifetime) {
1349                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1350                                          "Reload: lifetime mismatch\n");
1351                                 continue;
1352                         }
1353 
1354                         if (approval->lifebyte > p->lifebyte) {
1355                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1356                                          "Reload: lifebyte mismatch\n");
1357                                 continue;
1358                         }
1359                         break;
1360 
1361                 case RCT_PCT_EXACT:
1362                         if (approval->encklen != p->encklen) {
1363                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1364                                          "Reload: encklen mismatch\n");
1365                                 continue;
1366                         }
1367 
1368                         if (approval->lifetime != p->lifetime) {
1369                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1370                                          "Reload: lifetime mismatch\n");
1371                                 continue;
1372                         }
1373 
1374                         if (approval->lifebyte != p->lifebyte) {
1375                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1376                                          "Reload: lifebyte mismatch\n");
1377                                 continue;
1378                         }
1379                         break;
1380 
1381                 default:
1382                         plog(PLOG_INTERR, PLOGLOC, NULL, 
1383                             "unexpected check_level\n");
1384                         continue;
1385                         break;
1386                 }
1387 
1388                 if (approval->hashtype != p->hashtype) {
1389                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1390                                  "Reload: hashtype mismatch\n");
1391                         continue;
1392                 }
1393 
1394                 if (iph1->etype != ISAKMP_ETYPE_AGG &&
1395                     approval->dh_group != p->dh_group) {
1396                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1397                                  "Reload: dhgroup mismatch\n");
1398                         continue;
1399                 }
1400 
1401                 plog(PLOG_DEBUG, PLOGLOC, NULL, "Reload: Conf ok\n");
1402                 return 1;
1403         }
1404 
1405         plog(PLOG_DEBUG, PLOGLOC, NULL, "Reload: No valid conf found\n");
1406         return 0;
1407 }
1408 
1409 
1410 static int 
1411 revalidate_ph1tree(void)
1412 {
1413         struct ph1handle *p, *next;
1414 
1415         for (p = LIST_FIRST(&ph1tree); p; p = next) {
1416                 next = LIST_NEXT(p, chain);
1417 
1418                 if (p->status == PHASE1ST_EXPIRED)
1419                         continue;
1420 
1421                 if(!revalidate_ph1(p))
1422                         remove_ph1(p);
1423         }
1424 
1425         return 1;
1426 }
1427 
1428 static int 
1429 revalidate_ph2tree(void)
1430 {
1431         struct ph2handle *p, *next;
1432 
1433         for (p = LIST_FIRST(&ph2tree); p; p = next) {
1434                 next = LIST_NEXT(p, chain);
1435 
1436                 if (p->status == PHASE2ST_EXPIRED)
1437                         continue;
1438 
1439                 if(!revalidate_ph2(p)){
1440                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1441                                  "PH2 not validated, removing it\n");
1442                         remove_ph2(p);
1443                 }
1444         }
1445 
1446         return 1;
1447 }
1448 
1449 int 
1450 revalidate_ph12(void)
1451 {
1452 
1453         revalidate_ph1tree_rmconf();
1454 
1455         revalidate_ph2tree();
1456         revalidate_ph1tree();
1457 
1458         return 1;
1459 }
1460 #endif
1461 
1462 #ifdef ENABLE_HYBRID
1463 struct ph1handle *
1464 getph1bylogin(char *login)
1465 {
1466         struct ph1handle *p;
1467 
1468         LIST_FOREACH(p, &ph1tree, chain) {
1469                 if (p->mode_cfg == NULL)
1470                         continue;
1471                 if (strncmp(p->mode_cfg->login, login, LOGINLEN) == 0)
1472                         return p;
1473         }
1474 
1475         return NULL;
1476 }
1477 
1478 int
1479 purgeph1bylogin(char *login)
1480 {
1481         struct ph1handle *p;
1482         int found = 0;
1483 
1484         LIST_FOREACH(p, &ph1tree, chain) {
1485                 if (p->mode_cfg == NULL)
1486                         continue;
1487                 if (strncmp(p->mode_cfg->login, login, LOGINLEN) == 0) {
1488                         if (p->status == PHASE1ST_ESTABLISHED)
1489                                 isakmp_info_send_d1(p);
1490                         purge_remote(p);
1491                         found++;
1492                 }
1493         }
1494 
1495         return found;
1496 }
1497 #endif
1498 
1499 
1500 static int
1501 delete_ipsec_sa(struct sadb_request *r, 
1502                 struct sockaddr *src, struct sockaddr *dst, int proto, 
1503                 uint32_t spi/* network order */)
1504 {
1505         struct rcpfk_msg param;
1506         int satype;
1507         int retval;
1508 
1509         (void) memset(&param, 0, sizeof (param));
1510 
1511         switch (proto) {
1512         case IPSECDOI_PROTO_IPSEC_AH:
1513                 satype = RCT_SATYPE_AH;
1514                 break;
1515         case IPSECDOI_PROTO_IPSEC_ESP:
1516                 satype = RCT_SATYPE_ESP;
1517                 break;
1518         case IPSECDOI_PROTO_IPCOMP:
1519                 satype = RCT_SATYPE_IPCOMP;
1520                 break;
1521         default:
1522                 plog(PLOG_INTERR, PLOGLOC, 0,
1523                      "unsupported IPSECDOI protocol ID (%d)\n",
1524                      proto);
1525                 retval = -1;
1526                 goto done;
1527                 break;
1528         }
1529 
1530         param.sa_src = src;
1531         param.sa_dst = dst;
1532         param.satype = satype;
1533         param.spi = spi;
1534         retval = r->method->delete_sa(&param);
1535 
1536   done:
1537         return retval;
1538 }
1539 
1540 
1541 void
1542 purge_remote(struct ph1handle *iph1)
1543 {
1544         struct ph2handle *iph2;
1545         struct ph2handle *next_ph2;
1546         struct saprop *pp;
1547         struct saproto *pr;
1548 
1549         plog(PLOG_INFO, PLOGLOC, 0,
1550              "purging ISAKMP-SA spi=%s.\n",
1551              isakmp_pindex(&(iph1->index), iph1->msgid));
1552 
1553         /* Mark as expired. */
1554         iph1->status = PHASE1ST_EXPIRED;
1555 
1556         for (iph2 = LIST_FIRST(&ph2tree); iph2; iph2 = next_ph2) {
1557                 next_ph2 = LIST_NEXT(iph2, chain);
1558 
1559                 if (iph2->ph1 != iph1)
1560                         continue;
1561 
1562                 pp = iph2->approval;
1563                 if (pp != NULL) {
1564                         for (pr = pp->head; pr != NULL; pr = pr->next) {
1565                                 TRACE((PLOGLOC, "proto %d spi 0x%08" PRIx32 "\n",
1566                                        pr->proto_id, 
1567                                        ntohl(pr->spi)));
1568                                 (void) delete_ipsec_sa(&iph2->sadb_request,
1569                                                        iph2->src,
1570                                                        iph2->dst,
1571                                                        pr->proto_id, pr->spi_p);
1572                                 (void) delete_ipsec_sa(&iph2->sadb_request,
1573                                                        iph2->dst,
1574                                                        iph2->src,
1575                                                        pr->proto_id, pr->spi);
1576                         }
1577                 }
1578 
1579                 destroy_ph2(iph2);
1580         }
1581 }
1582 
1583 
1584 void
1585 purge_ipsec_spi(struct ph1handle *ph1, 
1586                 struct sockaddr *dst0, 
1587                 int proto_id, 
1588                 uint32_t *spi_ptr/*network byteorder*/, 
1589                 int n)
1590 {
1591         struct ph2handle *iph2;
1592         uint32_t spi;
1593         int all_done;
1594         struct saprop *pp;
1595         struct saproto *pr;
1596         int i;
1597 
1598         for (i = 0; i < n; ++i) {
1599                 spi = htonl(get_uint32(&spi_ptr[i]));
1600                 iph2 = getph2bysaidx(ph1->local, ph1->remote, proto_id, spi);
1601                 if (iph2 != NULL) {
1602                         pp = iph2->approval;
1603                         all_done = TRUE;
1604                         for (pr = pp->head; pr != NULL; pr = pr->next) {
1605                                 TRACE((PLOGLOC, "proto %d spi 0x%08" PRIx32 "\n",
1606                                        pr->proto_id, 
1607                                        ntohl(pr->spi_p)));
1608                                 if (pr->proto_id == proto_id && pr->spi_p == spi) {
1609                                         (void) delete_ipsec_sa(&iph2->sadb_request,
1610                                                                iph2->src,
1611                                                                iph2->dst,
1612                                                                proto_id, spi);
1613                                         pr->spi_p = 0;
1614                                 } else if (pr->spi_p != 0) {
1615                                         all_done = FALSE;
1616                                 }
1617                         }
1618 
1619                         if (all_done)
1620                                 destroy_ph2(iph2);
1621                 }
1622         }
1623 }
1624