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

55-freebsd-126-freebsd-12
Last change on this file since 8645c9d7 was ff36f5e, checked in by Christian Mauderer <christian.mauderer@…>, on 05/30/18 at 12:27:35

Import ipsec-tools 0.8.2.

Import unchanged ipsec-tools sources in the release version 0.8.2. The
homepage of ipsec-tools is http://ipsec-tools.sourceforge.net/. The
sources can be obtained from there.

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