Annotation of embedaddon/ipsec-tools/src/racoon/policy.c, revision 1.1.1.1
1.1 misho 1: /* $NetBSD: policy.c,v 1.12 2011/03/14 17:18:13 tteras Exp $ */
2:
3: /* $KAME: policy.c,v 1.46 2001/11/16 04:08:10 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 PATH_IPSEC_H
43:
44: #include <stdlib.h>
45: #include <stdio.h>
46: #include <string.h>
47: #include <errno.h>
48:
49: #include "var.h"
50: #include "misc.h"
51: #include "vmbuf.h"
52: #include "plog.h"
53: #include "sockmisc.h"
54: #include "debug.h"
55:
56: #include "policy.h"
57: #include "localconf.h"
58: #include "isakmp_var.h"
59: #include "isakmp.h"
60: #include "oakley.h"
61: #include "handler.h"
62: #include "strnames.h"
63: #include "gcmalloc.h"
64:
65: static TAILQ_HEAD(_sptree, secpolicy) sptree;
66:
67: /* perform exact match against security policy table. */
68: struct secpolicy *
69: getsp(spidx)
70: struct policyindex *spidx;
71: {
72: struct secpolicy *p;
73:
74: for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
75: if (!cmpspidxstrict(spidx, &p->spidx))
76: return p;
77: }
78:
79: return NULL;
80: }
81:
82: /*
83: * perform non-exact match against security policy table, only if this is
84: * transport mode SA negotiation. for example, 0.0.0.0/0 -> 0.0.0.0/0
85: * entry in policy.txt can be returned when we're negotiating transport
86: * mode SA. this is how the kernel works.
87: */
88: #if 1
89: struct secpolicy *
90: getsp_r(spidx)
91: struct policyindex *spidx;
92: {
93: struct secpolicy *p;
94: struct secpolicy *found = NULL;
95:
96: for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
97: if (!cmpspidxstrict(spidx, &p->spidx))
98: return p;
99:
100: if (!found && !cmpspidxwild(spidx, &p->spidx))
101: found = p;
102: }
103:
104: return found;
105: }
106: #else
107: struct secpolicy *
108: getsp_r(spidx, iph2)
109: struct policyindex *spidx;
110: struct ph2handle *iph2;
111: {
112: struct secpolicy *p;
113: u_int8_t prefixlen;
114:
115: plog(LLV_DEBUG, LOCATION, NULL, "checking for transport mode\n");
116:
117: if (spidx->src.ss_family != spidx->dst.ss_family) {
118: plog(LLV_ERROR, LOCATION, NULL,
119: "address family mismatch, src:%d dst:%d\n",
120: spidx->src.ss_family,
121: spidx->dst.ss_family);
122: return NULL;
123: }
124: switch (spidx->src.ss_family) {
125: case AF_INET:
126: prefixlen = sizeof(struct in_addr) << 3;
127: break;
128: #ifdef INET6
129: case AF_INET6:
130: prefixlen = sizeof(struct in6_addr) << 3;
131: break;
132: #endif
133: default:
134: plog(LLV_ERROR, LOCATION, NULL,
135: "invalid family: %d\n", spidx->src.ss_family);
136: return NULL;
137: }
138:
139: /* is it transport mode SA negotiation? */
140: plog(LLV_DEBUG, LOCATION, NULL, "src1: %s\n",
141: saddr2str(iph2->src));
142: plog(LLV_DEBUG, LOCATION, NULL, "src2: %s\n",
143: saddr2str((struct sockaddr *)&spidx->src));
144:
145: if (cmpsaddr(iph2->src, (struct sockaddr *) &spidx->src) != CMPSADDR_MATCH ||
146: spidx->prefs != prefixlen)
147: return NULL;
148:
149: plog(LLV_DEBUG, LOCATION, NULL, "dst1: %s\n",
150: saddr2str(iph2->dst));
151: plog(LLV_DEBUG, LOCATION, NULL, "dst2: %s\n",
152: saddr2str((struct sockaddr *)&spidx->dst));
153:
154: if (cmpsaddr(iph2->dst, (struct sockaddr *) &spidx->dst) != CMPSADDR_MATCH ||
155: spidx->prefd != prefixlen)
156: return NULL;
157:
158: plog(LLV_DEBUG, LOCATION, NULL, "looks to be transport mode\n");
159:
160: for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
161: if (!cmpspidx_wild(spidx, &p->spidx))
162: return p;
163: }
164:
165: return NULL;
166: }
167: #endif
168:
169: struct secpolicy *
170: getspbyspid(spid)
171: u_int32_t spid;
172: {
173: struct secpolicy *p;
174:
175: for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
176: if (p->id == spid)
177: return p;
178: }
179:
180: return NULL;
181: }
182:
183: /*
184: * compare policyindex.
185: * a: subject b: db
186: * OUT: 0: equal
187: * 1: not equal
188: */
189: int
190: cmpspidxstrict(a, b)
191: struct policyindex *a, *b;
192: {
193: plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a));
194: plog(LLV_DEBUG, LOCATION, NULL, "db :%p: %s\n", b, spidx2str(b));
195:
196: /* XXX don't check direction now, but it's to be checked carefully. */
197: if (a->dir != b->dir
198: || a->prefs != b->prefs
199: || a->prefd != b->prefd
200: || a->ul_proto != b->ul_proto)
201: return 1;
202:
203: if (cmpsaddr((struct sockaddr *) &a->src,
204: (struct sockaddr *) &b->src) != CMPSADDR_MATCH)
205: return 1;
206: if (cmpsaddr((struct sockaddr *) &a->dst,
207: (struct sockaddr *) &b->dst) != CMPSADDR_MATCH)
208: return 1;
209:
210: #ifdef HAVE_SECCTX
211: if (a->sec_ctx.ctx_alg != b->sec_ctx.ctx_alg
212: || a->sec_ctx.ctx_doi != b->sec_ctx.ctx_doi
213: || !within_range(a->sec_ctx.ctx_str, b->sec_ctx.ctx_str))
214: return 1;
215: #endif
216: return 0;
217: }
218:
219: /*
220: * compare policyindex, with wildcard address/protocol match.
221: * a: subject b: db, can contain wildcard things.
222: * OUT: 0: equal
223: * 1: not equal
224: */
225: int
226: cmpspidxwild(a, b)
227: struct policyindex *a, *b;
228: {
229: struct sockaddr_storage sa1, sa2;
230:
231: plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a));
232: plog(LLV_DEBUG, LOCATION, NULL, "db: %p: %s\n", b, spidx2str(b));
233:
234: if (!(b->dir == IPSEC_DIR_ANY || a->dir == b->dir))
235: return 1;
236:
237: if (!(b->ul_proto == IPSEC_ULPROTO_ANY ||
238: a->ul_proto == b->ul_proto))
239: return 1;
240:
241: if (a->src.ss_family != b->src.ss_family)
242: return 1;
243: if (a->dst.ss_family != b->dst.ss_family)
244: return 1;
245:
246: #ifndef __linux__
247: /* compare src address */
248: if (sizeof(sa1) < a->src.ss_len || sizeof(sa2) < b->src.ss_len) {
249: plog(LLV_ERROR, LOCATION, NULL,
250: "unexpected error: "
251: "src.ss_len:%d dst.ss_len:%d\n",
252: a->src.ss_len, b->src.ss_len);
253: return 1;
254: }
255: #endif
256: mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->src,
257: b->prefs);
258: mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->src,
259: b->prefs);
260: plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
261: a, b->prefs, saddr2str((struct sockaddr *)&sa1));
262: plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
263: b, b->prefs, saddr2str((struct sockaddr *)&sa2));
264: if (cmpsaddr((struct sockaddr *)&sa1, (struct sockaddr *)&sa2) > CMPSADDR_WILDPORT_MATCH)
265: return 1;
266:
267: #ifndef __linux__
268: /* compare dst address */
269: if (sizeof(sa1) < a->dst.ss_len || sizeof(sa2) < b->dst.ss_len) {
270: plog(LLV_ERROR, LOCATION, NULL, "unexpected error\n");
271: exit(1);
272: }
273: #endif
274: mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->dst,
275: b->prefd);
276: mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->dst,
277: b->prefd);
278: plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
279: a, b->prefd, saddr2str((struct sockaddr *)&sa1));
280: plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
281: b, b->prefd, saddr2str((struct sockaddr *)&sa2));
282: if (cmpsaddr((struct sockaddr *)&sa1, (struct sockaddr *)&sa2) > CMPSADDR_WILDPORT_MATCH)
283: return 1;
284:
285: #ifdef HAVE_SECCTX
286: if (a->sec_ctx.ctx_alg != b->sec_ctx.ctx_alg
287: || a->sec_ctx.ctx_doi != b->sec_ctx.ctx_doi
288: || !within_range(a->sec_ctx.ctx_str, b->sec_ctx.ctx_str))
289: return 1;
290: #endif
291: return 0;
292: }
293:
294: struct secpolicy *
295: newsp()
296: {
297: struct secpolicy *new;
298:
299: new = racoon_calloc(1, sizeof(*new));
300: if (new == NULL)
301: return NULL;
302:
303: return new;
304: }
305:
306: void
307: delsp(sp)
308: struct secpolicy *sp;
309: {
310: struct ipsecrequest *req = NULL, *next;
311:
312: for (req = sp->req; req; req = next) {
313: next = req->next;
314: racoon_free(req);
315: }
316:
317: if (sp->local)
318: racoon_free(sp->local);
319: if (sp->remote)
320: racoon_free(sp->remote);
321:
322: racoon_free(sp);
323: }
324:
325: void
326: delsp_bothdir(spidx0)
327: struct policyindex *spidx0;
328: {
329: struct policyindex spidx;
330: struct secpolicy *sp;
331: struct sockaddr_storage src, dst;
332: u_int8_t prefs, prefd;
333:
334: memcpy(&spidx, spidx0, sizeof(spidx));
335: switch (spidx.dir) {
336: case IPSEC_DIR_INBOUND:
337: #ifdef HAVE_POLICY_FWD
338: case IPSEC_DIR_FWD:
339: #endif
340: src = spidx.src;
341: dst = spidx.dst;
342: prefs = spidx.prefs;
343: prefd = spidx.prefd;
344: break;
345: case IPSEC_DIR_OUTBOUND:
346: src = spidx.dst;
347: dst = spidx.src;
348: prefs = spidx.prefd;
349: prefd = spidx.prefs;
350: break;
351: default:
352: return;
353: }
354:
355: spidx.src = src;
356: spidx.dst = dst;
357: spidx.prefs = prefs;
358: spidx.prefd = prefd;
359: spidx.dir = IPSEC_DIR_INBOUND;
360:
361: sp = getsp(&spidx);
362: if (sp) {
363: remsp(sp);
364: delsp(sp);
365: }
366:
367: #ifdef HAVE_POLICY_FWD
368: spidx.dir = IPSEC_DIR_FWD;
369:
370: sp = getsp(&spidx);
371: if (sp) {
372: remsp(sp);
373: delsp(sp);
374: }
375: #endif
376:
377: spidx.src = dst;
378: spidx.dst = src;
379: spidx.prefs = prefd;
380: spidx.prefd = prefs;
381: spidx.dir = IPSEC_DIR_OUTBOUND;
382:
383: sp = getsp(&spidx);
384: if (sp) {
385: remsp(sp);
386: delsp(sp);
387: }
388: }
389:
390: void
391: inssp(new)
392: struct secpolicy *new;
393: {
394: #ifdef HAVE_PFKEY_POLICY_PRIORITY
395: struct secpolicy *p;
396:
397: TAILQ_FOREACH(p, &sptree, chain) {
398: if (new->spidx.priority < p->spidx.priority) {
399: TAILQ_INSERT_BEFORE(p, new, chain);
400: return;
401: }
402: }
403: if (p == NULL)
404: #endif
405: TAILQ_INSERT_TAIL(&sptree, new, chain);
406:
407: return;
408: }
409:
410: void
411: remsp(sp)
412: struct secpolicy *sp;
413: {
414: TAILQ_REMOVE(&sptree, sp, chain);
415: }
416:
417: void
418: flushsp()
419: {
420: struct secpolicy *p, *next;
421:
422: for (p = TAILQ_FIRST(&sptree); p; p = next) {
423: next = TAILQ_NEXT(p, chain);
424: remsp(p);
425: delsp(p);
426: }
427: }
428:
429: void
430: initsp()
431: {
432: TAILQ_INIT(&sptree);
433: }
434:
435: struct ipsecrequest *
436: newipsecreq()
437: {
438: struct ipsecrequest *new;
439:
440: new = racoon_calloc(1, sizeof(*new));
441: if (new == NULL)
442: return NULL;
443:
444: return new;
445: }
446:
447: const char *
448: spidx2str(spidx)
449: const struct policyindex *spidx;
450: {
451: /* addr/pref[port] addr/pref[port] ul dir act */
452: static char buf[256];
453: char *p, *a, *b;
454: int blen, i;
455:
456: blen = sizeof(buf) - 1;
457: p = buf;
458:
459: a = saddr2str((const struct sockaddr *)&spidx->src);
460: for (b = a; *b != '\0'; b++)
461: if (*b == '[') {
462: *b = '\0';
463: b++;
464: break;
465: }
466: i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefs, b);
467: if (i < 0 || i >= blen)
468: return NULL;
469: p += i;
470: blen -= i;
471:
472: a = saddr2str((const struct sockaddr *)&spidx->dst);
473: for (b = a; *b != '\0'; b++)
474: if (*b == '[') {
475: *b = '\0';
476: b++;
477: break;
478: }
479: i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefd, b);
480: if (i < 0 || i >= blen)
481: return NULL;
482: p += i;
483: blen -= i;
484:
485: i = snprintf(p, blen, "proto=%s dir=%s",
486: s_proto(spidx->ul_proto), s_direction(spidx->dir));
487:
488: #ifdef HAVE_SECCTX
489: if (spidx->sec_ctx.ctx_strlen) {
490: p += i;
491: blen -= i;
492: snprintf(p, blen, " sec_ctx:doi=%d,alg=%d,len=%d,str=%s",
493: spidx->sec_ctx.ctx_doi, spidx->sec_ctx.ctx_alg,
494: spidx->sec_ctx.ctx_strlen, spidx->sec_ctx.ctx_str);
495: }
496: #endif
497: return buf;
498: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>