xref: /freebsd/lib/libipsec/policy_parse.y (revision 4f52dfbb)
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(msg)
217 	char *msg;
218 {
219 	fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
220 		msg, __libipsecyytext);
221 
222 	return;
223 }
224 
225 static struct sockaddr *
226 parse_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 
264 static int
265 rule_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 
295 static int
296 init_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 
321 static int
322 set_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 
353 static int
354 set_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 
372 static void
373 policy_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 
391 static caddr_t
392 policy_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 
423 caddr_t
424 ipsec_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