Sync usage with man page.
[netbsd-mini2440.git] / crypto / dist / ipsec-tools / src / racoon / policy.c
blobd200e349889992e2fe3a2f831e9c579691bbfd9e
1 /* $NetBSD: policy.c,v 1.10 2008/12/05 06:02:20 tteras Exp $ */
3 /* $KAME: policy.c,v 1.46 2001/11/16 04:08:10 sakane Exp $ */
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.
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.
34 #include "config.h"
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/queue.h>
41 #include <netinet/in.h>
42 #include PATH_IPSEC_H
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <errno.h>
49 #include "var.h"
50 #include "misc.h"
51 #include "vmbuf.h"
52 #include "plog.h"
53 #include "sockmisc.h"
54 #include "debug.h"
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"
65 static TAILQ_HEAD(_sptree, secpolicy) sptree;
67 /* perform exact match against security policy table. */
68 struct secpolicy *
69 getsp(spidx)
70 struct policyindex *spidx;
72 struct secpolicy *p;
74 for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
75 if (!cmpspidxstrict(spidx, &p->spidx))
76 return p;
79 return NULL;
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.
88 #if 1
89 struct secpolicy *
90 getsp_r(spidx)
91 struct policyindex *spidx;
93 struct secpolicy *p;
94 struct secpolicy *found = NULL;
96 for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
97 if (!cmpspidxstrict(spidx, &p->spidx))
98 return p;
100 if (!found && !cmpspidxwild(spidx, &p->spidx))
101 found = p;
104 return found;
106 #else
107 struct secpolicy *
108 getsp_r(spidx, iph2)
109 struct policyindex *spidx;
110 struct ph2handle *iph2;
112 struct secpolicy *p;
113 u_int8_t prefixlen;
115 plog(LLV_DEBUG, LOCATION, NULL, "checking for transport mode\n");
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;
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;
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));
145 if (cmpsaddr(iph2->src, (struct sockaddr *) &spidx->src) ||
146 spidx->prefs != prefixlen)
147 return NULL;
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));
154 if (cmpsaddr(iph2->dst, (struct sockaddr *) &spidx->dst) ||
155 spidx->prefd != prefixlen)
156 return NULL;
158 plog(LLV_DEBUG, LOCATION, NULL, "looks to be transport mode\n");
160 for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
161 if (!cmpspidx_wild(spidx, &p->spidx))
162 return p;
165 return NULL;
167 #endif
169 struct secpolicy *
170 getspbyspid(spid)
171 u_int32_t spid;
173 struct secpolicy *p;
175 for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
176 if (p->id == spid)
177 return p;
180 return NULL;
184 * compare policyindex.
185 * a: subject b: db
186 * OUT: 0: equal
187 * 1: not equal
190 cmpspidxstrict(a, b)
191 struct policyindex *a, *b;
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));
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;
203 if (cmpsaddr((struct sockaddr *) &a->src,
204 (struct sockaddr *) &b->src))
205 return 1;
206 if (cmpsaddr((struct sockaddr *) &a->dst,
207 (struct sockaddr *) &b->dst))
208 return 1;
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;
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
226 cmpspidxwild(a, b)
227 struct policyindex *a, *b;
229 struct sockaddr_storage sa1, sa2;
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));
234 if (!(b->dir == IPSEC_DIR_ANY || a->dir == b->dir))
235 return 1;
237 if (!(b->ul_proto == IPSEC_ULPROTO_ANY ||
238 a->ul_proto == b->ul_proto))
239 return 1;
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;
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;
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))
265 return 1;
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);
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))
283 return 1;
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;
294 struct secpolicy *
295 newsp()
297 struct secpolicy *new;
299 new = racoon_calloc(1, sizeof(*new));
300 if (new == NULL)
301 return NULL;
303 return new;
306 void
307 delsp(sp)
308 struct secpolicy *sp;
310 struct ipsecrequest *req = NULL, *next;
312 for (req = sp->req; req; req = next) {
313 next = req->next;
314 racoon_free(req);
317 if (sp->local)
318 racoon_free(sp->local);
319 if (sp->remote)
320 racoon_free(sp->remote);
322 racoon_free(sp);
325 void
326 delsp_bothdir(spidx0)
327 struct policyindex *spidx0;
329 struct policyindex spidx;
330 struct secpolicy *sp;
331 struct sockaddr_storage src, dst;
332 u_int8_t prefs, prefd;
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;
355 spidx.src = src;
356 spidx.dst = dst;
357 spidx.prefs = prefs;
358 spidx.prefd = prefd;
359 spidx.dir = IPSEC_DIR_INBOUND;
361 sp = getsp(&spidx);
362 if (sp) {
363 remsp(sp);
364 delsp(sp);
367 #ifdef HAVE_POLICY_FWD
368 spidx.dir = IPSEC_DIR_FWD;
370 sp = getsp(&spidx);
371 if (sp) {
372 remsp(sp);
373 delsp(sp);
375 #endif
377 spidx.src = dst;
378 spidx.dst = src;
379 spidx.prefs = prefd;
380 spidx.prefd = prefs;
381 spidx.dir = IPSEC_DIR_OUTBOUND;
383 sp = getsp(&spidx);
384 if (sp) {
385 remsp(sp);
386 delsp(sp);
390 void
391 inssp(new)
392 struct secpolicy *new;
394 #ifdef HAVE_PFKEY_POLICY_PRIORITY
395 struct secpolicy *p;
397 TAILQ_FOREACH(p, &sptree, chain) {
398 if (new->spidx.priority < p->spidx.priority) {
399 TAILQ_INSERT_BEFORE(p, new, chain);
400 return;
403 if (p == NULL)
404 #endif
405 TAILQ_INSERT_TAIL(&sptree, new, chain);
407 return;
410 void
411 remsp(sp)
412 struct secpolicy *sp;
414 TAILQ_REMOVE(&sptree, sp, chain);
417 void
418 flushsp()
420 struct secpolicy *p, *next;
422 for (p = TAILQ_FIRST(&sptree); p; p = next) {
423 next = TAILQ_NEXT(p, chain);
424 remsp(p);
425 delsp(p);
429 void
430 initsp()
432 TAILQ_INIT(&sptree);
435 struct ipsecrequest *
436 newipsecreq()
438 struct ipsecrequest *new;
440 new = racoon_calloc(1, sizeof(*new));
441 if (new == NULL)
442 return NULL;
444 return new;
447 const char *
448 spidx2str(spidx)
449 const struct policyindex *spidx;
451 /* addr/pref[port] addr/pref[port] ul dir act */
452 static char buf[256];
453 char *p, *a, *b;
454 int blen, i;
456 blen = sizeof(buf) - 1;
457 p = buf;
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;
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;
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;
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;
485 i = snprintf(p, blen, "proto=%s dir=%s",
486 s_proto(spidx->ul_proto), s_direction(spidx->dir));
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);
496 #endif
497 return buf;