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 *
getsainfo(const vchar_t * loc,const vchar_t * rmt,const vchar_t * peer,const vchar_t * client,uint32_t remoteid)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 *
newsainfo()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
delsainfo(struct sainfo * si)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
prisainfo(struct sainfo * s)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
inssainfo(struct sainfo * new)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
remsainfo(struct sainfo * si)298 remsainfo(struct sainfo *si)
299 {
300 LIST_REMOVE(si, chain);
301 }
302
303 void
flushsainfo()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
initsainfo()316 initsainfo()
317 {
318 LIST_INIT(&sitree);
319 }
320
321 struct sainfoalg *
newsainfoalg()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
delsainfoalg(struct sainfoalg * alg)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
inssainfoalg(struct sainfoalg ** head,struct sainfoalg * new)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 *
sainfo2str(const struct sainfo * si)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
sainfo_start_reload(void)391 void sainfo_start_reload(void){
392 sitree_save=sitree;
393 initsainfo();
394 }
395
sainfo_finish_reload(void)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
save_sainfotree_restore(void)405 void save_sainfotree_restore(void){
406 flushsainfo();
407 sitree=sitree_save;
408 }
409