1/*	$KAME: policy_parse.y,v 1.14 2003/06/27 03:39:20 itojun Exp $	*/
2
3/*-
4 * SPDX-License-Identifier: BSD-3-Clause
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 <policy>
37 *	out <policy>
38 *
39 * <policy> is one of following:
40 *	"discard", "none", "ipsec <requests>", "entrust", "bypass",
41 *
42 * The following requests are accepted as <requests>:
43 *
44 *	protocol/mode/src-dst/level
45 *	protocol/mode/src-dst		parsed as protocol/mode/src-dst/default
46 *	protocol/mode/src-dst/		parsed as protocol/mode/src-dst/default
47 *	protocol/transport		parsed as protocol/mode/any-any/default
48 *	protocol/transport//level	parsed as protocol/mode/any-any/level
49 *
50 * You can concatenate these requests with either ' '(single space) or '\n'.
51 */
52
53%{
54#include <sys/cdefs.h>
55__FBSDID("$FreeBSD$");
56
57#include <sys/types.h>
58#include <sys/param.h>
59#include <sys/socket.h>
60
61#include <netinet/in.h>
62#include <netipsec/ipsec.h>
63
64#include <stdlib.h>
65#include <stdio.h>
66#include <string.h>
67#include <netdb.h>
68
69#include "ipsec_strerror.h"
70
71#define ATOX(c) \
72  (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
73
74static caddr_t pbuf = NULL;		/* sadb_x_policy buffer */
75static int tlen = 0;			/* total length of pbuf */
76static int offset = 0;			/* offset of pbuf */
77static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid;
78static struct sockaddr *p_src = NULL;
79static struct sockaddr *p_dst = NULL;
80
81struct _val;
82extern void yyerror(char *msg);
83static struct sockaddr *parse_sockaddr(struct _val *buf);
84static int rule_check(void);
85static int init_x_policy(void);
86static int set_x_request(struct sockaddr *src, struct sockaddr *dst);
87static int set_sockaddr(struct sockaddr *addr);
88static void policy_parse_request_init(void);
89static caddr_t policy_parse(char *msg, int msglen);
90
91extern void __policy__strbuffer__init__(char *msg);
92extern void __policy__strbuffer__free__(void);
93extern int yylex(void);
94
95extern char *__libipsecyytext;	/*XXX*/
96
97%}
98
99%union {
100	u_int num;
101	struct _val {
102		int len;
103		char *buf;
104	} val;
105}
106
107%token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY
108%token IPADDRESS
109%token ME ANY
110%token SLASH HYPHEN
111%type <num> DIR ACTION PROTOCOL MODE LEVEL
112%type <val> IPADDRESS LEVEL_SPECIFY
113
114%%
115policy_spec
116	:	DIR ACTION
117		{
118			p_dir = $1;
119			p_type = $2;
120
121			if (init_x_policy())
122				return -1;
123		}
124		rules
125	|	DIR
126		{
127			p_dir = $1;
128			p_type = 0;	/* ignored it by kernel */
129
130			if (init_x_policy())
131				return -1;
132		}
133	;
134
135rules
136	:	/*NOTHING*/
137	|	rules rule {
138			if (rule_check() < 0)
139				return -1;
140
141			if (set_x_request(p_src, p_dst) < 0)
142				return -1;
143
144			policy_parse_request_init();
145		}
146	;
147
148rule
149	:	protocol SLASH mode SLASH addresses SLASH level
150	|	protocol SLASH mode SLASH addresses SLASH
151	|	protocol SLASH mode SLASH addresses
152	|	protocol SLASH mode SLASH
153	|	protocol SLASH mode SLASH SLASH level
154	|	protocol SLASH mode
155	|	protocol SLASH {
156			__ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
157			return -1;
158		}
159	|	protocol {
160			__ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
161			return -1;
162		}
163	;
164
165protocol
166	:	PROTOCOL { p_protocol = $1; }
167	;
168
169mode
170	:	MODE { p_mode = $1; }
171	;
172
173level
174	:	LEVEL {
175			p_level = $1;
176			p_reqid = 0;
177		}
178	|	LEVEL_SPECIFY {
179			p_level = IPSEC_LEVEL_UNIQUE;
180			p_reqid = atol($1.buf);	/* atol() is good. */
181		}
182	;
183
184addresses
185	:	IPADDRESS {
186			p_src = parse_sockaddr(&$1);
187			if (p_src == NULL)
188				return -1;
189		}
190		HYPHEN
191		IPADDRESS {
192			p_dst = parse_sockaddr(&$4);
193			if (p_dst == NULL)
194				return -1;
195		}
196	|	ME HYPHEN ANY {
197			if (p_dir != IPSEC_DIR_OUTBOUND) {
198				__ipsec_errcode = EIPSEC_INVAL_DIR;
199				return -1;
200			}
201		}
202	|	ANY HYPHEN ME {
203			if (p_dir != IPSEC_DIR_INBOUND) {
204				__ipsec_errcode = EIPSEC_INVAL_DIR;
205				return -1;
206			}
207		}
208		/*
209	|	ME HYPHEN ME
210		*/
211	;
212
213%%
214
215void
216yyerror(msg)
217	char *msg;
218{
219	fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
220		msg, __libipsecyytext);
221
222	return;
223}
224
225static struct sockaddr *
226parse_sockaddr(buf)
227	struct _val *buf;
228{
229	struct addrinfo hints, *res;
230	char *serv = NULL;
231	int error;
232	struct sockaddr *newaddr = NULL;
233
234	memset(&hints, 0, sizeof(hints));
235	hints.ai_family = PF_UNSPEC;
236	hints.ai_flags = AI_NUMERICHOST;
237	error = getaddrinfo(buf->buf, serv, &hints, &res);
238	if (error != 0) {
239		yyerror("invalid IP address");
240		__ipsec_set_strerror(gai_strerror(error));
241		return NULL;
242	}
243
244	if (res->ai_addr == NULL) {
245		yyerror("invalid IP address");
246		__ipsec_set_strerror(gai_strerror(error));
247		return NULL;
248	}
249
250	newaddr = malloc(res->ai_addr->sa_len);
251	if (newaddr == NULL) {
252		__ipsec_errcode = EIPSEC_NO_BUFS;
253		freeaddrinfo(res);
254		return NULL;
255	}
256	memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len);
257
258	freeaddrinfo(res);
259
260	__ipsec_errcode = EIPSEC_NO_ERROR;
261	return newaddr;
262}
263
264static int
265rule_check()
266{
267	if (p_type == IPSEC_POLICY_IPSEC) {
268		if (p_protocol == IPPROTO_IP) {
269			__ipsec_errcode = EIPSEC_NO_PROTO;
270			return -1;
271		}
272
273		if (p_mode != IPSEC_MODE_TRANSPORT
274		 && p_mode != IPSEC_MODE_TUNNEL) {
275			__ipsec_errcode = EIPSEC_INVAL_MODE;
276			return -1;
277		}
278
279		if (p_src == NULL && p_dst == NULL) {
280			 if (p_mode != IPSEC_MODE_TRANSPORT) {
281				__ipsec_errcode = EIPSEC_INVAL_ADDRESS;
282				return -1;
283			}
284		}
285		else if (p_src->sa_family != p_dst->sa_family) {
286			__ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
287			return -1;
288		}
289	}
290
291	__ipsec_errcode = EIPSEC_NO_ERROR;
292	return 0;
293}
294
295static int
296init_x_policy()
297{
298	struct sadb_x_policy *p;
299
300	tlen = sizeof(struct sadb_x_policy);
301
302	pbuf = malloc(tlen);
303	if (pbuf == NULL) {
304		__ipsec_errcode = EIPSEC_NO_BUFS;
305		return -1;
306	}
307	memset(pbuf, 0, tlen);
308	p = (struct sadb_x_policy *)pbuf;
309	p->sadb_x_policy_len = 0;	/* must update later */
310	p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
311	p->sadb_x_policy_type = p_type;
312	p->sadb_x_policy_dir = p_dir;
313	p->sadb_x_policy_id = 0;
314
315	offset = tlen;
316
317	__ipsec_errcode = EIPSEC_NO_ERROR;
318	return 0;
319}
320
321static int
322set_x_request(src, dst)
323	struct sockaddr *src, *dst;
324{
325	struct sadb_x_ipsecrequest *p;
326	int reqlen;
327
328	reqlen = sizeof(*p)
329		+ (src ? src->sa_len : 0)
330		+ (dst ? dst->sa_len : 0);
331	tlen += reqlen;		/* increment to total length */
332
333	pbuf = realloc(pbuf, tlen);
334	if (pbuf == NULL) {
335		__ipsec_errcode = EIPSEC_NO_BUFS;
336		return -1;
337	}
338	p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
339	p->sadb_x_ipsecrequest_len = reqlen;
340	p->sadb_x_ipsecrequest_proto = p_protocol;
341	p->sadb_x_ipsecrequest_mode = p_mode;
342	p->sadb_x_ipsecrequest_level = p_level;
343	p->sadb_x_ipsecrequest_reqid = p_reqid;
344	offset += sizeof(*p);
345
346	if (set_sockaddr(src) || set_sockaddr(dst))
347		return -1;
348
349	__ipsec_errcode = EIPSEC_NO_ERROR;
350	return 0;
351}
352
353static int
354set_sockaddr(addr)
355	struct sockaddr *addr;
356{
357	if (addr == NULL) {
358		__ipsec_errcode = EIPSEC_NO_ERROR;
359		return 0;
360	}
361
362	/* tlen has already incremented */
363
364	memcpy(&pbuf[offset], addr, addr->sa_len);
365
366	offset += addr->sa_len;
367
368	__ipsec_errcode = EIPSEC_NO_ERROR;
369	return 0;
370}
371
372static void
373policy_parse_request_init()
374{
375	p_protocol = IPPROTO_IP;
376	p_mode = IPSEC_MODE_ANY;
377	p_level = IPSEC_LEVEL_DEFAULT;
378	p_reqid = 0;
379	if (p_src != NULL) {
380		free(p_src);
381		p_src = NULL;
382	}
383	if (p_dst != NULL) {
384		free(p_dst);
385		p_dst = NULL;
386	}
387
388	return;
389}
390
391static caddr_t
392policy_parse(msg, msglen)
393	char *msg;
394	int msglen;
395{
396	int error;
397	pbuf = NULL;
398	tlen = 0;
399
400	/* initialize */
401	p_dir = IPSEC_DIR_INVALID;
402	p_type = IPSEC_POLICY_DISCARD;
403	policy_parse_request_init();
404	__policy__strbuffer__init__(msg);
405
406	error = yyparse();	/* it must be set errcode. */
407	__policy__strbuffer__free__();
408
409	if (error) {
410		if (pbuf != NULL)
411			free(pbuf);
412		return NULL;
413	}
414
415	/* update total length */
416	((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
417
418	__ipsec_errcode = EIPSEC_NO_ERROR;
419
420	return pbuf;
421}
422
423caddr_t
424ipsec_set_policy(msg, msglen)
425	char *msg;
426	int msglen;
427{
428	caddr_t policy;
429
430	policy = policy_parse(msg, msglen);
431	if (policy == NULL) {
432		if (__ipsec_errcode == EIPSEC_NO_ERROR)
433			__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
434		return NULL;
435	}
436
437	__ipsec_errcode = EIPSEC_NO_ERROR;
438	return policy;
439}
440
441