]> git.saurik.com Git - apple/ipsec.git/blame - ipsec-tools/libipsec/policy_parse.y
ipsec-164.10.tar.gz
[apple/ipsec.git] / ipsec-tools / libipsec / policy_parse.y
CommitLineData
52b7d2ce
A
1/* $KAME: policy_parse.y,v 1.21 2003/12/12 08:01:26 itojun Exp $ */
2
3/*
4 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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/*
33 * IN/OUT bound policy configuration take place such below:
34 * in <priority> <policy>
35 * out <priority> <policy>
36 *
37 * <priority> is one of the following:
38 * priority <signed int> where the integer is an offset from the default
39 * priority, where negative numbers indicate lower
40 * priority (towards end of list) and positive numbers
41 * indicate higher priority (towards beginning of list)
42 *
43 * priority {low,def,high} {+,-} <unsigned int> where low and high are
44 * constants which are closer
45 * to the end of the list and
46 * beginning of the list,
47 * respectively
48 *
49 * <policy> is one of following:
50 * "discard", "none", "ipsec <requests>", "entrust", "bypass",
51 *
52 * The following requests are accepted as <requests>:
53 *
54 * protocol/mode/src-dst/level
55 * protocol/mode/src-dst parsed as protocol/mode/src-dst/default
56 * protocol/mode/src-dst/ parsed as protocol/mode/src-dst/default
57 * protocol/transport parsed as protocol/mode/any-any/default
58 * protocol/transport//level parsed as protocol/mode/any-any/level
59 *
60 * You can concatenate these requests with either ' '(single space) or '\n'.
61 */
62
63%{
64#ifdef HAVE_CONFIG_H
65#include "config.h"
66#endif
67
68#include <sys/types.h>
69#include <sys/param.h>
70#include <sys/socket.h>
71
72#include <netinet/in.h>
73#ifdef HAVE_NETINET6_IPSEC
74# include <netinet6/ipsec.h>
75#else
76# include <netinet/ipsec.h>
77#endif
78
79#include <stdlib.h>
80#include <stdio.h>
81#include <string.h>
82#include <netdb.h>
83
84#include <errno.h>
85
86#include "config.h"
85f41bec 87#include "var.h"
52b7d2ce
A
88#include "ipsec_strerror.h"
89#include "libpfkey.h"
90
91#ifndef INT32_MAX
92#define INT32_MAX (0xffffffff)
93#endif
94
95#ifndef INT32_MIN
96#define INT32_MIN (-INT32_MAX-1)
97#endif
98
99#define ATOX(c) \
100 (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
101
102static u_int8_t *pbuf = NULL; /* sadb_x_policy buffer */
103static int tlen = 0; /* total length of pbuf */
104static int offset = 0; /* offset of pbuf */
105static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid;
106static u_int32_t p_priority = 0;
107static long p_priority_offset = 0;
85f41bec
A
108static struct sockaddr_storage *p_src = NULL;
109static struct sockaddr_storage *p_dst = NULL;
52b7d2ce
A
110
111struct _val;
112extern void yyerror __P((char *msg));
85f41bec 113static struct sockaddr_storage *parse_sockaddr __P((struct _val *addrbuf,
52b7d2ce
A
114 struct _val *portbuf));
115static int rule_check __P((void));
116static int init_x_policy __P((void));
85f41bec
A
117static int set_x_request __P((struct sockaddr_storage *, struct sockaddr_storage *));
118static int set_sockaddr __P((struct sockaddr_storage *));
52b7d2ce
A
119static void policy_parse_request_init __P((void));
120static void *policy_parse __P((const char *, int));
121
122extern void __policy__strbuffer__init__ __P((const char *));
123extern void __policy__strbuffer__free__ __P((void));
124extern int yyparse __P((void));
125extern int yylex __P((void));
126
127extern char *__libipsectext; /*XXX*/
128
129%}
130
131%union {
132 u_int num;
133 u_int32_t num32;
134 struct _val {
135 int len;
136 char *buf;
137 } val;
138}
139
140%token DIR
141%token PRIORITY PLUS
142%token <num32> PRIO_BASE
143%token <val> PRIO_OFFSET
144%token ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY IPADDRESS PORT
145%token ME ANY
146%token SLASH HYPHEN
147%type <num> DIR PRIORITY ACTION PROTOCOL MODE LEVEL
148%type <val> IPADDRESS LEVEL_SPECIFY PORT
149
150%%
151policy_spec
152 : DIR ACTION
153 {
154 p_dir = $1;
155 p_type = $2;
156
157#ifdef HAVE_PFKEY_POLICY_PRIORITY
158 p_priority = PRIORITY_DEFAULT;
159#else
160 p_priority = 0;
161#endif
162
163 if (init_x_policy())
164 return -1;
165 }
166 rules
167 | DIR PRIORITY PRIO_OFFSET ACTION
168 {
169 char *offset_buf;
170
171 p_dir = $1;
172 p_type = $4;
173
174 /* buffer big enough to hold a prepended negative sign */
175 offset_buf = malloc($3.len + 2);
176 if (offset_buf == NULL)
177 {
178 __ipsec_errcode = EIPSEC_NO_BUFS;
179 return -1;
180 }
181
182 /* positive input value means higher priority, therefore lower
183 actual value so that is closer to the beginning of the list */
184 snprintf (offset_buf, $3.len + 2, "-%s", $3.buf);
185
186 errno = 0;
187 p_priority_offset = atol(offset_buf);
188
189 free(offset_buf);
190
191 if (errno != 0 || p_priority_offset < INT32_MIN)
192 {
193 __ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET;
194 return -1;
195 }
196
197 p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset;
198
199 if (init_x_policy())
200 return -1;
201 }
202 rules
203 | DIR PRIORITY HYPHEN PRIO_OFFSET ACTION
204 {
205 p_dir = $1;
206 p_type = $5;
207
208 errno = 0;
209 p_priority_offset = atol($4.buf);
210
211 if (errno != 0 || p_priority_offset > INT32_MAX)
212 {
213 __ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET;
214 return -1;
215 }
216
217 /* negative input value means lower priority, therefore higher
218 actual value so that is closer to the end of the list */
219 p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset;
220
221 if (init_x_policy())
222 return -1;
223 }
224 rules
225 | DIR PRIORITY PRIO_BASE ACTION
226 {
227 p_dir = $1;
228 p_type = $4;
229
230 p_priority = $3;
231
232 if (init_x_policy())
233 return -1;
234 }
235 rules
236 | DIR PRIORITY PRIO_BASE PLUS PRIO_OFFSET ACTION
237 {
238 p_dir = $1;
239 p_type = $6;
240
241 errno = 0;
242 p_priority_offset = atol($5.buf);
243
244 if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_NEGATIVE_MAX)
245 {
246 __ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET;
247 return -1;
248 }
249
250 /* adding value means higher priority, therefore lower
251 actual value so that is closer to the beginning of the list */
252 p_priority = $3 - (u_int32_t) p_priority_offset;
253
254 if (init_x_policy())
255 return -1;
256 }
257 rules
258 | DIR PRIORITY PRIO_BASE HYPHEN PRIO_OFFSET ACTION
259 {
260 p_dir = $1;
261 p_type = $6;
262
263 errno = 0;
264 p_priority_offset = atol($5.buf);
265
266 if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_POSITIVE_MAX)
267 {
268 __ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET;
269 return -1;
270 }
271
272 /* subtracting value means lower priority, therefore higher
273 actual value so that is closer to the end of the list */
274 p_priority = $3 + (u_int32_t) p_priority_offset;
275
276 if (init_x_policy())
277 return -1;
278 }
279 rules
280 | DIR
281 {
282 p_dir = $1;
283 p_type = 0; /* ignored it by kernel */
284
285 p_priority = 0;
286
287 if (init_x_policy())
288 return -1;
289 }
290 ;
291
292rules
293 : /*NOTHING*/
294 | rules rule {
295 if (rule_check() < 0)
296 return -1;
297
298 if (set_x_request(p_src, p_dst) < 0)
299 return -1;
300
301 policy_parse_request_init();
302 }
303 ;
304
305rule
306 : protocol SLASH mode SLASH addresses SLASH level
307 | protocol SLASH mode SLASH addresses SLASH
308 | protocol SLASH mode SLASH addresses
309 | protocol SLASH mode SLASH
310 | protocol SLASH mode SLASH SLASH level
311 | protocol SLASH mode
312 | protocol SLASH {
313 __ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
314 return -1;
315 }
316 | protocol {
317 __ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
318 return -1;
319 }
320 ;
321
322protocol
323 : PROTOCOL { p_protocol = $1; }
324 ;
325
326mode
327 : MODE { p_mode = $1; }
328 ;
329
330level
331 : LEVEL {
332 p_level = $1;
333 p_reqid = 0;
334 }
335 | LEVEL_SPECIFY {
336 p_level = IPSEC_LEVEL_UNIQUE;
337 p_reqid = atol($1.buf); /* atol() is good. */
338 }
339 ;
340
341addresses
342 : IPADDRESS {
343 p_src = parse_sockaddr(&$1, NULL);
344 if (p_src == NULL)
345 return -1;
346 }
347 HYPHEN
348 IPADDRESS {
349 p_dst = parse_sockaddr(&$4, NULL);
350 if (p_dst == NULL)
351 return -1;
352 }
353 | IPADDRESS PORT {
354 p_src = parse_sockaddr(&$1, &$2);
355 if (p_src == NULL)
356 return -1;
357 }
358 HYPHEN
359 IPADDRESS PORT {
360 p_dst = parse_sockaddr(&$5, &$6);
361 if (p_dst == NULL)
362 return -1;
363 }
364 | ME HYPHEN ANY {
365 if (p_dir != IPSEC_DIR_OUTBOUND) {
366 __ipsec_errcode = EIPSEC_INVAL_DIR;
367 return -1;
368 }
369 }
370 | ANY HYPHEN ME {
371 if (p_dir != IPSEC_DIR_INBOUND) {
372 __ipsec_errcode = EIPSEC_INVAL_DIR;
373 return -1;
374 }
375 }
376 /*
377 | ME HYPHEN ME
378 */
379 ;
380
381%%
382
383void
384yyerror(msg)
385 char *msg;
386{
387 fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
388 msg, __libipsectext);
389
390 return;
391}
392
85f41bec 393static struct sockaddr_storage *
52b7d2ce
A
394parse_sockaddr(addrbuf, portbuf)
395 struct _val *addrbuf;
396 struct _val *portbuf;
397{
398 struct addrinfo hints, *res;
399 char *addr;
400 char *serv = NULL;
401 int error;
85f41bec 402 struct sockaddr_storage *newaddr = NULL;
d1e348cf
A
403 int addr_len;
404 int serv_len;
52b7d2ce 405
d1e348cf
A
406 addr_len = addrbuf->len + 1;
407 if ((addr = malloc(addr_len)) == NULL) {
52b7d2ce
A
408 yyerror("malloc failed");
409 __ipsec_set_strerror(strerror(errno));
410 return NULL;
411 }
d1e348cf
A
412
413 if (portbuf) {
414 serv_len = portbuf->len + 1;
415 if ((serv = malloc(serv_len)) == NULL) {
416 free(addr);
417 yyerror("malloc failed");
418 __ipsec_set_strerror(strerror(errno));
419 return NULL;
420 }
52b7d2ce
A
421 }
422
d1e348cf 423 strlcpy(addr, addrbuf->buf, addr_len);
52b7d2ce
A
424
425 if (portbuf) {
d1e348cf 426 strlcpy(serv, portbuf->buf, serv_len);
52b7d2ce
A
427 }
428
429 memset(&hints, 0, sizeof(hints));
430 hints.ai_family = PF_UNSPEC;
431 hints.ai_flags = AI_NUMERICHOST;
432 hints.ai_socktype = SOCK_DGRAM;
433 error = getaddrinfo(addr, serv, &hints, &res);
434 free(addr);
435 if (serv != NULL)
436 free(serv);
437 if (error != 0) {
438 yyerror("invalid IP address");
439 __ipsec_set_strerror(gai_strerror(error));
440 return NULL;
441 }
442
443 if (res->ai_addr == NULL) {
444 yyerror("invalid IP address");
445 __ipsec_set_strerror(gai_strerror(error));
446 return NULL;
447 }
448
449 newaddr = malloc(res->ai_addrlen);
450 if (newaddr == NULL) {
451 __ipsec_errcode = EIPSEC_NO_BUFS;
452 freeaddrinfo(res);
453 return NULL;
454 }
455 memcpy(newaddr, res->ai_addr, res->ai_addrlen);
456
457 freeaddrinfo(res);
458
459 __ipsec_errcode = EIPSEC_NO_ERROR;
460 return newaddr;
461}
462
463static int
464rule_check()
465{
466 if (p_type == IPSEC_POLICY_IPSEC) {
467 if (p_protocol == IPPROTO_IP) {
468 __ipsec_errcode = EIPSEC_NO_PROTO;
469 return -1;
470 }
471
472 if (p_mode != IPSEC_MODE_TRANSPORT
473 && p_mode != IPSEC_MODE_TUNNEL) {
474 __ipsec_errcode = EIPSEC_INVAL_MODE;
475 return -1;
476 }
477
478 if (p_src == NULL && p_dst == NULL) {
479 if (p_mode != IPSEC_MODE_TRANSPORT) {
480 __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
481 return -1;
482 }
483 }
85f41bec 484 else if (p_src->ss_family != p_dst->ss_family) {
52b7d2ce
A
485 __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
486 return -1;
487 }
488 }
489
490 __ipsec_errcode = EIPSEC_NO_ERROR;
491 return 0;
492}
493
494static int
495init_x_policy()
496{
497 struct sadb_x_policy *p;
498
499 if (pbuf) {
500 free(pbuf);
501 tlen = 0;
502 }
503 pbuf = malloc(sizeof(struct sadb_x_policy));
504 if (pbuf == NULL) {
505 __ipsec_errcode = EIPSEC_NO_BUFS;
506 return -1;
507 }
508 tlen = sizeof(struct sadb_x_policy);
509
510 memset(pbuf, 0, tlen);
85f41bec 511 p = ALIGNED_CAST(struct sadb_x_policy *)pbuf;
52b7d2ce
A
512 p->sadb_x_policy_len = 0; /* must update later */
513 p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
514 p->sadb_x_policy_type = p_type;
515 p->sadb_x_policy_dir = p_dir;
516 p->sadb_x_policy_id = 0;
517#ifdef HAVE_PFKEY_POLICY_PRIORITY
518 p->sadb_x_policy_priority = p_priority;
519#else
520 /* fail if given a priority and libipsec was not compiled with
521 priority support */
522 if (p_priority != 0)
523 {
524 __ipsec_errcode = EIPSEC_PRIORITY_NOT_COMPILED;
525 return -1;
526 }
527#endif
528
529 offset = tlen;
530
531 __ipsec_errcode = EIPSEC_NO_ERROR;
532 return 0;
533}
534
535static int
536set_x_request(src, dst)
85f41bec 537 struct sockaddr_storage *src, *dst;
52b7d2ce
A
538{
539 struct sadb_x_ipsecrequest *p;
540 int reqlen;
541 u_int8_t *n;
542
543 reqlen = sizeof(*p)
85f41bec
A
544 + (src ? sysdep_sa_len((struct sockaddr *)src) : 0)
545 + (dst ? sysdep_sa_len((struct sockaddr *)dst) : 0);
52b7d2ce
A
546 tlen += reqlen; /* increment to total length */
547
548 n = realloc(pbuf, tlen);
549 if (n == NULL) {
550 __ipsec_errcode = EIPSEC_NO_BUFS;
551 return -1;
552 }
553 pbuf = n;
554
85f41bec 555 p = ALIGNED_CAST(struct sadb_x_ipsecrequest *)&pbuf[offset]; // Wcast-align fix - malloc'd buffer/offset 64 bit multiple
52b7d2ce
A
556 p->sadb_x_ipsecrequest_len = reqlen;
557 p->sadb_x_ipsecrequest_proto = p_protocol;
558 p->sadb_x_ipsecrequest_mode = p_mode;
559 p->sadb_x_ipsecrequest_level = p_level;
560 p->sadb_x_ipsecrequest_reqid = p_reqid;
561 offset += sizeof(*p);
562
563 if (set_sockaddr(src) || set_sockaddr(dst))
564 return -1;
565
566 __ipsec_errcode = EIPSEC_NO_ERROR;
567 return 0;
568}
569
570static int
571set_sockaddr(addr)
85f41bec 572 struct sockaddr_storage *addr;
52b7d2ce
A
573{
574 if (addr == NULL) {
575 __ipsec_errcode = EIPSEC_NO_ERROR;
576 return 0;
577 }
578
579 /* tlen has already incremented */
580
85f41bec 581 memcpy(&pbuf[offset], addr, sysdep_sa_len((struct sockaddr *)addr));
52b7d2ce 582
85f41bec 583 offset += sysdep_sa_len((struct sockaddr *)addr);
52b7d2ce
A
584
585 __ipsec_errcode = EIPSEC_NO_ERROR;
586 return 0;
587}
588
589static void
590policy_parse_request_init()
591{
592 p_protocol = IPPROTO_IP;
593 p_mode = IPSEC_MODE_ANY;
594 p_level = IPSEC_LEVEL_DEFAULT;
595 p_reqid = 0;
596 if (p_src != NULL) {
597 free(p_src);
598 p_src = NULL;
599 }
600 if (p_dst != NULL) {
601 free(p_dst);
602 p_dst = NULL;
603 }
604
605 return;
606}
607
608static void *
609policy_parse(msg, msglen)
610 const char *msg;
611 int msglen;
612{
613 int error;
614
615 pbuf = NULL;
616 tlen = 0;
617
618 /* initialize */
619 p_dir = IPSEC_DIR_INVALID;
620 p_type = IPSEC_POLICY_DISCARD;
621 policy_parse_request_init();
622 __policy__strbuffer__init__(msg);
623
624 error = yyparse(); /* it must be set errcode. */
625 __policy__strbuffer__free__();
626
627 if (error) {
628 if (pbuf != NULL)
629 free(pbuf);
630 return NULL;
631 }
632
633 /* update total length */
85f41bec 634 (ALIGNED_CAST(struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
52b7d2ce
A
635
636 __ipsec_errcode = EIPSEC_NO_ERROR;
637
638 return pbuf;
639}
640
641ipsec_policy_t
642ipsec_set_policy(msg, msglen)
643 __ipsec_const char *msg;
644 int msglen;
645{
646 caddr_t policy;
647
648 policy = policy_parse(msg, msglen);
649 if (policy == NULL) {
650 if (__ipsec_errcode == EIPSEC_NO_ERROR)
651 __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
652 return NULL;
653 }
654
655 __ipsec_errcode = EIPSEC_NO_ERROR;
656 return policy;
657}