Return to policy_parse.y CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ipsec-tools / src / libipsec |
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: }