xref: /freebsd/lib/libipsec/policy_parse.y (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
1 /*	$KAME: policy_parse.y,v 1.14 2003/06/27 03:39:20 itojun Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * IN/OUT bound policy configuration take place such below:
34  *	in <policy>
35  *	out <policy>
36  *
37  * <policy> is one of following:
38  *	"discard", "none", "ipsec <requests>", "entrust", "bypass",
39  *
40  * The following requests are accepted as <requests>:
41  *
42  *	protocol/mode/src-dst/level
43  *	protocol/mode/src-dst		parsed as protocol/mode/src-dst/default
44  *	protocol/mode/src-dst/		parsed as protocol/mode/src-dst/default
45  *	protocol/transport		parsed as protocol/mode/any-any/default
46  *	protocol/transport//level	parsed as protocol/mode/any-any/level
47  *
48  * You can concatenate these requests with either ' '(single space) or '\n'.
49  */
50 
51 %{
52 #include <sys/cdefs.h>
53 __FBSDID("$FreeBSD$");
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 
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 yyparse(void);
92 extern int yylex(void);
93 
94 extern char *__libipsecyytext;	/*XXX*/
95 
96 %}
97 
98 %union {
99 	u_int num;
100 	struct _val {
101 		int len;
102 		char *buf;
103 	} val;
104 }
105 
106 %token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY
107 %token IPADDRESS
108 %token ME ANY
109 %token SLASH HYPHEN
110 %type <num> DIR ACTION PROTOCOL MODE LEVEL
111 %type <val> IPADDRESS LEVEL_SPECIFY
112 
113 %%
114 policy_spec
115 	:	DIR ACTION
116 		{
117 			p_dir = $1;
118 			p_type = $2;
119 
120 			if (init_x_policy())
121 				return -1;
122 		}
123 		rules
124 	|	DIR
125 		{
126 			p_dir = $1;
127 			p_type = 0;	/* ignored it by kernel */
128 
129 			if (init_x_policy())
130 				return -1;
131 		}
132 	;
133 
134 rules
135 	:	/*NOTHING*/
136 	|	rules rule {
137 			if (rule_check() < 0)
138 				return -1;
139 
140 			if (set_x_request(p_src, p_dst) < 0)
141 				return -1;
142 
143 			policy_parse_request_init();
144 		}
145 	;
146 
147 rule
148 	:	protocol SLASH mode SLASH addresses SLASH level
149 	|	protocol SLASH mode SLASH addresses SLASH
150 	|	protocol SLASH mode SLASH addresses
151 	|	protocol SLASH mode SLASH
152 	|	protocol SLASH mode SLASH SLASH level
153 	|	protocol SLASH mode
154 	|	protocol SLASH {
155 			__ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
156 			return -1;
157 		}
158 	|	protocol {
159 			__ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
160 			return -1;
161 		}
162 	;
163 
164 protocol
165 	:	PROTOCOL { p_protocol = $1; }
166 	;
167 
168 mode
169 	:	MODE { p_mode = $1; }
170 	;
171 
172 level
173 	:	LEVEL {
174 			p_level = $1;
175 			p_reqid = 0;
176 		}
177 	|	LEVEL_SPECIFY {
178 			p_level = IPSEC_LEVEL_UNIQUE;
179 			p_reqid = atol($1.buf);	/* atol() is good. */
180 		}
181 	;
182 
183 addresses
184 	:	IPADDRESS {
185 			p_src = parse_sockaddr(&$1);
186 			if (p_src == NULL)
187 				return -1;
188 		}
189 		HYPHEN
190 		IPADDRESS {
191 			p_dst = parse_sockaddr(&$4);
192 			if (p_dst == NULL)
193 				return -1;
194 		}
195 	|	ME HYPHEN ANY {
196 			if (p_dir != IPSEC_DIR_OUTBOUND) {
197 				__ipsec_errcode = EIPSEC_INVAL_DIR;
198 				return -1;
199 			}
200 		}
201 	|	ANY HYPHEN ME {
202 			if (p_dir != IPSEC_DIR_INBOUND) {
203 				__ipsec_errcode = EIPSEC_INVAL_DIR;
204 				return -1;
205 			}
206 		}
207 		/*
208 	|	ME HYPHEN ME
209 		*/
210 	;
211 
212 %%
213 
214 void
215 yyerror(msg)
216 	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(buf)
226 	struct _val *buf;
227 {
228 	struct addrinfo hints, *res;
229 	char *serv = NULL;
230 	int error;
231 	struct sockaddr *newaddr = NULL;
232 
233 	memset(&hints, 0, sizeof(hints));
234 	hints.ai_family = PF_UNSPEC;
235 	hints.ai_flags = AI_NUMERICHOST;
236 	error = getaddrinfo(buf->buf, serv, &hints, &res);
237 	if (error != 0) {
238 		yyerror("invalid IP address");
239 		__ipsec_set_strerror(gai_strerror(error));
240 		return NULL;
241 	}
242 
243 	if (res->ai_addr == NULL) {
244 		yyerror("invalid IP address");
245 		__ipsec_set_strerror(gai_strerror(error));
246 		return NULL;
247 	}
248 
249 	newaddr = malloc(res->ai_addr->sa_len);
250 	if (newaddr == NULL) {
251 		__ipsec_errcode = EIPSEC_NO_BUFS;
252 		freeaddrinfo(res);
253 		return NULL;
254 	}
255 	memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len);
256 
257 	freeaddrinfo(res);
258 
259 	__ipsec_errcode = EIPSEC_NO_ERROR;
260 	return newaddr;
261 }
262 
263 static int
264 rule_check()
265 {
266 	if (p_type == IPSEC_POLICY_IPSEC) {
267 		if (p_protocol == IPPROTO_IP) {
268 			__ipsec_errcode = EIPSEC_NO_PROTO;
269 			return -1;
270 		}
271 
272 		if (p_mode != IPSEC_MODE_TRANSPORT
273 		 && p_mode != IPSEC_MODE_TUNNEL) {
274 			__ipsec_errcode = EIPSEC_INVAL_MODE;
275 			return -1;
276 		}
277 
278 		if (p_src == NULL && p_dst == NULL) {
279 			 if (p_mode != IPSEC_MODE_TRANSPORT) {
280 				__ipsec_errcode = EIPSEC_INVAL_ADDRESS;
281 				return -1;
282 			}
283 		}
284 		else if (p_src->sa_family != p_dst->sa_family) {
285 			__ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
286 			return -1;
287 		}
288 	}
289 
290 	__ipsec_errcode = EIPSEC_NO_ERROR;
291 	return 0;
292 }
293 
294 static int
295 init_x_policy()
296 {
297 	struct sadb_x_policy *p;
298 
299 	tlen = sizeof(struct sadb_x_policy);
300 
301 	pbuf = malloc(tlen);
302 	if (pbuf == NULL) {
303 		__ipsec_errcode = EIPSEC_NO_BUFS;
304 		return -1;
305 	}
306 	memset(pbuf, 0, tlen);
307 	p = (struct sadb_x_policy *)pbuf;
308 	p->sadb_x_policy_len = 0;	/* must update later */
309 	p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
310 	p->sadb_x_policy_type = p_type;
311 	p->sadb_x_policy_dir = p_dir;
312 	p->sadb_x_policy_id = 0;
313 
314 	offset = tlen;
315 
316 	__ipsec_errcode = EIPSEC_NO_ERROR;
317 	return 0;
318 }
319 
320 static int
321 set_x_request(src, dst)
322 	struct sockaddr *src, *dst;
323 {
324 	struct sadb_x_ipsecrequest *p;
325 	int reqlen;
326 
327 	reqlen = sizeof(*p)
328 		+ (src ? src->sa_len : 0)
329 		+ (dst ? dst->sa_len : 0);
330 	tlen += reqlen;		/* increment to total length */
331 
332 	pbuf = realloc(pbuf, tlen);
333 	if (pbuf == NULL) {
334 		__ipsec_errcode = EIPSEC_NO_BUFS;
335 		return -1;
336 	}
337 	p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
338 	p->sadb_x_ipsecrequest_len = reqlen;
339 	p->sadb_x_ipsecrequest_proto = p_protocol;
340 	p->sadb_x_ipsecrequest_mode = p_mode;
341 	p->sadb_x_ipsecrequest_level = p_level;
342 	p->sadb_x_ipsecrequest_reqid = p_reqid;
343 	offset += sizeof(*p);
344 
345 	if (set_sockaddr(src) || set_sockaddr(dst))
346 		return -1;
347 
348 	__ipsec_errcode = EIPSEC_NO_ERROR;
349 	return 0;
350 }
351 
352 static int
353 set_sockaddr(addr)
354 	struct sockaddr *addr;
355 {
356 	if (addr == NULL) {
357 		__ipsec_errcode = EIPSEC_NO_ERROR;
358 		return 0;
359 	}
360 
361 	/* tlen has already incremented */
362 
363 	memcpy(&pbuf[offset], addr, addr->sa_len);
364 
365 	offset += addr->sa_len;
366 
367 	__ipsec_errcode = EIPSEC_NO_ERROR;
368 	return 0;
369 }
370 
371 static void
372 policy_parse_request_init()
373 {
374 	p_protocol = IPPROTO_IP;
375 	p_mode = IPSEC_MODE_ANY;
376 	p_level = IPSEC_LEVEL_DEFAULT;
377 	p_reqid = 0;
378 	if (p_src != NULL) {
379 		free(p_src);
380 		p_src = NULL;
381 	}
382 	if (p_dst != NULL) {
383 		free(p_dst);
384 		p_dst = NULL;
385 	}
386 
387 	return;
388 }
389 
390 static caddr_t
391 policy_parse(msg, msglen)
392 	char *msg;
393 	int msglen;
394 {
395 	int error;
396 	pbuf = NULL;
397 	tlen = 0;
398 
399 	/* initialize */
400 	p_dir = IPSEC_DIR_INVALID;
401 	p_type = IPSEC_POLICY_DISCARD;
402 	policy_parse_request_init();
403 	__policy__strbuffer__init__(msg);
404 
405 	error = yyparse();	/* it must be set errcode. */
406 	__policy__strbuffer__free__();
407 
408 	if (error) {
409 		if (pbuf != NULL)
410 			free(pbuf);
411 		return NULL;
412 	}
413 
414 	/* update total length */
415 	((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
416 
417 	__ipsec_errcode = EIPSEC_NO_ERROR;
418 
419 	return pbuf;
420 }
421 
422 caddr_t
423 ipsec_set_policy(msg, msglen)
424 	char *msg;
425 	int msglen;
426 {
427 	caddr_t policy;
428 
429 	policy = policy_parse(msg, msglen);
430 	if (policy == NULL) {
431 		if (__ipsec_errcode == EIPSEC_NO_ERROR)
432 			__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
433 		return NULL;
434 	}
435 
436 	__ipsec_errcode = EIPSEC_NO_ERROR;
437 	return policy;
438 }
439 
440