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