Merge branch 'vendor/GCC44'
[dragonfly.git] / lib / libipsec / policy_parse.y
1 /*      $FreeBSD: src/lib/libipsec/policy_parse.y,v 1.1.2.1 2000/07/15 07:24:04 kris Exp $      */
2 /*      $DragonFly: src/lib/libipsec/policy_parse.y,v 1.4 2008/09/30 16:57:05 swildner Exp $    */
3 /*      $KAME: policy_parse.y,v 1.10 2000/05/07 05:25:03 itojun Exp $   */
4
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/types.h>
55 #include <sys/param.h>
56 #include <sys/socket.h>
57
58 #include <netinet/in.h>
59 #include <netinet6/ipsec.h>
60
61 #include <stdlib.h>
62 #include <stdio.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, p_reqid;
75 static struct sockaddr *p_src = NULL;
76 static struct sockaddr *p_dst = NULL;
77
78 struct _val;
79 extern void yyerror (char *msg);
80 static struct sockaddr *parse_sockaddr (struct _val *buf);
81 static int rule_check (void);
82 static int init_x_policy (void);
83 static int set_x_request (struct sockaddr *src, struct sockaddr *dst);
84 static int set_sockaddr (struct sockaddr *addr);
85 static void policy_parse_request_init (void);
86 static caddr_t policy_parse (char *msg, int msglen);
87
88 extern void __policy__strbuffer__init__ (char *msg);
89 extern int yyparse (void);
90 extern int yylex (void);
91
92 %}
93
94 %union {
95         u_int num;
96         struct _val {
97                 int len;
98                 char *buf;
99         } val;
100 }
101
102 %token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY
103 %token IPADDRESS
104 %token ME ANY
105 %token SLASH HYPHEN
106 %type <num> DIR ACTION PROTOCOL MODE LEVEL
107 %type <val> IPADDRESS LEVEL_SPECIFY
108
109 %%
110 policy_spec
111         :       DIR ACTION
112                 {
113                         p_dir = $1;
114                         p_type = $2;
115
116                         if (init_x_policy())
117                                 return -1;
118                 }
119                 rules
120         |       DIR
121                 {
122                         p_dir = $1;
123                         p_type = 0;     /* ignored it by kernel */
124
125                         if (init_x_policy())
126                                 return -1;
127                 }
128         ;
129
130 rules
131         :       /*NOTHING*/
132         |       rules rule {
133                         if (rule_check() < 0)
134                                 return -1;
135
136                         if (set_x_request(p_src, p_dst) < 0)
137                                 return -1;
138
139                         policy_parse_request_init();
140                 }
141         ;
142
143 rule
144         :       protocol SLASH mode SLASH addresses SLASH level
145         |       protocol SLASH mode SLASH addresses SLASH
146         |       protocol SLASH mode SLASH addresses
147         |       protocol SLASH mode SLASH
148         |       protocol SLASH mode SLASH SLASH level
149         |       protocol SLASH mode
150         |       protocol SLASH {
151                         __ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
152                         return -1;
153                 }
154         |       protocol {
155                         __ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
156                         return -1;
157                 }
158         ;
159
160 protocol
161         :       PROTOCOL { p_protocol = $1; }
162         ;
163
164 mode
165         :       MODE { p_mode = $1; }
166         ;
167
168 level
169         :       LEVEL {
170                         p_level = $1;
171                         p_reqid = 0;
172                 }
173         |       LEVEL_SPECIFY {
174                         p_level = IPSEC_LEVEL_UNIQUE;
175                         p_reqid = atol($1.buf); /* atol() is good. */
176                 }
177         ;
178
179 addresses
180         :       IPADDRESS {
181                         p_src = parse_sockaddr(&$1);
182                         if (p_src == NULL)
183                                 return -1;
184                 }
185                 HYPHEN
186                 IPADDRESS {
187                         p_dst = parse_sockaddr(&$4);
188                         if (p_dst == NULL)
189                                 return -1;
190                 }
191         |       ME HYPHEN ANY {
192                         if (p_dir != IPSEC_DIR_OUTBOUND) {
193                                 __ipsec_errcode = EIPSEC_INVAL_DIR;
194                                 return -1;
195                         }
196                 }
197         |       ANY HYPHEN ME {
198                         if (p_dir != IPSEC_DIR_INBOUND) {
199                                 __ipsec_errcode = EIPSEC_INVAL_DIR;
200                                 return -1;
201                         }
202                 }
203                 /*
204         |       ME HYPHEN ME
205                 */
206         ;
207
208 %%
209
210 void
211 yyerror(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(struct _val *buf)
223 {
224         struct addrinfo hints, *res;
225         char *serv = NULL;
226         int error;
227         struct sockaddr *newaddr = NULL;
228
229         memset(&hints, 0, sizeof(hints));
230         hints.ai_family = PF_UNSPEC;
231         hints.ai_flags = AI_NUMERICHOST;
232         error = getaddrinfo(buf->buf, serv, &hints, &res);
233         if (error != 0) {
234                 yyerror("invalid IP address");
235                 __ipsec_set_strerror(gai_strerror(error));
236                 return NULL;
237         }
238
239         if (res->ai_addr == NULL) {
240                 yyerror("invalid IP address");
241                 __ipsec_set_strerror(gai_strerror(error));
242                 return NULL;
243         }
244
245         newaddr = malloc(res->ai_addr->sa_len);
246         if (newaddr == NULL) {
247                 __ipsec_errcode = EIPSEC_NO_BUFS;
248                 freeaddrinfo(res);
249                 return NULL;
250         }
251         memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len);
252
253         freeaddrinfo(res);
254
255         __ipsec_errcode = EIPSEC_NO_ERROR;
256         return newaddr;
257 }
258
259 static int
260 rule_check(void)
261 {
262         if (p_type == IPSEC_POLICY_IPSEC) {
263                 if (p_protocol == IPPROTO_IP) {
264                         __ipsec_errcode = EIPSEC_NO_PROTO;
265                         return -1;
266                 }
267
268                 if (p_mode != IPSEC_MODE_TRANSPORT
269                  && p_mode != IPSEC_MODE_TUNNEL) {
270                         __ipsec_errcode = EIPSEC_INVAL_MODE;
271                         return -1;
272                 }
273
274                 if (p_src == NULL && p_dst == NULL) {
275                          if (p_mode != IPSEC_MODE_TRANSPORT) {
276                                 __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
277                                 return -1;
278                         }
279                 }
280                 else if (p_src->sa_family != p_dst->sa_family) {
281                         __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
282                         return -1;
283                 }
284         }
285
286         __ipsec_errcode = EIPSEC_NO_ERROR;
287         return 0;
288 }
289
290 static int
291 init_x_policy(void)
292 {
293         struct sadb_x_policy *p;
294
295         tlen = sizeof(struct sadb_x_policy);
296
297         pbuf = malloc(tlen);
298         if (pbuf == NULL) {
299                 __ipsec_errcode = EIPSEC_NO_BUFS;
300                 return -1;
301         }
302         p = (struct sadb_x_policy *)pbuf;
303         p->sadb_x_policy_len = 0;       /* must update later */
304         p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
305         p->sadb_x_policy_type = p_type;
306         p->sadb_x_policy_dir = p_dir;
307         p->sadb_x_policy_reserved = 0;
308         offset = tlen;
309
310         __ipsec_errcode = EIPSEC_NO_ERROR;
311         return 0;
312 }
313
314 static int
315 set_x_request(struct sockaddr *src, struct sockaddr *dst)
316 {
317         struct sadb_x_ipsecrequest *p;
318         int reqlen;
319
320         reqlen = sizeof(*p)
321                 + (src ? src->sa_len : 0)
322                 + (dst ? dst->sa_len : 0);
323         tlen += reqlen;         /* increment to total length */
324
325         pbuf = realloc(pbuf, tlen);
326         if (pbuf == NULL) {
327                 __ipsec_errcode = EIPSEC_NO_BUFS;
328                 return -1;
329         }
330         p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
331         p->sadb_x_ipsecrequest_len = reqlen;
332         p->sadb_x_ipsecrequest_proto = p_protocol;
333         p->sadb_x_ipsecrequest_mode = p_mode;
334         p->sadb_x_ipsecrequest_level = p_level;
335         p->sadb_x_ipsecrequest_reqid = p_reqid;
336         offset += sizeof(*p);
337
338         if (set_sockaddr(src) || set_sockaddr(dst))
339                 return -1;
340
341         __ipsec_errcode = EIPSEC_NO_ERROR;
342         return 0;
343 }
344
345 static int
346 set_sockaddr(struct sockaddr *addr)
347 {
348         if (addr == NULL) {
349                 __ipsec_errcode = EIPSEC_NO_ERROR;
350                 return 0;
351         }
352
353         /* tlen has already incremented */
354
355         memcpy(&pbuf[offset], addr, addr->sa_len);
356
357         offset += addr->sa_len;
358
359         __ipsec_errcode = EIPSEC_NO_ERROR;
360         return 0;
361 }
362
363 static void
364 policy_parse_request_init(void)
365 {
366         p_protocol = IPPROTO_IP;
367         p_mode = IPSEC_MODE_ANY;
368         p_level = IPSEC_LEVEL_DEFAULT;
369         p_reqid = 0;
370         if (p_src != NULL) {
371                 free(p_src);
372                 p_src = NULL;
373         }
374         if (p_dst != NULL) {
375                 free(p_dst);
376                 p_dst = NULL;
377         }
378
379         return;
380 }
381
382 static caddr_t
383 policy_parse(char *msg, int msglen)
384 {
385         int error;
386         pbuf = NULL;
387         tlen = 0;
388
389         /* initialize */
390         p_dir = IPSEC_DIR_INVALID;
391         p_type = IPSEC_POLICY_DISCARD;
392         policy_parse_request_init();
393         __policy__strbuffer__init__(msg);
394
395         error = yyparse();      /* it must be set errcode. */
396         if (error) {
397                 if (pbuf != NULL)
398                         free(pbuf);
399                 return NULL;
400         }
401
402         /* update total length */
403         ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
404
405         __ipsec_errcode = EIPSEC_NO_ERROR;
406
407         return pbuf;
408 }
409
410 caddr_t
411 ipsec_set_policy(char *msg, int msglen)
412 {
413         caddr_t policy;
414
415         policy = policy_parse(msg, msglen);
416         if (policy == NULL) {
417                 if (__ipsec_errcode == EIPSEC_NO_ERROR)
418                         __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
419                 return NULL;
420         }
421
422         __ipsec_errcode = EIPSEC_NO_ERROR;
423         return policy;
424 }
425