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