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