parse.y revision 1.23
1/* $OpenBSD: parse.y,v 1.23 2005/08/19 08:47:56 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 *); 125 126typedef struct { 127 union { 128 u_int32_t number; 129 u_int8_t dir; 130 char *string; 131 int log; 132 u_int8_t protocol; 133 struct { 134 struct ipsec_addr *src; 135 struct ipsec_addr *dst; 136 } hosts; 137 struct ipsec_addr *peer; 138 struct ipsec_addr *host; 139 struct { 140 char *srcid; 141 char *dstid; 142 } ids; 143 char *id; 144 u_int16_t authtype; 145 struct { 146 u_int32_t spiout; 147 u_int32_t spiin; 148 } spis; 149 struct { 150 struct ipsec_key *keyout; 151 struct ipsec_key *keyin; 152 } authkeys; 153 struct { 154 struct ipsec_key *keyout; 155 struct ipsec_key *keyin; 156 } enckeys; 157 struct { 158 struct ipsec_key *keyout; 159 struct ipsec_key *keyin; 160 } keys; 161 struct ipsec_transforms *transforms; 162 } v; 163 int lineno; 164} YYSTYPE; 165 166%} 167 168%token FLOW FROM ESP AH IN PEER ON OUT TO SRCID DSTID RSA PSK TCPMD5 SPI 169%token AUTHKEY ENCKEY FILENAME AUTHXF ENCXF ERROR 170%token <v.string> STRING 171%type <v.dir> dir 172%type <v.protocol> protocol 173%type <v.number> number 174%type <v.hosts> hosts 175%type <v.peer> peer 176%type <v.host> host 177%type <v.ids> ids 178%type <v.id> id 179%type <v.authtype> authtype 180%type <v.spis> spispec 181%type <v.authkeys> authkeyspec 182%type <v.enckeys> enckeyspec 183%type <v.keys> keyspec 184%type <v.transforms> transforms 185%% 186 187grammar : /* empty */ 188 | grammar '\n' 189 | grammar flowrule '\n' 190 | grammar sarule '\n' 191 | grammar tcpmd5rule '\n' 192 | grammar error '\n' { errors++; } 193 ; 194 195number : STRING { 196 unsigned long ulval; 197 198 if (atoul($1, &ulval) == -1) { 199 yyerror("%s is not a number", $1); 200 free($1); 201 YYERROR; 202 } 203 if (ulval > UINT_MAX) { 204 yyerror("0x%lx out of range", ulval); 205 free($1); 206 YYERROR; 207 } 208 $$ = (u_int32_t)ulval; 209 free($1); 210 } 211 212tcpmd5rule : TCPMD5 hosts spispec authkeyspec { 213 struct ipsec_rule *r; 214 215 r = create_sa(IPSEC_TCPMD5, $2.src, $2.dst, $3.spiout, 216 NULL, $4.keyout, NULL); 217 if (r == NULL) 218 YYERROR; 219 r->nr = ipsec->rule_nr++; 220 221 if (ipsecctl_add_rule(ipsec, r)) 222 errx(1, "tcpmd5rule: ipsecctl_add_rule"); 223 224 /* Create and add reverse SA rule. */ 225 if ($3.spiin != 0 || $4.keyin != NULL) { 226 r = reverse_sa(r, $3.spiin, $4.keyin, NULL); 227 if (r == NULL) 228 YYERROR; 229 r->nr = ipsec->rule_nr++; 230 231 if (ipsecctl_add_rule(ipsec, r)) 232 errx(1, "tcpmd5rule: ipsecctl_add_rule"); 233 } 234 } 235 ; 236 237sarule : protocol hosts spispec transforms authkeyspec enckeyspec { 238 struct ipsec_rule *r; 239 240 r = create_sa($1, $2.src, $2.dst, $3.spiout, $4, 241 $5.keyout, $6.keyout); 242 if (r == NULL) 243 YYERROR; 244 r->nr = ipsec->rule_nr++; 245 246 if (ipsecctl_add_rule(ipsec, r)) 247 errx(1, "sarule: ipsecctl_add_rule"); 248 249 /* Create and add reverse SA rule. */ 250 if ($3.spiin != 0 || $5.keyin || $6.keyin) { 251 r = reverse_sa(r, $3.spiin, $5.keyin, 252 $6.keyin); 253 if (r == NULL) 254 YYERROR; 255 r->nr = ipsec->rule_nr++; 256 257 if (ipsecctl_add_rule(ipsec, r)) 258 errx(1, "sarule: ipsecctl_add_rule"); 259 } 260 } 261 ; 262 263flowrule : FLOW protocol dir hosts peer ids authtype { 264 struct ipsec_rule *r; 265 266 r = create_flow($3, $4.src, $4.dst, $5, $2, $6.srcid, 267 $6.dstid, $7); 268 if (r == NULL) 269 YYERROR; 270 r->nr = ipsec->rule_nr++; 271 272 if (ipsecctl_add_rule(ipsec, r)) 273 errx(1, "flowrule: ipsecctl_add_rule"); 274 275 /* Create and add reverse flow rule. */ 276 if ($3 == IPSEC_INOUT) { 277 r = reverse_rule(r); 278 r->nr = ipsec->rule_nr++; 279 280 if (ipsecctl_add_rule(ipsec, r)) 281 errx(1, "flowrule: ipsecctl_add_rule"); 282 } 283 } 284 ; 285 286protocol : /* empty */ { $$ = IPSEC_ESP; } 287 | ESP { $$ = IPSEC_ESP; } 288 | AH { $$ = IPSEC_AH; } 289 ; 290 291dir : /* empty */ { $$ = IPSEC_INOUT; } 292 | IN { $$ = IPSEC_IN; } 293 | OUT { $$ = IPSEC_OUT; } 294 ; 295 296hosts : FROM host TO host { 297 $$.src = $2; 298 $$.dst = $4; 299 } 300 ; 301 302peer : /* empty */ { $$ = NULL; } 303 | PEER STRING { 304 if (($$ = host($2)) == NULL) { 305 free($2); 306 yyerror("could not parse host specification"); 307 YYERROR; 308 } 309 free($2); 310 } 311 ; 312 313host : STRING { 314 if (($$ = host($1)) == NULL) { 315 free($1); 316 yyerror("could not parse host specification"); 317 YYERROR; 318 } 319 free($1); 320 } 321 | STRING '/' number { 322 char *buf; 323 324 if (asprintf(&buf, "%s/%u", $1, $3) == -1) 325 err(1, "host: asprintf"); 326 free($1); 327 if (($$ = host(buf)) == NULL) { 328 free(buf); 329 yyerror("could not parse host specification"); 330 YYERROR; 331 } 332 free(buf); 333 } 334 ; 335 336ids : /* empty */ { 337 $$.srcid = NULL; 338 $$.dstid = NULL; 339 } 340 | SRCID id DSTID id { 341 $$.srcid = $2; 342 $$.dstid = $4; 343 } 344 | SRCID id { 345 $$.srcid = $2; 346 $$.dstid = NULL; 347 } 348 | DSTID id { 349 $$.srcid = NULL; 350 $$.dstid = $2; 351 } 352 ; 353 354id : STRING { $$ = $1; } 355 ; 356 357authtype : /* empty */ { $$ = 0; } 358 | RSA { $$ = AUTH_RSA; } 359 | PSK { $$ = AUTH_PSK; } 360 ; 361 362spispec : SPI STRING { 363 u_int32_t spi; 364 char *p = strchr($2, ':'); 365 366 if (p != NULL) { 367 *p++ = 0; 368 369 if (atospi(p, &spi) == -1) { 370 yyerror("%s is not a valid spi", p); 371 free($2); 372 YYERROR; 373 } 374 $$.spiin = spi; 375 } 376 if (atospi($2, &spi) == -1) { 377 yyerror("%s is not a valid spi", $2); 378 free($2); 379 YYERROR; 380 } 381 $$.spiout = spi; 382 383 384 free($2); 385 } 386 ; 387 388transforms : /* empty */ { 389 struct ipsec_transforms *xfs; 390 391 if ((xfs = calloc(1, sizeof(struct ipsec_transforms))) 392 == NULL) 393 err(1, "calloc"); 394 $$ = xfs; 395 } 396 | AUTHXF STRING ENCXF STRING { 397 if (($$ = transforms($2, $4)) == NULL) { 398 free($2); 399 free($4); 400 yyerror("could not parse transforms"); 401 YYERROR; 402 } 403 free($2); 404 free($4); 405 } 406 | AUTHXF STRING { 407 if (($$ = transforms($2, NULL)) == NULL) { 408 free($2); 409 yyerror("could not parse transforms"); 410 YYERROR; 411 } 412 free($2); 413 } 414 | ENCXF STRING { 415 if (($$ = transforms(NULL, $2)) == NULL) { 416 free($2); 417 yyerror("could not parse transforms"); 418 YYERROR; 419 } 420 free($2); 421 } 422 ; 423 424authkeyspec : /* empty */ { 425 $$.keyout = NULL; 426 $$.keyin = NULL; 427 } 428 | AUTHKEY keyspec { 429 $$.keyout = $2.keyout; 430 $$.keyin = $2.keyin; 431 } 432 ; 433 434enckeyspec : /* empty */ { 435 $$.keyout = NULL; 436 $$.keyin = NULL; 437 } 438 | ENCKEY keyspec { 439 $$.keyout = $2.keyout; 440 $$.keyin = $2.keyin; 441 } 442 ; 443 444keyspec : STRING { 445 unsigned char *hex; 446 unsigned char *p = strchr($1, ':'); 447 448 if (p != NULL ) { 449 *p++ = 0; 450 451 if (!strncmp(p, "0x", 2)) 452 p += 2; 453 $$.keyin = parsekey(p, strlen(p)); 454 } 455 456 hex = $1; 457 if (!strncmp(hex, "0x", 2)) 458 hex += 2; 459 $$.keyout = parsekey(hex, strlen(hex)); 460 461 free($1); 462 } 463 | FILENAME STRING { 464 unsigned char *p = strchr($2, ':'); 465 466 if (p != NULL) { 467 *p++ = 0; 468 $$.keyin = parsekeyfile(p); 469 } 470 $$.keyout = parsekeyfile($2); 471 free($2); 472 } 473 ; 474%% 475 476struct keywords { 477 const char *k_name; 478 int k_val; 479}; 480 481int 482yyerror(const char *fmt, ...) 483{ 484 va_list ap; 485 extern char *infile; 486 487 errors = 1; 488 va_start(ap, fmt); 489 fprintf(stderr, "%s: %d: ", infile, yyval.lineno); 490 vfprintf(stderr, fmt, ap); 491 fprintf(stderr, "\n"); 492 va_end(ap); 493 return (0); 494} 495 496int 497kw_cmp(const void *k, const void *e) 498{ 499 return (strcmp(k, ((const struct keywords *)e)->k_name)); 500} 501 502int 503lookup(char *s) 504{ 505 /* this has to be sorted always */ 506 static const struct keywords keywords[] = { 507 { "ah", AH}, 508 { "auth", AUTHXF}, 509 { "authkey", AUTHKEY}, 510 { "dstid", DSTID}, 511 { "enc", ENCXF}, 512 { "enckey", ENCKEY}, 513 { "esp", ESP}, 514 { "file", FILENAME}, 515 { "flow", FLOW}, 516 { "from", FROM}, 517 { "in", IN}, 518 { "out", OUT}, 519 { "peer", PEER}, 520 { "psk", PSK}, 521 { "rsa", RSA}, 522 { "spi", SPI}, 523 { "srcid", SRCID}, 524 { "tcpmd5", TCPMD5}, 525 { "to", TO}, 526 }; 527 const struct keywords *p; 528 529 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 530 sizeof(keywords[0]), kw_cmp); 531 532 if (p) { 533 if (debug > 1) 534 fprintf(stderr, "%s: %d\n", s, p->k_val); 535 return (p->k_val); 536 } else { 537 if (debug > 1) 538 fprintf(stderr, "string: %s\n", s); 539 return (STRING); 540 } 541} 542 543#define MAXPUSHBACK 128 544 545char *parsebuf; 546int parseindex; 547char pushback_buffer[MAXPUSHBACK]; 548int pushback_index = 0; 549 550int 551lgetc(FILE *f) 552{ 553 int c, next; 554 555 if (parsebuf) { 556 /* Read character from the parsebuffer instead of input. */ 557 if (parseindex >= 0) { 558 c = parsebuf[parseindex++]; 559 if (c != '\0') 560 return (c); 561 parsebuf = NULL; 562 } else 563 parseindex++; 564 } 565 566 if (pushback_index) 567 return (pushback_buffer[--pushback_index]); 568 569 while ((c = getc(f)) == '\\') { 570 next = getc(f); 571 if (next != '\n') { 572 if (isspace(next)) 573 yyerror("whitespace after \\"); 574 ungetc(next, f); 575 break; 576 } 577 yylval.lineno = lineno; 578 lineno++; 579 } 580 if (c == '\t' || c == ' ') { 581 /* Compress blanks to a single space. */ 582 do { 583 c = getc(f); 584 } while (c == '\t' || c == ' '); 585 ungetc(c, f); 586 c = ' '; 587 } 588 589 return (c); 590} 591 592int 593lungetc(int c) 594{ 595 if (c == EOF) 596 return (EOF); 597 if (parsebuf) { 598 parseindex--; 599 if (parseindex >= 0) 600 return (c); 601 } 602 if (pushback_index < MAXPUSHBACK-1) 603 return (pushback_buffer[pushback_index++] = c); 604 else 605 return (EOF); 606} 607 608int 609findeol(void) 610{ 611 int c; 612 613 parsebuf = NULL; 614 pushback_index = 0; 615 616 /* skip to either EOF or the first real EOL */ 617 while (1) { 618 c = lgetc(fin); 619 if (c == '\n') { 620 lineno++; 621 break; 622 } 623 if (c == EOF) 624 break; 625 } 626 return (ERROR); 627} 628 629int 630yylex(void) 631{ 632 char buf[8096]; 633 char *p, *val; 634 int endc, c; 635 int token; 636 637top: 638 p = buf; 639 while ((c = lgetc(fin)) == ' ') 640 ; /* nothing */ 641 642 yylval.lineno = lineno; 643 if (c == '#') 644 while ((c = lgetc(fin)) != '\n' && c != EOF) 645 ; /* nothing */ 646 if (c == '$' && parsebuf == NULL) { 647 while (1) { 648 if ((c = lgetc(fin)) == EOF) 649 return (0); 650 651 if (p + 1 >= buf + sizeof(buf) - 1) { 652 yyerror("string too long"); 653 return (findeol()); 654 } 655 if (isalnum(c) || c == '_') { 656 *p++ = (char)c; 657 continue; 658 } 659 *p = '\0'; 660 lungetc(c); 661 break; 662 } 663 val = symget(buf); 664 if (val == NULL) { 665 yyerror("macro \"%s\" not defined", buf); 666 return (findeol()); 667 } 668 parsebuf = val; 669 parseindex = 0; 670 goto top; 671 } 672 673 switch (c) { 674 case '\'': 675 case '"': 676 endc = c; 677 while (1) { 678 if ((c = lgetc(fin)) == EOF) 679 return (0); 680 if (c == endc) { 681 *p = '\0'; 682 break; 683 } 684 if (c == '\n') { 685 lineno++; 686 continue; 687 } 688 if (p + 1 >= buf + sizeof(buf) - 1) { 689 yyerror("string too long"); 690 return (findeol()); 691 } 692 *p++ = (char)c; 693 } 694 yylval.v.string = strdup(buf); 695 if (yylval.v.string == NULL) 696 err(1, "yylex: strdup"); 697 return (STRING); 698 } 699 700#define allowed_in_string(x) \ 701 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 702 x != '{' && x != '}' && x != '<' && x != '>' && \ 703 x != '!' && x != '=' && x != '/' && x != '#' && \ 704 x != ',')) 705 706 if (isalnum(c) || c == ':' || c == '_' || c == '*') { 707 do { 708 *p++ = c; 709 if ((unsigned)(p-buf) >= sizeof(buf)) { 710 yyerror("string too long"); 711 return (findeol()); 712 } 713 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); 714 lungetc(c); 715 *p = '\0'; 716 if ((token = lookup(buf)) == STRING) 717 if ((yylval.v.string = strdup(buf)) == NULL) 718 err(1, "yylex: strdup"); 719 return (token); 720 } 721 if (c == '\n') { 722 yylval.lineno = lineno; 723 lineno++; 724 } 725 if (c == EOF) 726 return (0); 727 return (c); 728} 729 730int 731parse_rules(FILE *input, struct ipsecctl *ipsecx) 732{ 733 struct sym *sym, *next; 734 735 ipsec = ipsecx; 736 fin = input; 737 lineno = 1; 738 errors = 0; 739 740 yyparse(); 741 742 /* Free macros and check which have not been used. */ 743 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 744 next = TAILQ_NEXT(sym, entries); 745 free(sym->nam); 746 free(sym->val); 747 TAILQ_REMOVE(&symhead, sym, entries); 748 free(sym); 749 } 750 751 return (errors ? -1 : 0); 752} 753 754int 755symset(const char *nam, const char *val, int persist) 756{ 757 struct sym *sym; 758 759 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 760 sym = TAILQ_NEXT(sym, entries)) 761 ; /* nothing */ 762 763 if (sym != NULL) { 764 if (sym->persist == 1) 765 return (0); 766 else { 767 free(sym->nam); 768 free(sym->val); 769 TAILQ_REMOVE(&symhead, sym, entries); 770 free(sym); 771 } 772 } 773 if ((sym = calloc(1, sizeof(*sym))) == NULL) 774 return (-1); 775 776 sym->nam = strdup(nam); 777 if (sym->nam == NULL) { 778 free(sym); 779 return (-1); 780 } 781 sym->val = strdup(val); 782 if (sym->val == NULL) { 783 free(sym->nam); 784 free(sym); 785 return (-1); 786 } 787 sym->used = 0; 788 sym->persist = persist; 789 TAILQ_INSERT_TAIL(&symhead, sym, entries); 790 return (0); 791} 792 793int 794cmdline_symset(char *s) 795{ 796 char *sym, *val; 797 int ret; 798 size_t len; 799 800 if ((val = strrchr(s, '=')) == NULL) 801 return (-1); 802 803 len = strlen(s) - strlen(val) + 1; 804 if ((sym = malloc(len)) == NULL) 805 err(1, "cmdline_symset: malloc"); 806 807 strlcpy(sym, s, len); 808 809 ret = symset(sym, val + 1, 1); 810 free(sym); 811 812 return (ret); 813} 814 815char * 816symget(const char *nam) 817{ 818 struct sym *sym; 819 820 TAILQ_FOREACH(sym, &symhead, entries) 821 if (strcmp(nam, sym->nam) == 0) { 822 sym->used = 1; 823 return (sym->val); 824 } 825 return (NULL); 826} 827 828int 829atoul(char *s, u_long *ulvalp) 830{ 831 u_long ulval; 832 char *ep; 833 834 errno = 0; 835 ulval = strtoul(s, &ep, 0); 836 if (s[0] == '\0' || *ep != '\0') 837 return (-1); 838 if (errno == ERANGE && ulval == ULONG_MAX) 839 return (-1); 840 *ulvalp = ulval; 841 return (0); 842} 843 844int 845atospi(char *s, u_int32_t *spivalp) 846{ 847 unsigned long ulval; 848 849 if (atoul(s, &ulval) == -1) 850 return (-1); 851 if (ulval >= SPI_RESERVED_MIN && ulval <= SPI_RESERVED_MAX) { 852 yyerror("illegal SPI value"); 853 return (-1); 854 } 855 *spivalp = ulval; 856 return (0); 857} 858 859u_int8_t 860x2i(unsigned char *s) 861{ 862 char ss[3]; 863 864 ss[0] = s[0]; 865 ss[1] = s[1]; 866 ss[2] = 0; 867 868 if (!isxdigit(s[0]) || !isxdigit(s[1])) { 869 yyerror("keys need to be specified in hex digits"); 870 return (-1); 871 } 872 return ((u_int8_t)strtoul(ss, NULL, 16)); 873} 874 875struct ipsec_key * 876parsekey(unsigned char *hexkey, size_t len) 877{ 878 struct ipsec_key *key; 879 int i; 880 881 key = calloc(1, sizeof(struct ipsec_key)); 882 if (key == NULL) 883 err(1, "calloc"); 884 885 key->len = len / 2; 886 key->data = calloc(key->len, sizeof(u_int8_t)); 887 if (key->data == NULL) 888 err(1, "calloc"); 889 890 for (i = 0; i < (int)key->len; i++) 891 key->data[i] = x2i(hexkey + 2 * i); 892 893 return (key); 894} 895 896struct ipsec_key * 897parsekeyfile(char *filename) 898{ 899 struct stat sb; 900 int fd; 901 unsigned char *hex; 902 903 if (stat(filename, &sb) < 0) 904 err(1, "stat %s", filename); 905 if ((sb.st_size > KEYSIZE_LIMIT) || (sb.st_size == 0)) 906 errx(1, "key too %s", sb.st_size ? "large" : 907 "small"); 908 if ((hex = calloc(sb.st_size, sizeof(unsigned char))) 909 == NULL) 910 err(1, "calloc"); 911 if ((fd = open(filename, O_RDONLY)) < 0) 912 err(1, "open"); 913 if (read(fd, hex, sb.st_size) < sb.st_size) 914 err(1, "read"); 915 close(fd); 916 return (parsekey(hex, sb.st_size)); 917} 918 919struct ipsec_addr * 920host(const char *s) 921{ 922 struct ipsec_addr *ipa; 923 int i, bits = 32; 924 925 /* XXX for now only AF_INET. */ 926 927 ipa = calloc(1, sizeof(struct ipsec_addr)); 928 if (ipa == NULL) 929 err(1, "calloc"); 930 931 if (strrchr(s, '/') != NULL) { 932 bits = inet_net_pton(AF_INET, s, &ipa->v4, sizeof(ipa->v4)); 933 if (bits == -1 || bits > 32) { 934 free(ipa); 935 return(NULL); 936 } 937 } else { 938 if (inet_pton(AF_INET, s, &ipa->v4) != 1) { 939 free(ipa); 940 return NULL; 941 } 942 } 943 944 bzero(&ipa->v4mask, sizeof(ipa->v4mask)); 945 if (bits == 32) { 946 ipa->v4mask.mask32 = 0xffffffff; 947 ipa->netaddress = 0; 948 } else { 949 for (i = 31; i > 31 - bits; i--) 950 ipa->v4mask.mask32 |= (1 << i); 951 ipa->v4mask.mask32 = htonl(ipa->v4mask.mask32); 952 ipa->netaddress = 1; 953 } 954 955 ipa->af = AF_INET; 956 957 return ipa; 958} 959 960struct ipsec_addr * 961copyhost(const struct ipsec_addr *src) 962{ 963 struct ipsec_addr *dst; 964 965 dst = calloc(1, sizeof(struct ipsec_addr)); 966 if (dst == NULL) 967 err(1, "calloc"); 968 969 memcpy(dst, src, sizeof(struct ipsec_addr)); 970 return dst; 971} 972 973const struct ipsec_xf * 974parse_xf(const char *name, const struct ipsec_xf xfs[]) 975{ 976 int i; 977 978 for (i = 0; xfs[i].name != NULL; i++) { 979 if (strncmp(name, xfs[i].name, strlen(name))) 980 continue; 981 return &xfs[i]; 982 } 983 return (NULL); 984} 985 986struct ipsec_transforms * 987transforms(const char *authname, const char *encname) 988{ 989 struct ipsec_transforms *xfs; 990 991 xfs = calloc(1, sizeof(struct ipsec_transforms)); 992 if (xfs == NULL) 993 err(1, "calloc"); 994 995 if (authname) 996 xfs->authxf = parse_xf(authname, authxfs); 997 if (encname) 998 xfs->encxf = parse_xf(encname, encxfs); 999 1000 return (xfs); 1001} 1002 1003struct ipsec_transforms * 1004copytransforms(const struct ipsec_transforms *xfs) 1005{ 1006 struct ipsec_transforms *newxfs; 1007 1008 if (xfs == NULL) 1009 return (NULL); 1010 1011 newxfs = calloc(1, sizeof(struct ipsec_transforms)); 1012 if (newxfs == NULL) 1013 err(1, "calloc"); 1014 1015 memcpy(newxfs, xfs, sizeof(struct ipsec_transforms)); 1016 return (newxfs); 1017} 1018 1019int 1020validate_sa(u_int32_t spi, u_int8_t protocol, struct ipsec_transforms *xfs, 1021 struct ipsec_key *authkey, struct ipsec_key *enckey) 1022{ 1023 /* Sanity checks */ 1024 if (spi == 0) { 1025 yyerror("no SPI specified"); 1026 return (0); 1027 } 1028 if (protocol == IPSEC_AH) { 1029 if (!xfs) { 1030 yyerror("no transforms specified"); 1031 return (0); 1032 } 1033 if (!xfs->authxf) 1034 xfs->authxf = &authxfs[AUTHXF_HMAC_SHA2_256]; 1035 if (xfs->encxf) { 1036 yyerror("ah does not provide encryption"); 1037 return (0); 1038 } 1039 } 1040 if (protocol == IPSEC_ESP) { 1041 if (!xfs) { 1042 yyerror("no transforms specified"); 1043 return (0); 1044 } 1045 if (!xfs->authxf) 1046 xfs->authxf = &authxfs[AUTHXF_HMAC_SHA2_256]; 1047 if (!xfs->encxf) 1048 xfs->encxf = &encxfs[ENCXF_AESCTR]; 1049 } 1050 if (protocol == IPSEC_TCPMD5 && authkey == NULL) { 1051 yyerror("authentication key needed for tcpmd5"); 1052 return (0); 1053 } 1054 if (xfs && xfs->authxf) { 1055 if (!authkey) { 1056 yyerror("no authentication key specified"); 1057 return (0); 1058 } 1059 if (authkey->len != xfs->authxf->keymin) { 1060 yyerror("wrong authentication key length, needs to be " 1061 "%d bits", xfs->authxf->keymin * 8); 1062 return (0); 1063 } 1064 } 1065 if (xfs && xfs->encxf) { 1066 if (!enckey && xfs->encxf != &encxfs[ENCXF_NULL]) { 1067 yyerror("no encryption key specified"); 1068 return (0); 1069 } 1070 if (enckey) { 1071 if (enckey->len < xfs->encxf->keymin) { 1072 yyerror("encryption key too short, minimum %d bits", 1073 xfs->encxf->keymin * 8); 1074 return (0); 1075 } 1076 if (xfs->encxf->keymax < enckey->len) { 1077 yyerror("encryption key too long, maximum %d bits", 1078 xfs->encxf->keymax * 8); 1079 return (0); 1080 } 1081 } 1082 } 1083 1084 return 1; 1085} 1086 1087struct ipsec_rule * 1088create_sa(u_int8_t protocol, struct ipsec_addr *src, struct ipsec_addr *dst, 1089 u_int32_t spi, struct ipsec_transforms *xfs, struct ipsec_key *authkey, 1090 struct ipsec_key *enckey) 1091{ 1092 struct ipsec_rule *r; 1093 1094 if (validate_sa(spi, protocol, xfs, authkey, enckey) == 0) 1095 return (NULL); 1096 1097 r = calloc(1, sizeof(struct ipsec_rule)); 1098 if (r == NULL) 1099 err(1, "calloc"); 1100 1101 r->type |= RULE_SA; 1102 r->proto = protocol; 1103 r->src = src; 1104 r->dst = dst; 1105 r->spi = spi; 1106 r->xfs = xfs; 1107 r->authkey = authkey; 1108 r->enckey = enckey; 1109 1110 return r; 1111} 1112 1113struct ipsec_rule * 1114reverse_sa(struct ipsec_rule *rule, u_int32_t spi, struct ipsec_key *authkey, 1115 struct ipsec_key *enckey) 1116{ 1117 struct ipsec_rule *reverse; 1118 1119 if (validate_sa(spi, rule->proto, rule->xfs, authkey, enckey) == 0) 1120 return (NULL); 1121 1122 reverse = calloc(1, sizeof(struct ipsec_rule)); 1123 if (reverse == NULL) 1124 err(1, "calloc"); 1125 1126 reverse->type |= RULE_SA; 1127 reverse->proto = rule->proto; 1128 reverse->src = copyhost(rule->dst); 1129 reverse->dst = copyhost(rule->src); 1130 reverse->spi = spi; 1131 reverse->xfs = copytransforms(rule->xfs); 1132 reverse->authkey = authkey; 1133 reverse->enckey = enckey; 1134 1135 return (reverse); 1136} 1137 1138struct ipsec_rule * 1139create_flow(u_int8_t dir, struct ipsec_addr *src, struct ipsec_addr *dst, 1140 struct ipsec_addr *peer, u_int8_t proto, char *srcid, char *dstid, 1141 u_int16_t authtype) 1142{ 1143 struct ipsec_rule *r; 1144 1145 r = calloc(1, sizeof(struct ipsec_rule)); 1146 if (r == NULL) 1147 err(1, "calloc"); 1148 1149 r->type |= RULE_FLOW; 1150 1151 if (dir == IPSEC_INOUT) 1152 r->direction = IPSEC_OUT; 1153 else 1154 r->direction = dir; 1155 1156 if (r->direction == IPSEC_IN) 1157 r->flowtype = TYPE_USE; 1158 else 1159 r->flowtype = TYPE_REQUIRE; 1160 1161 r->src = src; 1162 r->dst = dst; 1163 1164 if (peer == NULL) { 1165 /* Set peer to remote host. Must be a host address. */ 1166 if (r->direction == IPSEC_IN) { 1167 if (r->src->netaddress) { 1168 yyerror("no peer specified"); 1169 goto errout; 1170 } 1171 r->peer = copyhost(r->src); 1172 } else { 1173 if (r->dst->netaddress) { 1174 yyerror("no peer specified"); 1175 goto errout; 1176 } 1177 r->peer = copyhost(r->dst); 1178 } 1179 } else 1180 r->peer = peer; 1181 1182 r->proto = proto; 1183 r->auth = calloc(1, sizeof(struct ipsec_auth)); 1184 if (r->auth == NULL) 1185 err(1, "calloc"); 1186 r->auth->srcid = srcid; 1187 r->auth->dstid = dstid; 1188 r->auth->idtype = ID_FQDN; /* XXX For now only FQDN. */ 1189#ifdef notyet 1190 r->auth->type = authtype; 1191#endif 1192 1193 return r; 1194 1195errout: 1196 free(r); 1197 if (srcid) 1198 free(srcid); 1199 if (dstid) 1200 free(dstid); 1201 free(src); 1202 free(dst); 1203 1204 return NULL; 1205} 1206 1207struct ipsec_rule * 1208reverse_rule(struct ipsec_rule *rule) 1209{ 1210 struct ipsec_rule *reverse; 1211 1212 reverse = calloc(1, sizeof(struct ipsec_rule)); 1213 if (reverse == NULL) 1214 err(1, "calloc"); 1215 1216 reverse->type |= RULE_FLOW; 1217 1218 if (rule->direction == (u_int8_t)IPSEC_OUT) { 1219 reverse->direction = (u_int8_t)IPSEC_IN; 1220 reverse->flowtype = TYPE_USE; 1221 } else { 1222 reverse->direction = (u_int8_t)IPSEC_OUT; 1223 reverse->flowtype = TYPE_REQUIRE; 1224 } 1225 1226 reverse->src = copyhost(rule->dst); 1227 reverse->dst = copyhost(rule->src); 1228 reverse->peer = copyhost(rule->peer); 1229 reverse->proto = (u_int8_t)rule->proto; 1230 1231 reverse->auth = calloc(1, sizeof(struct ipsec_auth)); 1232 if (reverse->auth == NULL) 1233 err(1, "calloc"); 1234 if (rule->auth->dstid && (reverse->auth->dstid = 1235 strdup(rule->auth->dstid)) == NULL) 1236 err(1, "strdup"); 1237 if (rule->auth->srcid && (reverse->auth->srcid = 1238 strdup(rule->auth->srcid)) == NULL) 1239 err(1, "strdup"); 1240 reverse->auth->idtype = rule->auth->idtype; 1241 reverse->auth->type = rule->auth->type; 1242 1243 return reverse; 1244} 1245