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         if (iph1->natt_flags & NAT_KA_QUEUED)
 279                 natt_keepalive_remove (iph1->local, iph1->remote);
 280 
 281         if (iph1->natt_options) {
 282                 racoon_free(iph1->natt_options);
 283                 iph1->natt_options = NULL;
 284         }
 285 #endif
 286 
 287         if (iph1->dpd_r_u != NULL)
 288                 SCHED_KILL(iph1->dpd_r_u);
 289 
 290         if (iph1->remote) {
 291                 racoon_free(iph1->remote);
 292                 iph1->remote = NULL;
 293         }
 294         if (iph1->local) {
 295                 racoon_free(iph1->local);
 296                 iph1->local = NULL;
 297         }
 298 
 299         if (iph1->approval) {
 300                 delisakmpsa(iph1->approval);
 301                 iph1->approval = NULL;
 302         }
 303 
 304 #ifdef ENABLE_HYBRID
 305         if (iph1->mode_cfg)
 306                 isakmp_cfg_rmstate(iph1);
 307 #endif
 308 
 309         VPTRINIT(iph1->authstr);
 310 
 311         sched_scrub_param(iph1);
 312         iph1->sce = NULL;
 313         iph1->scr = NULL;
 314 
 315         VPTRINIT(iph1->sendbuf);
 316 
 317         VPTRINIT(iph1->dhpriv);
 318         VPTRINIT(iph1->dhpub);
 319         VPTRINIT(iph1->dhpub_p);
 320         VPTRINIT(iph1->dhgxy);
 321         VPTRINIT(iph1->nonce);
 322         VPTRINIT(iph1->nonce_p);
 323         VPTRINIT(iph1->skeyid);
 324         VPTRINIT(iph1->skeyid_d);
 325         VPTRINIT(iph1->skeyid_a);
 326         VPTRINIT(iph1->skeyid_e);
 327         VPTRINIT(iph1->key);
 328         VPTRINIT(iph1->hash);
 329         VPTRINIT(iph1->sig);
 330         VPTRINIT(iph1->sig_p);
 331         oakley_delcert(iph1->cert);
 332         iph1->cert = NULL;
 333         oakley_delcert(iph1->cert_p);
 334         iph1->cert_p = NULL;
 335         oakley_delcert(iph1->crl_p);
 336         iph1->crl_p = NULL;
 337         oakley_delcert(iph1->cr_p);
 338         iph1->cr_p = NULL;
 339         VPTRINIT(iph1->id);
 340         VPTRINIT(iph1->id_p);
 341 
 342         if (iph1->approval)
 343                 delisakmpsa(iph1->approval);
 344 
 345         if (iph1->ivm) {
 346                 oakley_delivm(iph1->ivm);
 347                 iph1->ivm = NULL;
 348         }
 349 
 350         VPTRINIT(iph1->sa);
 351         VPTRINIT(iph1->sa_ret);
 352 
 353 #ifdef HAVE_GSSAPI
 354         VPTRINIT(iph1->gi_i);
 355         VPTRINIT(iph1->gi_r);
 356 
 357         gssapi_free_state(iph1);
 358 #endif
 359 
 360         racoon_free(iph1);
 361 }
 362 
 363 /*
 364  * create new isakmp Phase 1 status record to handle isakmp in Phase1
 365  */
 366 int
 367 insph1(struct ph1handle *iph1)
 368 {
 369         /* validity check */
 370         if (iph1->remote == NULL) {
 371                 plog(PLOG_INTERR, PLOGLOC, NULL,
 372                         "invalid isakmp SA handler. no remote address.\n");
 373                 return -1;
 374         }
 375         LIST_INSERT_HEAD(&ph1tree, iph1, chain);
 376 
 377         return 0;
 378 }
 379 
 380 void
 381 remph1(struct ph1handle *iph1)
 382 {
 383         LIST_REMOVE(iph1, chain);
 384 }
 385 
 386 /*
 387  * flush isakmp-sa
 388  */
 389 void
 390 flushph1(void)
 391 {
 392         struct ph1handle *p, *next;
 393 
 394         for (p = LIST_FIRST(&ph1tree); p; p = next) {
 395                 next = LIST_NEXT(p, chain);
 396 
 397                 /* send delete information */
 398                 if (p->status == PHASE1ST_ESTABLISHED) 
 399                         isakmp_info_send_d1(p);
 400 
 401                 remph1(p);
 402                 delph1(p);
 403         }
 404 }
 405 
 406 void
 407 initph1tree(void)
 408 {
 409         LIST_INIT(&ph1tree);
 410 }
 411 
 412 /* %%% management phase 2 handler */
 413 #if 0
 414 /*
 415  * search ph2handle with policy id.
 416  */
 417 struct ph2handle *
 418 getph2byspid(uint32_t spid)
 419 {
 420         struct ph2handle *p;
 421 
 422         LIST_FOREACH(p, &ph2tree, chain) {
 423                 /*
 424                  * there are ph2handle independent on policy
 425                  * such like informational exchange.
 426                  */
 427                 if (p->spid == spid)
 428                         return p;
 429         }
 430 
 431         return NULL;
 432 }
 433 #endif
 434 
 435 /*
 436  * search ph2handle with sequence number.
 437  */
 438 struct ph2handle *
 439 getph2byseq(uint32_t seq)
 440 {
 441         struct ph2handle *p;
 442 
 443         LIST_FOREACH(p, &ph2tree, chain) {
 444                 if (p->seq == seq)
 445                         return p;
 446         }
 447 
 448         return NULL;
 449 }
 450 
 451 /*
 452  * search ph2handle with message id.
 453  */
 454 struct ph2handle *
 455 getph2bymsgid(struct ph1handle *iph1, uint32_t msgid)
 456 {
 457         struct ph2handle *p;
 458 
 459         LIST_FOREACH(p, &ph2tree, chain) {
 460                 if (p->msgid == msgid)
 461                         return p;
 462         }
 463 
 464         return NULL;
 465 }
 466 
 467 struct ph2handle *
 468 getph2byselector(struct sockaddr *src, struct sockaddr *dst, struct rcf_selector *selector)
 469 {
 470         struct ph2handle *p;
 471 
 472         LIST_FOREACH(p, &ph2tree, chain) {
 473                 if (rc_vmemcmp(p->selector->sl_index, selector->sl_index)
 474                         == 0 &&
 475                     CMPSADDR(src, p->src) == 0 &&
 476                     CMPSADDR(dst, p->dst) == 0)
 477                         return p;
 478         }
 479 
 480         return NULL;
 481 }
 482 
 483 struct ph2handle *
 484 getph2bysaddr(struct sockaddr *src, struct sockaddr *dst)
 485 {
 486         struct ph2handle *p;
 487 
 488         LIST_FOREACH(p, &ph2tree, chain) {
 489                 if (rcs_cmpsa(src, p->src) == 0 &&
 490                     rcs_cmpsa(dst, p->dst) == 0)
 491                         return p;
 492         }
 493 
 494         return NULL;
 495 }
 496 
 497 /*
 498  * call by pk_recvexpire().
 499  */
 500 struct ph2handle *
 501 getph2bysaidx(struct sockaddr *src, struct sockaddr *dst, unsigned int proto_id, uint32_t spi)
 502 {
 503         struct ph2handle *iph2;
 504         struct saproto *pr;
 505 
 506         LIST_FOREACH(iph2, &ph2tree, chain) {
 507                 if (iph2->proposal == NULL && iph2->approval == NULL)
 508                         continue;
 509                 if (iph2->approval != NULL) {
 510                         for (pr = iph2->approval->head; pr != NULL;
 511                              pr = pr->next) {
 512                                 if (proto_id != pr->proto_id)
 513                                         break;
 514                                 if (spi == pr->spi || spi == pr->spi_p)
 515                                         return iph2;
 516                         }
 517                 } else if (iph2->proposal != NULL) {
 518                         for (pr = iph2->proposal->head; pr != NULL;
 519                              pr = pr->next) {
 520                                 if (proto_id != pr->proto_id)
 521                                         break;
 522                                 if (spi == pr->spi)
 523                                         return iph2;
 524                         }
 525                 }
 526         }
 527 
 528         return NULL;
 529 }
 530 
 531 /*
 532  * create new isakmp Phase 2 status record to handle isakmp in Phase2
 533  */
 534 struct ph2handle *
 535 newph2(void)
 536 {
 537         struct ph2handle *iph2 = NULL;
 538 
 539         /* create new iph2 */
 540         iph2 = racoon_calloc(1, sizeof(*iph2));
 541         if (iph2 == NULL)
 542                 return NULL;
 543 
 544         iph2->status = PHASE1ST_SPAWN;
 545 
 546         return iph2;
 547 }
 548 
 549 /*
 550  * initialize ph2handle
 551  * NOTE: don't initialize src/dst.
 552  *       SPI in the proposal is cleared.
 553  */
 554 void
 555 initph2(struct ph2handle *iph2)
 556 {
 557         sched_scrub_param(iph2);
 558         iph2->sce = NULL;
 559         iph2->scr = NULL;
 560 
 561         VPTRINIT(iph2->sendbuf);
 562         VPTRINIT(iph2->msg1);
 563 
 564         /* clear spi, keep variables in the proposal */
 565         if (iph2->proposal) {
 566                 struct saproto *pr;
 567                 for (pr = iph2->proposal->head; pr != NULL; pr = pr->next)
 568                         pr->spi = 0;
 569         }
 570 
 571         /* clear approval */
 572         if (iph2->approval) {
 573                 flushsaprop(iph2->approval);
 574                 iph2->approval = NULL;
 575         }
 576 
 577 #ifdef notyet
 578         /* clear the generated policy */
 579         if (iph2->spidx_gen) {
 580                 delsp_bothdir((struct policyindex *)iph2->spidx_gen);
 581                 racoon_free(iph2->spidx_gen);
 582                 iph2->spidx_gen = NULL;
 583         }
 584 #endif
 585 
 586         if (iph2->pfsgrp) {
 587                 oakley_dhgrp_free(iph2->pfsgrp);
 588                 iph2->pfsgrp = NULL;
 589         }
 590 
 591         VPTRINIT(iph2->dhpriv);
 592         VPTRINIT(iph2->dhpub);
 593         VPTRINIT(iph2->dhpub_p);
 594         VPTRINIT(iph2->dhgxy);
 595         VPTRINIT(iph2->id);
 596         VPTRINIT(iph2->id_p);
 597         VPTRINIT(iph2->nonce);
 598         VPTRINIT(iph2->nonce_p);
 599         VPTRINIT(iph2->sa);
 600         VPTRINIT(iph2->sa_ret);
 601 
 602         if (iph2->ivm) {
 603                 oakley_delivm(iph2->ivm);
 604                 iph2->ivm = NULL;
 605         }
 606 }
 607 
 608 /*
 609  * delete new isakmp Phase 2 status record to handle isakmp in Phase2
 610  */
 611 void
 612 delph2(struct ph2handle *iph2)
 613 {
 614         initph2(iph2);
 615 
 616         if (iph2->src) {
 617                 racoon_free(iph2->src);
 618                 iph2->src = NULL;
 619         }
 620         if (iph2->dst) {
 621                 racoon_free(iph2->dst);
 622                 iph2->dst = NULL;
 623         }
 624         if (iph2->src_id) {
 625               racoon_free(iph2->src_id);
 626               iph2->src_id = NULL;
 627         }
 628         if (iph2->dst_id) {
 629               racoon_free(iph2->dst_id);
 630               iph2->dst_id = NULL;
 631         }
 632 
 633         if (iph2->proposal) {
 634                 flushsaprop(iph2->proposal);
 635                 iph2->proposal = NULL;
 636         }
 637 
 638         sadb_request_finish(&iph2->sadb_request);
 639 
 640         racoon_free(iph2);
 641 }
 642 
 643 /*
 644  * create new isakmp Phase 2 status record to handle isakmp in Phase2
 645  */
 646 int
 647 insph2(struct ph2handle *iph2)
 648 {
 649         LIST_INSERT_HEAD(&ph2tree, iph2, chain);
 650 
 651         return 0;
 652 }
 653 
 654 void
 655 remph2(struct ph2handle *iph2)
 656 {
 657         LIST_REMOVE(iph2, chain);
 658 }
 659 
 660 void
 661 destroy_ph2(struct ph2handle *iph2)
 662 {
 663         /* delete_spd(iph2); */
 664         unbindph12(iph2);
 665         remph2(iph2);
 666         delph2(iph2);
 667 }
 668 
 669 
 670 void
 671 initph2tree(void)
 672 {
 673         LIST_INIT(&ph2tree);
 674 }
 675 
 676 void
 677 flushph2(void)
 678 {
 679         struct ph2handle *p, *next;
 680 
 681         for (p = LIST_FIRST(&ph2tree); p; p = next) {
 682                 next = LIST_NEXT(p, chain);
 683 
 684                 /* send delete information */
 685                 if (p->status == PHASE2ST_ESTABLISHED) 
 686                         isakmp_info_send_d2(p);
 687 
 688                 destroy_ph2(p);
 689         }
 690 }
 691 
 692 /*
 693  * Delete all Phase 2 handlers for this src/dst/proto.  This
 694  * is used during INITIAL-CONTACT processing (so no need to
 695  * send a message to the peer).
 696  */
 697 void
 698 deleteallph2(struct sockaddr *src, struct sockaddr *dst, unsigned int proto_id)
 699 {
 700         struct ph2handle *iph2, *next;
 701         struct saproto *pr;
 702 
 703         for (iph2 = LIST_FIRST(&ph2tree); iph2 != NULL; iph2 = next) {
 704                 next = LIST_NEXT(iph2, chain);
 705                 if (iph2->proposal == NULL && iph2->approval == NULL)
 706                         continue;
 707                 if (iph2->approval != NULL) {
 708                         for (pr = iph2->approval->head; pr != NULL;
 709                              pr = pr->next) {
 710                                 if (proto_id == pr->proto_id)
 711                                         goto zap_it;
 712                         }
 713                 } else if (iph2->proposal != NULL) {
 714                         for (pr = iph2->proposal->head; pr != NULL;
 715                              pr = pr->next) {
 716                                 if (proto_id == pr->proto_id)
 717                                         goto zap_it;
 718                         }
 719                 }
 720                 continue;
 721  zap_it:
 722                 unbindph12(iph2);
 723                 remph2(iph2);
 724                 delph2(iph2);
 725         }
 726 }
 727 
 728 /* %%% */
 729 void
 730 bindph12(struct ph1handle *iph1, struct ph2handle *iph2)
 731 {
 732         iph2->ph1 = iph1;
 733         LIST_INSERT_HEAD(&iph1->ph2tree, iph2, ph1bind);
 734 }
 735 
 736 void
 737 unbindph12(struct ph2handle *iph2)
 738 {
 739         if (iph2->ph1 != NULL) {
 740                 iph2->ph1 = NULL;
 741                 LIST_REMOVE(iph2, ph1bind);
 742         }
 743 }
 744 
 745 /* %%% management contacted list */
 746 /*
 747  * search contacted list.
 748  */
 749 struct contacted *
 750 getcontacted(struct sockaddr *remote)
 751 {
 752         struct contacted *p;
 753 
 754         LIST_FOREACH(p, &ctdtree, chain) {
 755                 if (rcs_cmpsa(remote, p->remote) == 0)
 756                         return p;
 757         }
 758 
 759         return NULL;
 760 }
 761 
 762 /*
 763  * create new isakmp Phase 2 status record to handle isakmp in Phase2
 764  */
 765 int
 766 inscontacted(struct sockaddr *remote)
 767 {
 768         struct contacted *new;
 769 
 770         /* create new iph2 */
 771         new = racoon_calloc(1, sizeof(*new));
 772         if (new == NULL)
 773                 return -1;
 774 
 775         new->remote = rcs_sadup(remote);
 776         if (!new->remote) {
 777                 racoon_free(new);
 778                 return -1;
 779         }
 780 
 781         LIST_INSERT_HEAD(&ctdtree, new, chain);
 782 
 783         return 0;
 784 }
 785 
 786 void
 787 initctdtree(void)
 788 {
 789         LIST_INIT(&ctdtree);
 790 }
 791 
 792 /*
 793  * check the response has been sent to the peer.  when not, simply reply
 794  * the buffered packet to the peer.
 795  * OUT:
 796  *       0:     the packet is received at the first time.
 797  *       1:     the packet was processed before.
 798  *       2:     the packet was processed before, but the address mismatches.
 799  *      -1:     error happened.
 800  */
 801 int
 802 check_recvdpkt(struct sockaddr *remote, struct sockaddr *local, rc_vchar_t *rbuf)
 803 {
 804         rc_vchar_t *hash;
 805         struct recvdpkt *r;
 806         time_t t;
 807         int len, s;
 808 
 809         /* set current time */
 810         t = time(NULL);
 811 
 812         hash = eay_md5_one(rbuf);
 813         if (!hash) {
 814                 plog(PLOG_INTERR, PLOGLOC, NULL,
 815                         "failed to allocate buffer.\n");
 816                 return -1;
 817         }
 818 
 819         LIST_FOREACH(r, &rcptree, chain) {
 820                 if (memcmp(hash->v, r->hash->v, r->hash->l) == 0)
 821                         break;
 822         }
 823         rc_vfree(hash);
 824 
 825         /* this is the first time to receive the packet */
 826         if (r == NULL)
 827                 return 0;
 828 
 829         /*
 830          * the packet was processed before, but the remote address mismatches.
 831          */
 832         if (rcs_cmpsa(remote, r->remote) != 0)
 833                 return 2;
 834 
 835         /*
 836          * it should not check the local address because the packet
 837          * may arrive at other interface.
 838          */
 839 
 840         /* check the previous time to send */
 841         if (t - r->time_send < 1) {
 842                 plog(PLOG_PROTOWARN, PLOGLOC, NULL,
 843                         "the packet retransmitted in a short time from %s\n",
 844                      rcs_sa2str(remote));
 845                 /*XXX should it be error ? */
 846         }
 847 
 848         /* select the socket to be sent */
 849         s = getsockmyaddr(r->local);
 850         if (s == -1)
 851                 return -1;
 852 
 853         /* resend the packet if needed */
 854         len = sendfromto(s, r->sendbuf->v, r->sendbuf->l,
 855                          r->local, r->remote, 1 /* lcconf->count_persend */);
 856         if (len == -1) {
 857                 plog(PLOG_INTERR, PLOGLOC, NULL, "sendfromto failed\n");
 858                 return -1;
 859         }
 860 
 861         /* check the retry counter */
 862         r->retry_counter--;
 863         if (r->retry_counter <= 0) {
 864                 rem_recvdpkt(r);
 865                 del_recvdpkt(r);
 866                 plog(PLOG_DEBUG, PLOGLOC, NULL,
 867                         "deleted the retransmission packet to %s.\n",
 868                      rcs_sa2str(remote));
 869         } else
 870                 r->time_send = t;
 871 
 872         return 1;
 873 }
 874 
 875 /*
 876  * adding a hash of received packet into the received list.
 877  */
 878 int
 879 add_recvdpkt(struct sockaddr *remote, struct sockaddr *local, 
 880              rc_vchar_t *sbuf, rc_vchar_t *rbuf, struct rcf_remote *conf)
 881 {
 882         struct recvdpkt *new = NULL;
 883         int lifetime;
 884 
 885         lifetime = ikev1_max_retry_to_send(conf) * ikev1_interval_to_send(conf);
 886         if (lifetime == 0) {
 887                 /* no need to add it */
 888                 return 0;
 889         }
 890 
 891         new = racoon_calloc(1, sizeof(*new));
 892         if (!new) {
 893                 plog(PLOG_INTERR, PLOGLOC, NULL,
 894                         "failed to allocate buffer.\n");
 895                 return -1;
 896         }
 897 
 898         new->hash = eay_md5_one(rbuf);
 899         if (!new->hash) {
 900                 plog(PLOG_INTERR, PLOGLOC, NULL,
 901                         "failed to allocate buffer.\n");
 902                 del_recvdpkt(new);
 903                 return -1;
 904         }
 905         new->remote = rcs_sadup(remote);
 906         if (new->remote == NULL) {
 907                 plog(PLOG_INTERR, PLOGLOC, NULL,
 908                         "failed to allocate buffer.\n");
 909                 del_recvdpkt(new);
 910                 return -1;
 911         }
 912         new->local = rcs_sadup(local);
 913         if (new->local == NULL) {
 914                 plog(PLOG_INTERR, PLOGLOC, NULL,
 915                         "failed to allocate buffer.\n");
 916                 del_recvdpkt(new);
 917                 return -1;
 918         }
 919         new->sendbuf = rc_vdup(sbuf);
 920         if (new->sendbuf == NULL) {
 921                 plog(PLOG_INTERR, PLOGLOC, NULL,
 922                         "failed to allocate buffer.\n");
 923                 del_recvdpkt(new);
 924                 return -1;
 925         }
 926 
 927         new->lifetime = lifetime;
 928         new->time_send = 0;
 929         new->created = time(NULL);
 930 
 931         LIST_INSERT_HEAD(&rcptree, new, chain);
 932 
 933         return 0;
 934 }
 935 
 936 void
 937 del_recvdpkt(struct recvdpkt *r)
 938 {
 939         if (r->remote)
 940                 racoon_free(r->remote);
 941         if (r->local)
 942                 racoon_free(r->local);
 943         if (r->hash)
 944                 rc_vfree(r->hash);
 945         if (r->sendbuf)
 946                 rc_vfree(r->sendbuf);
 947         racoon_free(r);
 948 }
 949 
 950 void
 951 rem_recvdpkt(struct recvdpkt *r)
 952 {
 953         LIST_REMOVE(r, chain);
 954 }
 955 
 956 int ikev1_recvdpkt_sweep_interval = 5; /* ??? */
 957 
 958 void
 959 sweep_recvdpkt(void *dummy)
 960 {
 961         struct recvdpkt *r, *next;
 962         time_t t;
 963 
 964         /* set current time */
 965         t = time(NULL);
 966 
 967         for (r = LIST_FIRST(&rcptree); r; r = next) {
 968                 next = LIST_NEXT(r, chain);
 969 
 970                 if (t > r->created + r->lifetime) {
 971                         rem_recvdpkt(r);
 972                         del_recvdpkt(r);
 973                 }
 974         }
 975 
 976         sched_new(ikev1_recvdpkt_sweep_interval, sweep_recvdpkt, NULL);
 977 }
 978 
 979 void
 980 init_recvdpkt(void)
 981 {
 982         LIST_INIT(&rcptree);
 983 
 984         sched_new(ikev1_recvdpkt_sweep_interval, sweep_recvdpkt, NULL);
 985 }
 986 
 987 #ifdef ENABLE_HYBRID
 988 /* 
 989  * Retruns 0 if the address was obtained by ISAKMP mode config, 1 otherwise
 990  * This should be in isakmp_cfg.c but ph1tree being private, it must be there
 991  */
 992 int
 993 exclude_cfg_addr(const struct sockaddr *addr)
 994 {
 995         struct ph1handle *p;
 996         struct sockaddr_in *sin;
 997 
 998         LIST_FOREACH(p, &ph1tree, chain) {
 999                 if ((p->mode_cfg != NULL) &&
1000                     (p->mode_cfg->flags & ISAKMP_CFG_GOT_ADDR4) &&
1001                     (addr->sa_family == AF_INET)) {
1002                         sin = (struct sockaddr_in *)addr;
1003                         if (sin->sin_addr.s_addr == p->mode_cfg->addr4.s_addr)
1004                                 return 0;
1005                 }
1006         }
1007 
1008         return 1;
1009 }
1010 #endif
1011 
1012 
1013 
1014 #if 0
1015 /* 
1016  * Reload conf code
1017  */
1018 static int revalidate_ph2(struct ph2handle *iph2){
1019         struct sainfoalg *alg;
1020         int found, check_level;
1021         struct sainfo *sainfo;
1022         struct saprop *approval;
1023 
1024         /* 
1025          * Get the new sainfo using values of the old one
1026          */
1027         iph2->sainfo = getsainfo(iph2->sainfo->idsrc, 
1028             iph2->sainfo->iddst, iph2->sainfo->id_i);
1029         approval = iph2->approval;
1030         sainfo = iph2->sainfo;
1031 
1032         if (sainfo == NULL) {
1033                 /* 
1034                  * Sainfo has been removed
1035                  */
1036                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1037                          "Reload: No sainfo for ph2\n");
1038                 return 0;
1039         }
1040 
1041         if (approval == NULL) {
1042                 /*
1043                  * XXX why do we have a NULL approval sometimes ???
1044                  */
1045                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1046                          "No approval found !\n");
1047                 return 0;
1048         }       
1049 
1050         /*
1051          * Don't care about proposals, should we do something ?
1052          * We have to keep iph2->proposal valid at least for initiator,
1053          * for pk_sendgetspi()
1054          */
1055 
1056         plog(PLOG_DEBUG, PLOGLOC, NULL, "active single bundle:\n");
1057         printsaprop0(PLOG_DEBUG, approval);
1058 
1059         /*
1060          * Validate approval against sainfo
1061          * Note: we must have an updated ph1->rmconf before doing that,
1062          * we'll set check_level to EXACT if we don't have a ph1
1063          * XXX try tu find the new remote section to get the new check level ?
1064          * XXX lifebyte
1065          */
1066         if (iph2->ph1 != NULL && iph2->ph1->rmconf != NULL) {
1067                 check_level = ikev1_proposal_check(iph2->ph1->rmconf);
1068         } else {
1069                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1070                          "No phase1 rmconf found !\n");
1071                 check_level = RCT_PCT_EXACT;
1072         }
1073 
1074         switch (check_level) {
1075         case RCT_PCT_OBEY:
1076                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1077                          "Reload: OBEY for ph2, ok\n");
1078                 return 1;
1079                 break;
1080 
1081         case RCT_PCT_STRICT:
1082                 /* FALLTHROUGH */
1083         case RCT_PCT_CLAIM:
1084                 if (sainfo->lifetime < approval->lifetime) {
1085                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1086                                  "Reload: lifetime mismatch\n");
1087                         return 0;
1088                 }
1089 
1090                 if (sainfo->lifebyte < approval->lifebyte) {
1091                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1092                                  "Reload: lifebyte mismatch\n");
1093                         return 0;
1094                 }
1095 
1096                 if (sainfo->pfs_group &&
1097                    sainfo->pfs_group != approval->pfs_group) {
1098                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1099                                  "Reload: PFS group mismatch\n");
1100                         return 0;
1101                 }
1102                 break;
1103 
1104         case RCT_PCT_EXACT:
1105                 if (sainfo->lifetime != approval->lifetime ||
1106                     sainfo->lifebyte != approval->lifebyte ||
1107                     sainfo->pfs_group != iph2->approval->pfs_group) {
1108                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1109                             "Reload: lifetime | pfs mismatch\n");
1110                         return 0;
1111                 }
1112                 break;
1113 
1114         default:
1115                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1116                          "Reload: Shouldn't be here !\n");
1117                 return 0;
1118                 break;
1119         }
1120 
1121         for (alg = sainfo->algs[algclass_ipsec_auth]; alg; alg = alg->next) {
1122                 if (alg->alg == approval->head->head->authtype)
1123                         break;
1124         }
1125         if (alg == NULL) {
1126                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1127                          "Reload: alg == NULL (auth)\n");
1128                 return 0;
1129         }
1130 
1131         found = 0;
1132         for (alg = sainfo->algs[algclass_ipsec_enc]; 
1133             (found == 0 && alg != NULL); alg = alg->next) {
1134                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1135                          "Reload: next ph2 enc alg...\n");
1136 
1137                 if (alg->alg != approval->head->head->trns_id){
1138                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1139                                  "Reload: encmode mismatch (%d / %d)\n",
1140                                  alg->alg, approval->head->head->trns_id);
1141                         continue;
1142                 }
1143 
1144                 switch (check_level){
1145                 /* RCT_PCT_STRICT cannot happen here */
1146                 case RCT_PCT_EXACT:
1147                         if (alg->encklen != approval->head->head->encklen) {
1148                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1149                                          "Reload: enclen mismatch\n");
1150                                 continue;
1151                         }
1152                         break;
1153 
1154                 case RCT_PCT_CLAIM:
1155                         /* FALLTHROUGH */
1156                 case RCT_PCT_STRICT:
1157                         if (alg->encklen > approval->head->head->encklen) {
1158                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1159                                          "Reload: enclen mismatch\n");
1160                                 continue;
1161                         }
1162                         break;
1163 
1164                 default:
1165                         plog(PLOG_INTERR, PLOGLOC, NULL, 
1166                             "unexpected check_level\n");
1167                         continue;
1168                         break;
1169                 }
1170                 found = 1;
1171         }
1172 
1173         if (!found){
1174                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1175                          "Reload: No valid enc\n");
1176                 return 0;
1177         }
1178 
1179         /*
1180          * XXX comp
1181          */
1182         plog(PLOG_DEBUG, PLOGLOC, NULL,
1183                  "Reload: ph2 check ok\n");
1184 
1185         return 1;
1186 }
1187 #endif
1188 
1189 
1190 #ifdef notyet
1191 static void 
1192 remove_ph2(struct ph2handle *iph2)
1193 {
1194         uint32_t spis[2];
1195 
1196         if(iph2 == NULL)
1197                 return;
1198 
1199         plog(PLOG_DEBUG, PLOGLOC, NULL,
1200                  "Deleting a Ph2...\n");
1201 
1202         if (iph2->status == PHASE2ST_ESTABLISHED)
1203                 isakmp_info_send_d2(iph2);
1204 
1205         if(iph2->approval != NULL && iph2->approval->head != NULL){
1206                 spis[0]=iph2->approval->head->spi;
1207                 spis[1]=iph2->approval->head->spi_p;
1208 
1209                 /* purge_ipsec_spi() will do all the work:
1210                  * - delete SPIs in kernel
1211                  * - delete generated SPD
1212                  * - unbind / rem / del ph2
1213                  */
1214                 purge_ipsec_spi(iph2->ph1, iph2->dst, iph2->approval->head->proto_id,
1215                                                 spis, 2);
1216         }else{
1217                 unbindph12(iph2);
1218                 remph2(iph2);
1219                 delph2(iph2);
1220         }
1221 }
1222 
1223 static void 
1224 remove_ph1(struct ph1handle *iph1)
1225 {
1226         struct ph2handle *iph2, *iph2_next;
1227 
1228         if(iph1 == NULL)
1229                 return;
1230 
1231         plog(PLOG_DEBUG, PLOGLOC, NULL,
1232                  "Removing PH1...\n");
1233 
1234         if (iph1->status == PHASE1ST_ESTABLISHED){
1235                 for (iph2 = LIST_FIRST(&iph1->ph2tree); iph2; iph2 = iph2_next) {
1236                         iph2_next = LIST_NEXT(iph2, chain);
1237                         remove_ph2(iph2);
1238                 }
1239                 isakmp_info_send_d1(iph1);
1240         }
1241         iph1->status = PHASE1ST_EXPIRED;
1242         iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
1243 }
1244 
1245 
1246 static int 
1247 revalidate_ph1tree_rmconf(void)
1248 {
1249         struct ph1handle *p, *next;
1250         struct rcf_remote *newrmconf;
1251 
1252         for (p = LIST_FIRST(&ph1tree); p; p = next) {
1253                 next = LIST_NEXT(p, chain);
1254 
1255                 if (p->status == PHASE1ST_EXPIRED)
1256                         continue;
1257 
1258                 newrmconf=getrmconf(p->remote);
1259                 if(newrmconf == NULL){
1260                         p->rmconf = NULL;
1261                         remove_ph1(p);
1262                 }else{
1263                         /* Do not free old rmconf, it is just a pointer to an entry in rmtree
1264                          */
1265                         p->rmconf=newrmconf;
1266                         if(p->approval != NULL){
1267                                 struct isakmpsa *tmpsa;
1268 
1269                                 tmpsa=dupisakmpsa(p->approval);
1270                                 if(tmpsa != NULL){
1271                                         delisakmpsa(p->approval);
1272                                         p->approval=tmpsa;
1273                                         p->approval->rmconf=newrmconf;
1274                                 }
1275                         }
1276                 }
1277         }
1278 
1279         return 1;
1280 }
1281 
1282 
1283 /* rmconf is already updated here
1284  */
1285 static int 
1286 revalidate_ph1(struct ph1handle *iph1)
1287 {
1288         rc_type exchange_mode;
1289         struct isakmpsa *p, *approval;
1290         struct etypes *e;
1291 
1292         if(iph1 == NULL ||
1293            iph1->approval == NULL ||
1294                 iph1->rmconf == NULL)
1295                 return 0;
1296 
1297         approval=iph1->approval;
1298         for (p=iph1->rmconf->proposal; p != NULL; p=p->next){
1299                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1300                          "Reload: Trying next proposal...\n");
1301 
1302                 if(approval->authmethod != p->authmethod){
1303                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1304                                  "Reload: Authmethod mismatch\n");
1305                         continue;
1306                 }
1307 
1308                 if(approval->enctype != p->enctype){
1309                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1310                                  "Reload: enctype mismatch\n");
1311                         continue;
1312                 }
1313 
1314                 switch (iph1->rmconf->pcheck_level) {
1315                 case RCT_PCT_OBEY:
1316                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1317                                  "Reload: OBEY pcheck level, ok...\n");
1318                         return 1;
1319                         break;
1320 
1321                 case RCT_PCT_CLAIM:
1322                         /* FALLTHROUGH */
1323                 case RCT_PCT_STRICT:
1324                         if (approval->encklen < p->encklen) {
1325                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1326                                          "Reload: encklen mismatch\n");
1327                                 continue;
1328                         }
1329 
1330                         if (approval->lifetime > p->lifetime) {
1331                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1332                                          "Reload: lifetime mismatch\n");
1333                                 continue;
1334                         }
1335 
1336                         if (approval->lifebyte > p->lifebyte) {
1337                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1338                                          "Reload: lifebyte mismatch\n");
1339                                 continue;
1340                         }
1341                         break;
1342 
1343                 case RCT_PCT_EXACT:
1344                         if (approval->encklen != p->encklen) {
1345                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1346                                          "Reload: encklen mismatch\n");
1347                                 continue;
1348                         }
1349 
1350                         if (approval->lifetime != p->lifetime) {
1351                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1352                                          "Reload: lifetime mismatch\n");
1353                                 continue;
1354                         }
1355 
1356                         if (approval->lifebyte != p->lifebyte) {
1357                                 plog(PLOG_DEBUG, PLOGLOC, NULL,
1358                                          "Reload: lifebyte mismatch\n");
1359                                 continue;
1360                         }
1361                         break;
1362 
1363                 default:
1364                         plog(PLOG_INTERR, PLOGLOC, NULL, 
1365                             "unexpected check_level\n");
1366                         continue;
1367                         break;
1368                 }
1369 
1370                 if (approval->hashtype != p->hashtype) {
1371                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1372                                  "Reload: hashtype mismatch\n");
1373                         continue;
1374                 }
1375 
1376                 if (iph1->etype != ISAKMP_ETYPE_AGG &&
1377                     approval->dh_group != p->dh_group) {
1378                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1379                                  "Reload: dhgroup mismatch\n");
1380                         continue;
1381                 }
1382 
1383                 plog(PLOG_DEBUG, PLOGLOC, NULL, "Reload: Conf ok\n");
1384                 return 1;
1385         }
1386 
1387         plog(PLOG_DEBUG, PLOGLOC, NULL, "Reload: No valid conf found\n");
1388         return 0;
1389 }
1390 
1391 
1392 static int 
1393 revalidate_ph1tree(void)
1394 {
1395         struct ph1handle *p, *next;
1396 
1397         for (p = LIST_FIRST(&ph1tree); p; p = next) {
1398                 next = LIST_NEXT(p, chain);
1399 
1400                 if (p->status == PHASE1ST_EXPIRED)
1401                         continue;
1402 
1403                 if(!revalidate_ph1(p))
1404                         remove_ph1(p);
1405         }
1406 
1407         return 1;
1408 }
1409 
1410 static int 
1411 revalidate_ph2tree(void)
1412 {
1413         struct ph2handle *p, *next;
1414 
1415         for (p = LIST_FIRST(&ph2tree); p; p = next) {
1416                 next = LIST_NEXT(p, chain);
1417 
1418                 if (p->status == PHASE2ST_EXPIRED)
1419                         continue;
1420 
1421                 if(!revalidate_ph2(p)){
1422                         plog(PLOG_DEBUG, PLOGLOC, NULL,
1423                                  "PH2 not validated, removing it\n");
1424                         remove_ph2(p);
1425                 }
1426         }
1427 
1428         return 1;
1429 }
1430 
1431 int 
1432 revalidate_ph12(void)
1433 {
1434 
1435         revalidate_ph1tree_rmconf();
1436 
1437         revalidate_ph2tree();
1438         revalidate_ph1tree();
1439 
1440         return 1;
1441 }
1442 #endif
1443 
1444 #ifdef ENABLE_HYBRID
1445 struct ph1handle *
1446 getph1bylogin(char *login)
1447 {
1448         struct ph1handle *p;
1449 
1450         LIST_FOREACH(p, &ph1tree, chain) {
1451                 if (p->mode_cfg == NULL)
1452                         continue;
1453                 if (strncmp(p->mode_cfg->login, login, LOGINLEN) == 0)
1454                         return p;
1455         }
1456 
1457         return NULL;
1458 }
1459 
1460 int
1461 purgeph1bylogin(char *login)
1462 {
1463         struct ph1handle *p;
1464         int found = 0;
1465 
1466         LIST_FOREACH(p, &ph1tree, chain) {
1467                 if (p->mode_cfg == NULL)
1468                         continue;
1469                 if (strncmp(p->mode_cfg->login, login, LOGINLEN) == 0) {
1470                         if (p->status == PHASE1ST_ESTABLISHED)
1471                                 isakmp_info_send_d1(p);
1472                         purge_remote(p);
1473                         found++;
1474                 }
1475         }
1476 
1477         return found;
1478 }
1479 #endif
1480 
1481 
1482 static int
1483 delete_ipsec_sa(struct sadb_request *r, 
1484                 struct sockaddr *src, struct sockaddr *dst, int proto, 
1485                 uint32_t spi/* network order */)
1486 {
1487         struct rcpfk_msg param;
1488         int satype;
1489         int retval;
1490 
1491         switch (proto) {
1492         case IPSECDOI_PROTO_IPSEC_AH:
1493                 satype = RCT_SATYPE_AH;
1494                 break;
1495         case IPSECDOI_PROTO_IPSEC_ESP:
1496                 satype = RCT_SATYPE_ESP;
1497                 break;
1498         case IPSECDOI_PROTO_IPCOMP:
1499                 satype = RCT_SATYPE_IPCOMP;
1500                 break;
1501         default:
1502                 plog(PLOG_INTERR, PLOGLOC, 0,
1503                      "unsupported IPSECDOI protocol ID (%d)\n",
1504                      proto);
1505                 retval = -1;
1506                 goto done;
1507                 break;
1508         }
1509 
1510         param.sa_src = src;
1511         param.sa_dst = dst;
1512         param.satype = satype;
1513         param.spi = spi;
1514         retval = r->method->delete_sa(&param);
1515 
1516   done:
1517         return retval;
1518 }
1519 
1520 
1521 void
1522 purge_remote(struct ph1handle *iph1)
1523 {
1524         struct ph2handle *iph2;
1525         struct ph2handle *next_ph2;
1526         struct saprop *pp;
1527         struct saproto *pr;
1528 
1529         plog(PLOG_INFO, PLOGLOC, 0,
1530              "purging ISAKMP-SA spi=%s.\n",
1531              isakmp_pindex(&(iph1->index), iph1->msgid));
1532 
1533         /* Mark as expired. */
1534         iph1->status = PHASE1ST_EXPIRED;
1535 
1536         for (iph2 = LIST_FIRST(&ph2tree); iph2; iph2 = next_ph2) {
1537                 next_ph2 = LIST_NEXT(iph2, chain);
1538 
1539                 if (iph2->ph1 != iph1)
1540                         continue;
1541 
1542                 pp = iph2->approval;
1543                 if (pp != NULL) {
1544                         for (pr = pp->head; pr != NULL; pr = pr->next) {
1545                                 TRACE((PLOGLOC, "proto %d spi 0x%08" PRIx32 "\n",
1546                                        pr->proto_id, 
1547                                        ntohl(pr->spi)));
1548                                 (void) delete_ipsec_sa(&iph2->sadb_request,
1549                                                        iph2->src,
1550                                                        iph2->dst,
1551                                                        pr->proto_id, pr->spi_p);
1552                                 (void) delete_ipsec_sa(&iph2->sadb_request,
1553                                                        iph2->dst,
1554                                                        iph2->src,
1555                                                        pr->proto_id, pr->spi);
1556                         }
1557                 }
1558 
1559                 destroy_ph2(iph2);
1560         }
1561 }
1562 
1563 
1564 void
1565 purge_ipsec_spi(struct ph1handle *ph1, 
1566                 struct sockaddr *dst0, 
1567                 int proto_id, 
1568                 uint32_t *spi_ptr/*network byteorder*/, 
1569                 int n)
1570 {
1571         struct ph2handle *iph2;
1572         uint32_t spi;
1573         int all_done;
1574         struct saprop *pp;
1575         struct saproto *pr;
1576         int i;
1577 
1578         for (i = 0; i < n; ++i) {
1579                 spi = htonl(get_uint32(&spi_ptr[i]));
1580                 iph2 = getph2bysaidx(ph1->local, ph1->remote, proto_id, spi);
1581                 if (iph2 != NULL) {
1582                         pp = iph2->approval;
1583                         all_done = TRUE;
1584                         for (pr = pp->head; pr != NULL; pr = pr->next) {
1585                                 TRACE((PLOGLOC, "proto %d spi 0x%08" PRIx32 "\n",
1586                                        pr->proto_id, 
1587                                        ntohl(pr->spi_p)));
1588                                 if (pr->proto_id == proto_id && pr->spi_p == spi) {
1589                                         (void) delete_ipsec_sa(&iph2->sadb_request,
1590                                                                iph2->src,
1591                                                                iph2->dst,
1592                                                                proto_id, spi);
1593                                         pr->spi_p = 0;
1594                                 } else if (pr->spi_p != 0) {
1595                                         all_done = FALSE;
1596                                 }
1597                         }
1598 
1599                         if (all_done)
1600                                 destroy_ph2(iph2);
1601                 }
1602         }
1603 }
1604