xref: /freebsd/lib/libipsec/policy_parse.y (revision 2008043f386721d58158e37e0d7e50df8095942d)
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 #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 
72 static caddr_t pbuf = NULL;		/* sadb_x_policy buffer */
73 static int tlen = 0;			/* total length of pbuf */
74 static int offset = 0;			/* offset of pbuf */
75 static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid;
76 static struct sockaddr *p_src = NULL;
77 static struct sockaddr *p_dst = NULL;
78 
79 struct _val;
80 extern void yyerror(char *msg);
81 static struct sockaddr *parse_sockaddr(struct _val *buf);
82 static int rule_check(void);
83 static int init_x_policy(void);
84 static int set_x_request(struct sockaddr *src, struct sockaddr *dst);
85 static int set_sockaddr(struct sockaddr *addr);
86 static void policy_parse_request_init(void);
87 static caddr_t policy_parse(char *msg, int msglen);
88 
89 extern void __policy__strbuffer__init__(char *msg);
90 extern void __policy__strbuffer__free__(void);
91 extern int yylex(void);
92 
93 extern 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 %%
113 policy_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 
133 rules
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 
146 rule
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 
163 protocol
164 	:	PROTOCOL { p_protocol = $1; }
165 	;
166 
167 mode
168 	:	MODE { p_mode = $1; }
169 	;
170 
171 level
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 
182 addresses
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 
213 void
214 yyerror(char *msg)
215 {
216 	fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
217 		msg, __libipsecyytext);
218 
219 	return;
220 }
221 
222 static struct sockaddr *
223 parse_sockaddr(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 
260 static int
261 rule_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 
291 static int
292 init_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 
317 static int
318 set_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 
348 static int
349 set_sockaddr(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 
366 static void
367 policy_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 
385 static caddr_t
386 policy_parse(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 
415 caddr_t
416 ipsec_set_policy(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