xref: /freebsd/lib/libipsec/policy_parse.y (revision 2b833162)
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 
74 static caddr_t pbuf = NULL;		/* sadb_x_policy buffer */
75 static int tlen = 0;			/* total length of pbuf */
76 static int offset = 0;			/* offset of pbuf */
77 static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid;
78 static struct sockaddr *p_src = NULL;
79 static struct sockaddr *p_dst = NULL;
80 
81 struct _val;
82 extern void yyerror(char *msg);
83 static struct sockaddr *parse_sockaddr(struct _val *buf);
84 static int rule_check(void);
85 static int init_x_policy(void);
86 static int set_x_request(struct sockaddr *src, struct sockaddr *dst);
87 static int set_sockaddr(struct sockaddr *addr);
88 static void policy_parse_request_init(void);
89 static caddr_t policy_parse(char *msg, int msglen);
90 
91 extern void __policy__strbuffer__init__(char *msg);
92 extern void __policy__strbuffer__free__(void);
93 extern int yylex(void);
94 
95 extern 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 %%
115 policy_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 
135 rules
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 
148 rule
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 
165 protocol
166 	:	PROTOCOL { p_protocol = $1; }
167 	;
168 
169 mode
170 	:	MODE { p_mode = $1; }
171 	;
172 
173 level
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 
184 addresses
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 
215 void
216 yyerror(char *msg)
217 {
218 	fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
219 		msg, __libipsecyytext);
220 
221 	return;
222 }
223 
224 static struct sockaddr *
225 parse_sockaddr(struct _val *buf)
226 {
227 	struct addrinfo hints, *res;
228 	char *serv = NULL;
229 	int error;
230 	struct sockaddr *newaddr = NULL;
231 
232 	memset(&hints, 0, sizeof(hints));
233 	hints.ai_family = PF_UNSPEC;
234 	hints.ai_flags = AI_NUMERICHOST;
235 	error = getaddrinfo(buf->buf, serv, &hints, &res);
236 	if (error != 0) {
237 		yyerror("invalid IP address");
238 		__ipsec_set_strerror(gai_strerror(error));
239 		return NULL;
240 	}
241 
242 	if (res->ai_addr == NULL) {
243 		yyerror("invalid IP address");
244 		__ipsec_set_strerror(gai_strerror(error));
245 		return NULL;
246 	}
247 
248 	newaddr = malloc(res->ai_addr->sa_len);
249 	if (newaddr == NULL) {
250 		__ipsec_errcode = EIPSEC_NO_BUFS;
251 		freeaddrinfo(res);
252 		return NULL;
253 	}
254 	memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len);
255 
256 	freeaddrinfo(res);
257 
258 	__ipsec_errcode = EIPSEC_NO_ERROR;
259 	return newaddr;
260 }
261 
262 static int
263 rule_check(void)
264 {
265 	if (p_type == IPSEC_POLICY_IPSEC) {
266 		if (p_protocol == IPPROTO_IP) {
267 			__ipsec_errcode = EIPSEC_NO_PROTO;
268 			return -1;
269 		}
270 
271 		if (p_mode != IPSEC_MODE_TRANSPORT
272 		 && p_mode != IPSEC_MODE_TUNNEL) {
273 			__ipsec_errcode = EIPSEC_INVAL_MODE;
274 			return -1;
275 		}
276 
277 		if (p_src == NULL && p_dst == NULL) {
278 			 if (p_mode != IPSEC_MODE_TRANSPORT) {
279 				__ipsec_errcode = EIPSEC_INVAL_ADDRESS;
280 				return -1;
281 			}
282 		}
283 		else if (p_src->sa_family != p_dst->sa_family) {
284 			__ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
285 			return -1;
286 		}
287 	}
288 
289 	__ipsec_errcode = EIPSEC_NO_ERROR;
290 	return 0;
291 }
292 
293 static int
294 init_x_policy(void)
295 {
296 	struct sadb_x_policy *p;
297 
298 	tlen = sizeof(struct sadb_x_policy);
299 
300 	pbuf = malloc(tlen);
301 	if (pbuf == NULL) {
302 		__ipsec_errcode = EIPSEC_NO_BUFS;
303 		return -1;
304 	}
305 	memset(pbuf, 0, tlen);
306 	p = (struct sadb_x_policy *)pbuf;
307 	p->sadb_x_policy_len = 0;	/* must update later */
308 	p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
309 	p->sadb_x_policy_type = p_type;
310 	p->sadb_x_policy_dir = p_dir;
311 	p->sadb_x_policy_id = 0;
312 
313 	offset = tlen;
314 
315 	__ipsec_errcode = EIPSEC_NO_ERROR;
316 	return 0;
317 }
318 
319 static int
320 set_x_request(struct sockaddr *src, struct sockaddr *dst)
321 {
322 	struct sadb_x_ipsecrequest *p;
323 	int reqlen;
324 
325 	reqlen = sizeof(*p)
326 		+ (src ? src->sa_len : 0)
327 		+ (dst ? dst->sa_len : 0);
328 	tlen += reqlen;		/* increment to total length */
329 
330 	pbuf = realloc(pbuf, tlen);
331 	if (pbuf == NULL) {
332 		__ipsec_errcode = EIPSEC_NO_BUFS;
333 		return -1;
334 	}
335 	p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
336 	p->sadb_x_ipsecrequest_len = reqlen;
337 	p->sadb_x_ipsecrequest_proto = p_protocol;
338 	p->sadb_x_ipsecrequest_mode = p_mode;
339 	p->sadb_x_ipsecrequest_level = p_level;
340 	p->sadb_x_ipsecrequest_reqid = p_reqid;
341 	offset += sizeof(*p);
342 
343 	if (set_sockaddr(src) || set_sockaddr(dst))
344 		return -1;
345 
346 	__ipsec_errcode = EIPSEC_NO_ERROR;
347 	return 0;
348 }
349 
350 static int
351 set_sockaddr(struct sockaddr *addr)
352 {
353 	if (addr == NULL) {
354 		__ipsec_errcode = EIPSEC_NO_ERROR;
355 		return 0;
356 	}
357 
358 	/* tlen has already incremented */
359 
360 	memcpy(&pbuf[offset], addr, addr->sa_len);
361 
362 	offset += addr->sa_len;
363 
364 	__ipsec_errcode = EIPSEC_NO_ERROR;
365 	return 0;
366 }
367 
368 static void
369 policy_parse_request_init(void)
370 {
371 	p_protocol = IPPROTO_IP;
372 	p_mode = IPSEC_MODE_ANY;
373 	p_level = IPSEC_LEVEL_DEFAULT;
374 	p_reqid = 0;
375 	if (p_src != NULL) {
376 		free(p_src);
377 		p_src = NULL;
378 	}
379 	if (p_dst != NULL) {
380 		free(p_dst);
381 		p_dst = NULL;
382 	}
383 
384 	return;
385 }
386 
387 static caddr_t
388 policy_parse(char *msg, int msglen)
389 {
390 	int error;
391 	pbuf = NULL;
392 	tlen = 0;
393 
394 	/* initialize */
395 	p_dir = IPSEC_DIR_INVALID;
396 	p_type = IPSEC_POLICY_DISCARD;
397 	policy_parse_request_init();
398 	__policy__strbuffer__init__(msg);
399 
400 	error = yyparse();	/* it must be set errcode. */
401 	__policy__strbuffer__free__();
402 
403 	if (error) {
404 		if (pbuf != NULL)
405 			free(pbuf);
406 		return NULL;
407 	}
408 
409 	/* update total length */
410 	((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
411 
412 	__ipsec_errcode = EIPSEC_NO_ERROR;
413 
414 	return pbuf;
415 }
416 
417 caddr_t
418 ipsec_set_policy(char *msg, int msglen)
419 {
420 	caddr_t policy;
421 
422 	policy = policy_parse(msg, msglen);
423 	if (policy == NULL) {
424 		if (__ipsec_errcode == EIPSEC_NO_ERROR)
425 			__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
426 		return NULL;
427 	}
428 
429 	__ipsec_errcode = EIPSEC_NO_ERROR;
430 	return policy;
431 }
432 
433