source: rtems-libbsd/ipsec-tools/src/libipsec/policy_parse.y @ b376ae1

55-freebsd-126-freebsd-12
Last change on this file since b376ae1 was b376ae1, checked in by Christian Mauderer <christian.mauderer@…>, on 05/03/18 at 12:15:11

ipsec-tools: Port libipsec, setkey and racoon.

Note that this replaces the libipsec from FreeBSD with the one provided
by ipsec-tools.

  • Property mode set to 100644
File size: 14.1 KB
Line 
1/*      $NetBSD: policy_parse.y,v 1.11 2009/02/16 18:36:21 tteras Exp $ */
2
3/*      $KAME: policy_parse.y,v 1.21 2003/12/12 08:01:26 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 <priority> <policy>
37 *      out <priority> <policy>
38 *
39 * <priority> is one of the following:
40 * priority <signed int> where the integer is an offset from the default
41 *                       priority, where negative numbers indicate lower
42 *                       priority (towards end of list) and positive numbers
43 *                       indicate higher priority (towards beginning of list)
44 *
45 * priority {low,def,high} {+,-} <unsigned int>  where low and high are
46 *                                               constants which are closer
47 *                                               to the end of the list and
48 *                                               beginning of the list,
49 *                                               respectively
50 *
51 * <policy> is one of following:
52 *      "discard", "none", "ipsec <requests>", "entrust", "bypass",
53 *
54 * The following requests are accepted as <requests>:
55 *
56 *      protocol/mode/src-dst/level
57 *      protocol/mode/src-dst           parsed as protocol/mode/src-dst/default
58 *      protocol/mode/src-dst/          parsed as protocol/mode/src-dst/default
59 *      protocol/transport              parsed as protocol/mode/any-any/default
60 *      protocol/transport//level       parsed as protocol/mode/any-any/level
61 *
62 * You can concatenate these requests with either ' '(single space) or '\n'.
63 */
64
65%{
66#ifdef __rtems__
67#include <machine/rtems-bsd-user-space.h>
68#endif /* __rtems__ */
69#ifdef HAVE_CONFIG_H
70#include "config.h"
71#endif
72
73#include <sys/types.h>
74#include <sys/param.h>
75#include <sys/socket.h>
76
77#include <netinet/in.h>
78#include PATH_IPSEC_H
79
80#include <stdlib.h>
81#include <stdio.h>
82#include <string.h>
83#include <netdb.h>
84
85#include <errno.h>
86
87#include "config.h"
88
89#include "ipsec_strerror.h"
90#include "libpfkey.h"
91
92#ifndef INT32_MAX
93#define INT32_MAX       (0xffffffff)
94#endif
95
96#ifndef INT32_MIN
97#define INT32_MIN       (-INT32_MAX-1)
98#endif
99
100#define ATOX(c) \
101  (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) ))
102
103static u_int8_t *pbuf = NULL;           /* sadb_x_policy buffer */
104static int tlen = 0;                    /* total length of pbuf */
105static int offset = 0;                  /* offset of pbuf */
106static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid;
107static u_int32_t p_priority = 0;
108static long p_priority_offset = 0;
109static struct sockaddr *p_src = NULL;
110static struct sockaddr *p_dst = NULL;
111
112struct _val;
113extern void yyerror __P((char *msg));
114static struct sockaddr *parse_sockaddr __P((struct _val *addrbuf,
115    struct _val *portbuf));
116static int rule_check __P((void));
117static int init_x_policy __P((void));
118static int set_x_request __P((struct sockaddr *, struct sockaddr *));
119static int set_sockaddr __P((struct sockaddr *));
120static void policy_parse_request_init __P((void));
121static void *policy_parse __P((const char *, int));
122
123extern void __policy__strbuffer__init__ __P((const char *));
124extern void __policy__strbuffer__free__ __P((void));
125extern int yyparse __P((void));
126extern int yylex __P((void));
127
128extern char *__libipsectext;    /*XXX*/
129
130%}
131
132%union {
133        u_int num;
134        u_int32_t num32;
135        struct _val {
136                int len;
137                char *buf;
138        } val;
139}
140
141%token DIR
142%token PRIORITY PLUS
143%token <num32> PRIO_BASE
144%token <val> PRIO_OFFSET
145%token ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY IPADDRESS PORT
146%token ME ANY
147%token SLASH HYPHEN
148%type <num> DIR PRIORITY ACTION PROTOCOL MODE LEVEL
149%type <val> IPADDRESS LEVEL_SPECIFY PORT
150
151%%
152policy_spec
153        :       DIR ACTION
154                {
155                        p_dir = $1;
156                        p_type = $2;
157
158#ifdef HAVE_PFKEY_POLICY_PRIORITY
159                        p_priority = PRIORITY_DEFAULT;
160#else
161                        p_priority = 0;
162#endif
163
164                        if (init_x_policy())
165                                return -1;
166                }
167                rules
168        |       DIR PRIORITY PRIO_OFFSET ACTION
169                {
170                        p_dir = $1;
171                        p_type = $4;
172                        p_priority_offset = -atol($3.buf);
173
174                        errno = 0;
175                        if (errno != 0 || p_priority_offset < INT32_MIN)
176                        {
177                                __ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET;
178                                return -1;
179                        }
180
181                        p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset;
182
183                        if (init_x_policy())
184                                return -1;
185                }
186                rules
187        |       DIR PRIORITY HYPHEN PRIO_OFFSET ACTION
188                {
189                        p_dir = $1;
190                        p_type = $5;
191
192                        errno = 0;
193                        p_priority_offset = atol($4.buf);
194
195                        if (errno != 0 || p_priority_offset > INT32_MAX)
196                        {
197                                __ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET;
198                                return -1;
199                        }
200
201                        /* negative input value means lower priority, therefore higher
202                           actual value so that is closer to the end of the list */
203                        p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset;
204
205                        if (init_x_policy())
206                                return -1;
207                }
208                rules
209        |       DIR PRIORITY PRIO_BASE ACTION
210                {
211                        p_dir = $1;
212                        p_type = $4;
213
214                        p_priority = $3;
215
216                        if (init_x_policy())
217                                return -1;
218                }
219                rules
220        |       DIR PRIORITY PRIO_BASE PLUS PRIO_OFFSET ACTION
221                {
222                        p_dir = $1;
223                        p_type = $6;
224
225                        errno = 0;
226                        p_priority_offset = atol($5.buf);
227
228                        if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_NEGATIVE_MAX)
229                        {
230                                __ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET;
231                                return -1;
232                        }
233
234                        /* adding value means higher priority, therefore lower
235                           actual value so that is closer to the beginning of the list */
236                        p_priority = $3 - (u_int32_t) p_priority_offset;
237
238                        if (init_x_policy())
239                                return -1;
240                }
241                rules
242        |       DIR PRIORITY PRIO_BASE HYPHEN PRIO_OFFSET ACTION
243                {
244                        p_dir = $1;
245                        p_type = $6;
246
247                        errno = 0;
248                        p_priority_offset = atol($5.buf);
249
250                        if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_POSITIVE_MAX)
251                        {
252                                __ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET;
253                                return -1;
254                        }
255
256                        /* subtracting value means lower priority, therefore higher
257                           actual value so that is closer to the end of the list */
258                        p_priority = $3 + (u_int32_t) p_priority_offset;
259
260                        if (init_x_policy())
261                                return -1;
262                }
263                rules
264        |       DIR
265                {
266                        p_dir = $1;
267                        p_type = 0;     /* ignored it by kernel */
268
269                        p_priority = 0;
270
271                        if (init_x_policy())
272                                return -1;
273                }
274        ;
275
276rules
277        :       /*NOTHING*/
278        |       rules rule {
279                        if (rule_check() < 0)
280                                return -1;
281
282                        if (set_x_request(p_src, p_dst) < 0)
283                                return -1;
284
285                        policy_parse_request_init();
286                }
287        ;
288
289rule
290        :       protocol SLASH mode SLASH addresses SLASH level
291        |       protocol SLASH mode SLASH addresses SLASH
292        |       protocol SLASH mode SLASH addresses
293        |       protocol SLASH mode SLASH
294        |       protocol SLASH mode SLASH SLASH level
295        |       protocol SLASH mode
296        |       protocol SLASH {
297                        __ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
298                        return -1;
299                }
300        |       protocol {
301                        __ipsec_errcode = EIPSEC_FEW_ARGUMENTS;
302                        return -1;
303                }
304        ;
305
306protocol
307        :       PROTOCOL { p_protocol = $1; }
308        ;
309
310mode
311        :       MODE { p_mode = $1; }
312        ;
313
314level
315        :       LEVEL {
316                        p_level = $1;
317                        p_reqid = 0;
318                }
319        |       LEVEL_SPECIFY {
320                        p_level = IPSEC_LEVEL_UNIQUE;
321                        p_reqid = atol($1.buf); /* atol() is good. */
322                }
323        ;
324
325addresses
326        :       IPADDRESS {
327                        p_src = parse_sockaddr(&$1, NULL);
328                        if (p_src == NULL)
329                                return -1;
330                }
331                HYPHEN
332                IPADDRESS {
333                        p_dst = parse_sockaddr(&$4, NULL);
334                        if (p_dst == NULL)
335                                return -1;
336                }
337        |       IPADDRESS PORT {
338                        p_src = parse_sockaddr(&$1, &$2);
339                        if (p_src == NULL)
340                                return -1;
341                }
342                HYPHEN
343                IPADDRESS PORT {
344                        p_dst = parse_sockaddr(&$5, &$6);
345                        if (p_dst == NULL)
346                                return -1;
347                }
348        |       ME HYPHEN ANY {
349                        if (p_dir != IPSEC_DIR_OUTBOUND) {
350                                __ipsec_errcode = EIPSEC_INVAL_DIR;
351                                return -1;
352                        }
353                }
354        |       ANY HYPHEN ME {
355                        if (p_dir != IPSEC_DIR_INBOUND) {
356                                __ipsec_errcode = EIPSEC_INVAL_DIR;
357                                return -1;
358                        }
359                }
360                /*
361        |       ME HYPHEN ME
362                */
363        ;
364
365%%
366
367void
368yyerror(msg)
369        char *msg;
370{
371        fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
372                msg, __libipsectext);
373
374        return;
375}
376
377static struct sockaddr *
378parse_sockaddr(addrbuf, portbuf)
379        struct _val *addrbuf;
380        struct _val *portbuf;
381{
382        struct addrinfo hints, *res;
383        char *addr;
384        char *serv = NULL;
385        int error;
386        struct sockaddr *newaddr = NULL;
387
388        if ((addr = malloc(addrbuf->len + 1)) == NULL) {
389                yyerror("malloc failed");
390                __ipsec_set_strerror(strerror(errno));
391                return NULL;
392        }
393
394        if (portbuf && ((serv = malloc(portbuf->len + 1)) == NULL)) {
395                free(addr);
396                yyerror("malloc failed");
397                __ipsec_set_strerror(strerror(errno));
398                return NULL;
399        }
400
401        strncpy(addr, addrbuf->buf, addrbuf->len);
402        addr[addrbuf->len] = '\0';
403
404        if (portbuf) {
405                strncpy(serv, portbuf->buf, portbuf->len);
406                serv[portbuf->len] = '\0';
407        }
408
409        memset(&hints, 0, sizeof(hints));
410        hints.ai_family = PF_UNSPEC;
411        hints.ai_flags = AI_NUMERICHOST;
412        hints.ai_socktype = SOCK_DGRAM;
413        error = getaddrinfo(addr, serv, &hints, &res);
414        free(addr);
415        if (serv != NULL)
416                free(serv);
417        if (error != 0) {
418                yyerror("invalid IP address");
419                __ipsec_set_strerror(gai_strerror(error));
420                return NULL;
421        }
422
423        if (res->ai_addr == NULL) {
424                yyerror("invalid IP address");
425                __ipsec_set_strerror(gai_strerror(error));
426                return NULL;
427        }
428
429        newaddr = malloc(res->ai_addrlen);
430        if (newaddr == NULL) {
431                __ipsec_errcode = EIPSEC_NO_BUFS;
432                freeaddrinfo(res);
433                return NULL;
434        }
435        memcpy(newaddr, res->ai_addr, res->ai_addrlen);
436
437        freeaddrinfo(res);
438
439        __ipsec_errcode = EIPSEC_NO_ERROR;
440        return newaddr;
441}
442
443static int
444rule_check()
445{
446        if (p_type == IPSEC_POLICY_IPSEC) {
447                if (p_protocol == IPPROTO_IP) {
448                        __ipsec_errcode = EIPSEC_NO_PROTO;
449                        return -1;
450                }
451
452                if (p_mode != IPSEC_MODE_TRANSPORT
453                 && p_mode != IPSEC_MODE_TUNNEL) {
454                        __ipsec_errcode = EIPSEC_INVAL_MODE;
455                        return -1;
456                }
457
458                if (p_src == NULL && p_dst == NULL) {
459                         if (p_mode != IPSEC_MODE_TRANSPORT) {
460                                __ipsec_errcode = EIPSEC_INVAL_ADDRESS;
461                                return -1;
462                        }
463                }
464                else if (p_src->sa_family != p_dst->sa_family) {
465                        __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
466                        return -1;
467                }
468        }
469
470        __ipsec_errcode = EIPSEC_NO_ERROR;
471        return 0;
472}
473
474static int
475init_x_policy()
476{
477        struct sadb_x_policy *p;
478
479        if (pbuf) {
480                free(pbuf);
481                tlen = 0;
482        }
483        pbuf = malloc(sizeof(struct sadb_x_policy));
484        if (pbuf == NULL) {
485                __ipsec_errcode = EIPSEC_NO_BUFS;
486                return -1;
487        }
488        tlen = sizeof(struct sadb_x_policy);
489
490        memset(pbuf, 0, tlen);
491        p = (struct sadb_x_policy *)pbuf;
492        p->sadb_x_policy_len = 0;       /* must update later */
493        p->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
494        p->sadb_x_policy_type = p_type;
495        p->sadb_x_policy_dir = p_dir;
496        p->sadb_x_policy_id = 0;
497#ifdef HAVE_PFKEY_POLICY_PRIORITY
498        p->sadb_x_policy_priority = p_priority;
499#else
500    /* fail if given a priority and libipsec was not compiled with
501           priority support */
502        if (p_priority != 0)
503        {
504                __ipsec_errcode = EIPSEC_PRIORITY_NOT_COMPILED;
505                return -1;
506        }
507#endif
508
509        offset = tlen;
510
511        __ipsec_errcode = EIPSEC_NO_ERROR;
512        return 0;
513}
514
515static int
516set_x_request(src, dst)
517        struct sockaddr *src, *dst;
518{
519        struct sadb_x_ipsecrequest *p;
520        int reqlen;
521        u_int8_t *n;
522
523        reqlen = sizeof(*p)
524                + (src ? sysdep_sa_len(src) : 0)
525                + (dst ? sysdep_sa_len(dst) : 0);
526        tlen += reqlen;         /* increment to total length */
527
528        n = realloc(pbuf, tlen);
529        if (n == NULL) {
530                __ipsec_errcode = EIPSEC_NO_BUFS;
531                return -1;
532        }
533        pbuf = n;
534
535        p = (struct sadb_x_ipsecrequest *)&pbuf[offset];
536        p->sadb_x_ipsecrequest_len = reqlen;
537        p->sadb_x_ipsecrequest_proto = p_protocol;
538        p->sadb_x_ipsecrequest_mode = p_mode;
539        p->sadb_x_ipsecrequest_level = p_level;
540        p->sadb_x_ipsecrequest_reqid = p_reqid;
541        offset += sizeof(*p);
542
543        if (set_sockaddr(src) || set_sockaddr(dst))
544                return -1;
545
546        __ipsec_errcode = EIPSEC_NO_ERROR;
547        return 0;
548}
549
550static int
551set_sockaddr(addr)
552        struct sockaddr *addr;
553{
554        if (addr == NULL) {
555                __ipsec_errcode = EIPSEC_NO_ERROR;
556                return 0;
557        }
558
559        /* tlen has already incremented */
560
561        memcpy(&pbuf[offset], addr, sysdep_sa_len(addr));
562
563        offset += sysdep_sa_len(addr);
564
565        __ipsec_errcode = EIPSEC_NO_ERROR;
566        return 0;
567}
568
569static void
570policy_parse_request_init()
571{
572        p_protocol = IPPROTO_IP;
573        p_mode = IPSEC_MODE_ANY;
574        p_level = IPSEC_LEVEL_DEFAULT;
575        p_reqid = 0;
576        if (p_src != NULL) {
577                free(p_src);
578                p_src = NULL;
579        }
580        if (p_dst != NULL) {
581                free(p_dst);
582                p_dst = NULL;
583        }
584
585        return;
586}
587
588static void *
589policy_parse(msg, msglen)
590        const char *msg;
591        int msglen;
592{
593        int error;
594
595        pbuf = NULL;
596        tlen = 0;
597
598        /* initialize */
599        p_dir = IPSEC_DIR_INVALID;
600        p_type = IPSEC_POLICY_DISCARD;
601        policy_parse_request_init();
602        __policy__strbuffer__init__(msg);
603
604        error = yyparse();      /* it must be set errcode. */
605        __policy__strbuffer__free__();
606        #ifdef __rtems__
607        /* This frees the p_src and p_dst buffers. */
608        policy_parse_request_init();
609        #endif /* __rtems__ */
610
611        if (error) {
612                if (pbuf != NULL)
613                        free(pbuf);
614                return NULL;
615        }
616
617        /* update total length */
618        ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen);
619
620        __ipsec_errcode = EIPSEC_NO_ERROR;
621
622        return pbuf;
623}
624
625ipsec_policy_t
626ipsec_set_policy(msg, msglen)
627        __ipsec_const char *msg;
628        int msglen;
629{
630        caddr_t policy;
631
632        policy = policy_parse(msg, msglen);
633        if (policy == NULL) {
634                if (__ipsec_errcode == EIPSEC_NO_ERROR)
635                        __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
636                return NULL;
637        }
638
639        __ipsec_errcode = EIPSEC_NO_ERROR;
640        return policy;
641}
642#ifdef __rtems__
643
644void
645ipsec_free_policy(ipsec_policy_t buf)
646{
647        free(buf);
648}
649#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.