source: rtems-libbsd/ipsec-tools/src/racoon/policy.c

6-freebsd-12
Last change on this file was b376ae1, checked in by Christian Mauderer <christian.mauderer@…>, on 05/03/18 at 12:15:11

ipsec-tools: Port libipsec, setkey and racoon.

Note that this replaces the libipsec from FreeBSD with the one provided
by ipsec-tools.

  • Property mode set to 100644
File size: 11.4 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2#ifdef __rtems__
3#include <machine/rtems-bsd-program.h>
4#include "rtems-bsd-racoon-namespace.h"
5#endif /* __rtems__ */
6
7/*      $NetBSD: policy.c,v 1.12 2011/03/14 17:18:13 tteras Exp $       */
8
9/*      $KAME: policy.c,v 1.46 2001/11/16 04:08:10 sakane Exp $ */
10
11/*
12 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
13 * All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 * 3. Neither the name of the project nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40#include "config.h"
41
42#include <sys/param.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <sys/queue.h>
46
47#include <netinet/in.h>
48#include PATH_IPSEC_H
49
50#include <stdlib.h>
51#include <stdio.h>
52#include <string.h>
53#include <errno.h>
54
55#include "var.h"
56#include "misc.h"
57#include "vmbuf.h"
58#include "plog.h"
59#include "sockmisc.h"
60#include "debug.h"
61
62#include "policy.h"
63#include "localconf.h"
64#include "isakmp_var.h"
65#include "isakmp.h"
66#include "oakley.h"
67#include "handler.h"
68#include "strnames.h"
69#include "gcmalloc.h"
70
71static TAILQ_HEAD(_sptree, secpolicy) sptree;
72
73/* perform exact match against security policy table. */
74struct secpolicy *
75getsp(spidx)
76        struct policyindex *spidx;
77{
78        struct secpolicy *p;
79
80        for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
81                if (!cmpspidxstrict(spidx, &p->spidx))
82                        return p;
83        }
84
85        return NULL;
86}
87
88/*
89 * perform non-exact match against security policy table, only if this is
90 * transport mode SA negotiation.  for example, 0.0.0.0/0 -> 0.0.0.0/0
91 * entry in policy.txt can be returned when we're negotiating transport
92 * mode SA.  this is how the kernel works.
93 */
94#if 1
95struct secpolicy *
96getsp_r(spidx)
97        struct policyindex *spidx;
98{
99        struct secpolicy *p;
100        struct secpolicy *found = NULL;
101
102        for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
103                if (!cmpspidxstrict(spidx, &p->spidx))
104                        return p;
105
106                if (!found && !cmpspidxwild(spidx, &p->spidx))
107                        found = p;
108        }
109
110        return found;
111}
112#else
113struct secpolicy *
114getsp_r(spidx, iph2)
115        struct policyindex *spidx;
116        struct ph2handle *iph2;
117{
118        struct secpolicy *p;
119        u_int8_t prefixlen;
120
121        plog(LLV_DEBUG, LOCATION, NULL, "checking for transport mode\n");
122
123        if (spidx->src.ss_family != spidx->dst.ss_family) {
124                plog(LLV_ERROR, LOCATION, NULL,
125                        "address family mismatch, src:%d dst:%d\n",
126                                spidx->src.ss_family,
127                                spidx->dst.ss_family);
128                return NULL;
129        }
130        switch (spidx->src.ss_family) {
131        case AF_INET:
132                prefixlen = sizeof(struct in_addr) << 3;
133                break;
134#ifdef INET6
135        case AF_INET6:
136                prefixlen = sizeof(struct in6_addr) << 3;
137                break;
138#endif
139        default:
140                plog(LLV_ERROR, LOCATION, NULL,
141                        "invalid family: %d\n", spidx->src.ss_family);
142                return NULL;
143        }
144
145        /* is it transport mode SA negotiation? */
146        plog(LLV_DEBUG, LOCATION, NULL, "src1: %s\n",
147                saddr2str(iph2->src));
148        plog(LLV_DEBUG, LOCATION, NULL, "src2: %s\n",
149                saddr2str((struct sockaddr *)&spidx->src));
150
151        if (cmpsaddr(iph2->src, (struct sockaddr *) &spidx->src) != CMPSADDR_MATCH ||
152            spidx->prefs != prefixlen)
153                return NULL;
154
155        plog(LLV_DEBUG, LOCATION, NULL, "dst1: %s\n",
156                saddr2str(iph2->dst));
157        plog(LLV_DEBUG, LOCATION, NULL, "dst2: %s\n",
158                saddr2str((struct sockaddr *)&spidx->dst));
159
160        if (cmpsaddr(iph2->dst, (struct sockaddr *) &spidx->dst) != CMPSADDR_MATCH ||
161            spidx->prefd != prefixlen)
162                return NULL;
163
164        plog(LLV_DEBUG, LOCATION, NULL, "looks to be transport mode\n");
165
166        for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
167                if (!cmpspidx_wild(spidx, &p->spidx))
168                        return p;
169        }
170
171        return NULL;
172}
173#endif
174
175struct secpolicy *
176getspbyspid(spid)
177        u_int32_t spid;
178{
179        struct secpolicy *p;
180
181        for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
182                if (p->id == spid)
183                        return p;
184        }
185
186        return NULL;
187}
188
189/*
190 * compare policyindex.
191 * a: subject b: db
192 * OUT: 0:      equal
193 *      1:      not equal
194 */
195int
196cmpspidxstrict(a, b)
197        struct policyindex *a, *b;
198{
199        plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a));
200        plog(LLV_DEBUG, LOCATION, NULL, "db :%p: %s\n", b, spidx2str(b));
201
202        /* XXX don't check direction now, but it's to be checked carefully. */
203        if (a->dir != b->dir
204         || a->prefs != b->prefs
205         || a->prefd != b->prefd
206         || a->ul_proto != b->ul_proto)
207                return 1;
208
209        if (cmpsaddr((struct sockaddr *) &a->src,
210                     (struct sockaddr *) &b->src) != CMPSADDR_MATCH)
211                return 1;
212        if (cmpsaddr((struct sockaddr *) &a->dst,
213                     (struct sockaddr *) &b->dst) != CMPSADDR_MATCH)
214                return 1;
215
216#ifdef HAVE_SECCTX
217        if (a->sec_ctx.ctx_alg != b->sec_ctx.ctx_alg
218            || a->sec_ctx.ctx_doi != b->sec_ctx.ctx_doi
219            || !within_range(a->sec_ctx.ctx_str, b->sec_ctx.ctx_str))
220                return 1;
221#endif
222        return 0;
223}
224
225/*
226 * compare policyindex, with wildcard address/protocol match.
227 * a: subject b: db, can contain wildcard things.
228 * OUT: 0:      equal
229 *      1:      not equal
230 */
231int
232cmpspidxwild(a, b)
233        struct policyindex *a, *b;
234{
235        struct sockaddr_storage sa1, sa2;
236
237        plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a));
238        plog(LLV_DEBUG, LOCATION, NULL, "db: %p: %s\n", b, spidx2str(b));
239
240        if (!(b->dir == IPSEC_DIR_ANY || a->dir == b->dir))
241                return 1;
242
243        if (!(b->ul_proto == IPSEC_ULPROTO_ANY ||
244              a->ul_proto == b->ul_proto))
245                return 1;
246
247        if (a->src.ss_family != b->src.ss_family)
248                return 1;
249        if (a->dst.ss_family != b->dst.ss_family)
250                return 1;
251
252#ifndef __linux__
253        /* compare src address */
254        if (sizeof(sa1) < a->src.ss_len || sizeof(sa2) < b->src.ss_len) {
255                plog(LLV_ERROR, LOCATION, NULL,
256                        "unexpected error: "
257                        "src.ss_len:%d dst.ss_len:%d\n",
258                        a->src.ss_len, b->src.ss_len);
259                return 1;
260        }
261#endif
262        mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->src,
263                b->prefs);
264        mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->src,
265                b->prefs);
266        plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
267                a, b->prefs, saddr2str((struct sockaddr *)&sa1));
268        plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
269                b, b->prefs, saddr2str((struct sockaddr *)&sa2));
270        if (cmpsaddr((struct sockaddr *)&sa1, (struct sockaddr *)&sa2) > CMPSADDR_WILDPORT_MATCH)
271                return 1;
272
273#ifndef __linux__
274        /* compare dst address */
275        if (sizeof(sa1) < a->dst.ss_len || sizeof(sa2) < b->dst.ss_len) {
276                plog(LLV_ERROR, LOCATION, NULL, "unexpected error\n");
277                exit(1);
278        }
279#endif
280        mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->dst,
281                b->prefd);
282        mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->dst,
283                b->prefd);
284        plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
285                a, b->prefd, saddr2str((struct sockaddr *)&sa1));
286        plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
287                b, b->prefd, saddr2str((struct sockaddr *)&sa2));
288        if (cmpsaddr((struct sockaddr *)&sa1, (struct sockaddr *)&sa2) > CMPSADDR_WILDPORT_MATCH)
289                return 1;
290
291#ifdef HAVE_SECCTX
292        if (a->sec_ctx.ctx_alg != b->sec_ctx.ctx_alg
293            || a->sec_ctx.ctx_doi != b->sec_ctx.ctx_doi
294            || !within_range(a->sec_ctx.ctx_str, b->sec_ctx.ctx_str))
295                return 1;
296#endif
297        return 0;
298}
299
300struct secpolicy *
301newsp()
302{
303        struct secpolicy *new;
304
305        new = racoon_calloc(1, sizeof(*new));
306        if (new == NULL)
307                return NULL;
308
309        return new;
310}
311
312void
313delsp(sp)
314        struct secpolicy *sp;
315{
316        struct ipsecrequest *req = NULL, *next;
317
318        for (req = sp->req; req; req = next) {
319                next = req->next;
320                racoon_free(req);
321        }
322       
323        if (sp->local)
324                racoon_free(sp->local);
325        if (sp->remote)
326                racoon_free(sp->remote);
327
328        racoon_free(sp);
329}
330
331void
332delsp_bothdir(spidx0)
333        struct policyindex *spidx0;
334{
335        struct policyindex spidx;
336        struct secpolicy *sp;
337        struct sockaddr_storage src, dst;
338        u_int8_t prefs, prefd;
339
340        memcpy(&spidx, spidx0, sizeof(spidx));
341        switch (spidx.dir) {
342        case IPSEC_DIR_INBOUND:
343#ifdef HAVE_POLICY_FWD
344        case IPSEC_DIR_FWD:
345#endif
346                src   = spidx.src;
347                dst   = spidx.dst;
348                prefs = spidx.prefs;
349                prefd = spidx.prefd;
350                break;
351        case IPSEC_DIR_OUTBOUND:
352                src   = spidx.dst;
353                dst   = spidx.src;
354                prefs = spidx.prefd;
355                prefd = spidx.prefs;
356                break;
357        default:
358                return;
359        }
360
361        spidx.src   = src;
362        spidx.dst   = dst;
363        spidx.prefs = prefs;
364        spidx.prefd = prefd;
365        spidx.dir   = IPSEC_DIR_INBOUND;
366
367        sp = getsp(&spidx);
368        if (sp) {
369                remsp(sp);
370                delsp(sp);
371        }
372
373#ifdef HAVE_POLICY_FWD
374        spidx.dir   = IPSEC_DIR_FWD;
375
376        sp = getsp(&spidx);
377        if (sp) {
378                remsp(sp);
379                delsp(sp);
380        }
381#endif
382
383        spidx.src   = dst;
384        spidx.dst   = src;
385        spidx.prefs = prefd;
386        spidx.prefd = prefs;
387        spidx.dir   = IPSEC_DIR_OUTBOUND;
388
389        sp = getsp(&spidx);
390        if (sp) {
391                remsp(sp);
392                delsp(sp);
393        }
394}
395
396void
397inssp(new)
398        struct secpolicy *new;
399{
400#ifdef HAVE_PFKEY_POLICY_PRIORITY
401        struct secpolicy *p;
402
403        TAILQ_FOREACH(p, &sptree, chain) {
404                if (new->spidx.priority < p->spidx.priority) {
405                        TAILQ_INSERT_BEFORE(p, new, chain);
406                        return;
407                }
408        }
409        if (p == NULL)
410#endif
411                TAILQ_INSERT_TAIL(&sptree, new, chain);
412
413        return;
414}
415
416void
417remsp(sp)
418        struct secpolicy *sp;
419{
420        TAILQ_REMOVE(&sptree, sp, chain);
421}
422
423void
424flushsp()
425{
426        struct secpolicy *p, *next;
427
428        for (p = TAILQ_FIRST(&sptree); p; p = next) {
429                next = TAILQ_NEXT(p, chain);
430                remsp(p);
431                delsp(p);
432        }
433}
434
435void
436initsp()
437{
438        TAILQ_INIT(&sptree);
439}
440
441struct ipsecrequest *
442newipsecreq()
443{
444        struct ipsecrequest *new;
445
446        new = racoon_calloc(1, sizeof(*new));
447        if (new == NULL)
448                return NULL;
449
450        return new;
451}
452
453const char *
454spidx2str(spidx)
455        const struct policyindex *spidx;
456{
457        /* addr/pref[port] addr/pref[port] ul dir act */
458        static char buf[256];
459        char *p, *a, *b;
460        int blen, i;
461
462        blen = sizeof(buf) - 1;
463        p = buf;
464
465        a = saddr2str((const struct sockaddr *)&spidx->src);
466        for (b = a; *b != '\0'; b++)
467                if (*b == '[') {
468                        *b = '\0';
469                        b++;
470                        break;
471                }
472        i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefs, b);
473        if (i < 0 || i >= blen)
474                return NULL;
475        p += i;
476        blen -= i;
477
478        a = saddr2str((const struct sockaddr *)&spidx->dst);
479        for (b = a; *b != '\0'; b++)
480                if (*b == '[') {
481                        *b = '\0';
482                        b++;
483                        break;
484                }
485        i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefd, b);
486        if (i < 0 || i >= blen)
487                return NULL;
488        p += i;
489        blen -= i;
490
491        i = snprintf(p, blen, "proto=%s dir=%s",
492                s_proto(spidx->ul_proto), s_direction(spidx->dir));
493
494#ifdef HAVE_SECCTX
495        if (spidx->sec_ctx.ctx_strlen) {
496                p += i;
497                blen -= i;
498                snprintf(p, blen, " sec_ctx:doi=%d,alg=%d,len=%d,str=%s",
499                         spidx->sec_ctx.ctx_doi, spidx->sec_ctx.ctx_alg,
500                         spidx->sec_ctx.ctx_strlen, spidx->sec_ctx.ctx_str);
501        }
502#endif
503        return buf;
504}
505#ifdef __rtems__
506#include "rtems-bsd-racoon-policy-data.h"
507#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.