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