xref: /netbsd-src/crypto/dist/ipsec-tools/src/libipsec/policy_parse.y (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: policy_parse.y,v 1.10 2007/07/18 12:07:50 vanhu 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 			char *offset_buf;
168 
169 			p_dir = $1;
170 			p_type = $4;
171 
172 			/* buffer big enough to hold a prepended negative sign */
173 			offset_buf = malloc($3.len + 2);
174 			if (offset_buf == NULL)
175 			{
176 				__ipsec_errcode = EIPSEC_NO_BUFS;
177 				return -1;
178 			}
179 
180 			/* positive input value means higher priority, therefore lower
181 			   actual value so that is closer to the beginning of the list */
182 			sprintf (offset_buf, "-%s", $3.buf);
183 
184 			errno = 0;
185 			p_priority_offset = atol(offset_buf);
186 
187 			free(offset_buf);
188 
189 			if (errno != 0 || p_priority_offset < INT32_MIN)
190 			{
191 				__ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET;
192 				return -1;
193 			}
194 
195 			p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset;
196 
197 			if (init_x_policy())
198 				return -1;
199 		}
200 		rules
201 	|	DIR PRIORITY HYPHEN PRIO_OFFSET ACTION
202 		{
203 			p_dir = $1;
204 			p_type = $5;
205 
206 			errno = 0;
207 			p_priority_offset = atol($4.buf);
208 
209 			if (errno != 0 || p_priority_offset > INT32_MAX)
210 			{
211 				__ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET;
212 				return -1;
213 			}
214 
215 			/* negative input value means lower priority, therefore higher
216 			   actual value so that is closer to the end of the list */
217 			p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset;
218 
219 			if (init_x_policy())
220 				return -1;
221 		}
222 		rules
223 	|	DIR PRIORITY PRIO_BASE ACTION
224 		{
225 			p_dir = $1;
226 			p_type = $4;
227 
228 			p_priority = $3;
229 
230 			if (init_x_policy())
231 				return -1;
232 		}
233 		rules
234 	|	DIR PRIORITY PRIO_BASE PLUS PRIO_OFFSET ACTION
235 		{
236 			p_dir = $1;
237 			p_type = $6;
238 
239 			errno = 0;
240 			p_priority_offset = atol($5.buf);
241 
242 			if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_NEGATIVE_MAX)
243 			{
244 				__ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET;
245 				return -1;
246 			}
247 
248 			/* adding value means higher priority, therefore lower
249 			   actual value so that is closer to the beginning of the list */
250 			p_priority = $3 - (u_int32_t) p_priority_offset;
251 
252 			if (init_x_policy())
253 				return -1;
254 		}
255 		rules
256 	|	DIR PRIORITY PRIO_BASE HYPHEN PRIO_OFFSET ACTION
257 		{
258 			p_dir = $1;
259 			p_type = $6;
260 
261 			errno = 0;
262 			p_priority_offset = atol($5.buf);
263 
264 			if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_POSITIVE_MAX)
265 			{
266 				__ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET;
267 				return -1;
268 			}
269 
270 			/* subtracting value means lower priority, therefore higher
271 			   actual value so that is closer to the end of the list */
272 			p_priority = $3 + (u_int32_t) p_priority_offset;
273 
274 			if (init_x_policy())
275 				return -1;
276 		}
277 		rules
278 	|	DIR
279 		{
280 			p_dir = $1;
281 			p_type = 0;	/* ignored it by kernel */
282 
283 			p_priority = 0;
284 
285 			if (init_x_policy())
286 				return -1;
287 		}
288 	;
289 
290 rules
291 	:	/*NOTHING*/
292 	|	rules rule {
293 			if (rule_check() < 0)
294 				return -1;
295 
296 			if (set_x_request(p_src, p_dst) < 0)
297 				return -1;
298 
299 			policy_parse_request_init();
300 		}
301 	;
302 
303 rule
304 	:	protocol SLASH mode SLASH addresses SLASH level
305 	|	protocol SLASH mode SLASH addresses SLASH
306 	|	protocol SLASH mode SLASH addresses
307 	|	protocol SLASH mode SLASH
308 	|	protocol SLASH mode SLASH SLASH level
309 	|	protocol SLASH mode
310 	|	protocol SLASH {
311 			__ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
312 			return -1;
313 		}
314 	|	protocol {
315 			__ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
316 			return -1;
317 		}
318 	;
319 
320 protocol
321 	:	PROTOCOL { p_protocol = $1; }
322 	;
323 
324 mode
325 	:	MODE { p_mode = $1; }
326 	;
327 
328 level
329 	:	LEVEL {
330 			p_level = $1;
331 			p_reqid = 0;
332 		}
333 	|	LEVEL_SPECIFY {
334 			p_level = IPSEC_LEVEL_UNIQUE;
335 			p_reqid = atol($1.buf);	/* atol() is good. */
336 		}
337 	;
338 
339 addresses
340 	:	IPADDRESS {
341 			p_src = parse_sockaddr(&$1, NULL);
342 			if (p_src == NULL)
343 				return -1;
344 		}
345 		HYPHEN
346 		IPADDRESS {
347 			p_dst = parse_sockaddr(&$4, NULL);
348 			if (p_dst == NULL)
349 				return -1;
350 		}
351 	|	IPADDRESS PORT {
352 			p_src = parse_sockaddr(&$1, &$2);
353 			if (p_src == NULL)
354 				return -1;
355 		}
356 		HYPHEN
357 		IPADDRESS PORT {
358 			p_dst = parse_sockaddr(&$5, &$6);
359 			if (p_dst == NULL)
360 				return -1;
361 		}
362 	|	ME HYPHEN ANY {
363 			if (p_dir != IPSEC_DIR_OUTBOUND) {
364 				__ipsec_errcode = EIPSEC_INVAL_DIR;
365 				return -1;
366 			}
367 		}
368 	|	ANY HYPHEN ME {
369 			if (p_dir != IPSEC_DIR_INBOUND) {
370 				__ipsec_errcode = EIPSEC_INVAL_DIR;
371 				return -1;
372 			}
373 		}
374 		/*
375 	|	ME HYPHEN ME
376 		*/
377 	;
378 
379 %%
380 
381 void
382 yyerror(msg)
383 	char *msg;
384 {
385 	fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
386 		msg, __libipsectext);
387 
388 	return;
389 }
390 
391 static struct sockaddr *
392 parse_sockaddr(addrbuf, portbuf)
393 	struct _val *addrbuf;
394 	struct _val *portbuf;
395 {
396 	struct addrinfo hints, *res;
397 	char *addr;
398 	char *serv = NULL;
399 	int error;
400 	struct sockaddr *newaddr = NULL;
401 
402 	if ((addr = malloc(addrbuf->len + 1)) == NULL) {
403 		yyerror("malloc failed");
404 		__ipsec_set_strerror(strerror(errno));
405 		return NULL;
406 	}
407 
408 	if (portbuf && ((serv = malloc(portbuf->len + 1)) == NULL)) {
409 		free(addr);
410 		yyerror("malloc failed");
411 		__ipsec_set_strerror(strerror(errno));
412 		return NULL;
413 	}
414 
415 	strncpy(addr, addrbuf->buf, addrbuf->len);
416 	addr[addrbuf->len] = '\0';
417 
418 	if (portbuf) {
419 		strncpy(serv, portbuf->buf, portbuf->len);
420 		serv[portbuf->len] = '\0';
421 	}
422 
423 	memset(&hints, 0, sizeof(hints));
424 	hints.ai_family = PF_UNSPEC;
425 	hints.ai_flags = AI_NUMERICHOST;
426 	hints.ai_socktype = SOCK_DGRAM;
427 	error = getaddrinfo(addr, serv, &hints, &res);
428 	free(addr);
429 	if (serv != NULL)
430 		free(serv);
431 	if (error != 0) {
432 		yyerror("invalid IP address");
433 		__ipsec_set_strerror(gai_strerror(error));
434 		return NULL;
435 	}
436 
437 	if (res->ai_addr == NULL) {
438 		yyerror("invalid IP address");
439 		__ipsec_set_strerror(gai_strerror(error));
440 		return NULL;
441 	}
442 
443 	newaddr = malloc(res->ai_addrlen);
444 	if (newaddr == NULL) {
445 		__ipsec_errcode = EIPSEC_NO_BUFS;
446 		freeaddrinfo(res);
447 		return NULL;
448 	}
449 	memcpy(newaddr, res->ai_addr, res->ai_addrlen);
450 
451 	freeaddrinfo(res);
452 
453 	__ipsec_errcode = EIPSEC_NO_ERROR;
454 	return newaddr;
455 }
456 
457 static int
458 rule_check()
459 {
460 	if (p_type == IPSEC_POLICY_IPSEC) {
461 		if (p_protocol == IPPROTO_IP) {
462 			__ipsec_errcode = EIPSEC_NO_PROTO;
463 			return -1;
464 		}
465 
466 		if (p_mode != IPSEC_MODE_TRANSPORT
467 		 && p_mode != IPSEC_MODE_TUNNEL) {
468 			__ipsec_errcode = EIPSEC_INVAL_MODE;
469 			return -1;
470 		}
471 
472 		if (p_src == NULL && p_dst == NULL) {
473 			 if (p_mode != IPSEC_MODE_TRANSPORT) {
474 				__ipsec_errcode = EIPSEC_INVAL_ADDRESS;
475 				return -1;
476 			}
477 		}
478 		else if (p_src->sa_family != p_dst->sa_family) {
479 			__ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
480 			return -1;
481 		}
482 	}
483 
484 	__ipsec_errcode = EIPSEC_NO_ERROR;
485 	return 0;
486 }
487 
488 static int
489 init_x_policy()
490 {
491 	struct sadb_x_policy *p;
492 
493 	if (pbuf) {
494 		free(pbuf);
495 		tlen = 0;
496 	}
497 	pbuf = malloc(sizeof(struct sadb_x_policy));
498 	if (pbuf == NULL) {
499 		__ipsec_errcode = EIPSEC_NO_BUFS;
500 		return -1;
501 	}
502 	tlen = sizeof(struct sadb_x_policy);
503 
504 	memset(pbuf, 0, tlen);
505 	p = (struct sadb_x_policy *)pbuf;
506 	p->sadb_x_policy_len = 0;	/* must update later */
507 	p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
508 	p->sadb_x_policy_type = p_type;
509 	p->sadb_x_policy_dir = p_dir;
510 	p->sadb_x_policy_id = 0;
511 #ifdef HAVE_PFKEY_POLICY_PRIORITY
512 	p->sadb_x_policy_priority = p_priority;
513 #else
514     /* fail if given a priority and libipsec was not compiled with
515 	   priority support */
516 	if (p_priority != 0)
517 	{
518 		__ipsec_errcode = EIPSEC_PRIORITY_NOT_COMPILED;
519 		return -1;
520 	}
521 #endif
522 
523 	offset = tlen;
524 
525 	__ipsec_errcode = EIPSEC_NO_ERROR;
526 	return 0;
527 }
528 
529 static int
530 set_x_request(src, dst)
531 	struct sockaddr *src, *dst;
532 {
533 	struct sadb_x_ipsecrequest *p;
534 	int reqlen;
535 	u_int8_t *n;
536 
537 	reqlen = sizeof(*p)
538 		+ (src ? sysdep_sa_len(src) : 0)
539 		+ (dst ? sysdep_sa_len(dst) : 0);
540 	tlen += reqlen;		/* increment to total length */
541 
542 	n = realloc(pbuf, tlen);
543 	if (n == NULL) {
544 		__ipsec_errcode = EIPSEC_NO_BUFS;
545 		return -1;
546 	}
547 	pbuf = n;
548 
549 	p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
550 	p->sadb_x_ipsecrequest_len = reqlen;
551 	p->sadb_x_ipsecrequest_proto = p_protocol;
552 	p->sadb_x_ipsecrequest_mode = p_mode;
553 	p->sadb_x_ipsecrequest_level = p_level;
554 	p->sadb_x_ipsecrequest_reqid = p_reqid;
555 	offset += sizeof(*p);
556 
557 	if (set_sockaddr(src) || set_sockaddr(dst))
558 		return -1;
559 
560 	__ipsec_errcode = EIPSEC_NO_ERROR;
561 	return 0;
562 }
563 
564 static int
565 set_sockaddr(addr)
566 	struct sockaddr *addr;
567 {
568 	if (addr == NULL) {
569 		__ipsec_errcode = EIPSEC_NO_ERROR;
570 		return 0;
571 	}
572 
573 	/* tlen has already incremented */
574 
575 	memcpy(&pbuf[offset], addr, sysdep_sa_len(addr));
576 
577 	offset += sysdep_sa_len(addr);
578 
579 	__ipsec_errcode = EIPSEC_NO_ERROR;
580 	return 0;
581 }
582 
583 static void
584 policy_parse_request_init()
585 {
586 	p_protocol = IPPROTO_IP;
587 	p_mode = IPSEC_MODE_ANY;
588 	p_level = IPSEC_LEVEL_DEFAULT;
589 	p_reqid = 0;
590 	if (p_src != NULL) {
591 		free(p_src);
592 		p_src = NULL;
593 	}
594 	if (p_dst != NULL) {
595 		free(p_dst);
596 		p_dst = NULL;
597 	}
598 
599 	return;
600 }
601 
602 static void *
603 policy_parse(msg, msglen)
604 	const char *msg;
605 	int msglen;
606 {
607 	int error;
608 
609 	pbuf = NULL;
610 	tlen = 0;
611 
612 	/* initialize */
613 	p_dir = IPSEC_DIR_INVALID;
614 	p_type = IPSEC_POLICY_DISCARD;
615 	policy_parse_request_init();
616 	__policy__strbuffer__init__(msg);
617 
618 	error = yyparse();	/* it must be set errcode. */
619 	__policy__strbuffer__free__();
620 
621 	if (error) {
622 		if (pbuf != NULL)
623 			free(pbuf);
624 		return NULL;
625 	}
626 
627 	/* update total length */
628 	((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
629 
630 	__ipsec_errcode = EIPSEC_NO_ERROR;
631 
632 	return pbuf;
633 }
634 
635 ipsec_policy_t
636 ipsec_set_policy(msg, msglen)
637 	__ipsec_const char *msg;
638 	int msglen;
639 {
640 	caddr_t policy;
641 
642 	policy = policy_parse(msg, msglen);
643 	if (policy == NULL) {
644 		if (__ipsec_errcode == EIPSEC_NO_ERROR)
645 			__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
646 		return NULL;
647 	}
648 
649 	__ipsec_errcode = EIPSEC_NO_ERROR;
650 	return policy;
651 }
652