1 /* $NetBSD: sainfo.c,v 1.17 2025/03/07 15:55:29 christos 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(const vchar_t *loc, const vchar_t *rmt, const vchar_t *peer, 81 const vchar_t *client, uint32_t remoteid) 82 { 83 struct sainfo *s = NULL; 84 85 /* debug level output */ 86 if(loglevel >= LLV_DEBUG) { 87 char *dloc, *drmt, *dpeer, *dclient; 88 89 if (loc == NULL) 90 dloc = strdup("ANONYMOUS"); 91 else 92 dloc = ipsecdoi_id2str(loc); 93 94 if (rmt == SAINFO_ANONYMOUS) 95 drmt = strdup("ANONYMOUS"); 96 else if (rmt == SAINFO_CLIENTADDR) 97 drmt = strdup("CLIENTADDR"); 98 else 99 drmt = ipsecdoi_id2str(rmt); 100 101 if (peer == NULL) 102 dpeer = strdup("NULL"); 103 else 104 dpeer = ipsecdoi_id2str(peer); 105 106 if (client == NULL) 107 dclient = strdup("NULL"); 108 else 109 dclient = ipsecdoi_id2str(client); 110 111 plog(LLV_DEBUG, LOCATION, NULL, 112 "getsainfo params: loc=\'%s\' rmt=\'%s\' peer=\'%s\' client=\'%s\' id=%u\n", 113 dloc, drmt, dpeer, dclient, remoteid ); 114 115 racoon_free(dloc); 116 racoon_free(drmt); 117 racoon_free(dpeer); 118 racoon_free(dclient); 119 } 120 121 LIST_FOREACH(s, &sitree, chain) { 122 const char *sainfostr = sainfo2str(s); 123 plog(LLV_DEBUG, LOCATION, NULL, 124 "evaluating sainfo: %s\n", sainfostr); 125 126 if(s->remoteid != remoteid) { 127 plog(LLV_DEBUG, LOCATION, NULL, 128 "remoteid mismatch: %u != %u\n", 129 s->remoteid, remoteid); 130 continue; 131 } 132 133 /* compare 'from' id value */ 134 if (s->id_i != NULL) 135 if (ipsecdoi_chkcmpids(peer, s->id_i, 0)) 136 continue; 137 138 /* compare ids - client */ 139 if( s->iddst == SAINFO_CLIENTADDR ) { 140 /* 141 * This sainfo section enforces client address 142 * checking. Prevent match if the client value 143 * ( modecfg or tunnel address ) is NULL. 144 */ 145 146 if (client == NULL) 147 continue; 148 149 if( rmt == SAINFO_CLIENTADDR ) { 150 /* 151 * In the case where a supplied rmt value is 152 * also SAINFO_CLIENTADDR, we are comparing 153 * with another sainfo to check for duplicate. 154 * Only compare the local values to determine 155 * a match. 156 */ 157 158 if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0)) 159 return s; 160 } 161 else { 162 /* 163 * In the case where a supplied rmt value is 164 * not SAINFO_CLIENTADDR, do a standard match 165 * for local values and enforce that the rmt 166 * id matches the client address value. 167 */ 168 169 if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0) && 170 !ipsecdoi_chkcmpids(rmt, client, 0)) 171 return s; 172 } 173 174 continue; 175 } 176 177 178 /* compare ids - standard */ 179 if (!ipsecdoi_chkcmpids(loc, s->idsrc, 0) && 180 !ipsecdoi_chkcmpids(rmt, s->iddst, 0)) 181 return s; 182 } 183 184 return NULL; 185 } 186 187 struct sainfo * 188 newsainfo() 189 { 190 struct sainfo *new; 191 192 new = racoon_calloc(1, sizeof(*new)); 193 if (new == NULL) 194 return NULL; 195 196 new->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT; 197 new->lifebyte = IPSECDOI_ATTR_SA_LD_KB_MAX; 198 199 return new; 200 } 201 202 void 203 delsainfo(struct sainfo *si) 204 { 205 int i; 206 207 if (si == NULL) 208 return; 209 210 for (i = 0; i < MAXALGCLASS; i++) 211 delsainfoalg(si->algs[i]); 212 213 if (si->idsrc) 214 vfree(si->idsrc); 215 if (si->iddst != NULL && 216 si->iddst != SAINFO_CLIENTADDR) 217 vfree(si->iddst); 218 219 #ifdef ENABLE_HYBRID 220 if (si->group) 221 vfree(si->group); 222 #endif 223 224 racoon_free(si); 225 } 226 227 static int 228 prisainfo(struct sainfo *s) 229 { 230 /* 231 * determine the matching priority 232 * of an sainfo section 233 */ 234 235 int pri = 0; 236 237 if(s->remoteid) 238 pri += 3; 239 240 if(s->id_i) 241 pri += 3; 242 243 if(s->idsrc) 244 pri++; 245 246 if(s->iddst) 247 pri++; 248 249 return pri; 250 } 251 252 void 253 inssainfo(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 for (;;) { 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(struct sainfo *si) 299 { 300 LIST_REMOVE(si, chain); 301 } 302 303 void 304 flushsainfo() 305 { 306 struct sainfo *s, *next; 307 308 for (s = LIST_FIRST(&sitree); s; s = next) { 309 next = LIST_NEXT(s, chain); 310 remsainfo(s); 311 delsainfo(s); 312 } 313 } 314 315 void 316 initsainfo() 317 { 318 LIST_INIT(&sitree); 319 } 320 321 struct sainfoalg * 322 newsainfoalg() 323 { 324 struct sainfoalg *new; 325 326 new = racoon_calloc(1, sizeof(*new)); 327 if (new == NULL) 328 return NULL; 329 330 return new; 331 } 332 333 void 334 delsainfoalg(struct sainfoalg *alg) 335 { 336 struct sainfoalg *a, *next; 337 338 for (a = alg; a; a = next) { 339 next = a->next; 340 racoon_free(a); 341 } 342 } 343 344 void 345 inssainfoalg(struct sainfoalg **head, struct sainfoalg *new) 346 { 347 struct sainfoalg *a; 348 349 for (a = *head; a && a->next; a = a->next) 350 ; 351 if (a) 352 a->next = new; 353 else 354 *head = new; 355 } 356 357 const char * 358 sainfo2str(const struct sainfo *si) 359 { 360 static char buf[256]; 361 362 char *idloc = NULL, *idrmt = NULL, *id_i; 363 364 if (si->idsrc == SAINFO_ANONYMOUS) 365 idloc = strdup("ANONYMOUS"); 366 else 367 idloc = ipsecdoi_id2str(si->idsrc); 368 369 if (si->iddst == SAINFO_ANONYMOUS) 370 idrmt = strdup("ANONYMOUS"); 371 else if (si->iddst == SAINFO_CLIENTADDR) 372 idrmt = strdup("CLIENTADDR"); 373 else 374 idrmt = ipsecdoi_id2str(si->iddst); 375 376 if (si->id_i == NULL) 377 id_i = strdup("ANY"); 378 else 379 id_i = ipsecdoi_id2str(si->id_i); 380 381 snprintf(buf, 255, "loc=\'%s\', rmt=\'%s\', peer=\'%s\', id=%u", 382 idloc, idrmt, id_i, si->remoteid); 383 384 racoon_free(idloc); 385 racoon_free(idrmt); 386 racoon_free(id_i); 387 388 return buf; 389 } 390 391 void sainfo_start_reload(void){ 392 sitree_save=sitree; 393 initsainfo(); 394 } 395 396 void sainfo_finish_reload(void){ 397 sainfo_tailq_head_t sitree_tmp; 398 399 sitree_tmp=sitree; 400 sitree=sitree_save; 401 flushsainfo(); 402 sitree=sitree_tmp; 403 } 404 405 void save_sainfotree_restore(void){ 406 flushsainfo(); 407 sitree=sitree_save; 408 } 409