Home | History | Annotate | Download | only in libipsec
      1 /*	$NetBSD: policy_parse.y,v 1.9.6.2 2009/02/16 18:38:26 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