1 /* $NetBSD: sainfo.c,v 1.14 2011/02/02 15:21:34 vanhu Exp $ */ 2 3 /* $KAME: sainfo.c,v 1.16 2003/06/27 07:32:39 sakane 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/param.h> 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 #include <sys/queue.h> 40 41 #include <netinet/in.h> 42 #include <netinet/in.h> 43 #include PATH_IPSEC_H 44 45 #include <stdlib.h> 46 #include <stdio.h> 47 #include <string.h> 48 #include <errno.h> 49 50 #include "var.h" 51 #include "misc.h" 52 #include "vmbuf.h" 53 #include "plog.h" 54 #include "sockmisc.h" 55 #include "debug.h" 56 57 #include "localconf.h" 58 #include "isakmp_var.h" 59 #include "isakmp.h" 60 #include "ipsec_doi.h" 61 #include "oakley.h" 62 #include "handler.h" 63 #include "algorithm.h" 64 #include "sainfo.h" 65 #include "gcmalloc.h" 66 67 typedef LIST_HEAD(_sitree, sainfo) sainfo_tailq_head_t; 68 static sainfo_tailq_head_t sitree, sitree_save; 69 70 /* %%% 71 * modules for ipsec sa info 72 */ 73 /* 74 * return matching entry. 75 * no matching entry found and if there is anonymous entry, return it. 76 * else return NULL. 77 * First pass is for sainfo from a specified peer, second for others. 78 */ 79 struct sainfo * 80 getsainfo(loc, rmt, peer, client, remoteid) 81 const vchar_t *loc, *rmt, *peer, *client; 82 uint32_t remoteid; 83 { 84 struct sainfo *s = NULL; 85 86 /* debug level output */ 87 if(loglevel >= LLV_DEBUG) { 88 char *dloc, *drmt, *dpeer, *dclient; 89 90 if (loc == NULL) 91 dloc = strdup("ANONYMOUS"); 92 else 93 dloc = ipsecdoi_id2str(loc); 94 95 if (rmt == SAINFO_ANONYMOUS) 96 drmt = strdup("ANONYMOUS"); 97 else if (rmt == SAINFO_CLIENTADDR) 98 drmt = strdup("CLIENTADDR"); 99 else 100 drmt = ipsecdoi_id2str(rmt); 101 102 if (peer == NULL) 103 dpeer = strdup("NULL"); 104 else 105 dpeer = ipsecdoi_id2str(peer); 106 107 if (client == NULL) 108 dclient = strdup("NULL"); 109 else 110 dclient = ipsecdoi_id2str(client); 111 112 plog(LLV_DEBUG, LOCATION, NULL, 113 "getsainfo params: loc=\'%s\' rmt=\'%s\' peer=\'%s\' client=\'%s\' id=%u\n", 114 dloc, drmt, dpeer, dclient, remoteid ); 115 116 racoon_free(dloc); 117 racoon_free(drmt); 118 racoon_free(dpeer); 119 racoon_free(dclient); 120 } 121 122 LIST_FOREACH(s, &sitree, chain) { 123 const char *sainfostr = sainfo2str(s); 124 plog(LLV_DEBUG, LOCATION, NULL, 125 "evaluating sainfo: %s\n", sainfostr); 126 127 if(s->remoteid != remoteid) { 128 plog(LLV_DEBUG, LOCATION, NULL, 129 "remoteid mismatch: %u != %u\n", 130 s->remoteid, remoteid); 131 continue; 132 } 133 134 /* compare 'from' id value */ 135 if (s->id_i != NULL) 136 if (ipsecdoi_chkcmpids(peer, s->id_i, 0)) 137 continue; 138 139 /* compare ids - client */ 140 if( s->iddst == SAINFO_CLIENTADDR ) { 141 /* 142 * This sainfo section enforces client address 143 * checking. Prevent match if the client value 144 * ( modecfg or tunnel address ) is NULL. 145 */ 146 147 if (client == NULL) 148 continue; 149 150 if( rmt == SAINFO_CLIENTADDR ) { 151 /* 152 * In the case where a supplied rmt value is 153 * also SAINFO_CLIENTADDR, we are comparing 154 * with another sainfo to check for duplicate. 155 * Only compare the local values to determine 156 * a match. 157 */ 158 159 if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0)) 160 return s; 161 } 162 else { 163 /* 164 * In the case where a supplied rmt value is 165 * not SAINFO_CLIENTADDR, do a standard match 166 * for local values and enforce that the rmt 167 * id matches the client address value. 168 */ 169 170 if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0) && 171 !ipsecdoi_chkcmpids(rmt, client, 0)) 172 return s; 173 } 174 175 continue; 176 } 177 178 179 /* compare ids - standard */ 180 if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0) && 181 !ipsecdoi_chkcmpids(rmt, s->iddst, 0)) 182 return s; 183 } 184 185 return NULL; 186 } 187 188 struct sainfo * 189 newsainfo() 190 { 191 struct sainfo *new; 192 193 new = racoon_calloc(1, sizeof(*new)); 194 if (new == NULL) 195 return NULL; 196 197 new->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT; 198 new->lifebyte = IPSECDOI_ATTR_SA_LD_KB_MAX; 199 200 return new; 201 } 202 203 void 204 delsainfo(si) 205 struct sainfo *si; 206 { 207 int i; 208 209 for (i = 0; i < MAXALGCLASS; i++) 210 delsainfoalg(si->algs[i]); 211 212 if (si->idsrc) 213 vfree(si->idsrc); 214 if (si->iddst != NULL && 215 si->iddst != SAINFO_CLIENTADDR) 216 vfree(si->iddst); 217 218 #ifdef ENABLE_HYBRID 219 if (si->group) 220 vfree(si->group); 221 #endif 222 223 racoon_free(si); 224 } 225 226 int prisainfo(s) 227 struct sainfo *s; 228 { 229 /* 230 * determine the matching priority 231 * of an sainfo section 232 */ 233 234 int pri = 0; 235 236 if(s->remoteid) 237 pri += 3; 238 239 if(s->id_i) 240 pri += 3; 241 242 if(s->idsrc) 243 pri++; 244 245 if(s->iddst) 246 pri++; 247 248 return pri; 249 } 250 251 void 252 inssainfo(new) 253 struct sainfo *new; 254 { 255 if(LIST_EMPTY(&sitree)) { 256 257 /* first in list */ 258 LIST_INSERT_HEAD(&sitree, new, chain); 259 } 260 else { 261 int npri, spri; 262 struct sainfo *s, *n; 263 264 /* 265 * insert our new sainfo section 266 * into our list which is sorted 267 * based on the match priority 268 */ 269 270 npri = prisainfo(new); 271 272 s = LIST_FIRST(&sitree); 273 while (1) { 274 275 spri = prisainfo(s); 276 n = LIST_NEXT(s, chain); 277 278 if(npri > spri) 279 { 280 /* higher priority */ 281 LIST_INSERT_BEFORE(s, new, chain); 282 return; 283 } 284 285 if(n == NULL) 286 { 287 /* last in list */ 288 LIST_INSERT_AFTER(s, new, chain); 289 return; 290 } 291 292 s = n; 293 } 294 } 295 } 296 297 void 298 remsainfo(si) 299 struct sainfo *si; 300 { 301 LIST_REMOVE(si, chain); 302 } 303 304 void 305 flushsainfo() 306 { 307 struct sainfo *s, *next; 308 309 for (s = LIST_FIRST(&sitree); s; s = next) { 310 next = LIST_NEXT(s, chain); 311 remsainfo(s); 312 delsainfo(s); 313 } 314 } 315 316 void 317 initsainfo() 318 { 319 LIST_INIT(&sitree); 320 } 321 322 struct sainfoalg * 323 newsainfoalg() 324 { 325 struct sainfoalg *new; 326 327 new = racoon_calloc(1, sizeof(*new)); 328 if (new == NULL) 329 return NULL; 330 331 return new; 332 } 333 334 void 335 delsainfoalg(alg) 336 struct sainfoalg *alg; 337 { 338 struct sainfoalg *a, *next; 339 340 for (a = alg; a; a = next) { 341 next = a->next; 342 racoon_free(a); 343 } 344 } 345 346 void 347 inssainfoalg(head, new) 348 struct sainfoalg **head; 349 struct sainfoalg *new; 350 { 351 struct sainfoalg *a; 352 353 for (a = *head; a && a->next; a = a->next) 354 ; 355 if (a) 356 a->next = new; 357 else 358 *head = new; 359 } 360 361 const char * 362 sainfo2str(si) 363 const struct sainfo *si; 364 { 365 static char buf[256]; 366 367 char *idloc = NULL, *idrmt = NULL, *id_i; 368 369 if (si->idsrc == SAINFO_ANONYMOUS) 370 idloc = strdup("ANONYMOUS"); 371 else 372 idloc = ipsecdoi_id2str(si->idsrc); 373 374 if (si->iddst == SAINFO_ANONYMOUS) 375 idrmt = strdup("ANONYMOUS"); 376 else if (si->iddst == SAINFO_CLIENTADDR) 377 idrmt = strdup("CLIENTADDR"); 378 else 379 idrmt = ipsecdoi_id2str(si->iddst); 380 381 if (si->id_i == NULL) 382 id_i = strdup("ANY"); 383 else 384 id_i = ipsecdoi_id2str(si->id_i); 385 386 snprintf(buf, 255, "loc=\'%s\', rmt=\'%s\', peer=\'%s\', id=%u", 387 idloc, idrmt, id_i, si->remoteid); 388 389 racoon_free(idloc); 390 racoon_free(idrmt); 391 racoon_free(id_i); 392 393 return buf; 394 } 395 396 void sainfo_start_reload(void){ 397 sitree_save=sitree; 398 initsainfo(); 399 } 400 401 void sainfo_finish_reload(void){ 402 sainfo_tailq_head_t sitree_tmp; 403 404 sitree_tmp=sitree; 405 sitree=sitree_save; 406 flushsainfo(); 407 sitree=sitree_tmp; 408 } 409 410 void save_sainfotree_restore(void){ 411 flushsainfo(); 412 sitree=sitree_save; 413 } 414