xref: /freebsd/lib/libipsec/policy_parse.y (revision 23f282aa31e9b6fceacd449020e936e98d6f2298)
1 /*
2  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 /* KAME $Id: policy_parse.y,v 1.1 1999/10/20 01:26:41 sakane Exp $ */
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 <errno.h>
63 #include <string.h>
64 #include <netdb.h>
65 
66 #include "ipsec_strerror.h"
67 
68 #define	ATOX(c) \
69   (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
70 
71 static caddr_t pbuf = NULL;		/* sadb_x_policy buffer */
72 static int tlen = 0;			/* total length of pbuf */
73 static int offset = 0;			/* offset of pbuf */
74 static int p_dir, p_type, p_protocol, p_mode, p_level;
75 static struct sockaddr *p_src = NULL;
76 static struct sockaddr *p_dst = NULL;
77 
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();
89 extern int yylex();
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
102 %token IPADDRESS
103 %token ME ANY
104 %token SLASH HYPHEN
105 %type <num> DIR ACTION PROTOCOL MODE LEVEL
106 %type <val> IPADDRESS
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 	;
120 
121 rules
122 	:	/*NOTHING*/
123 	|	rules rule {
124 			if (rule_check() < 0)
125 				return -1;
126 
127 			if (set_x_request(p_src, p_dst) < 0)
128 				return -1;
129 
130 			policy_parse_request_init();
131 		}
132 	;
133 
134 rule
135 	:	protocol SLASH mode SLASH addresses SLASH level
136 	|	protocol SLASH mode SLASH addresses SLASH
137 	|	protocol SLASH mode SLASH addresses
138 	|	protocol SLASH mode SLASH
139 	|	protocol SLASH mode SLASH SLASH level
140 	|	protocol SLASH mode
141 	|	protocol SLASH {
142 			ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
143 			return -1;
144 		}
145 	|	protocol {
146 			ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
147 			return -1;
148 		}
149 	;
150 
151 protocol
152 	:	PROTOCOL { p_protocol = $1; }
153 	;
154 
155 mode
156 	:	MODE { p_mode = $1; }
157 	;
158 
159 level
160 	:	LEVEL { p_level = $1; }
161 	;
162 
163 addresses
164 	:	IPADDRESS {
165 			p_src = parse_sockaddr(&$1);
166 			if (p_src == NULL)
167 				return -1;
168 		}
169 		HYPHEN
170 		IPADDRESS {
171 			p_dst = parse_sockaddr(&$4);
172 			if (p_dst == NULL)
173 				return -1;
174 		}
175 	|	ME HYPHEN ANY {
176 			if (p_dir != IPSEC_DIR_OUTBOUND) {
177 				ipsec_errcode = EIPSEC_INVAL_DIR;
178 				return -1;
179 			}
180 		}
181 	|	ANY HYPHEN ME {
182 			if (p_dir != IPSEC_DIR_INBOUND) {
183 				ipsec_errcode = EIPSEC_INVAL_DIR;
184 				return -1;
185 			}
186 		}
187 		/*
188 	|	ME HYPHEN ME
189 		*/
190 	;
191 
192 %%
193 
194 void
195 yyerror(msg)
196 	char *msg;
197 {
198 	fprintf(stderr, "%s\n", msg);
199 
200 	return;
201 }
202 
203 static struct sockaddr *
204 parse_sockaddr(buf)
205 	struct _val *buf;
206 {
207 	struct addrinfo hints, *res;
208 	char *serv = NULL;
209 	int error;
210 	struct sockaddr *newaddr = NULL;
211 
212 	memset(&hints, 0, sizeof(hints));
213 	hints.ai_family = PF_UNSPEC;
214 	hints.ai_flags = AI_NUMERICHOST;
215 	error = getaddrinfo(buf->buf, serv, &hints, &res);
216 	if (error != 0 || res->ai_addr == NULL) {
217 		ipsec_set_strerror(error == EAI_SYSTEM ?
218 				   gai_strerror(error) : strerror(errno));
219 		return NULL;
220 	}
221 
222 	if (res->ai_addr == NULL) {
223 		ipsec_set_strerror(gai_strerror(error));
224 		return NULL;
225 	}
226 
227 	newaddr = malloc(res->ai_addr->sa_len);
228 	if (newaddr == NULL) {
229 		ipsec_errcode = EIPSEC_NO_BUFS;
230 		freeaddrinfo(res);
231 		return NULL;
232 	}
233 	memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len);
234 
235 	/*
236 	 * XXX: If the scope of the destination is link-local,
237 	 * embed the scope-id(in this case, interface index)
238 	 * into the address.
239 	 */
240 	if (newaddr->sa_family == AF_INET6) {
241 		struct sockaddr_in6 *sin6;
242 
243 		sin6 = (struct sockaddr_in6 *)newaddr;
244 		if(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
245 		   sin6->sin6_scope_id != 0)
246 			*(u_short *)&sin6->sin6_addr.s6_addr[2] =
247 				htons(sin6->sin6_scope_id & 0xffff);
248 	}
249 
250 	freeaddrinfo(res);
251 
252 	ipsec_errcode = EIPSEC_NO_ERROR;
253 	return newaddr;
254 }
255 
256 static int
257 rule_check()
258 {
259 	if (p_type == IPSEC_POLICY_IPSEC) {
260 		if (p_protocol == IPPROTO_IP) {
261 			ipsec_errcode = EIPSEC_NO_PROTO;
262 			return -1;
263 		}
264 
265 		if (p_mode != IPSEC_MODE_TRANSPORT
266 		 && p_mode != IPSEC_MODE_TUNNEL) {
267 			ipsec_errcode = EIPSEC_INVAL_MODE;
268 			return -1;
269 		}
270 
271 		if (p_src == NULL && p_dst == NULL) {
272 			 if (p_mode != IPSEC_MODE_TRANSPORT) {
273 				ipsec_errcode = EIPSEC_INVAL_ADDRESS;
274 				return -1;
275 			}
276 		}
277 		else if (p_src->sa_family != p_dst->sa_family) {
278 			ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
279 			return -1;
280 		}
281 	}
282 
283 	ipsec_errcode = EIPSEC_NO_ERROR;
284 	return 0;
285 }
286 
287 static int
288 init_x_policy()
289 {
290 	struct sadb_x_policy *p;
291 
292 	tlen = sizeof(struct sadb_x_policy);
293 
294 	pbuf = malloc(tlen);
295 	if (pbuf == NULL) {
296 		ipsec_errcode = EIPSEC_NO_BUFS;
297 		return -1;
298 	}
299 	p = (struct sadb_x_policy *)pbuf;
300 	p->sadb_x_policy_len = 0;	/* must update later */
301 	p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
302 	p->sadb_x_policy_type = p_type;
303 	p->sadb_x_policy_dir = p_dir;
304 	p->sadb_x_policy_reserved = 0;
305 	offset = tlen;
306 
307 	ipsec_errcode = EIPSEC_NO_ERROR;
308 	return 0;
309 }
310 
311 static int
312 set_x_request(src, dst)
313 	struct sockaddr *src, *dst;
314 {
315 	struct sadb_x_ipsecrequest *p;
316 	int reqlen;
317 
318 	reqlen = sizeof(*p)
319 		+ (src ? src->sa_len : 0)
320 		+ (dst ? dst->sa_len : 0);
321 	tlen += reqlen;		/* increment to total length */
322 
323 	pbuf = realloc(pbuf, tlen);
324 	if (pbuf == NULL) {
325 		ipsec_errcode = EIPSEC_NO_BUFS;
326 		return -1;
327 	}
328 	p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
329 	p->sadb_x_ipsecrequest_len = reqlen;
330 	p->sadb_x_ipsecrequest_proto = p_protocol;
331 	p->sadb_x_ipsecrequest_mode = p_mode;
332 	p->sadb_x_ipsecrequest_level = p_level;
333 	offset += sizeof(*p);
334 
335 	if (set_sockaddr(src) || set_sockaddr(dst))
336 		return -1;
337 
338 	ipsec_errcode = EIPSEC_NO_ERROR;
339 	return 0;
340 }
341 
342 static int
343 set_sockaddr(addr)
344 	struct sockaddr *addr;
345 {
346 	if (addr == NULL) {
347 		ipsec_errcode = EIPSEC_NO_ERROR;
348 		return 0;
349 	}
350 
351 	/* tlen has already incremented */
352 
353 	memcpy(&pbuf[offset], addr, addr->sa_len);
354 
355 	offset += addr->sa_len;
356 
357 	ipsec_errcode = EIPSEC_NO_ERROR;
358 	return 0;
359 }
360 
361 static void
362 policy_parse_request_init()
363 {
364 	p_protocol = IPPROTO_IP;
365 	p_mode = IPSEC_MODE_ANY;
366 	p_level = IPSEC_LEVEL_DEFAULT;
367 	if (p_src != NULL) {
368 		free(p_src);
369 		p_src = NULL;
370 	}
371 	if (p_dst != NULL) {
372 		free(p_dst);
373 		p_dst = NULL;
374 	}
375 
376 	return;
377 }
378 
379 static caddr_t
380 policy_parse(msg, msglen)
381 	char *msg;
382 	int msglen;
383 {
384 	int error;
385 	pbuf = NULL;
386 	tlen = 0;
387 
388 	/* initialize */
389 	p_dir = IPSEC_DIR_INVALID;
390 	p_type = IPSEC_POLICY_DISCARD;
391 	policy_parse_request_init();
392 	__policy__strbuffer__init__(msg);
393 
394 	error = yyparse();	/* it must be set errcode. */
395 	if (error) {
396 		if (pbuf != NULL)
397 			free(pbuf);
398 		return NULL;
399 	}
400 
401 	/* update total length */
402 	((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
403 
404 	ipsec_errcode = EIPSEC_NO_ERROR;
405 
406 	return pbuf;
407 }
408 
409 caddr_t
410 ipsec_set_policy(msg, msglen)
411 	char *msg;
412 	int msglen;
413 {
414 	caddr_t policy;
415 
416 	policy = policy_parse(msg, msglen);
417 	if (policy == NULL) {
418 		if (ipsec_errcode == EIPSEC_NO_ERROR)
419 			ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
420 		return NULL;
421 	}
422 
423 	ipsec_errcode = EIPSEC_NO_ERROR;
424 	return policy;
425 }
426 
427