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 *
getsainfo(loc,rmt,peer,client,remoteid)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 *
newsainfo()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
delsainfo(si)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
prisainfo(s)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
inssainfo(new)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
remsainfo(si)298 remsainfo(si)
299 struct sainfo *si;
300 {
301 LIST_REMOVE(si, chain);
302 }
303
304 void
flushsainfo()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
initsainfo()317 initsainfo()
318 {
319 LIST_INIT(&sitree);
320 }
321
322 struct sainfoalg *
newsainfoalg()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
delsainfoalg(alg)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
inssainfoalg(head,new)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 *
sainfo2str(si)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
sainfo_start_reload(void)396 void sainfo_start_reload(void){
397 sitree_save=sitree;
398 initsainfo();
399 }
400
sainfo_finish_reload(void)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
save_sainfotree_restore(void)410 void save_sainfotree_restore(void){
411 flushsainfo();
412 sitree=sitree_save;
413 }
414