/* $NetBSD: sainfo.c,v 1.14 2011/02/02 15:21:34 vanhu Exp $ */ /* $KAME: sainfo.c,v 1.16 2003/06/27 07:32:39 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #include <sys/param.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/queue.h> #include <netinet/in.h> #include <netinet/in.h> #include PATH_IPSEC_H #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include "var.h" #include "misc.h" #include "vmbuf.h" #include "plog.h" #include "sockmisc.h" #include "debug.h" #include "localconf.h" #include "isakmp_var.h" #include "isakmp.h" #include "ipsec_doi.h" #include "oakley.h" #include "handler.h" #include "algorithm.h" #include "sainfo.h" #include "gcmalloc.h" typedef LIST_HEAD(_sitree, sainfo) sainfo_tailq_head_t; static sainfo_tailq_head_t sitree, sitree_save; /* %%% * modules for ipsec sa info */ /* * return matching entry. * no matching entry found and if there is anonymous entry, return it. * else return NULL. * First pass is for sainfo from a specified peer, second for others. */ struct sainfo * getsainfo(loc, rmt, peer, client, remoteid) const vchar_t *loc, *rmt, *peer, *client; uint32_t remoteid; { struct sainfo *s = NULL; /* debug level output */ if(loglevel >= LLV_DEBUG) { char *dloc, *drmt, *dpeer, *dclient; if (loc == NULL) dloc = strdup("ANONYMOUS"); else dloc = ipsecdoi_id2str(loc); if (rmt == SAINFO_ANONYMOUS) drmt = strdup("ANONYMOUS"); else if (rmt == SAINFO_CLIENTADDR) drmt = strdup("CLIENTADDR"); else drmt = ipsecdoi_id2str(rmt); if (peer == NULL) dpeer = strdup("NULL"); else dpeer = ipsecdoi_id2str(peer); if (client == NULL) dclient = strdup("NULL"); else dclient = ipsecdoi_id2str(client); plog(LLV_DEBUG, LOCATION, NULL, "getsainfo params: loc=\'%s\' rmt=\'%s\' peer=\'%s\' client=\'%s\' id=%u\n", dloc, drmt, dpeer, dclient, remoteid ); racoon_free(dloc); racoon_free(drmt); racoon_free(dpeer); racoon_free(dclient); } LIST_FOREACH(s, &sitree, chain) { const char *sainfostr = sainfo2str(s); plog(LLV_DEBUG, LOCATION, NULL, "evaluating sainfo: %s\n", sainfostr); if(s->remoteid != remoteid) { plog(LLV_DEBUG, LOCATION, NULL, "remoteid mismatch: %u != %u\n", s->remoteid, remoteid); continue; } /* compare 'from' id value */ if (s->id_i != NULL) if (ipsecdoi_chkcmpids(peer, s->id_i, 0)) continue; /* compare ids - client */ if( s->iddst == SAINFO_CLIENTADDR ) { /* * This sainfo section enforces client address * checking. Prevent match if the client value * ( modecfg or tunnel address ) is NULL. */ if (client == NULL) continue; if( rmt == SAINFO_CLIENTADDR ) { /* * In the case where a supplied rmt value is * also SAINFO_CLIENTADDR, we are comparing * with another sainfo to check for duplicate. * Only compare the local values to determine * a match. */ if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0)) return s; } else { /* * In the case where a supplied rmt value is * not SAINFO_CLIENTADDR, do a standard match * for local values and enforce that the rmt * id matches the client address value. */ if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0) && !ipsecdoi_chkcmpids(rmt, client, 0)) return s; } continue; } /* compare ids - standard */ if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0) && !ipsecdoi_chkcmpids(rmt, s->iddst, 0)) return s; } return NULL; } struct sainfo * newsainfo() { struct sainfo *new; new = racoon_calloc(1, sizeof(*new)); if (new == NULL) return NULL; new->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT; new->lifebyte = IPSECDOI_ATTR_SA_LD_KB_MAX; return new; } void delsainfo(si) struct sainfo *si; { int i; for (i = 0; i < MAXALGCLASS; i++) delsainfoalg(si->algs[i]); if (si->idsrc) vfree(si->idsrc); if (si->iddst != NULL && si->iddst != SAINFO_CLIENTADDR) vfree(si->iddst); #ifdef ENABLE_HYBRID if (si->group) vfree(si->group); #endif racoon_free(si); } int prisainfo(s) struct sainfo *s; { /* * determine the matching priority * of an sainfo section */ int pri = 0; if(s->remoteid) pri += 3; if(s->id_i) pri += 3; if(s->idsrc) pri++; if(s->iddst) pri++; return pri; } void inssainfo(new) struct sainfo *new; { if(LIST_EMPTY(&sitree)) { /* first in list */ LIST_INSERT_HEAD(&sitree, new, chain); } else { int npri, spri; struct sainfo *s, *n; /* * insert our new sainfo section * into our list which is sorted * based on the match priority */ npri = prisainfo(new); s = LIST_FIRST(&sitree); while (1) { spri = prisainfo(s); n = LIST_NEXT(s, chain); if(npri > spri) { /* higher priority */ LIST_INSERT_BEFORE(s, new, chain); return; } if(n == NULL) { /* last in list */ LIST_INSERT_AFTER(s, new, chain); return; } s = n; } } } void remsainfo(si) struct sainfo *si; { LIST_REMOVE(si, chain); } void flushsainfo() { struct sainfo *s, *next; for (s = LIST_FIRST(&sitree); s; s = next) { next = LIST_NEXT(s, chain); remsainfo(s); delsainfo(s); } } void initsainfo() { LIST_INIT(&sitree); } struct sainfoalg * newsainfoalg() { struct sainfoalg *new; new = racoon_calloc(1, sizeof(*new)); if (new == NULL) return NULL; return new; } void delsainfoalg(alg) struct sainfoalg *alg; { struct sainfoalg *a, *next; for (a = alg; a; a = next) { next = a->next; racoon_free(a); } } void inssainfoalg(head, new) struct sainfoalg **head; struct sainfoalg *new; { struct sainfoalg *a; for (a = *head; a && a->next; a = a->next) ; if (a) a->next = new; else *head = new; } const char * sainfo2str(si) const struct sainfo *si; { static char buf[256]; char *idloc = NULL, *idrmt = NULL, *id_i; if (si->idsrc == SAINFO_ANONYMOUS) idloc = strdup("ANONYMOUS"); else idloc = ipsecdoi_id2str(si->idsrc); if (si->iddst == SAINFO_ANONYMOUS) idrmt = strdup("ANONYMOUS"); else if (si->iddst == SAINFO_CLIENTADDR) idrmt = strdup("CLIENTADDR"); else idrmt = ipsecdoi_id2str(si->iddst); if (si->id_i == NULL) id_i = strdup("ANY"); else id_i = ipsecdoi_id2str(si->id_i); snprintf(buf, 255, "loc=\'%s\', rmt=\'%s\', peer=\'%s\', id=%u", idloc, idrmt, id_i, si->remoteid); racoon_free(idloc); racoon_free(idrmt); racoon_free(id_i); return buf; } void sainfo_start_reload(void){ sitree_save=sitree; initsainfo(); } void sainfo_finish_reload(void){ sainfo_tailq_head_t sitree_tmp; sitree_tmp=sitree; sitree=sitree_save; flushsainfo(); sitree=sitree_tmp; } void save_sainfotree_restore(void){ flushsainfo(); sitree=sitree_save; }