]> git.saurik.com Git - apple/network_cmds.git/blob - racoon.tproj/policy.c
network_cmds-176.tar.gz
[apple/network_cmds.git] / racoon.tproj / policy.c
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 <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/queue.h>
36
37 #include <netkey/key_var.h>
38 #include <netinet/in.h>
39 #include <netinet6/ipsec.h>
40
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <errno.h>
45
46 #include "var.h"
47 #include "misc.h"
48 #include "vmbuf.h"
49 #include "plog.h"
50 #include "sockmisc.h"
51 #include "debug.h"
52
53 #include "policy.h"
54 #include "localconf.h"
55 #include "isakmp_var.h"
56 #include "isakmp.h"
57 #include "oakley.h"
58 #include "handler.h"
59 #include "strnames.h"
60 #include "gcmalloc.h"
61
62 static TAILQ_HEAD(_sptree, secpolicy) sptree;
63
64 /* perform exact match against security policy table. */
65 struct secpolicy *
66 getsp(spidx)
67 struct policyindex *spidx;
68 {
69 struct secpolicy *p;
70
71 for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
72 if (!cmpspidxstrict(spidx, &p->spidx))
73 return p;
74 }
75
76 return NULL;
77 }
78
79 /*
80 * perform non-exact match against security policy table, only if this is
81 * transport mode SA negotiation. for example, 0.0.0.0/0 -> 0.0.0.0/0
82 * entry in policy.txt can be returned when we're negotiating transport
83 * mode SA. this is how the kernel works.
84 */
85 #if 1
86 struct secpolicy *
87 getsp_r(spidx)
88 struct policyindex *spidx;
89 {
90 struct secpolicy *p;
91
92 for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
93 if (!cmpspidxwild(spidx, &p->spidx))
94 return p;
95 }
96
97 return NULL;
98 }
99 #else
100 struct secpolicy *
101 getsp_r(spidx, iph2)
102 struct policyindex *spidx;
103 struct ph2handle *iph2;
104 {
105 struct secpolicy *p;
106 u_int8_t prefixlen;
107
108 plog(LLV_DEBUG, LOCATION, NULL, "checking for transport mode\n");
109
110 if (spidx->src.ss_family != spidx->dst.ss_family) {
111 plog(LLV_ERROR, LOCATION, NULL,
112 "address family mismatch, src:%d dst:%d\n",
113 spidx->src.ss_family,
114 spidx->dst.ss_family);
115 return NULL;
116 }
117 switch (spidx->src.ss_family) {
118 case AF_INET:
119 prefixlen = sizeof(struct in_addr) << 3;
120 break;
121 #ifdef INET6
122 case AF_INET6:
123 prefixlen = sizeof(struct in6_addr) << 3;
124 break;
125 #endif
126 default:
127 plog(LLV_ERROR, LOCATION, NULL,
128 "invalid family: %d\n", spidx->src.ss_family);
129 return NULL;
130 }
131
132 /* is it transport mode SA negotiation? */
133 plog(LLV_DEBUG, LOCATION, NULL, "src1: %s\n",
134 saddr2str(iph2->src));
135 plog(LLV_DEBUG, LOCATION, NULL, "src2: %s\n",
136 saddr2str((struct sockaddr *)&spidx->src));
137 if (cmpsaddrwop(iph2->src, (struct sockaddr *)&spidx->src)
138 || spidx->prefs != prefixlen)
139 return NULL;
140
141 plog(LLV_DEBUG, LOCATION, NULL, "dst1: %s\n",
142 saddr2str(iph2->dst));
143 plog(LLV_DEBUG, LOCATION, NULL, "dst2: %s\n",
144 saddr2str((struct sockaddr *)&spidx->dst));
145 if (cmpsaddrwop(iph2->dst, (struct sockaddr *)&spidx->dst)
146 || spidx->prefd != prefixlen)
147 return NULL;
148
149 plog(LLV_DEBUG, LOCATION, NULL, "looks to be transport mode\n");
150
151 for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
152 if (!cmpspidx_wild(spidx, &p->spidx))
153 return p;
154 }
155
156 return NULL;
157 }
158 #endif
159
160 struct secpolicy *
161 getspbyspid(spid)
162 u_int32_t spid;
163 {
164 struct secpolicy *p;
165
166 for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) {
167 if (p->id == spid)
168 return p;
169 }
170
171 return NULL;
172 }
173
174 /*
175 * compare policyindex.
176 * a: subject b: db
177 * OUT: 0: equal
178 * 1: not equal
179 */
180 int
181 cmpspidxstrict(a, b)
182 struct policyindex *a, *b;
183 {
184 plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a));
185 plog(LLV_DEBUG, LOCATION, NULL, "db :%p: %s\n", b, spidx2str(b));
186
187 /* XXX don't check direction now, but it's to be checked carefully. */
188 if (a->dir != b->dir
189 || a->prefs != b->prefs
190 || a->prefd != b->prefd
191 || a->ul_proto != b->ul_proto)
192 return 1;
193
194 if (cmpsaddrstrict((struct sockaddr *)&a->src,
195 (struct sockaddr *)&b->src))
196 return 1;
197 if (cmpsaddrstrict((struct sockaddr *)&a->dst,
198 (struct sockaddr *)&b->dst))
199 return 1;
200
201 return 0;
202 }
203
204 /*
205 * compare policyindex, with wildcard address/protocol match.
206 * a: subject b: db, can contain wildcard things.
207 * OUT: 0: equal
208 * 1: not equal
209 */
210 int
211 cmpspidxwild(a, b)
212 struct policyindex *a, *b;
213 {
214 struct sockaddr_storage sa1, sa2;
215
216 plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a));
217 plog(LLV_DEBUG, LOCATION, NULL, "db: %p: %s\n", b, spidx2str(b));
218
219 if (!(b->dir == IPSEC_DIR_ANY || a->dir == b->dir))
220 return 1;
221
222 if (!(a->ul_proto == IPSEC_ULPROTO_ANY ||
223 b->ul_proto == IPSEC_ULPROTO_ANY ||
224 a->ul_proto == b->ul_proto))
225 return 1;
226
227 if (a->src.ss_family != b->src.ss_family)
228 return 1;
229 if (a->dst.ss_family != b->dst.ss_family)
230 return 1;
231
232 /* compare src address */
233 if (sizeof(sa1) < a->src.ss_len || sizeof(sa2) < b->src.ss_len) {
234 plog(LLV_ERROR, LOCATION, NULL,
235 "unexpected error: "
236 "src.ss_len:%d dst.ss_len:%d\n",
237 a->src.ss_len, b->src.ss_len);
238 return 1;
239 }
240 mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->src,
241 b->prefs);
242 mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->src,
243 b->prefs);
244 plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
245 a, b->prefs, saddr2str((struct sockaddr *)&sa1));
246 plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
247 b, b->prefs, saddr2str((struct sockaddr *)&sa2));
248 if (cmpsaddrwild((struct sockaddr *)&sa1, (struct sockaddr *)&sa2))
249 return 1;
250
251 /* compare dst address */
252 if (sizeof(sa1) < a->dst.ss_len || sizeof(sa2) < b->dst.ss_len) {
253 plog(LLV_ERROR, LOCATION, NULL, "unexpected error\n");
254 exit(1);
255 }
256 mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->dst,
257 b->prefd);
258 mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->dst,
259 b->prefd);
260 plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
261 a, b->prefd, saddr2str((struct sockaddr *)&sa1));
262 plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n",
263 b, b->prefd, saddr2str((struct sockaddr *)&sa2));
264 if (cmpsaddrwild((struct sockaddr *)&sa1, (struct sockaddr *)&sa2))
265 return 1;
266
267 return 0;
268 }
269
270 struct secpolicy *
271 newsp()
272 {
273 struct secpolicy *new;
274
275 new = racoon_calloc(1, sizeof(*new));
276 if (new == NULL)
277 return NULL;
278
279 return new;
280 }
281
282 void
283 delsp(sp)
284 struct secpolicy *sp;
285 {
286 struct ipsecrequest *req = NULL, *next;
287
288 for (req = sp->req; req; req = next) {
289 next = req->next;
290 racoon_free(req);
291 }
292
293 racoon_free(sp);
294 }
295
296 void
297 delsp_bothdir(spidx0)
298 struct policyindex *spidx0;
299 {
300 struct policyindex spidx;
301 struct secpolicy *sp;
302 struct sockaddr_storage addr;
303 u_int8_t pref;
304
305 memcpy(&spidx, spidx0, sizeof(spidx));
306
307 sp = getsp(&spidx);
308 if (sp) {
309 remsp(sp);
310 delsp(sp);
311 }
312
313 spidx.dir = spidx.dir == IPSEC_DIR_OUTBOUND
314 ? IPSEC_DIR_INBOUND
315 : IPSEC_DIR_OUTBOUND ;
316 addr = spidx.src;
317 spidx.src = spidx.dst;
318 spidx.dst = addr;
319 pref = spidx.prefs;
320 spidx.prefs = spidx.prefd;
321 spidx.prefd = pref;
322
323 sp = getsp(&spidx);
324 if (sp) {
325 remsp(sp);
326 delsp(sp);
327 }
328 }
329
330 void
331 inssp(new)
332 struct secpolicy *new;
333 {
334 TAILQ_INSERT_TAIL(&sptree, new, chain);
335 }
336
337 void
338 remsp(sp)
339 struct secpolicy *sp;
340 {
341 TAILQ_REMOVE(&sptree, sp, chain);
342 }
343
344 void
345 flushsp()
346 {
347 struct secpolicy *p, *next;
348
349 for (p = TAILQ_FIRST(&sptree); p; p = next) {
350 next = TAILQ_NEXT(p, chain);
351 remsp(p);
352 delsp(p);
353 }
354 }
355
356 void
357 initsp()
358 {
359 TAILQ_INIT(&sptree);
360 }
361
362 struct ipsecrequest *
363 newipsecreq()
364 {
365 struct ipsecrequest *new;
366
367 new = racoon_calloc(1, sizeof(*new));
368 if (new == NULL)
369 return NULL;
370
371 return new;
372 }
373
374 const char *
375 spidx2str(spidx)
376 const struct policyindex *spidx;
377 {
378 /* addr/pref[port] addr/pref[port] ul dir act */
379 static char buf[256];
380 char *p, *a, *b;
381 int blen, i;
382
383 blen = sizeof(buf) - 1;
384 p = buf;
385
386 a = saddr2str((const struct sockaddr *)&spidx->src);
387 for (b = a; *b != '\0'; b++)
388 if (*b == '[') {
389 *b = '\0';
390 b++;
391 break;
392 }
393 i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefs, b);
394 if (i < 0 || i >= blen)
395 return NULL;
396 p += i;
397 blen -= i;
398
399 a = saddr2str((const struct sockaddr *)&spidx->dst);
400 for (b = a; *b != '\0'; b++)
401 if (*b == '[') {
402 *b = '\0';
403 b++;
404 break;
405 }
406 i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefd, b);
407 if (i < 0 || i >= blen)
408 return NULL;
409 p += i;
410 blen -= i;
411
412 snprintf(p, blen, "proto=%s dir=%s",
413 s_proto(spidx->ul_proto), s_direction(spidx->dir));
414
415 return buf;
416 }