xref: /freebsd/lib/libipsec/policy_parse.y (revision 41466b50c1d5bfd1cf6adaae547a579a75d7c04e)
1 /*	$FreeBSD$	*/
2 /*	$KAME: policy_parse.y,v 1.10 2000/05/07 05:25:03 itojun Exp $	*/
3 
4 /*
5  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * IN/OUT bound policy configuration take place such below:
35  *	in <policy>
36  *	out <policy>
37  *
38  * <policy> is one of following:
39  *	"discard", "none", "ipsec <requests>", "entrust", "bypass",
40  *
41  * The following requests are accepted as <requests>:
42  *
43  *	protocol/mode/src-dst/level
44  *	protocol/mode/src-dst		parsed as protocol/mode/src-dst/default
45  *	protocol/mode/src-dst/		parsed as protocol/mode/src-dst/default
46  *	protocol/transport		parsed as protocol/mode/any-any/default
47  *	protocol/transport//level	parsed as protocol/mode/any-any/level
48  *
49  * You can concatenate these requests with either ' '(single space) or '\n'.
50  */
51 
52 %{
53 #include <sys/types.h>
54 #include <sys/param.h>
55 #include <sys/socket.h>
56 
57 #include <netinet/in.h>
58 #include <netinet6/ipsec.h>
59 
60 #include <stdlib.h>
61 #include <stdio.h>
62 #include <string.h>
63 #include <netdb.h>
64 
65 #include "ipsec_strerror.h"
66 
67 #define ATOX(c) \
68   (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
69 
70 static caddr_t pbuf = NULL;		/* sadb_x_policy buffer */
71 static int tlen = 0;			/* total length of pbuf */
72 static int offset = 0;			/* offset of pbuf */
73 static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid;
74 static struct sockaddr *p_src = NULL;
75 static struct sockaddr *p_dst = NULL;
76 
77 struct _val;
78 extern void yyerror __P((char *msg));
79 static struct sockaddr *parse_sockaddr __P((struct _val *buf));
80 static int rule_check __P((void));
81 static int init_x_policy __P((void));
82 static int set_x_request __P((struct sockaddr *src, struct sockaddr *dst));
83 static int set_sockaddr __P((struct sockaddr *addr));
84 static void policy_parse_request_init __P((void));
85 static caddr_t policy_parse __P((char *msg, int msglen));
86 
87 extern void __policy__strbuffer__init__ __P((char *msg));
88 extern int yyparse __P((void));
89 extern int yylex __P((void));
90 
91 %}
92 
93 %union {
94 	u_int num;
95 	struct _val {
96 		int len;
97 		char *buf;
98 	} val;
99 }
100 
101 %token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY
102 %token IPADDRESS
103 %token ME ANY
104 %token SLASH HYPHEN
105 %type <num> DIR ACTION PROTOCOL MODE LEVEL
106 %type <val> IPADDRESS LEVEL_SPECIFY
107 
108 %%
109 policy_spec
110 	:	DIR ACTION
111 		{
112 			p_dir = $1;
113 			p_type = $2;
114 
115 			if (init_x_policy())
116 				return -1;
117 		}
118 		rules
119 	|	DIR
120 		{
121 			p_dir = $1;
122 			p_type = 0;	/* ignored it by kernel */
123 
124 			if (init_x_policy())
125 				return -1;
126 		}
127 	;
128 
129 rules
130 	:	/*NOTHING*/
131 	|	rules rule {
132 			if (rule_check() < 0)
133 				return -1;
134 
135 			if (set_x_request(p_src, p_dst) < 0)
136 				return -1;
137 
138 			policy_parse_request_init();
139 		}
140 	;
141 
142 rule
143 	:	protocol SLASH mode SLASH addresses SLASH level
144 	|	protocol SLASH mode SLASH addresses SLASH
145 	|	protocol SLASH mode SLASH addresses
146 	|	protocol SLASH mode SLASH
147 	|	protocol SLASH mode SLASH SLASH level
148 	|	protocol SLASH mode
149 	|	protocol SLASH {
150 			__ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
151 			return -1;
152 		}
153 	|	protocol {
154 			__ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
155 			return -1;
156 		}
157 	;
158 
159 protocol
160 	:	PROTOCOL { p_protocol = $1; }
161 	;
162 
163 mode
164 	:	MODE { p_mode = $1; }
165 	;
166 
167 level
168 	:	LEVEL {
169 			p_level = $1;
170 			p_reqid = 0;
171 		}
172 	|	LEVEL_SPECIFY {
173 			p_level = IPSEC_LEVEL_UNIQUE;
174 			p_reqid = atol($1.buf);	/* atol() is good. */
175 		}
176 	;
177 
178 addresses
179 	:	IPADDRESS {
180 			p_src = parse_sockaddr(&$1);
181 			if (p_src == NULL)
182 				return -1;
183 		}
184 		HYPHEN
185 		IPADDRESS {
186 			p_dst = parse_sockaddr(&$4);
187 			if (p_dst == NULL)
188 				return -1;
189 		}
190 	|	ME HYPHEN ANY {
191 			if (p_dir != IPSEC_DIR_OUTBOUND) {
192 				__ipsec_errcode = EIPSEC_INVAL_DIR;
193 				return -1;
194 			}
195 		}
196 	|	ANY HYPHEN ME {
197 			if (p_dir != IPSEC_DIR_INBOUND) {
198 				__ipsec_errcode = EIPSEC_INVAL_DIR;
199 				return -1;
200 			}
201 		}
202 		/*
203 	|	ME HYPHEN ME
204 		*/
205 	;
206 
207 %%
208 
209 void
210 yyerror(msg)
211 	char *msg;
212 {
213 	extern char *__libipsecyytext;	/*XXX*/
214 
215 	fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
216 		msg, __libipsecyytext);
217 
218 	return;
219 }
220 
221 static struct sockaddr *
222 parse_sockaddr(buf)
223 	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()
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()
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 	p = (struct sadb_x_policy *)pbuf;
304 	p->sadb_x_policy_len = 0;	/* must update later */
305 	p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
306 	p->sadb_x_policy_type = p_type;
307 	p->sadb_x_policy_dir = p_dir;
308 	p->sadb_x_policy_reserved = 0;
309 	offset = tlen;
310 
311 	__ipsec_errcode = EIPSEC_NO_ERROR;
312 	return 0;
313 }
314 
315 static int
316 set_x_request(src, dst)
317 	struct sockaddr *src, *dst;
318 {
319 	struct sadb_x_ipsecrequest *p;
320 	int reqlen;
321 
322 	reqlen = sizeof(*p)
323 		+ (src ? src->sa_len : 0)
324 		+ (dst ? dst->sa_len : 0);
325 	tlen += reqlen;		/* increment to total length */
326 
327 	pbuf = realloc(pbuf, tlen);
328 	if (pbuf == NULL) {
329 		__ipsec_errcode = EIPSEC_NO_BUFS;
330 		return -1;
331 	}
332 	p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
333 	p->sadb_x_ipsecrequest_len = reqlen;
334 	p->sadb_x_ipsecrequest_proto = p_protocol;
335 	p->sadb_x_ipsecrequest_mode = p_mode;
336 	p->sadb_x_ipsecrequest_level = p_level;
337 	p->sadb_x_ipsecrequest_reqid = p_reqid;
338 	offset += sizeof(*p);
339 
340 	if (set_sockaddr(src) || set_sockaddr(dst))
341 		return -1;
342 
343 	__ipsec_errcode = EIPSEC_NO_ERROR;
344 	return 0;
345 }
346 
347 static int
348 set_sockaddr(addr)
349 	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()
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(msg, msglen)
387 	char *msg;
388 	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 	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(msg, msglen)
417 	char *msg;
418 	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