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(¶m, 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(¶m);
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