Annotation of embedaddon/ipsec-tools/src/libipsec/policy_parse.y, revision 1.1
1.1 ! misho 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:
! 100: static u_int8_t *pbuf = NULL; /* sadb_x_policy buffer */
! 101: static int tlen = 0; /* total length of pbuf */
! 102: static int offset = 0; /* offset of pbuf */
! 103: static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid;
! 104: static u_int32_t p_priority = 0;
! 105: static long p_priority_offset = 0;
! 106: static struct sockaddr *p_src = NULL;
! 107: static struct sockaddr *p_dst = NULL;
! 108:
! 109: struct _val;
! 110: extern void yyerror __P((char *msg));
! 111: static struct sockaddr *parse_sockaddr __P((struct _val *addrbuf,
! 112: struct _val *portbuf));
! 113: static int rule_check __P((void));
! 114: static int init_x_policy __P((void));
! 115: static int set_x_request __P((struct sockaddr *, struct sockaddr *));
! 116: static int set_sockaddr __P((struct sockaddr *));
! 117: static void policy_parse_request_init __P((void));
! 118: static void *policy_parse __P((const char *, int));
! 119:
! 120: extern void __policy__strbuffer__init__ __P((const char *));
! 121: extern void __policy__strbuffer__free__ __P((void));
! 122: extern int yyparse __P((void));
! 123: extern int yylex __P((void));
! 124:
! 125: extern 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: %%
! 149: policy_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:
! 273: rules
! 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:
! 286: rule
! 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:
! 303: protocol
! 304: : PROTOCOL { p_protocol = $1; }
! 305: ;
! 306:
! 307: mode
! 308: : MODE { p_mode = $1; }
! 309: ;
! 310:
! 311: level
! 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:
! 322: addresses
! 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:
! 364: void
! 365: yyerror(msg)
! 366: char *msg;
! 367: {
! 368: fprintf(stderr, "libipsec: %s while parsing \"%s\"\n",
! 369: msg, __libipsectext);
! 370:
! 371: return;
! 372: }
! 373:
! 374: static struct sockaddr *
! 375: parse_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:
! 440: static int
! 441: rule_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:
! 471: static int
! 472: init_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:
! 512: static int
! 513: set_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:
! 547: static int
! 548: set_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:
! 566: static void
! 567: policy_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:
! 585: static void *
! 586: policy_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:
! 618: ipsec_policy_t
! 619: ipsec_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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>