Initial import from FreeBSD RELENG_4:
[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 /*      $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