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