policy_parse.y revision 122107
1122107Sume/*	$KAME: policy_parse.y,v 1.14 2003/06/27 03:39:20 itojun Exp $	*/
262583Sitojun
355505Sshin/*
455505Sshin * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
555505Sshin * All rights reserved.
655505Sshin *
755505Sshin * Redistribution and use in source and binary forms, with or without
855505Sshin * modification, are permitted provided that the following conditions
955505Sshin * are met:
1055505Sshin * 1. Redistributions of source code must retain the above copyright
1155505Sshin *    notice, this list of conditions and the following disclaimer.
1255505Sshin * 2. Redistributions in binary form must reproduce the above copyright
1355505Sshin *    notice, this list of conditions and the following disclaimer in the
1455505Sshin *    documentation and/or other materials provided with the distribution.
1555505Sshin * 3. Neither the name of the project nor the names of its contributors
1655505Sshin *    may be used to endorse or promote products derived from this software
1755505Sshin *    without specific prior written permission.
1855505Sshin *
1955505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2055505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2155505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2255505Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2355505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2455505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2555505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2655505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2755505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2855505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2955505Sshin * SUCH DAMAGE.
3055505Sshin */
3155505Sshin
3255505Sshin/*
3355505Sshin * IN/OUT bound policy configuration take place such below:
3455505Sshin *	in <policy>
3555505Sshin *	out <policy>
3655505Sshin *
3755505Sshin * <policy> is one of following:
3855505Sshin *	"discard", "none", "ipsec <requests>", "entrust", "bypass",
3955505Sshin *
4055505Sshin * The following requests are accepted as <requests>:
4155505Sshin *
4255505Sshin *	protocol/mode/src-dst/level
4355505Sshin *	protocol/mode/src-dst		parsed as protocol/mode/src-dst/default
4455505Sshin *	protocol/mode/src-dst/		parsed as protocol/mode/src-dst/default
4555505Sshin *	protocol/transport		parsed as protocol/mode/any-any/default
4655505Sshin *	protocol/transport//level	parsed as protocol/mode/any-any/level
4755505Sshin *
4855505Sshin * You can concatenate these requests with either ' '(single space) or '\n'.
4955505Sshin */
5055505Sshin
5155505Sshin%{
52122107Sume#include <sys/cdefs.h>
53122107Sume__FBSDID("$FreeBSD: head/lib/libipsec/policy_parse.y 122107 2003-11-05 09:41:23Z ume $");
54122107Sume
5555505Sshin#include <sys/types.h>
5655505Sshin#include <sys/param.h>
5755505Sshin#include <sys/socket.h>
5855505Sshin
5955505Sshin#include <netinet/in.h>
6055505Sshin#include <netinet6/ipsec.h>
6155505Sshin
6255505Sshin#include <stdlib.h>
6355505Sshin#include <stdio.h>
6455505Sshin#include <string.h>
6555505Sshin#include <netdb.h>
6655505Sshin
6755505Sshin#include "ipsec_strerror.h"
6855505Sshin
6962583Sitojun#define ATOX(c) \
7055505Sshin  (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
7155505Sshin
7255505Sshinstatic caddr_t pbuf = NULL;		/* sadb_x_policy buffer */
7355505Sshinstatic int tlen = 0;			/* total length of pbuf */
7455505Sshinstatic int offset = 0;			/* offset of pbuf */
7562583Sitojunstatic int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid;
7655505Sshinstatic struct sockaddr *p_src = NULL;
7755505Sshinstatic struct sockaddr *p_dst = NULL;
7855505Sshin
7962583Sitojunstruct _val;
8092917Sobrienextern void yyerror(char *msg);
8192917Sobrienstatic struct sockaddr *parse_sockaddr(struct _val *buf);
8292917Sobrienstatic int rule_check(void);
8392917Sobrienstatic int init_x_policy(void);
8492917Sobrienstatic int set_x_request(struct sockaddr *src, struct sockaddr *dst);
8592917Sobrienstatic int set_sockaddr(struct sockaddr *addr);
8692917Sobrienstatic void policy_parse_request_init(void);
8792917Sobrienstatic caddr_t policy_parse(char *msg, int msglen);
8855505Sshin
8992917Sobrienextern void __policy__strbuffer__init__(char *msg);
90122107Sumeextern void __policy__strbuffer__free__(void);
9192917Sobrienextern int yyparse(void);
9292917Sobrienextern int yylex(void);
9355505Sshin
94122107Sumeextern char *__libipsecyytext;	/*XXX*/
95122107Sume
9655505Sshin%}
9755505Sshin
9855505Sshin%union {
9955505Sshin	u_int num;
10055505Sshin	struct _val {
10155505Sshin		int len;
10255505Sshin		char *buf;
10355505Sshin	} val;
10455505Sshin}
10555505Sshin
10662583Sitojun%token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY
10755505Sshin%token IPADDRESS
10855505Sshin%token ME ANY
10955505Sshin%token SLASH HYPHEN
11055505Sshin%type <num> DIR ACTION PROTOCOL MODE LEVEL
11162583Sitojun%type <val> IPADDRESS LEVEL_SPECIFY
11255505Sshin
11355505Sshin%%
11455505Sshinpolicy_spec
11555505Sshin	:	DIR ACTION
11655505Sshin		{
11755505Sshin			p_dir = $1;
11855505Sshin			p_type = $2;
11955505Sshin
12055505Sshin			if (init_x_policy())
12155505Sshin				return -1;
12255505Sshin		}
12355505Sshin		rules
12462583Sitojun	|	DIR
12562583Sitojun		{
12662583Sitojun			p_dir = $1;
12762583Sitojun			p_type = 0;	/* ignored it by kernel */
12862583Sitojun
12962583Sitojun			if (init_x_policy())
13062583Sitojun				return -1;
13162583Sitojun		}
13255505Sshin	;
13355505Sshin
13455505Sshinrules
13555505Sshin	:	/*NOTHING*/
13655505Sshin	|	rules rule {
13755505Sshin			if (rule_check() < 0)
13855505Sshin				return -1;
13955505Sshin
14055505Sshin			if (set_x_request(p_src, p_dst) < 0)
14155505Sshin				return -1;
14255505Sshin
14355505Sshin			policy_parse_request_init();
14455505Sshin		}
14555505Sshin	;
14655505Sshin
14755505Sshinrule
14855505Sshin	:	protocol SLASH mode SLASH addresses SLASH level
14955505Sshin	|	protocol SLASH mode SLASH addresses SLASH
15055505Sshin	|	protocol SLASH mode SLASH addresses
15155505Sshin	|	protocol SLASH mode SLASH
15255505Sshin	|	protocol SLASH mode SLASH SLASH level
15355505Sshin	|	protocol SLASH mode
15455505Sshin	|	protocol SLASH {
15562583Sitojun			__ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
15655505Sshin			return -1;
15755505Sshin		}
15855505Sshin	|	protocol {
15962583Sitojun			__ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
16055505Sshin			return -1;
16155505Sshin		}
16255505Sshin	;
16355505Sshin
16455505Sshinprotocol
16555505Sshin	:	PROTOCOL { p_protocol = $1; }
16655505Sshin	;
16755505Sshin
16855505Sshinmode
16955505Sshin	:	MODE { p_mode = $1; }
17055505Sshin	;
17155505Sshin
17255505Sshinlevel
17362583Sitojun	:	LEVEL {
17462583Sitojun			p_level = $1;
17562583Sitojun			p_reqid = 0;
17662583Sitojun		}
17762583Sitojun	|	LEVEL_SPECIFY {
17862583Sitojun			p_level = IPSEC_LEVEL_UNIQUE;
17962583Sitojun			p_reqid = atol($1.buf);	/* atol() is good. */
18062583Sitojun		}
18155505Sshin	;
18255505Sshin
18355505Sshinaddresses
18455505Sshin	:	IPADDRESS {
18555505Sshin			p_src = parse_sockaddr(&$1);
18655505Sshin			if (p_src == NULL)
18755505Sshin				return -1;
18855505Sshin		}
18955505Sshin		HYPHEN
19055505Sshin		IPADDRESS {
19155505Sshin			p_dst = parse_sockaddr(&$4);
19255505Sshin			if (p_dst == NULL)
19355505Sshin				return -1;
19455505Sshin		}
19555505Sshin	|	ME HYPHEN ANY {
19655505Sshin			if (p_dir != IPSEC_DIR_OUTBOUND) {
19762583Sitojun				__ipsec_errcode = EIPSEC_INVAL_DIR;
19855505Sshin				return -1;
19955505Sshin			}
20055505Sshin		}
20155505Sshin	|	ANY HYPHEN ME {
20255505Sshin			if (p_dir != IPSEC_DIR_INBOUND) {
20362583Sitojun				__ipsec_errcode = EIPSEC_INVAL_DIR;
20455505Sshin				return -1;
20555505Sshin			}
20655505Sshin		}
20755505Sshin		/*
20855505Sshin	|	ME HYPHEN ME
20955505Sshin		*/
21055505Sshin	;
21155505Sshin
21255505Sshin%%
21355505Sshin
21455505Sshinvoid
21555505Sshinyyerror(msg)
21655505Sshin	char *msg;
21755505Sshin{
21862583Sitojun	fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
21962583Sitojun		msg, __libipsecyytext);
22062583Sitojun
22155505Sshin	return;
22255505Sshin}
22355505Sshin
22455505Sshinstatic struct sockaddr *
22555505Sshinparse_sockaddr(buf)
22655505Sshin	struct _val *buf;
22755505Sshin{
22855505Sshin	struct addrinfo hints, *res;
22955505Sshin	char *serv = NULL;
23055505Sshin	int error;
23155505Sshin	struct sockaddr *newaddr = NULL;
23255505Sshin
23355505Sshin	memset(&hints, 0, sizeof(hints));
23455505Sshin	hints.ai_family = PF_UNSPEC;
23555505Sshin	hints.ai_flags = AI_NUMERICHOST;
23655505Sshin	error = getaddrinfo(buf->buf, serv, &hints, &res);
23762583Sitojun	if (error != 0) {
23862583Sitojun		yyerror("invalid IP address");
23962583Sitojun		__ipsec_set_strerror(gai_strerror(error));
24055505Sshin		return NULL;
24155505Sshin	}
24255505Sshin
24355505Sshin	if (res->ai_addr == NULL) {
24462583Sitojun		yyerror("invalid IP address");
24562583Sitojun		__ipsec_set_strerror(gai_strerror(error));
24655505Sshin		return NULL;
24755505Sshin	}
24855505Sshin
24955505Sshin	newaddr = malloc(res->ai_addr->sa_len);
25055505Sshin	if (newaddr == NULL) {
25162583Sitojun		__ipsec_errcode = EIPSEC_NO_BUFS;
25255505Sshin		freeaddrinfo(res);
25355505Sshin		return NULL;
25455505Sshin	}
25555505Sshin	memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len);
25655505Sshin
25755505Sshin	freeaddrinfo(res);
25855505Sshin
25962583Sitojun	__ipsec_errcode = EIPSEC_NO_ERROR;
26055505Sshin	return newaddr;
26155505Sshin}
26255505Sshin
26355505Sshinstatic int
26455505Sshinrule_check()
26555505Sshin{
26655505Sshin	if (p_type == IPSEC_POLICY_IPSEC) {
26755505Sshin		if (p_protocol == IPPROTO_IP) {
26862583Sitojun			__ipsec_errcode = EIPSEC_NO_PROTO;
26955505Sshin			return -1;
27055505Sshin		}
27155505Sshin
27255505Sshin		if (p_mode != IPSEC_MODE_TRANSPORT
27355505Sshin		 && p_mode != IPSEC_MODE_TUNNEL) {
27462583Sitojun			__ipsec_errcode = EIPSEC_INVAL_MODE;
27555505Sshin			return -1;
27655505Sshin		}
27755505Sshin
27855505Sshin		if (p_src == NULL && p_dst == NULL) {
27955505Sshin			 if (p_mode != IPSEC_MODE_TRANSPORT) {
28062583Sitojun				__ipsec_errcode = EIPSEC_INVAL_ADDRESS;
28155505Sshin				return -1;
28255505Sshin			}
28355505Sshin		}
28455505Sshin		else if (p_src->sa_family != p_dst->sa_family) {
28562583Sitojun			__ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
28655505Sshin			return -1;
28755505Sshin		}
28855505Sshin	}
28955505Sshin
29062583Sitojun	__ipsec_errcode = EIPSEC_NO_ERROR;
29155505Sshin	return 0;
29255505Sshin}
29355505Sshin
29455505Sshinstatic int
29555505Sshininit_x_policy()
29655505Sshin{
29755505Sshin	struct sadb_x_policy *p;
29855505Sshin
29955505Sshin	tlen = sizeof(struct sadb_x_policy);
30055505Sshin
30155505Sshin	pbuf = malloc(tlen);
30255505Sshin	if (pbuf == NULL) {
30362583Sitojun		__ipsec_errcode = EIPSEC_NO_BUFS;
30455505Sshin		return -1;
30555505Sshin	}
306122107Sume	memset(pbuf, 0, tlen);
30755505Sshin	p = (struct sadb_x_policy *)pbuf;
30855505Sshin	p->sadb_x_policy_len = 0;	/* must update later */
30955505Sshin	p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
31055505Sshin	p->sadb_x_policy_type = p_type;
31155505Sshin	p->sadb_x_policy_dir = p_dir;
312122107Sume	p->sadb_x_policy_id = 0;
313122107Sume
31455505Sshin	offset = tlen;
31555505Sshin
31662583Sitojun	__ipsec_errcode = EIPSEC_NO_ERROR;
31755505Sshin	return 0;
31855505Sshin}
31955505Sshin
32055505Sshinstatic int
32155505Sshinset_x_request(src, dst)
32255505Sshin	struct sockaddr *src, *dst;
32355505Sshin{
32455505Sshin	struct sadb_x_ipsecrequest *p;
32555505Sshin	int reqlen;
32655505Sshin
32755505Sshin	reqlen = sizeof(*p)
32855505Sshin		+ (src ? src->sa_len : 0)
32955505Sshin		+ (dst ? dst->sa_len : 0);
33055505Sshin	tlen += reqlen;		/* increment to total length */
33155505Sshin
33255505Sshin	pbuf = realloc(pbuf, tlen);
33355505Sshin	if (pbuf == NULL) {
33462583Sitojun		__ipsec_errcode = EIPSEC_NO_BUFS;
33555505Sshin		return -1;
33655505Sshin	}
33755505Sshin	p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
33855505Sshin	p->sadb_x_ipsecrequest_len = reqlen;
33955505Sshin	p->sadb_x_ipsecrequest_proto = p_protocol;
34055505Sshin	p->sadb_x_ipsecrequest_mode = p_mode;
34155505Sshin	p->sadb_x_ipsecrequest_level = p_level;
34262583Sitojun	p->sadb_x_ipsecrequest_reqid = p_reqid;
34355505Sshin	offset += sizeof(*p);
34455505Sshin
34555505Sshin	if (set_sockaddr(src) || set_sockaddr(dst))
34655505Sshin		return -1;
34755505Sshin
34862583Sitojun	__ipsec_errcode = EIPSEC_NO_ERROR;
34955505Sshin	return 0;
35055505Sshin}
35155505Sshin
35255505Sshinstatic int
35355505Sshinset_sockaddr(addr)
35455505Sshin	struct sockaddr *addr;
35555505Sshin{
35655505Sshin	if (addr == NULL) {
35762583Sitojun		__ipsec_errcode = EIPSEC_NO_ERROR;
35855505Sshin		return 0;
35955505Sshin	}
36055505Sshin
36155505Sshin	/* tlen has already incremented */
36255505Sshin
36355505Sshin	memcpy(&pbuf[offset], addr, addr->sa_len);
36455505Sshin
36555505Sshin	offset += addr->sa_len;
36655505Sshin
36762583Sitojun	__ipsec_errcode = EIPSEC_NO_ERROR;
36855505Sshin	return 0;
36955505Sshin}
37055505Sshin
37155505Sshinstatic void
37255505Sshinpolicy_parse_request_init()
37355505Sshin{
37455505Sshin	p_protocol = IPPROTO_IP;
37555505Sshin	p_mode = IPSEC_MODE_ANY;
37655505Sshin	p_level = IPSEC_LEVEL_DEFAULT;
37762583Sitojun	p_reqid = 0;
37855505Sshin	if (p_src != NULL) {
37955505Sshin		free(p_src);
38055505Sshin		p_src = NULL;
38155505Sshin	}
38255505Sshin	if (p_dst != NULL) {
38355505Sshin		free(p_dst);
38455505Sshin		p_dst = NULL;
38555505Sshin	}
38655505Sshin
38755505Sshin	return;
38855505Sshin}
38955505Sshin
39055505Sshinstatic caddr_t
39155505Sshinpolicy_parse(msg, msglen)
39255505Sshin	char *msg;
39355505Sshin	int msglen;
39455505Sshin{
39555505Sshin	int error;
39655505Sshin	pbuf = NULL;
39755505Sshin	tlen = 0;
39855505Sshin
39955505Sshin	/* initialize */
40055505Sshin	p_dir = IPSEC_DIR_INVALID;
40155505Sshin	p_type = IPSEC_POLICY_DISCARD;
40255505Sshin	policy_parse_request_init();
40355505Sshin	__policy__strbuffer__init__(msg);
40455505Sshin
40555505Sshin	error = yyparse();	/* it must be set errcode. */
406122107Sume	__policy__strbuffer__free__();
407122107Sume
40855505Sshin	if (error) {
40955505Sshin		if (pbuf != NULL)
41055505Sshin			free(pbuf);
41155505Sshin		return NULL;
41255505Sshin	}
41355505Sshin
41455505Sshin	/* update total length */
41555505Sshin	((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
41655505Sshin
41762583Sitojun	__ipsec_errcode = EIPSEC_NO_ERROR;
41855505Sshin
41955505Sshin	return pbuf;
42055505Sshin}
42155505Sshin
42255505Sshincaddr_t
42355505Sshinipsec_set_policy(msg, msglen)
42455505Sshin	char *msg;
42555505Sshin	int msglen;
42655505Sshin{
42755505Sshin	caddr_t policy;
42855505Sshin
42955505Sshin	policy = policy_parse(msg, msglen);
43055505Sshin	if (policy == NULL) {
43162583Sitojun		if (__ipsec_errcode == EIPSEC_NO_ERROR)
43262583Sitojun			__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
43355505Sshin		return NULL;
43455505Sshin	}
43555505Sshin
43662583Sitojun	__ipsec_errcode = EIPSEC_NO_ERROR;
43755505Sshin	return policy;
43855505Sshin}
43955505Sshin
440