1 /* $NetBSD: policy_parse.y,v 1.10 2007/07/18 12:07:50 vanhu 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 char *offset_buf; 168 169 p_dir = $1; 170 p_type = $4; 171 172 /* buffer big enough to hold a prepended negative sign */ 173 offset_buf = malloc($3.len + 2); 174 if (offset_buf == NULL) 175 { 176 __ipsec_errcode = EIPSEC_NO_BUFS; 177 return -1; 178 } 179 180 /* positive input value means higher priority, therefore lower 181 actual value so that is closer to the beginning of the list */ 182 sprintf (offset_buf, "-%s", $3.buf); 183 184 errno = 0; 185 p_priority_offset = atol(offset_buf); 186 187 free(offset_buf); 188 189 if (errno != 0 || p_priority_offset < INT32_MIN) 190 { 191 __ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET; 192 return -1; 193 } 194 195 p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset; 196 197 if (init_x_policy()) 198 return -1; 199 } 200 rules 201 | DIR PRIORITY HYPHEN PRIO_OFFSET ACTION 202 { 203 p_dir = $1; 204 p_type = $5; 205 206 errno = 0; 207 p_priority_offset = atol($4.buf); 208 209 if (errno != 0 || p_priority_offset > INT32_MAX) 210 { 211 __ipsec_errcode = EIPSEC_INVAL_PRIORITY_OFFSET; 212 return -1; 213 } 214 215 /* negative input value means lower priority, therefore higher 216 actual value so that is closer to the end of the list */ 217 p_priority = PRIORITY_DEFAULT + (u_int32_t) p_priority_offset; 218 219 if (init_x_policy()) 220 return -1; 221 } 222 rules 223 | DIR PRIORITY PRIO_BASE ACTION 224 { 225 p_dir = $1; 226 p_type = $4; 227 228 p_priority = $3; 229 230 if (init_x_policy()) 231 return -1; 232 } 233 rules 234 | DIR PRIORITY PRIO_BASE PLUS PRIO_OFFSET ACTION 235 { 236 p_dir = $1; 237 p_type = $6; 238 239 errno = 0; 240 p_priority_offset = atol($5.buf); 241 242 if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_NEGATIVE_MAX) 243 { 244 __ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET; 245 return -1; 246 } 247 248 /* adding value means higher priority, therefore lower 249 actual value so that is closer to the beginning of the list */ 250 p_priority = $3 - (u_int32_t) p_priority_offset; 251 252 if (init_x_policy()) 253 return -1; 254 } 255 rules 256 | DIR PRIORITY PRIO_BASE HYPHEN PRIO_OFFSET ACTION 257 { 258 p_dir = $1; 259 p_type = $6; 260 261 errno = 0; 262 p_priority_offset = atol($5.buf); 263 264 if (errno != 0 || p_priority_offset > PRIORITY_OFFSET_POSITIVE_MAX) 265 { 266 __ipsec_errcode = EIPSEC_INVAL_PRIORITY_BASE_OFFSET; 267 return -1; 268 } 269 270 /* subtracting value means lower priority, therefore higher 271 actual value so that is closer to the end of the list */ 272 p_priority = $3 + (u_int32_t) p_priority_offset; 273 274 if (init_x_policy()) 275 return -1; 276 } 277 rules 278 | DIR 279 { 280 p_dir = $1; 281 p_type = 0; /* ignored it by kernel */ 282 283 p_priority = 0; 284 285 if (init_x_policy()) 286 return -1; 287 } 288 ; 289 290 rules 291 : /*NOTHING*/ 292 | rules rule { 293 if (rule_check() < 0) 294 return -1; 295 296 if (set_x_request(p_src, p_dst) < 0) 297 return -1; 298 299 policy_parse_request_init(); 300 } 301 ; 302 303 rule 304 : protocol SLASH mode SLASH addresses SLASH level 305 | protocol SLASH mode SLASH addresses SLASH 306 | protocol SLASH mode SLASH addresses 307 | protocol SLASH mode SLASH 308 | protocol SLASH mode SLASH SLASH level 309 | protocol SLASH mode 310 | protocol SLASH { 311 __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 312 return -1; 313 } 314 | protocol { 315 __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; 316 return -1; 317 } 318 ; 319 320 protocol 321 : PROTOCOL { p_protocol = $1; } 322 ; 323 324 mode 325 : MODE { p_mode = $1; } 326 ; 327 328 level 329 : LEVEL { 330 p_level = $1; 331 p_reqid = 0; 332 } 333 | LEVEL_SPECIFY { 334 p_level = IPSEC_LEVEL_UNIQUE; 335 p_reqid = atol($1.buf); /* atol() is good. */ 336 } 337 ; 338 339 addresses 340 : IPADDRESS { 341 p_src = parse_sockaddr(&$1, NULL); 342 if (p_src == NULL) 343 return -1; 344 } 345 HYPHEN 346 IPADDRESS { 347 p_dst = parse_sockaddr(&$4, NULL); 348 if (p_dst == NULL) 349 return -1; 350 } 351 | IPADDRESS PORT { 352 p_src = parse_sockaddr(&$1, &$2); 353 if (p_src == NULL) 354 return -1; 355 } 356 HYPHEN 357 IPADDRESS PORT { 358 p_dst = parse_sockaddr(&$5, &$6); 359 if (p_dst == NULL) 360 return -1; 361 } 362 | ME HYPHEN ANY { 363 if (p_dir != IPSEC_DIR_OUTBOUND) { 364 __ipsec_errcode = EIPSEC_INVAL_DIR; 365 return -1; 366 } 367 } 368 | ANY HYPHEN ME { 369 if (p_dir != IPSEC_DIR_INBOUND) { 370 __ipsec_errcode = EIPSEC_INVAL_DIR; 371 return -1; 372 } 373 } 374 /* 375 | ME HYPHEN ME 376 */ 377 ; 378 379 %% 380 381 void 382 yyerror(msg) 383 char *msg; 384 { 385 fprintf(stderr, "libipsec: %s while parsing \"%s\"\n", 386 msg, __libipsectext); 387 388 return; 389 } 390 391 static struct sockaddr * 392 parse_sockaddr(addrbuf, portbuf) 393 struct _val *addrbuf; 394 struct _val *portbuf; 395 { 396 struct addrinfo hints, *res; 397 char *addr; 398 char *serv = NULL; 399 int error; 400 struct sockaddr *newaddr = NULL; 401 402 if ((addr = malloc(addrbuf->len + 1)) == NULL) { 403 yyerror("malloc failed"); 404 __ipsec_set_strerror(strerror(errno)); 405 return NULL; 406 } 407 408 if (portbuf && ((serv = malloc(portbuf->len + 1)) == NULL)) { 409 free(addr); 410 yyerror("malloc failed"); 411 __ipsec_set_strerror(strerror(errno)); 412 return NULL; 413 } 414 415 strncpy(addr, addrbuf->buf, addrbuf->len); 416 addr[addrbuf->len] = '\0'; 417 418 if (portbuf) { 419 strncpy(serv, portbuf->buf, portbuf->len); 420 serv[portbuf->len] = '\0'; 421 } 422 423 memset(&hints, 0, sizeof(hints)); 424 hints.ai_family = PF_UNSPEC; 425 hints.ai_flags = AI_NUMERICHOST; 426 hints.ai_socktype = SOCK_DGRAM; 427 error = getaddrinfo(addr, serv, &hints, &res); 428 free(addr); 429 if (serv != NULL) 430 free(serv); 431 if (error != 0) { 432 yyerror("invalid IP address"); 433 __ipsec_set_strerror(gai_strerror(error)); 434 return NULL; 435 } 436 437 if (res->ai_addr == NULL) { 438 yyerror("invalid IP address"); 439 __ipsec_set_strerror(gai_strerror(error)); 440 return NULL; 441 } 442 443 newaddr = malloc(res->ai_addrlen); 444 if (newaddr == NULL) { 445 __ipsec_errcode = EIPSEC_NO_BUFS; 446 freeaddrinfo(res); 447 return NULL; 448 } 449 memcpy(newaddr, res->ai_addr, res->ai_addrlen); 450 451 freeaddrinfo(res); 452 453 __ipsec_errcode = EIPSEC_NO_ERROR; 454 return newaddr; 455 } 456 457 static int 458 rule_check() 459 { 460 if (p_type == IPSEC_POLICY_IPSEC) { 461 if (p_protocol == IPPROTO_IP) { 462 __ipsec_errcode = EIPSEC_NO_PROTO; 463 return -1; 464 } 465 466 if (p_mode != IPSEC_MODE_TRANSPORT 467 && p_mode != IPSEC_MODE_TUNNEL) { 468 __ipsec_errcode = EIPSEC_INVAL_MODE; 469 return -1; 470 } 471 472 if (p_src == NULL && p_dst == NULL) { 473 if (p_mode != IPSEC_MODE_TRANSPORT) { 474 __ipsec_errcode = EIPSEC_INVAL_ADDRESS; 475 return -1; 476 } 477 } 478 else if (p_src->sa_family != p_dst->sa_family) { 479 __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; 480 return -1; 481 } 482 } 483 484 __ipsec_errcode = EIPSEC_NO_ERROR; 485 return 0; 486 } 487 488 static int 489 init_x_policy() 490 { 491 struct sadb_x_policy *p; 492 493 if (pbuf) { 494 free(pbuf); 495 tlen = 0; 496 } 497 pbuf = malloc(sizeof(struct sadb_x_policy)); 498 if (pbuf == NULL) { 499 __ipsec_errcode = EIPSEC_NO_BUFS; 500 return -1; 501 } 502 tlen = sizeof(struct sadb_x_policy); 503 504 memset(pbuf, 0, tlen); 505 p = (struct sadb_x_policy *)pbuf; 506 p->sadb_x_policy_len = 0; /* must update later */ 507 p->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 508 p->sadb_x_policy_type = p_type; 509 p->sadb_x_policy_dir = p_dir; 510 p->sadb_x_policy_id = 0; 511 #ifdef HAVE_PFKEY_POLICY_PRIORITY 512 p->sadb_x_policy_priority = p_priority; 513 #else 514 /* fail if given a priority and libipsec was not compiled with 515 priority support */ 516 if (p_priority != 0) 517 { 518 __ipsec_errcode = EIPSEC_PRIORITY_NOT_COMPILED; 519 return -1; 520 } 521 #endif 522 523 offset = tlen; 524 525 __ipsec_errcode = EIPSEC_NO_ERROR; 526 return 0; 527 } 528 529 static int 530 set_x_request(src, dst) 531 struct sockaddr *src, *dst; 532 { 533 struct sadb_x_ipsecrequest *p; 534 int reqlen; 535 u_int8_t *n; 536 537 reqlen = sizeof(*p) 538 + (src ? sysdep_sa_len(src) : 0) 539 + (dst ? sysdep_sa_len(dst) : 0); 540 tlen += reqlen; /* increment to total length */ 541 542 n = realloc(pbuf, tlen); 543 if (n == NULL) { 544 __ipsec_errcode = EIPSEC_NO_BUFS; 545 return -1; 546 } 547 pbuf = n; 548 549 p = (struct sadb_x_ipsecrequest *)&pbuf[offset]; 550 p->sadb_x_ipsecrequest_len = reqlen; 551 p->sadb_x_ipsecrequest_proto = p_protocol; 552 p->sadb_x_ipsecrequest_mode = p_mode; 553 p->sadb_x_ipsecrequest_level = p_level; 554 p->sadb_x_ipsecrequest_reqid = p_reqid; 555 offset += sizeof(*p); 556 557 if (set_sockaddr(src) || set_sockaddr(dst)) 558 return -1; 559 560 __ipsec_errcode = EIPSEC_NO_ERROR; 561 return 0; 562 } 563 564 static int 565 set_sockaddr(addr) 566 struct sockaddr *addr; 567 { 568 if (addr == NULL) { 569 __ipsec_errcode = EIPSEC_NO_ERROR; 570 return 0; 571 } 572 573 /* tlen has already incremented */ 574 575 memcpy(&pbuf[offset], addr, sysdep_sa_len(addr)); 576 577 offset += sysdep_sa_len(addr); 578 579 __ipsec_errcode = EIPSEC_NO_ERROR; 580 return 0; 581 } 582 583 static void 584 policy_parse_request_init() 585 { 586 p_protocol = IPPROTO_IP; 587 p_mode = IPSEC_MODE_ANY; 588 p_level = IPSEC_LEVEL_DEFAULT; 589 p_reqid = 0; 590 if (p_src != NULL) { 591 free(p_src); 592 p_src = NULL; 593 } 594 if (p_dst != NULL) { 595 free(p_dst); 596 p_dst = NULL; 597 } 598 599 return; 600 } 601 602 static void * 603 policy_parse(msg, msglen) 604 const char *msg; 605 int msglen; 606 { 607 int error; 608 609 pbuf = NULL; 610 tlen = 0; 611 612 /* initialize */ 613 p_dir = IPSEC_DIR_INVALID; 614 p_type = IPSEC_POLICY_DISCARD; 615 policy_parse_request_init(); 616 __policy__strbuffer__init__(msg); 617 618 error = yyparse(); /* it must be set errcode. */ 619 __policy__strbuffer__free__(); 620 621 if (error) { 622 if (pbuf != NULL) 623 free(pbuf); 624 return NULL; 625 } 626 627 /* update total length */ 628 ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen); 629 630 __ipsec_errcode = EIPSEC_NO_ERROR; 631 632 return pbuf; 633 } 634 635 ipsec_policy_t 636 ipsec_set_policy(msg, msglen) 637 __ipsec_const char *msg; 638 int msglen; 639 { 640 caddr_t policy; 641 642 policy = policy_parse(msg, msglen); 643 if (policy == NULL) { 644 if (__ipsec_errcode == EIPSEC_NO_ERROR) 645 __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; 646 return NULL; 647 } 648 649 __ipsec_errcode = EIPSEC_NO_ERROR; 650 return policy; 651 } 652