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 }
635