]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libipsec/policy_parse.y
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / libipsec / policy_parse.y
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