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