parse.y revision 1.27
1/* $OpenBSD: parse.y,v 1.27 2005/10/16 21:29:22 hshoexer Exp $ */ 2 3/* 4 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2001 Markus Friedl. All rights reserved. 6 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 7 * Copyright (c) 2001 Theo de Raadt. All rights reserved. 8 * Copyright (c) 2004, 2005 Hans-Joerg Hoexer <hshoexer@openbsd.org> 9 * 10 * Permission to use, copy, modify, and distribute this software for any 11 * purpose with or without fee is hereby granted, provided that the above 12 * copyright notice and this permission notice appear in all copies. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23%{ 24#include <sys/types.h> 25#include <sys/queue.h> 26#include <sys/socket.h> 27#include <sys/stat.h> 28#include <netinet/in.h> 29#include <netinet/ip_ipsp.h> 30#include <arpa/inet.h> 31 32#include <ctype.h> 33#include <err.h> 34#include <errno.h> 35#include <fcntl.h> 36#include <limits.h> 37#include <stdarg.h> 38#include <stdio.h> 39#include <string.h> 40#include <syslog.h> 41#include <unistd.h> 42 43#include "ipsecctl.h" 44 45#define KEYSIZE_LIMIT 1024 46 47static struct ipsecctl *ipsec = NULL; 48static FILE *fin = NULL; 49static int lineno = 1; 50static int errors = 0; 51static int debug = 0; 52 53const struct ipsec_xf authxfs[] = { 54 {"unknown", AUTHXF_UNKNOWN, 0, 0}, 55 {"none", AUTHXF_NONE, 0, 0}, 56 {"hmac-md5", AUTHXF_HMAC_MD5, 16, 0}, 57 {"hmac-ripemd160", AUTHXF_HMAC_RIPEMD160, 20, 0}, 58 {"hmac-sha1", AUTHXF_HMAC_SHA1, 20, 0}, 59 {"hmac-sha2-256", AUTHXF_HMAC_SHA2_256, 32, 0}, 60 {"hmac-sha2-384", AUTHXF_HMAC_SHA2_384, 48, 0}, 61 {"hmac-sha2-512", AUTHXF_HMAC_SHA2_512, 64, 0}, 62 {"md5", AUTHXF_MD5, 16, 0}, 63 {"sha1", AUTHXF_SHA1, 20, 0}, 64 {NULL, 0, 0, 0}, 65}; 66 67const struct ipsec_xf encxfs[] = { 68 {"unknown", ENCXF_UNKNOWN, 0, 0}, 69 {"none", ENCXF_NONE, 0, 0}, 70 {"3des-cbc", ENCXF_3DES_CBC, 24, 24}, 71 {"des-cbc", ENCXF_DES_CBC, 8, 8}, 72 {"aes", ENCXF_AES, 16, 32}, 73 {"aesctr", ENCXF_AESCTR, 16+4, 32+4}, 74 {"blowfish", ENCXF_BLOWFISH, 5, 56}, 75 {"cast128", ENCXF_CAST128, 5, 16}, 76 {"null", ENCXF_NULL, 0, 0}, 77 {"skipjack", ENCXF_SKIPJACK, 10, 10}, 78 {NULL, 0, 0, 0}, 79}; 80 81int yyerror(const char *, ...); 82int yyparse(void); 83int kw_cmp(const void *, const void *); 84int lookup(char *); 85int lgetc(FILE *); 86int lungetc(int); 87int findeol(void); 88int yylex(void); 89 90TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 91struct sym { 92 TAILQ_ENTRY(sym) entries; 93 int used; 94 int persist; 95 char *nam; 96 char *val; 97}; 98 99int symset(const char *, const char *, int); 100int cmdline_symset(char *); 101char *symget(const char *); 102int atoul(char *, u_long *); 103int atospi(char *, u_int32_t *); 104u_int8_t x2i(unsigned char *); 105struct ipsec_key *parsekey(unsigned char *, size_t); 106struct ipsec_key *parsekeyfile(char *); 107struct ipsec_addr *host(const char *); 108struct ipsec_addr *copyhost(const struct ipsec_addr *); 109const struct ipsec_xf *parse_xf(const char *, const struct ipsec_xf *); 110struct ipsec_transforms *transforms(const char *, const char *); 111struct ipsec_transforms *copytransforms(const struct ipsec_transforms *); 112int validate_sa(u_int32_t, u_int8_t, 113 struct ipsec_transforms *, struct ipsec_key *, 114 struct ipsec_key *); 115struct ipsec_rule *create_sa(u_int8_t, struct ipsec_addr *, 116 struct ipsec_addr *, u_int32_t, 117 struct ipsec_transforms *, struct ipsec_key *, 118 struct ipsec_key *); 119struct ipsec_rule *reverse_sa(struct ipsec_rule *, u_int32_t, 120 struct ipsec_key *, struct ipsec_key *); 121struct ipsec_rule *create_flow(u_int8_t, struct ipsec_addr *, struct 122 ipsec_addr *, struct ipsec_addr *, u_int8_t, 123 char *, char *, u_int16_t); 124struct ipsec_rule *reverse_rule(struct ipsec_rule *); 125struct ipsec_rule *create_ike(struct ipsec_addr *, struct ipsec_addr *, 126 struct ipsec_addr *, struct ipsec_transforms *, 127 struct ipsec_transforms *, u_int8_t, u_int8_t, 128 char *, char *); 129 130typedef struct { 131 union { 132 u_int32_t number; 133 u_int8_t ikemode; 134 u_int8_t dir; 135 char *string; 136 u_int8_t protocol; 137 struct { 138 struct ipsec_addr *src; 139 struct ipsec_addr *dst; 140 } hosts; 141 struct ipsec_addr *peer; 142 struct ipsec_addr *host; 143 struct { 144 char *srcid; 145 char *dstid; 146 } ids; 147 char *id; 148 u_int16_t authtype; 149 struct { 150 u_int32_t spiout; 151 u_int32_t spiin; 152 } spis; 153 struct { 154 struct ipsec_key *keyout; 155 struct ipsec_key *keyin; 156 } authkeys; 157 struct { 158 struct ipsec_key *keyout; 159 struct ipsec_key *keyin; 160 } enckeys; 161 struct { 162 struct ipsec_key *keyout; 163 struct ipsec_key *keyin; 164 } keys; 165 struct ipsec_transforms *transforms; 166 struct ipsec_transforms *mmxfs; 167 struct ipsec_transforms *qmxfs; 168 } v; 169 int lineno; 170} YYSTYPE; 171 172%} 173 174%token FLOW FROM ESP AH IN PEER ON OUT TO SRCID DSTID RSA PSK TCPMD5 SPI 175%token AUTHKEY ENCKEY FILENAME AUTHXF ENCXF ERROR IKE MAIN QUICK PASSIVE 176%token ACTIVE ANY 177%token <v.string> STRING 178%type <v.dir> dir 179%type <v.protocol> protocol 180%type <v.number> number 181%type <v.hosts> hosts 182%type <v.peer> peer 183%type <v.host> host 184%type <v.ids> ids 185%type <v.id> id 186%type <v.authtype> authtype 187%type <v.spis> spispec 188%type <v.authkeys> authkeyspec 189%type <v.enckeys> enckeyspec 190%type <v.keys> keyspec 191%type <v.transforms> transforms 192%type <v.mmxfs> mmxfs 193%type <v.qmxfs> qmxfs 194%type <v.ikemode> ikemode 195%% 196 197grammar : /* empty */ 198 | grammar '\n' 199 | grammar ikerule '\n' 200 | grammar flowrule '\n' 201 | grammar sarule '\n' 202 | grammar tcpmd5rule '\n' 203 | grammar error '\n' { errors++; } 204 ; 205 206number : STRING { 207 unsigned long ulval; 208 209 if (atoul($1, &ulval) == -1) { 210 yyerror("%s is not a number", $1); 211 free($1); 212 YYERROR; 213 } 214 if (ulval > UINT_MAX) { 215 yyerror("0x%lx out of range", ulval); 216 free($1); 217 YYERROR; 218 } 219 $$ = (u_int32_t)ulval; 220 free($1); 221 } 222 ; 223 224tcpmd5rule : TCPMD5 hosts spispec authkeyspec { 225 struct ipsec_rule *r; 226 227 r = create_sa(IPSEC_TCPMD5, $2.src, $2.dst, $3.spiout, 228 NULL, $4.keyout, NULL); 229 if (r == NULL) 230 YYERROR; 231 r->nr = ipsec->rule_nr++; 232 233 if (ipsecctl_add_rule(ipsec, r)) 234 errx(1, "tcpmd5rule: ipsecctl_add_rule"); 235 236 /* Create and add reverse SA rule. */ 237 if ($3.spiin != 0 || $4.keyin != NULL) { 238 r = reverse_sa(r, $3.spiin, $4.keyin, NULL); 239 if (r == NULL) 240 YYERROR; 241 r->nr = ipsec->rule_nr++; 242 243 if (ipsecctl_add_rule(ipsec, r)) 244 errx(1, "tcpmd5rule: ipsecctl_add_rule"); 245 } 246 } 247 ; 248 249sarule : protocol hosts spispec transforms authkeyspec enckeyspec { 250 struct ipsec_rule *r; 251 252 r = create_sa($1, $2.src, $2.dst, $3.spiout, $4, 253 $5.keyout, $6.keyout); 254 if (r == NULL) 255 YYERROR; 256 r->nr = ipsec->rule_nr++; 257 258 if (ipsecctl_add_rule(ipsec, r)) 259 errx(1, "sarule: ipsecctl_add_rule"); 260 261 /* Create and add reverse SA rule. */ 262 if ($3.spiin != 0 || $5.keyin || $6.keyin) { 263 r = reverse_sa(r, $3.spiin, $5.keyin, 264 $6.keyin); 265 if (r == NULL) 266 YYERROR; 267 r->nr = ipsec->rule_nr++; 268 269 if (ipsecctl_add_rule(ipsec, r)) 270 errx(1, "sarule: ipsecctl_add_rule"); 271 } 272 } 273 ; 274 275flowrule : FLOW protocol dir hosts peer ids authtype { 276 struct ipsec_rule *r; 277 278 r = create_flow($3, $4.src, $4.dst, $5, $2, $6.srcid, 279 $6.dstid, $7); 280 if (r == NULL) 281 YYERROR; 282 r->nr = ipsec->rule_nr++; 283 284 if (ipsecctl_add_rule(ipsec, r)) 285 errx(1, "flowrule: ipsecctl_add_rule"); 286 287 /* Create and add reverse flow rule. */ 288 if ($3 == IPSEC_INOUT) { 289 r = reverse_rule(r); 290 r->nr = ipsec->rule_nr++; 291 292 if (ipsecctl_add_rule(ipsec, r)) 293 errx(1, "flowrule: ipsecctl_add_rule"); 294 } 295 } 296 ; 297 298ikerule : IKE ikemode protocol hosts peer mmxfs qmxfs ids { 299 struct ipsec_rule *r; 300 301 r = create_ike($4.src, $4.dst, $5, $6, $7, $3, $2, 302 $8.srcid, $8.dstid); 303 if (r == NULL) 304 YYERROR; 305 r->nr = ipsec->rule_nr++; 306 307 if (ipsecctl_add_rule(ipsec, r)) 308 errx(1, "ikerule: ipsecctl_add_rule"); 309 }; 310 311protocol : /* empty */ { $$ = IPSEC_ESP; } 312 | ESP { $$ = IPSEC_ESP; } 313 | AH { $$ = IPSEC_AH; } 314 ; 315 316dir : /* empty */ { $$ = IPSEC_INOUT; } 317 | IN { $$ = IPSEC_IN; } 318 | OUT { $$ = IPSEC_OUT; } 319 ; 320 321hosts : FROM host TO host { 322 $$.src = $2; 323 $$.dst = $4; 324 } 325 ; 326 327peer : /* empty */ { $$ = NULL; } 328 | PEER STRING { 329 if (($$ = host($2)) == NULL) { 330 free($2); 331 yyerror("could not parse host specification"); 332 YYERROR; 333 } 334 free($2); 335 } 336 ; 337 338host : STRING { 339 if (($$ = host($1)) == NULL) { 340 free($1); 341 yyerror("could not parse host specification"); 342 YYERROR; 343 } 344 free($1); 345 } 346 | STRING '/' number { 347 char *buf; 348 349 if (asprintf(&buf, "%s/%u", $1, $3) == -1) 350 err(1, "host: asprintf"); 351 free($1); 352 if (($$ = host(buf)) == NULL) { 353 free(buf); 354 yyerror("could not parse host specification"); 355 YYERROR; 356 } 357 free(buf); 358 } 359 | ANY { 360 struct ipsec_addr *ipa; 361 362 ipa = calloc(1, sizeof(struct ipsec_addr)); 363 if (ipa == NULL) 364 err(1, "calloc"); 365 366 ipa->af = AF_INET; 367 ipa->netaddress = 1; 368 if ((ipa->name = strdup("0.0.0.0/0")) == NULL) 369 err(1, "strdup"); 370 $$ = ipa; 371 } 372 ; 373 374ids : /* empty */ { 375 $$.srcid = NULL; 376 $$.dstid = NULL; 377 } 378 | SRCID id DSTID id { 379 $$.srcid = $2; 380 $$.dstid = $4; 381 } 382 | SRCID id { 383 $$.srcid = $2; 384 $$.dstid = NULL; 385 } 386 | DSTID id { 387 $$.srcid = NULL; 388 $$.dstid = $2; 389 } 390 ; 391 392id : STRING { $$ = $1; } 393 ; 394 395authtype : /* empty */ { $$ = 0; } 396 | RSA { $$ = AUTH_RSA; } 397 | PSK { $$ = AUTH_PSK; } 398 ; 399 400spispec : SPI STRING { 401 u_int32_t spi; 402 char *p = strchr($2, ':'); 403 404 if (p != NULL) { 405 *p++ = 0; 406 407 if (atospi(p, &spi) == -1) { 408 yyerror("%s is not a valid spi", p); 409 free($2); 410 YYERROR; 411 } 412 $$.spiin = spi; 413 } 414 if (atospi($2, &spi) == -1) { 415 yyerror("%s is not a valid spi", $2); 416 free($2); 417 YYERROR; 418 } 419 $$.spiout = spi; 420 421 422 free($2); 423 } 424 ; 425 426transforms : /* empty */ { 427 struct ipsec_transforms *xfs; 428 429 /* We create just an empty transform */ 430 if ((xfs = calloc(1, sizeof(struct ipsec_transforms))) 431 == NULL) 432 err(1, "transforms: calloc"); 433 $$ = xfs; 434 } 435 | AUTHXF STRING ENCXF STRING { 436 if (($$ = transforms($2, $4)) == NULL) { 437 free($2); 438 free($4); 439 yyerror("could not parse transforms"); 440 YYERROR; 441 } 442 free($2); 443 free($4); 444 } 445 | AUTHXF STRING { 446 if (($$ = transforms($2, NULL)) == NULL) { 447 free($2); 448 yyerror("could not parse transforms"); 449 YYERROR; 450 } 451 free($2); 452 } 453 | ENCXF STRING { 454 if (($$ = transforms(NULL, $2)) == NULL) { 455 free($2); 456 yyerror("could not parse transforms"); 457 YYERROR; 458 } 459 free($2); 460 } 461 ; 462 463mmxfs : /* empty */ { 464 struct ipsec_transforms *xfs; 465 466 /* We create just an empty transform */ 467 if ((xfs = calloc(1, sizeof(struct ipsec_transforms))) 468 == NULL) 469 err(1, "mmxfs: calloc"); 470 $$ = xfs; 471 } 472 | MAIN transforms { $$ = $2; } 473 ; 474 475qmxfs : /* empty */ { 476 struct ipsec_transforms *xfs; 477 478 /* We create just an empty transform */ 479 if ((xfs = calloc(1, sizeof(struct ipsec_transforms))) 480 == NULL) 481 err(1, "qmxfs: calloc"); 482 $$ = xfs; 483 } 484 | QUICK transforms { $$ = $2; } 485 ; 486 487authkeyspec : /* empty */ { 488 $$.keyout = NULL; 489 $$.keyin = NULL; 490 } 491 | AUTHKEY keyspec { 492 $$.keyout = $2.keyout; 493 $$.keyin = $2.keyin; 494 } 495 ; 496 497enckeyspec : /* empty */ { 498 $$.keyout = NULL; 499 $$.keyin = NULL; 500 } 501 | ENCKEY keyspec { 502 $$.keyout = $2.keyout; 503 $$.keyin = $2.keyin; 504 } 505 ; 506 507keyspec : STRING { 508 unsigned char *hex; 509 unsigned char *p = strchr($1, ':'); 510 511 if (p != NULL ) { 512 *p++ = 0; 513 514 if (!strncmp(p, "0x", 2)) 515 p += 2; 516 $$.keyin = parsekey(p, strlen(p)); 517 } 518 519 hex = $1; 520 if (!strncmp(hex, "0x", 2)) 521 hex += 2; 522 $$.keyout = parsekey(hex, strlen(hex)); 523 524 free($1); 525 } 526 | FILENAME STRING { 527 unsigned char *p = strchr($2, ':'); 528 529 if (p != NULL) { 530 *p++ = 0; 531 $$.keyin = parsekeyfile(p); 532 } 533 $$.keyout = parsekeyfile($2); 534 free($2); 535 } 536 ; 537ikemode : /* empty */ { $$ = IKE_ACTIVE; } 538 | PASSIVE { $$ = IKE_PASSIVE; } 539 | ACTIVE { $$ = IKE_ACTIVE; } 540 ; 541%% 542 543struct keywords { 544 const char *k_name; 545 int k_val; 546}; 547 548int 549yyerror(const char *fmt, ...) 550{ 551 va_list ap; 552 extern char *infile; 553 554 errors = 1; 555 va_start(ap, fmt); 556 fprintf(stderr, "%s: %d: ", infile, yyval.lineno); 557 vfprintf(stderr, fmt, ap); 558 fprintf(stderr, "\n"); 559 va_end(ap); 560 return (0); 561} 562 563int 564kw_cmp(const void *k, const void *e) 565{ 566 return (strcmp(k, ((const struct keywords *)e)->k_name)); 567} 568 569int 570lookup(char *s) 571{ 572 /* this has to be sorted always */ 573 static const struct keywords keywords[] = { 574 { "active", ACTIVE}, 575 { "ah", AH}, 576 { "any", ANY}, 577 { "auth", AUTHXF}, 578 { "authkey", AUTHKEY}, 579 { "dstid", DSTID}, 580 { "enc", ENCXF}, 581 { "enckey", ENCKEY}, 582 { "esp", ESP}, 583 { "file", FILENAME}, 584 { "flow", FLOW}, 585 { "from", FROM}, 586 { "ike", IKE}, 587 { "in", IN}, 588 { "main", MAIN}, 589 { "out", OUT}, 590 { "passive", PASSIVE}, 591 { "peer", PEER}, 592 { "psk", PSK}, 593 { "quick", QUICK}, 594 { "rsa", RSA}, 595 { "spi", SPI}, 596 { "srcid", SRCID}, 597 { "tcpmd5", TCPMD5}, 598 { "to", TO}, 599 }; 600 const struct keywords *p; 601 602 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 603 sizeof(keywords[0]), kw_cmp); 604 605 if (p) { 606 if (debug > 1) 607 fprintf(stderr, "%s: %d\n", s, p->k_val); 608 return (p->k_val); 609 } else { 610 if (debug > 1) 611 fprintf(stderr, "string: %s\n", s); 612 return (STRING); 613 } 614} 615 616#define MAXPUSHBACK 128 617 618char *parsebuf; 619int parseindex; 620char pushback_buffer[MAXPUSHBACK]; 621int pushback_index = 0; 622 623int 624lgetc(FILE *f) 625{ 626 int c, next; 627 628 if (parsebuf) { 629 /* Read character from the parsebuffer instead of input. */ 630 if (parseindex >= 0) { 631 c = parsebuf[parseindex++]; 632 if (c != '\0') 633 return (c); 634 parsebuf = NULL; 635 } else 636 parseindex++; 637 } 638 639 if (pushback_index) 640 return (pushback_buffer[--pushback_index]); 641 642 while ((c = getc(f)) == '\\') { 643 next = getc(f); 644 if (next != '\n') { 645 if (isspace(next)) 646 yyerror("whitespace after \\"); 647 ungetc(next, f); 648 break; 649 } 650 yylval.lineno = lineno; 651 lineno++; 652 } 653 if (c == '\t' || c == ' ') { 654 /* Compress blanks to a single space. */ 655 do { 656 c = getc(f); 657 } while (c == '\t' || c == ' '); 658 ungetc(c, f); 659 c = ' '; 660 } 661 662 return (c); 663} 664 665int 666lungetc(int c) 667{ 668 if (c == EOF) 669 return (EOF); 670 if (parsebuf) { 671 parseindex--; 672 if (parseindex >= 0) 673 return (c); 674 } 675 if (pushback_index < MAXPUSHBACK-1) 676 return (pushback_buffer[pushback_index++] = c); 677 else 678 return (EOF); 679} 680 681int 682findeol(void) 683{ 684 int c; 685 686 parsebuf = NULL; 687 pushback_index = 0; 688 689 /* skip to either EOF or the first real EOL */ 690 while (1) { 691 c = lgetc(fin); 692 if (c == '\n') { 693 lineno++; 694 break; 695 } 696 if (c == EOF) 697 break; 698 } 699 return (ERROR); 700} 701 702int 703yylex(void) 704{ 705 char buf[8096]; 706 char *p, *val; 707 int endc, c; 708 int token; 709 710top: 711 p = buf; 712 while ((c = lgetc(fin)) == ' ') 713 ; /* nothing */ 714 715 yylval.lineno = lineno; 716 if (c == '#') 717 while ((c = lgetc(fin)) != '\n' && c != EOF) 718 ; /* nothing */ 719 if (c == '$' && parsebuf == NULL) { 720 while (1) { 721 if ((c = lgetc(fin)) == EOF) 722 return (0); 723 724 if (p + 1 >= buf + sizeof(buf) - 1) { 725 yyerror("string too long"); 726 return (findeol()); 727 } 728 if (isalnum(c) || c == '_') { 729 *p++ = (char)c; 730 continue; 731 } 732 *p = '\0'; 733 lungetc(c); 734 break; 735 } 736 val = symget(buf); 737 if (val == NULL) { 738 yyerror("macro \"%s\" not defined", buf); 739 return (findeol()); 740 } 741 parsebuf = val; 742 parseindex = 0; 743 goto top; 744 } 745 746 switch (c) { 747 case '\'': 748 case '"': 749 endc = c; 750 while (1) { 751 if ((c = lgetc(fin)) == EOF) 752 return (0); 753 if (c == endc) { 754 *p = '\0'; 755 break; 756 } 757 if (c == '\n') { 758 lineno++; 759 continue; 760 } 761 if (p + 1 >= buf + sizeof(buf) - 1) { 762 yyerror("string too long"); 763 return (findeol()); 764 } 765 *p++ = (char)c; 766 } 767 yylval.v.string = strdup(buf); 768 if (yylval.v.string == NULL) 769 err(1, "yylex: strdup"); 770 return (STRING); 771 } 772 773#define allowed_in_string(x) \ 774 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 775 x != '{' && x != '}' && x != '<' && x != '>' && \ 776 x != '!' && x != '=' && x != '/' && x != '#' && \ 777 x != ',')) 778 779 if (isalnum(c) || c == ':' || c == '_' || c == '*') { 780 do { 781 *p++ = c; 782 if ((unsigned)(p-buf) >= sizeof(buf)) { 783 yyerror("string too long"); 784 return (findeol()); 785 } 786 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); 787 lungetc(c); 788 *p = '\0'; 789 if ((token = lookup(buf)) == STRING) 790 if ((yylval.v.string = strdup(buf)) == NULL) 791 err(1, "yylex: strdup"); 792 return (token); 793 } 794 if (c == '\n') { 795 yylval.lineno = lineno; 796 lineno++; 797 } 798 if (c == EOF) 799 return (0); 800 return (c); 801} 802 803int 804parse_rules(FILE *input, struct ipsecctl *ipsecx) 805{ 806 struct sym *sym, *next; 807 808 ipsec = ipsecx; 809 fin = input; 810 lineno = 1; 811 errors = 0; 812 813 yyparse(); 814 815 /* Free macros and check which have not been used. */ 816 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 817 next = TAILQ_NEXT(sym, entries); 818 free(sym->nam); 819 free(sym->val); 820 TAILQ_REMOVE(&symhead, sym, entries); 821 free(sym); 822 } 823 824 return (errors ? -1 : 0); 825} 826 827int 828symset(const char *nam, const char *val, int persist) 829{ 830 struct sym *sym; 831 832 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 833 sym = TAILQ_NEXT(sym, entries)) 834 ; /* nothing */ 835 836 if (sym != NULL) { 837 if (sym->persist == 1) 838 return (0); 839 else { 840 free(sym->nam); 841 free(sym->val); 842 TAILQ_REMOVE(&symhead, sym, entries); 843 free(sym); 844 } 845 } 846 if ((sym = calloc(1, sizeof(*sym))) == NULL) 847 return (-1); 848 849 sym->nam = strdup(nam); 850 if (sym->nam == NULL) { 851 free(sym); 852 return (-1); 853 } 854 sym->val = strdup(val); 855 if (sym->val == NULL) { 856 free(sym->nam); 857 free(sym); 858 return (-1); 859 } 860 sym->used = 0; 861 sym->persist = persist; 862 TAILQ_INSERT_TAIL(&symhead, sym, entries); 863 return (0); 864} 865 866int 867cmdline_symset(char *s) 868{ 869 char *sym, *val; 870 int ret; 871 size_t len; 872 873 if ((val = strrchr(s, '=')) == NULL) 874 return (-1); 875 876 len = strlen(s) - strlen(val) + 1; 877 if ((sym = malloc(len)) == NULL) 878 err(1, "cmdline_symset: malloc"); 879 880 strlcpy(sym, s, len); 881 882 ret = symset(sym, val + 1, 1); 883 free(sym); 884 885 return (ret); 886} 887 888char * 889symget(const char *nam) 890{ 891 struct sym *sym; 892 893 TAILQ_FOREACH(sym, &symhead, entries) 894 if (strcmp(nam, sym->nam) == 0) { 895 sym->used = 1; 896 return (sym->val); 897 } 898 return (NULL); 899} 900 901int 902atoul(char *s, u_long *ulvalp) 903{ 904 u_long ulval; 905 char *ep; 906 907 errno = 0; 908 ulval = strtoul(s, &ep, 0); 909 if (s[0] == '\0' || *ep != '\0') 910 return (-1); 911 if (errno == ERANGE && ulval == ULONG_MAX) 912 return (-1); 913 *ulvalp = ulval; 914 return (0); 915} 916 917int 918atospi(char *s, u_int32_t *spivalp) 919{ 920 unsigned long ulval; 921 922 if (atoul(s, &ulval) == -1) 923 return (-1); 924 if (ulval >= SPI_RESERVED_MIN && ulval <= SPI_RESERVED_MAX) { 925 yyerror("illegal SPI value"); 926 return (-1); 927 } 928 *spivalp = ulval; 929 return (0); 930} 931 932u_int8_t 933x2i(unsigned char *s) 934{ 935 char ss[3]; 936 937 ss[0] = s[0]; 938 ss[1] = s[1]; 939 ss[2] = 0; 940 941 if (!isxdigit(s[0]) || !isxdigit(s[1])) { 942 yyerror("keys need to be specified in hex digits"); 943 return (-1); 944 } 945 return ((u_int8_t)strtoul(ss, NULL, 16)); 946} 947 948struct ipsec_key * 949parsekey(unsigned char *hexkey, size_t len) 950{ 951 struct ipsec_key *key; 952 int i; 953 954 key = calloc(1, sizeof(struct ipsec_key)); 955 if (key == NULL) 956 err(1, "parsekey: calloc"); 957 958 key->len = len / 2; 959 key->data = calloc(key->len, sizeof(u_int8_t)); 960 if (key->data == NULL) 961 err(1, "parsekey: calloc"); 962 963 for (i = 0; i < (int)key->len; i++) 964 key->data[i] = x2i(hexkey + 2 * i); 965 966 return (key); 967} 968 969struct ipsec_key * 970parsekeyfile(char *filename) 971{ 972 struct stat sb; 973 int fd; 974 unsigned char *hex; 975 976 if (stat(filename, &sb) < 0) 977 err(1, "parsekeyfile: stat %s", filename); 978 if ((sb.st_size > KEYSIZE_LIMIT) || (sb.st_size == 0)) 979 errx(1, "key too %s", sb.st_size ? "large" : 980 "small"); 981 if ((hex = calloc(sb.st_size, sizeof(unsigned char))) 982 == NULL) 983 err(1, "parsekeyfile: calloc"); 984 if ((fd = open(filename, O_RDONLY)) < 0) 985 err(1, "parsekeyfile: open"); 986 if (read(fd, hex, sb.st_size) < sb.st_size) 987 err(1, "parsekeyfile: read"); 988 close(fd); 989 return (parsekey(hex, sb.st_size)); 990} 991 992struct ipsec_addr * 993host(const char *s) 994{ 995 struct ipsec_addr *ipa; 996 int i, bits = 32; 997 998 /* XXX for now only AF_INET. */ 999 1000 ipa = calloc(1, sizeof(struct ipsec_addr)); 1001 if (ipa == NULL) 1002 err(1, "host: calloc"); 1003 1004 if ((ipa->name = strdup(s)) == NULL) 1005 err(1, "host: strdup"); 1006 1007 if (strrchr(s, '/') != NULL) { 1008 bits = inet_net_pton(AF_INET, s, &ipa->v4, sizeof(ipa->v4)); 1009 if (bits == -1 || bits > 32) { 1010 free(ipa->name); 1011 free(ipa); 1012 return(NULL); 1013 } 1014 } else { 1015 if (inet_pton(AF_INET, s, &ipa->v4) != 1) { 1016 free(ipa->name); 1017 free(ipa); 1018 return (NULL); 1019 } 1020 } 1021 1022 bzero(&ipa->v4mask, sizeof(ipa->v4mask)); 1023 if (bits == 32) { 1024 ipa->v4mask.mask32 = 0xffffffff; 1025 ipa->netaddress = 0; 1026 } else { 1027 for (i = 31; i > 31 - bits; i--) 1028 ipa->v4mask.mask32 |= (1 << i); 1029 ipa->v4mask.mask32 = htonl(ipa->v4mask.mask32); 1030 ipa->netaddress = 1; 1031 } 1032 1033 ipa->af = AF_INET; 1034 1035 return (ipa); 1036} 1037 1038struct ipsec_addr * 1039copyhost(const struct ipsec_addr *src) 1040{ 1041 struct ipsec_addr *dst; 1042 1043 dst = calloc(1, sizeof(struct ipsec_addr)); 1044 if (dst == NULL) 1045 err(1, "copyhost: calloc"); 1046 1047 memcpy(dst, src, sizeof(struct ipsec_addr)); 1048 1049 if ((dst->name = strdup(src->name)) == NULL) 1050 err(1, "copyhost: strdup"); 1051 1052 return dst; 1053} 1054 1055const struct ipsec_xf * 1056parse_xf(const char *name, const struct ipsec_xf xfs[]) 1057{ 1058 int i; 1059 1060 for (i = 0; xfs[i].name != NULL; i++) { 1061 if (strncmp(name, xfs[i].name, strlen(name))) 1062 continue; 1063 return &xfs[i]; 1064 } 1065 return (NULL); 1066} 1067 1068struct ipsec_transforms * 1069transforms(const char *authname, const char *encname) 1070{ 1071 struct ipsec_transforms *xfs; 1072 1073 xfs = calloc(1, sizeof(struct ipsec_transforms)); 1074 if (xfs == NULL) 1075 err(1, "transforms: calloc"); 1076 1077 if (authname) { 1078 xfs->authxf = parse_xf(authname, authxfs); 1079 if (xfs->authxf == NULL) 1080 yyerror("%s not a valid transform", authname); 1081 } 1082 if (encname) { 1083 xfs->encxf = parse_xf(encname, encxfs); 1084 if (xfs->encxf == NULL) 1085 yyerror("%s not a valid transform", encname); 1086 } 1087 1088 return (xfs); 1089} 1090 1091struct ipsec_transforms * 1092copytransforms(const struct ipsec_transforms *xfs) 1093{ 1094 struct ipsec_transforms *newxfs; 1095 1096 if (xfs == NULL) 1097 return (NULL); 1098 1099 newxfs = calloc(1, sizeof(struct ipsec_transforms)); 1100 if (newxfs == NULL) 1101 err(1, "copytransforms: calloc"); 1102 1103 memcpy(newxfs, xfs, sizeof(struct ipsec_transforms)); 1104 return (newxfs); 1105} 1106 1107int 1108validate_sa(u_int32_t spi, u_int8_t protocol, struct ipsec_transforms *xfs, 1109 struct ipsec_key *authkey, struct ipsec_key *enckey) 1110{ 1111 /* Sanity checks */ 1112 if (spi == 0) { 1113 yyerror("no SPI specified"); 1114 return (0); 1115 } 1116 if (protocol == IPSEC_AH) { 1117 if (!xfs) { 1118 yyerror("no transforms specified"); 1119 return (0); 1120 } 1121 if (!xfs->authxf) 1122 xfs->authxf = &authxfs[AUTHXF_HMAC_SHA2_256]; 1123 if (xfs->encxf) { 1124 yyerror("ah does not provide encryption"); 1125 return (0); 1126 } 1127 } 1128 if (protocol == IPSEC_ESP) { 1129 if (!xfs) { 1130 yyerror("no transforms specified"); 1131 return (0); 1132 } 1133 if (!xfs->authxf) 1134 xfs->authxf = &authxfs[AUTHXF_HMAC_SHA2_256]; 1135 if (!xfs->encxf) 1136 xfs->encxf = &encxfs[ENCXF_AESCTR]; 1137 } 1138 if (protocol == IPSEC_TCPMD5 && authkey == NULL) { 1139 yyerror("authentication key needed for tcpmd5"); 1140 return (0); 1141 } 1142 if (xfs && xfs->authxf) { 1143 if (!authkey) { 1144 yyerror("no authentication key specified"); 1145 return (0); 1146 } 1147 if (authkey->len != xfs->authxf->keymin) { 1148 yyerror("wrong authentication key length, needs to be " 1149 "%d bits", xfs->authxf->keymin * 8); 1150 return (0); 1151 } 1152 } 1153 if (xfs && xfs->encxf) { 1154 if (!enckey && xfs->encxf != &encxfs[ENCXF_NULL]) { 1155 yyerror("no encryption key specified"); 1156 return (0); 1157 } 1158 if (enckey) { 1159 if (enckey->len < xfs->encxf->keymin) { 1160 yyerror("encryption key too short, minimum %d bits", 1161 xfs->encxf->keymin * 8); 1162 return (0); 1163 } 1164 if (xfs->encxf->keymax < enckey->len) { 1165 yyerror("encryption key too long, maximum %d bits", 1166 xfs->encxf->keymax * 8); 1167 return (0); 1168 } 1169 } 1170 } 1171 1172 return 1; 1173} 1174 1175struct ipsec_rule * 1176create_sa(u_int8_t protocol, struct ipsec_addr *src, struct ipsec_addr *dst, 1177 u_int32_t spi, struct ipsec_transforms *xfs, struct ipsec_key *authkey, 1178 struct ipsec_key *enckey) 1179{ 1180 struct ipsec_rule *r; 1181 1182 if (validate_sa(spi, protocol, xfs, authkey, enckey) == 0) 1183 return (NULL); 1184 1185 r = calloc(1, sizeof(struct ipsec_rule)); 1186 if (r == NULL) 1187 err(1, "create_sa: calloc"); 1188 1189 r->type |= RULE_SA; 1190 r->proto = protocol; 1191 r->src = src; 1192 r->dst = dst; 1193 r->spi = spi; 1194 r->xfs = xfs; 1195 r->authkey = authkey; 1196 r->enckey = enckey; 1197 1198 return r; 1199} 1200 1201struct ipsec_rule * 1202reverse_sa(struct ipsec_rule *rule, u_int32_t spi, struct ipsec_key *authkey, 1203 struct ipsec_key *enckey) 1204{ 1205 struct ipsec_rule *reverse; 1206 1207 if (validate_sa(spi, rule->proto, rule->xfs, authkey, enckey) == 0) 1208 return (NULL); 1209 1210 reverse = calloc(1, sizeof(struct ipsec_rule)); 1211 if (reverse == NULL) 1212 err(1, "reverse_sa: calloc"); 1213 1214 reverse->type |= RULE_SA; 1215 reverse->proto = rule->proto; 1216 reverse->src = copyhost(rule->dst); 1217 reverse->dst = copyhost(rule->src); 1218 reverse->spi = spi; 1219 reverse->xfs = copytransforms(rule->xfs); 1220 reverse->authkey = authkey; 1221 reverse->enckey = enckey; 1222 1223 return (reverse); 1224} 1225 1226struct ipsec_rule * 1227create_flow(u_int8_t dir, struct ipsec_addr *src, struct ipsec_addr *dst, 1228 struct ipsec_addr *peer, u_int8_t proto, char *srcid, char *dstid, 1229 u_int16_t authtype) 1230{ 1231 struct ipsec_rule *r; 1232 1233 r = calloc(1, sizeof(struct ipsec_rule)); 1234 if (r == NULL) 1235 err(1, "create_flow: calloc"); 1236 1237 r->type |= RULE_FLOW; 1238 1239 if (dir == IPSEC_INOUT) 1240 r->direction = IPSEC_OUT; 1241 else 1242 r->direction = dir; 1243 1244 if (r->direction == IPSEC_IN) 1245 r->flowtype = TYPE_USE; 1246 else 1247 r->flowtype = TYPE_REQUIRE; 1248 1249 r->src = src; 1250 r->dst = dst; 1251 1252 if (peer == NULL) { 1253 /* Set peer to remote host. Must be a host address. */ 1254 if (r->direction == IPSEC_IN) { 1255 if (r->src->netaddress) { 1256 yyerror("no peer specified"); 1257 goto errout; 1258 } 1259 r->peer = copyhost(r->src); 1260 } else { 1261 if (r->dst->netaddress) { 1262 yyerror("no peer specified"); 1263 goto errout; 1264 } 1265 r->peer = copyhost(r->dst); 1266 } 1267 } else 1268 r->peer = peer; 1269 1270 r->proto = proto; 1271 r->auth = calloc(1, sizeof(struct ipsec_auth)); 1272 if (r->auth == NULL) 1273 err(1, "create_flow: calloc"); 1274 r->auth->srcid = srcid; 1275 r->auth->dstid = dstid; 1276 r->auth->idtype = ID_FQDN; /* XXX For now only FQDN. */ 1277#ifdef notyet 1278 r->auth->type = authtype; 1279#endif 1280 1281 return r; 1282 1283errout: 1284 free(r); 1285 if (srcid) 1286 free(srcid); 1287 if (dstid) 1288 free(dstid); 1289 free(src); 1290 free(dst); 1291 1292 return NULL; 1293} 1294 1295struct ipsec_rule * 1296reverse_rule(struct ipsec_rule *rule) 1297{ 1298 struct ipsec_rule *reverse; 1299 1300 reverse = calloc(1, sizeof(struct ipsec_rule)); 1301 if (reverse == NULL) 1302 err(1, "reverse_rule: calloc"); 1303 1304 reverse->type |= RULE_FLOW; 1305 1306 if (rule->direction == (u_int8_t)IPSEC_OUT) { 1307 reverse->direction = (u_int8_t)IPSEC_IN; 1308 reverse->flowtype = TYPE_USE; 1309 } else { 1310 reverse->direction = (u_int8_t)IPSEC_OUT; 1311 reverse->flowtype = TYPE_REQUIRE; 1312 } 1313 1314 reverse->src = copyhost(rule->dst); 1315 reverse->dst = copyhost(rule->src); 1316 reverse->peer = copyhost(rule->peer); 1317 reverse->proto = (u_int8_t)rule->proto; 1318 1319 reverse->auth = calloc(1, sizeof(struct ipsec_auth)); 1320 if (reverse->auth == NULL) 1321 err(1, "reverse_rule: calloc"); 1322 if (rule->auth->dstid && (reverse->auth->dstid = 1323 strdup(rule->auth->dstid)) == NULL) 1324 err(1, "reverse_rule: strdup"); 1325 if (rule->auth->srcid && (reverse->auth->srcid = 1326 strdup(rule->auth->srcid)) == NULL) 1327 err(1, "reverse_rule: strdup"); 1328 reverse->auth->idtype = rule->auth->idtype; 1329 reverse->auth->type = rule->auth->type; 1330 1331 return reverse; 1332} 1333 1334struct ipsec_rule * 1335create_ike(struct ipsec_addr *src, struct ipsec_addr *dst, struct ipsec_addr * 1336 peer, struct ipsec_transforms *mmxfs, struct ipsec_transforms *qmxfs, 1337 u_int8_t proto, u_int8_t mode, char *srcid, char *dstid) 1338{ 1339 struct ipsec_rule *r; 1340 1341 r = calloc(1, sizeof(struct ipsec_rule)); 1342 if (r == NULL) 1343 err(1, "create_ike: calloc"); 1344 1345 r->type = RULE_IKE; 1346 1347 r->src = src; 1348 r->dst = dst; 1349 1350 if (peer == NULL) { 1351 /* Set peer to remote host. Must be a host address. */ 1352 if (r->direction == IPSEC_IN) { 1353 if (r->src->netaddress) { 1354 yyerror("no peer specified"); 1355 goto errout; 1356 } 1357 r->peer = copyhost(r->src); 1358 } else { 1359 if (r->dst->netaddress) { 1360 yyerror("no peer specified"); 1361 goto errout; 1362 } 1363 r->peer = copyhost(r->dst); 1364 } 1365 } else 1366 r->peer = peer; 1367 1368 r->proto = proto; 1369 r->ikemode = mode; 1370 r->mmxfs = mmxfs; 1371 r->qmxfs = qmxfs; 1372 r->auth = calloc(1, sizeof(struct ipsec_auth)); 1373 if (r->auth == NULL) 1374 err(1, "create_ike: calloc"); 1375 r->auth->srcid = srcid; 1376 r->auth->dstid = dstid; 1377 r->auth->idtype = ID_FQDN; /* XXX For now only FQDN. */ 1378 1379 return (r); 1380 1381errout: 1382 free(r); 1383 if (srcid) 1384 free(srcid); 1385 if (dstid) 1386 free(dstid); 1387 free(src); 1388 free(dst); 1389 1390 return (NULL); 1391} 1392