xref: /netbsd-src/crypto/dist/ipsec-tools/src/racoon/sainfo.c (revision 165b31ce969841b1b96165ce3c8c8b91653ed8df)
1 /*	$NetBSD: sainfo.c,v 1.16 2018/05/19 20:14:56 maxv 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 	if (si == NULL)
210 		return;
211 
212 	for (i = 0; i < MAXALGCLASS; i++)
213 		delsainfoalg(si->algs[i]);
214 
215 	if (si->idsrc)
216 		vfree(si->idsrc);
217 	if (si->iddst != NULL &&
218 		si->iddst != SAINFO_CLIENTADDR)
219 		vfree(si->iddst);
220 
221 #ifdef ENABLE_HYBRID
222 	if (si->group)
223 		vfree(si->group);
224 #endif
225 
226 	racoon_free(si);
227 }
228 
229 static int
prisainfo(struct sainfo * s)230 prisainfo(struct sainfo *s)
231 {
232 	/*
233 	 * determine the matching priority
234 	 * of an sainfo section
235 	 */
236 
237 	int pri = 0;
238 
239 	if(s->remoteid)
240 		pri += 3;
241 
242 	if(s->id_i)
243 		pri += 3;
244 
245 	if(s->idsrc)
246 		pri++;
247 
248 	if(s->iddst)
249 		pri++;
250 
251 	return pri;
252 }
253 
254 void
inssainfo(new)255 inssainfo(new)
256 	struct sainfo *new;
257 {
258 	if(LIST_EMPTY(&sitree)) {
259 
260 		/* first in list */
261 		LIST_INSERT_HEAD(&sitree, new, chain);
262 	}
263 	else {
264 		int npri, spri;
265 		struct sainfo *s, *n;
266 
267 		/*
268 		 * insert our new sainfo section
269 		 * into our list which is sorted
270 		 * based on the match priority
271 		 */
272 
273 		npri = prisainfo(new);
274 
275 		s = LIST_FIRST(&sitree);
276 		while (1) {
277 
278 			spri = prisainfo(s);
279 			n = LIST_NEXT(s, chain);
280 
281 			if(npri > spri)
282 			{
283 				/* higher priority */
284 				LIST_INSERT_BEFORE(s, new, chain);
285 				return;
286 			}
287 
288 			if(n == NULL)
289 			{
290 				/* last in list */
291 				LIST_INSERT_AFTER(s, new, chain);
292 				return;
293 			}
294 
295 			s = n;
296 		}
297 	}
298 }
299 
300 void
remsainfo(si)301 remsainfo(si)
302 	struct sainfo *si;
303 {
304 	LIST_REMOVE(si, chain);
305 }
306 
307 void
flushsainfo()308 flushsainfo()
309 {
310 	struct sainfo *s, *next;
311 
312 	for (s = LIST_FIRST(&sitree); s; s = next) {
313 		next = LIST_NEXT(s, chain);
314 		remsainfo(s);
315 		delsainfo(s);
316 	}
317 }
318 
319 void
initsainfo()320 initsainfo()
321 {
322 	LIST_INIT(&sitree);
323 }
324 
325 struct sainfoalg *
newsainfoalg()326 newsainfoalg()
327 {
328 	struct sainfoalg *new;
329 
330 	new = racoon_calloc(1, sizeof(*new));
331 	if (new == NULL)
332 		return NULL;
333 
334 	return new;
335 }
336 
337 void
delsainfoalg(alg)338 delsainfoalg(alg)
339 	struct sainfoalg *alg;
340 {
341 	struct sainfoalg *a, *next;
342 
343 	for (a = alg; a; a = next) {
344 		next = a->next;
345 		racoon_free(a);
346 	}
347 }
348 
349 void
inssainfoalg(head,new)350 inssainfoalg(head, new)
351 	struct sainfoalg **head;
352 	struct sainfoalg *new;
353 {
354 	struct sainfoalg *a;
355 
356 	for (a = *head; a && a->next; a = a->next)
357 		;
358 	if (a)
359 		a->next = new;
360 	else
361 		*head = new;
362 }
363 
364 const char *
sainfo2str(si)365 sainfo2str(si)
366 	const struct sainfo *si;
367 {
368         static char buf[256];
369 
370         char *idloc = NULL, *idrmt = NULL, *id_i;
371 
372         if (si->idsrc == SAINFO_ANONYMOUS)
373                 idloc = strdup("ANONYMOUS");
374         else
375                 idloc = ipsecdoi_id2str(si->idsrc);
376 
377         if (si->iddst == SAINFO_ANONYMOUS)
378                 idrmt = strdup("ANONYMOUS");
379 	else if (si->iddst == SAINFO_CLIENTADDR)
380                 idrmt = strdup("CLIENTADDR");
381         else
382                 idrmt = ipsecdoi_id2str(si->iddst);
383 
384         if (si->id_i == NULL)
385                 id_i = strdup("ANY");
386         else
387                 id_i = ipsecdoi_id2str(si->id_i);
388 
389         snprintf(buf, 255, "loc=\'%s\', rmt=\'%s\', peer=\'%s\', id=%u",
390 		idloc, idrmt, id_i, si->remoteid);
391 
392         racoon_free(idloc);
393         racoon_free(idrmt);
394         racoon_free(id_i);
395 
396         return buf;
397 }
398 
sainfo_start_reload(void)399 void sainfo_start_reload(void){
400 	sitree_save=sitree;
401 	initsainfo();
402 }
403 
sainfo_finish_reload(void)404 void sainfo_finish_reload(void){
405 	sainfo_tailq_head_t sitree_tmp;
406 
407 	sitree_tmp=sitree;
408 	sitree=sitree_save;
409 	flushsainfo();
410 	sitree=sitree_tmp;
411 }
412 
save_sainfotree_restore(void)413 void save_sainfotree_restore(void){
414 	flushsainfo();
415 	sitree=sitree_save;
416 }
417