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