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