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 *
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 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 *
getsp_r(spidx,iph2)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 *
getspbyspid(spid)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
cmpspidxstrict(a,b)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
cmpspidxwild(a,b)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 *
newsp()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
delsp(sp)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
delsp_bothdir(spidx0)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
inssp(new)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
remsp(sp)411 remsp(sp)
412 struct secpolicy *sp;
413 {
414 TAILQ_REMOVE(&sptree, sp, chain);
415 }
416
417 void
flushsp()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
initsp()430 initsp()
431 {
432 TAILQ_INIT(&sptree);
433 }
434
435 struct ipsecrequest *
newipsecreq()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 *
spidx2str(spidx)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 }
499