1 /* $OpenBSD: parse.y,v 1.21 2022/10/15 13:27:45 florian Exp $ */ 2 3 /* 4 * Copyright (c) 2018 Florian Obser <florian@openbsd.org> 5 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org> 7 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> 8 * Copyright (c) 2001 Markus Friedl. All rights reserved. 9 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 10 * Copyright (c) 2001 Theo de Raadt. All rights reserved. 11 * 12 * Permission to use, copy, modify, and distribute this software for any 13 * purpose with or without fee is hereby granted, provided that the above 14 * copyright notice and this permission notice appear in all copies. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 22 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25 %{ 26 #include <sys/types.h> 27 #include <sys/queue.h> 28 #include <sys/socket.h> 29 #include <sys/stat.h> 30 31 #include <netinet/in.h> 32 #include <net/if.h> 33 34 #include <arpa/inet.h> 35 36 #include <ctype.h> 37 #include <err.h> 38 #include <errno.h> 39 #include <event.h> 40 #include <imsg.h> 41 #include <limits.h> 42 #include <stdarg.h> 43 #include <stdio.h> 44 #include <string.h> 45 #include <syslog.h> 46 #include <unistd.h> 47 48 #include "log.h" 49 #include "rad.h" 50 #include "frontend.h" 51 52 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 53 static struct file { 54 TAILQ_ENTRY(file) entry; 55 FILE *stream; 56 char *name; 57 size_t ungetpos; 58 size_t ungetsize; 59 u_char *ungetbuf; 60 int eof_reached; 61 int lineno; 62 int errors; 63 } *file, *topfile; 64 struct file *pushfile(const char *, int); 65 int popfile(void); 66 int check_file_secrecy(int, const char *); 67 int yyparse(void); 68 int yylex(void); 69 int yyerror(const char *, ...) 70 __attribute__((__format__ (printf, 1, 2))) 71 __attribute__((__nonnull__ (1))); 72 int kw_cmp(const void *, const void *); 73 int lookup(char *); 74 int igetc(void); 75 int lgetc(int); 76 void lungetc(int); 77 int findeol(void); 78 79 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 80 struct sym { 81 TAILQ_ENTRY(sym) entry; 82 int used; 83 int persist; 84 char *nam; 85 char *val; 86 }; 87 88 int symset(const char *, const char *, int); 89 char *symget(const char *); 90 91 void clear_config(struct rad_conf *xconf); 92 93 static struct rad_conf *conf; 94 static struct ra_options_conf *ra_options; 95 static int errors; 96 97 static struct ra_iface_conf *ra_iface_conf; 98 static struct ra_prefix_conf *ra_prefix_conf; 99 static struct ra_pref64_conf *ra_pref64_conf; 100 101 struct ra_prefix_conf *conf_get_ra_prefix(struct in6_addr*, int); 102 struct ra_pref64_conf *conf_get_ra_pref64(struct in6_addr*, int); 103 struct ra_iface_conf *conf_get_ra_iface(char *); 104 void copy_dns_options(const struct ra_options_conf *, 105 struct ra_options_conf *); 106 void copy_pref64_options(const struct ra_options_conf *, 107 struct ra_options_conf *); 108 109 typedef struct { 110 union { 111 int64_t number; 112 char *string; 113 } v; 114 int lineno; 115 } YYSTYPE; 116 117 %} 118 119 %token RA_IFACE YES NO INCLUDE ERROR 120 %token DEFAULT ROUTER HOP LIMIT MANAGED ADDRESS 121 %token CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER 122 %token AUTO PREFIX VALID PREFERRED LIFETIME ONLINK AUTONOMOUS 123 %token ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU NAT64 124 125 %token <v.string> STRING 126 %token <v.number> NUMBER 127 %type <v.number> yesno 128 %type <v.string> string 129 130 %% 131 132 grammar : /* empty */ 133 | grammar include '\n' 134 | grammar '\n' 135 | grammar { ra_options = &conf->ra_options; } conf_main '\n' 136 | grammar varset '\n' 137 | grammar ra_iface '\n' 138 | grammar error '\n' { file->errors++; } 139 ; 140 141 include : INCLUDE STRING { 142 struct file *nfile; 143 144 if ((nfile = pushfile($2, 0)) == NULL) { 145 yyerror("failed to include file %s", $2); 146 free($2); 147 YYERROR; 148 } 149 free($2); 150 151 file = nfile; 152 lungetc('\n'); 153 } 154 ; 155 156 string : string STRING { 157 if (asprintf(&$$, "%s %s", $1, $2) == -1) { 158 free($1); 159 free($2); 160 yyerror("string: asprintf"); 161 YYERROR; 162 } 163 free($1); 164 free($2); 165 } 166 | STRING 167 ; 168 169 yesno : YES { $$ = 1; } 170 | NO { $$ = 0; } 171 ; 172 173 varset : STRING '=' string { 174 char *s = $1; 175 if (cmd_opts & OPT_VERBOSE) 176 printf("%s = \"%s\"\n", $1, $3); 177 while (*s++) { 178 if (isspace((unsigned char)*s)) { 179 yyerror("macro name cannot contain " 180 "whitespace"); 181 free($1); 182 free($3); 183 YYERROR; 184 } 185 } 186 if (symset($1, $3, 0) == -1) 187 fatal("cannot store variable"); 188 free($1); 189 free($3); 190 } 191 ; 192 193 conf_main : ra_opt_block { 194 ra_options = &conf->ra_options; 195 } 196 ; 197 198 ra_opt_block : DEFAULT ROUTER yesno { 199 ra_options->dfr = $3; 200 } 201 | HOP LIMIT NUMBER { 202 ra_options->cur_hl = $3; 203 } 204 | MANAGED ADDRESS CONFIGURATION yesno { 205 ra_options->m_flag = $4; 206 } 207 | OTHER CONFIGURATION yesno { 208 ra_options->o_flag = $3; 209 } 210 | ROUTER LIFETIME NUMBER { 211 ra_options->router_lifetime = $3; 212 } 213 | REACHABLE TIME NUMBER { 214 ra_options->reachable_time = $3; 215 } 216 | RETRANS TIMER NUMBER { 217 ra_options->retrans_timer = $3; 218 } 219 | MTU NUMBER { 220 ra_options->mtu = $2; 221 } 222 | NAT64 PREFIX STRING { 223 struct in6_addr addr; 224 int prefixlen; 225 char *p; 226 const char *errstr; 227 228 memset(&addr, 0, sizeof(addr)); 229 p = strchr($3, '/'); 230 if (p != NULL) { 231 *p++ = '\0'; 232 prefixlen = strtonum(p, 0, 128, &errstr); 233 if (errstr != NULL) { 234 yyerror("error parsing prefix " 235 "\"%s/%s\"", $3, p); 236 free($3); 237 YYERROR; 238 } 239 } else 240 prefixlen = 96; 241 242 switch (prefixlen) { 243 case 96: 244 case 64: 245 case 56: 246 case 48: 247 case 40: 248 case 32: 249 break; 250 default: 251 yyerror("invalid nat64 prefix length: %d", 252 prefixlen); 253 YYERROR; 254 break; 255 } 256 if(inet_pton(AF_INET6, $3, &addr) == 0) { 257 yyerror("error parsing prefix \"%s/%d\"", $3, 258 prefixlen); 259 free($3); 260 YYERROR; 261 } 262 mask_prefix(&addr, prefixlen); 263 ra_pref64_conf = conf_get_ra_pref64(&addr, prefixlen); 264 } ra_pref64_block { 265 ra_pref64_conf = NULL; 266 } 267 | DNS dns_block 268 ; 269 270 optnl : '\n' optnl /* zero or more newlines */ 271 | /*empty*/ 272 ; 273 274 nl : '\n' optnl /* one or more newlines */ 275 ; 276 277 ra_iface : RA_IFACE STRING { 278 ra_iface_conf = conf_get_ra_iface($2); 279 /* set auto prefix defaults */ 280 ra_iface_conf->autoprefix = conf_get_ra_prefix(NULL, 0); 281 ra_options = &ra_iface_conf->ra_options; 282 } ra_iface_block { 283 ra_iface_conf = NULL; 284 ra_options = &conf->ra_options; 285 } 286 ; 287 288 ra_iface_block : '{' optnl ra_ifaceopts_l '}' 289 | '{' optnl '}' 290 | /* empty */ 291 ; 292 293 ra_ifaceopts_l : ra_ifaceopts_l ra_ifaceoptsl nl 294 | ra_ifaceoptsl optnl 295 ; 296 297 ra_ifaceoptsl : NO AUTO PREFIX { 298 free(ra_iface_conf->autoprefix); 299 ra_iface_conf->autoprefix = NULL; 300 } 301 | AUTO PREFIX { 302 if (ra_iface_conf->autoprefix == NULL) 303 ra_iface_conf->autoprefix = 304 conf_get_ra_prefix(NULL, 0); 305 ra_prefix_conf = ra_iface_conf->autoprefix; 306 } ra_prefix_block { 307 ra_prefix_conf = NULL; 308 } 309 | PREFIX STRING { 310 struct in6_addr addr; 311 int prefixlen; 312 char *p; 313 const char *errstr; 314 315 memset(&addr, 0, sizeof(addr)); 316 p = strchr($2, '/'); 317 if (p != NULL) { 318 *p++ = '\0'; 319 prefixlen = strtonum(p, 0, 128, &errstr); 320 if (errstr != NULL) { 321 yyerror("error parsing prefix " 322 "\"%s/%s\"", $2, p); 323 free($2); 324 YYERROR; 325 } 326 } else 327 prefixlen = 64; 328 if(inet_pton(AF_INET6, $2, &addr) == 0) { 329 yyerror("error parsing prefix \"%s/%d\"", $2, 330 prefixlen); 331 free($2); 332 YYERROR; 333 } 334 mask_prefix(&addr, prefixlen); 335 ra_prefix_conf = conf_get_ra_prefix(&addr, prefixlen); 336 } ra_prefix_block { 337 ra_prefix_conf = NULL; 338 } 339 | ra_opt_block 340 ; 341 342 ra_prefix_block : '{' optnl ra_prefixopts_l '}' 343 | '{' optnl '}' 344 | /* empty */ 345 ; 346 347 ra_prefixopts_l : ra_prefixopts_l ra_prefixoptsl nl 348 | ra_prefixoptsl optnl 349 ; 350 351 ra_prefixoptsl : VALID LIFETIME NUMBER { 352 ra_prefix_conf->vltime = $3; 353 } 354 | PREFERRED LIFETIME NUMBER { 355 ra_prefix_conf->pltime = $3; 356 } 357 | ONLINK yesno { 358 ra_prefix_conf->lflag = $2; 359 } 360 | AUTONOMOUS ADDRESS_CONFIGURATION yesno { 361 ra_prefix_conf->aflag = $3; 362 } 363 ; 364 365 ra_pref64_block : '{' optnl ra_pref64opts_l '}' 366 | '{' optnl '}' 367 | /* empty */ 368 ; 369 370 ra_pref64opts_l : ra_pref64opts_l ra_pref64optsl nl 371 | ra_pref64optsl optnl 372 ; 373 374 ra_pref64optsl : LIFETIME NUMBER { 375 if ($2 < 0 || $2 > 65528) { 376 yyerror("Invalid nat64 prefix lifetime: %lld", 377 $2); 378 YYERROR; 379 } 380 ra_pref64_conf->ltime = $2; 381 } 382 ; 383 384 dns_block : '{' optnl dnsopts_l '}' 385 | '{' optnl '}' 386 | /* empty */ 387 ; 388 389 dnsopts_l : dnsopts_l dnsoptsl nl 390 | dnsoptsl optnl 391 ; 392 393 dnsoptsl : LIFETIME NUMBER { 394 ra_options->rdns_lifetime = $2; 395 } 396 | NAMESERVER nserver_block 397 | SEARCH search_block 398 ; 399 nserver_block : '{' optnl nserveropts_l '}' 400 | '{' optnl '}' 401 | nserveroptsl 402 | /* empty */ 403 ; 404 405 nserveropts_l : nserveropts_l nserveroptsl optnl 406 | nserveroptsl optnl 407 ; 408 409 nserveroptsl : STRING { 410 struct ra_rdnss_conf *ra_rdnss_conf; 411 struct in6_addr addr; 412 413 memset(&addr, 0, sizeof(addr)); 414 if (inet_pton(AF_INET6, $1, &addr) 415 != 1) { 416 yyerror("error parsing nameserver address %s", 417 $1); 418 free($1); 419 YYERROR; 420 } 421 if ((ra_rdnss_conf = calloc(1, sizeof(*ra_rdnss_conf))) 422 == NULL) 423 err(1, "%s", __func__); 424 memcpy(&ra_rdnss_conf->rdnss, &addr, sizeof(addr)); 425 SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list, 426 ra_rdnss_conf, entry); 427 ra_options->rdnss_count++; 428 } 429 ; 430 search_block : '{' optnl searchopts_l '}' 431 | '{' optnl '}' 432 | searchoptsl 433 | /* empty */ 434 ; 435 436 searchopts_l : searchopts_l searchoptsl optnl 437 | searchoptsl optnl 438 ; 439 440 searchoptsl : STRING { 441 struct ra_dnssl_conf *ra_dnssl_conf; 442 size_t len; 443 444 if ((ra_dnssl_conf = calloc(1, 445 sizeof(*ra_dnssl_conf))) == NULL) 446 err(1, "%s", __func__); 447 448 if ((len = strlcpy(ra_dnssl_conf->search, $1, 449 sizeof(ra_dnssl_conf->search))) >= 450 sizeof(ra_dnssl_conf->search)) { 451 yyerror("search string too long"); 452 free($1); 453 YYERROR; 454 } 455 if (ra_dnssl_conf->search[len] != '.') { 456 if ((len = strlcat(ra_dnssl_conf->search, ".", 457 sizeof(ra_dnssl_conf->search))) > 458 sizeof(ra_dnssl_conf->search)) { 459 yyerror("search string too long"); 460 free($1); 461 YYERROR; 462 } 463 } 464 SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list, 465 ra_dnssl_conf, entry); 466 ra_options->dnssl_len += len + 1; 467 } 468 ; 469 %% 470 471 struct keywords { 472 const char *k_name; 473 int k_val; 474 }; 475 476 int 477 yyerror(const char *fmt, ...) 478 { 479 va_list ap; 480 char *msg; 481 482 file->errors++; 483 va_start(ap, fmt); 484 if (vasprintf(&msg, fmt, ap) == -1) 485 fatalx("yyerror vasprintf"); 486 va_end(ap); 487 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); 488 free(msg); 489 return (0); 490 } 491 492 int 493 kw_cmp(const void *k, const void *e) 494 { 495 return (strcmp(k, ((const struct keywords *)e)->k_name)); 496 } 497 498 int 499 lookup(char *s) 500 { 501 /* This has to be sorted always. */ 502 static const struct keywords keywords[] = { 503 {"address", ADDRESS}, 504 {"address-configuration", ADDRESS_CONFIGURATION}, 505 {"auto", AUTO}, 506 {"autonomous", AUTONOMOUS}, 507 {"configuration", CONFIGURATION}, 508 {"default", DEFAULT}, 509 {"dns", DNS}, 510 {"hop", HOP}, 511 {"include", INCLUDE}, 512 {"interface", RA_IFACE}, 513 {"lifetime", LIFETIME}, 514 {"limit", LIMIT}, 515 {"managed", MANAGED}, 516 {"mtu", MTU}, 517 {"nameserver", NAMESERVER}, 518 {"nat64", NAT64}, 519 {"no", NO}, 520 {"on-link", ONLINK}, 521 {"other", OTHER}, 522 {"preferred", PREFERRED}, 523 {"prefix", PREFIX}, 524 {"reachable", REACHABLE}, 525 {"retrans", RETRANS}, 526 {"router", ROUTER}, 527 {"search", SEARCH}, 528 {"time", TIME}, 529 {"timer", TIMER}, 530 {"valid", VALID}, 531 {"yes", YES}, 532 }; 533 const struct keywords *p; 534 535 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 536 sizeof(keywords[0]), kw_cmp); 537 538 if (p) 539 return (p->k_val); 540 else 541 return (STRING); 542 } 543 544 #define START_EXPAND 1 545 #define DONE_EXPAND 2 546 547 static int expanding; 548 549 int 550 igetc(void) 551 { 552 int c; 553 554 while (1) { 555 if (file->ungetpos > 0) 556 c = file->ungetbuf[--file->ungetpos]; 557 else 558 c = getc(file->stream); 559 560 if (c == START_EXPAND) 561 expanding = 1; 562 else if (c == DONE_EXPAND) 563 expanding = 0; 564 else 565 break; 566 } 567 return (c); 568 } 569 570 int 571 lgetc(int quotec) 572 { 573 int c, next; 574 575 if (quotec) { 576 if ((c = igetc()) == EOF) { 577 yyerror("reached end of file while parsing " 578 "quoted string"); 579 if (file == topfile || popfile() == EOF) 580 return (EOF); 581 return (quotec); 582 } 583 return (c); 584 } 585 586 while ((c = igetc()) == '\\') { 587 next = igetc(); 588 if (next != '\n') { 589 c = next; 590 break; 591 } 592 yylval.lineno = file->lineno; 593 file->lineno++; 594 } 595 596 if (c == EOF) { 597 /* 598 * Fake EOL when hit EOF for the first time. This gets line 599 * count right if last line in included file is syntactically 600 * invalid and has no newline. 601 */ 602 if (file->eof_reached == 0) { 603 file->eof_reached = 1; 604 return ('\n'); 605 } 606 while (c == EOF) { 607 if (file == topfile || popfile() == EOF) 608 return (EOF); 609 c = igetc(); 610 } 611 } 612 return (c); 613 } 614 615 void 616 lungetc(int c) 617 { 618 if (c == EOF) 619 return; 620 621 if (file->ungetpos >= file->ungetsize) { 622 void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); 623 if (p == NULL) 624 err(1, "lungetc"); 625 file->ungetbuf = p; 626 file->ungetsize *= 2; 627 } 628 file->ungetbuf[file->ungetpos++] = c; 629 } 630 631 int 632 findeol(void) 633 { 634 int c; 635 636 /* Skip to either EOF or the first real EOL. */ 637 while (1) { 638 c = lgetc(0); 639 if (c == '\n') { 640 file->lineno++; 641 break; 642 } 643 if (c == EOF) 644 break; 645 } 646 return (ERROR); 647 } 648 649 int 650 yylex(void) 651 { 652 char buf[8096]; 653 char *p, *val; 654 int quotec, next, c; 655 int token; 656 657 top: 658 p = buf; 659 while ((c = lgetc(0)) == ' ' || c == '\t') 660 ; /* nothing */ 661 662 yylval.lineno = file->lineno; 663 if (c == '#') 664 while ((c = lgetc(0)) != '\n' && c != EOF) 665 ; /* nothing */ 666 if (c == '$' && !expanding) { 667 while (1) { 668 if ((c = lgetc(0)) == EOF) 669 return (0); 670 671 if (p + 1 >= buf + sizeof(buf) - 1) { 672 yyerror("string too long"); 673 return (findeol()); 674 } 675 if (isalnum(c) || c == '_') { 676 *p++ = c; 677 continue; 678 } 679 *p = '\0'; 680 lungetc(c); 681 break; 682 } 683 val = symget(buf); 684 if (val == NULL) { 685 yyerror("macro '%s' not defined", buf); 686 return (findeol()); 687 } 688 p = val + strlen(val) - 1; 689 lungetc(DONE_EXPAND); 690 while (p >= val) { 691 lungetc((unsigned char)*p); 692 p--; 693 } 694 lungetc(START_EXPAND); 695 goto top; 696 } 697 698 switch (c) { 699 case '\'': 700 case '"': 701 quotec = c; 702 while (1) { 703 if ((c = lgetc(quotec)) == EOF) 704 return (0); 705 if (c == '\n') { 706 file->lineno++; 707 continue; 708 } else if (c == '\\') { 709 if ((next = lgetc(quotec)) == EOF) 710 return (0); 711 if (next == quotec || next == ' ' || 712 next == '\t') 713 c = next; 714 else if (next == '\n') { 715 file->lineno++; 716 continue; 717 } else 718 lungetc(next); 719 } else if (c == quotec) { 720 *p = '\0'; 721 break; 722 } else if (c == '\0') { 723 yyerror("syntax error"); 724 return (findeol()); 725 } 726 if (p + 1 >= buf + sizeof(buf) - 1) { 727 yyerror("string too long"); 728 return (findeol()); 729 } 730 *p++ = c; 731 } 732 yylval.v.string = strdup(buf); 733 if (yylval.v.string == NULL) 734 err(1, "yylex: strdup"); 735 return (STRING); 736 } 737 738 #define allowed_to_end_number(x) \ 739 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 740 741 if (c == '-' || isdigit(c)) { 742 do { 743 *p++ = c; 744 if ((size_t)(p-buf) >= sizeof(buf)) { 745 yyerror("string too long"); 746 return (findeol()); 747 } 748 } while ((c = lgetc(0)) != EOF && isdigit(c)); 749 lungetc(c); 750 if (p == buf + 1 && buf[0] == '-') 751 goto nodigits; 752 if (c == EOF || allowed_to_end_number(c)) { 753 const char *errstr = NULL; 754 755 *p = '\0'; 756 yylval.v.number = strtonum(buf, LLONG_MIN, 757 LLONG_MAX, &errstr); 758 if (errstr) { 759 yyerror("\"%s\" invalid number: %s", 760 buf, errstr); 761 return (findeol()); 762 } 763 return (NUMBER); 764 } else { 765 nodigits: 766 while (p > buf + 1) 767 lungetc((unsigned char)*--p); 768 c = (unsigned char)*--p; 769 if (c == '-') 770 return (c); 771 } 772 } 773 774 #define allowed_in_string(x) \ 775 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 776 x != '{' && x != '}' && \ 777 x != '!' && x != '=' && x != '#' && \ 778 x != ',')) 779 780 if (isalnum(c) || c == ':' || c == '_') { 781 do { 782 *p++ = c; 783 if ((size_t)(p-buf) >= sizeof(buf)) { 784 yyerror("string too long"); 785 return (findeol()); 786 } 787 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 788 lungetc(c); 789 *p = '\0'; 790 if ((token = lookup(buf)) == STRING) 791 if ((yylval.v.string = strdup(buf)) == NULL) 792 err(1, "yylex: strdup"); 793 return (token); 794 } 795 if (c == '\n') { 796 yylval.lineno = file->lineno; 797 file->lineno++; 798 } 799 if (c == EOF) 800 return (0); 801 return (c); 802 } 803 804 int 805 check_file_secrecy(int fd, const char *fname) 806 { 807 struct stat st; 808 809 if (fstat(fd, &st)) { 810 log_warn("cannot stat %s", fname); 811 return (-1); 812 } 813 if (st.st_uid != 0 && st.st_uid != getuid()) { 814 log_warnx("%s: owner not root or current user", fname); 815 return (-1); 816 } 817 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { 818 log_warnx("%s: group writable or world read/writable", fname); 819 return (-1); 820 } 821 return (0); 822 } 823 824 struct file * 825 pushfile(const char *name, int secret) 826 { 827 struct file *nfile; 828 829 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 830 log_warn("calloc"); 831 return (NULL); 832 } 833 if ((nfile->name = strdup(name)) == NULL) { 834 log_warn("strdup"); 835 free(nfile); 836 return (NULL); 837 } 838 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 839 log_warn("%s", nfile->name); 840 free(nfile->name); 841 free(nfile); 842 return (NULL); 843 } else if (secret && 844 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 845 fclose(nfile->stream); 846 free(nfile->name); 847 free(nfile); 848 return (NULL); 849 } 850 nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0; 851 nfile->ungetsize = 16; 852 nfile->ungetbuf = malloc(nfile->ungetsize); 853 if (nfile->ungetbuf == NULL) { 854 log_warn("malloc"); 855 fclose(nfile->stream); 856 free(nfile->name); 857 free(nfile); 858 return (NULL); 859 } 860 TAILQ_INSERT_TAIL(&files, nfile, entry); 861 return (nfile); 862 } 863 864 int 865 popfile(void) 866 { 867 struct file *prev; 868 869 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 870 prev->errors += file->errors; 871 872 TAILQ_REMOVE(&files, file, entry); 873 fclose(file->stream); 874 free(file->name); 875 free(file->ungetbuf); 876 free(file); 877 file = prev; 878 return (file ? 0 : EOF); 879 } 880 881 struct rad_conf * 882 parse_config(char *filename) 883 { 884 struct sym *sym, *next; 885 struct ra_iface_conf *iface; 886 887 conf = config_new_empty(); 888 ra_options = NULL; 889 890 file = pushfile(filename, 0); 891 if (file == NULL) { 892 free(conf); 893 return (NULL); 894 } 895 topfile = file; 896 897 yyparse(); 898 errors = file->errors; 899 popfile(); 900 901 /* Free macros and check which have not been used. */ 902 TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { 903 if ((cmd_opts & OPT_VERBOSE2) && !sym->used) 904 fprintf(stderr, "warning: macro '%s' not used\n", 905 sym->nam); 906 if (!sym->persist) { 907 free(sym->nam); 908 free(sym->val); 909 TAILQ_REMOVE(&symhead, sym, entry); 910 free(sym); 911 } 912 } 913 914 if (errors) { 915 clear_config(conf); 916 return (NULL); 917 } 918 919 if (!SIMPLEQ_EMPTY(&conf->ra_options.ra_rdnss_list) || 920 !SIMPLEQ_EMPTY(&conf->ra_options.ra_dnssl_list)) { 921 SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry) 922 copy_dns_options(&conf->ra_options, 923 &iface->ra_options); 924 } 925 926 if (!SIMPLEQ_EMPTY(&conf->ra_options.ra_pref64_list)) { 927 SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry) 928 copy_pref64_options(&conf->ra_options, 929 &iface->ra_options); 930 } 931 932 return (conf); 933 } 934 935 void 936 copy_dns_options(const struct ra_options_conf *src, struct ra_options_conf *dst) 937 { 938 struct ra_rdnss_conf *ra_rdnss, *nra_rdnss; 939 struct ra_dnssl_conf *ra_dnssl, *nra_dnssl; 940 941 if (SIMPLEQ_EMPTY(&dst->ra_rdnss_list)) { 942 SIMPLEQ_FOREACH(ra_rdnss, &src->ra_rdnss_list, entry) { 943 if ((nra_rdnss = calloc(1, sizeof(*nra_rdnss))) == NULL) 944 err(1, "%s", __func__); 945 memcpy(nra_rdnss, ra_rdnss, sizeof(*nra_rdnss)); 946 SIMPLEQ_INSERT_TAIL(&dst->ra_rdnss_list, nra_rdnss, 947 entry); 948 } 949 dst->rdnss_count = src->rdnss_count; 950 } 951 if (SIMPLEQ_EMPTY(&dst->ra_dnssl_list)) { 952 SIMPLEQ_FOREACH(ra_dnssl, &src->ra_dnssl_list, entry) { 953 if ((nra_dnssl = calloc(1, sizeof(*nra_dnssl))) == NULL) 954 err(1, "%s", __func__); 955 memcpy(nra_dnssl, ra_dnssl, sizeof(*nra_dnssl)); 956 SIMPLEQ_INSERT_TAIL(&dst->ra_dnssl_list, nra_dnssl, 957 entry); 958 } 959 dst->dnssl_len = src->dnssl_len; 960 } 961 } 962 963 void 964 copy_pref64_options(const struct ra_options_conf *src, struct ra_options_conf 965 *dst) 966 { 967 struct ra_pref64_conf *pref64, *npref64; 968 969 SIMPLEQ_FOREACH(pref64, &src->ra_pref64_list, entry) { 970 if ((npref64 = calloc(1, sizeof(*npref64))) == NULL) 971 err(1, "%s", __func__); 972 memcpy(npref64, pref64, sizeof(*npref64)); 973 SIMPLEQ_INSERT_TAIL(&dst->ra_pref64_list, npref64, entry); 974 } 975 } 976 977 int 978 symset(const char *nam, const char *val, int persist) 979 { 980 struct sym *sym; 981 982 TAILQ_FOREACH(sym, &symhead, entry) { 983 if (strcmp(nam, sym->nam) == 0) 984 break; 985 } 986 987 if (sym != NULL) { 988 if (sym->persist == 1) 989 return (0); 990 else { 991 free(sym->nam); 992 free(sym->val); 993 TAILQ_REMOVE(&symhead, sym, entry); 994 free(sym); 995 } 996 } 997 if ((sym = calloc(1, sizeof(*sym))) == NULL) 998 return (-1); 999 1000 sym->nam = strdup(nam); 1001 if (sym->nam == NULL) { 1002 free(sym); 1003 return (-1); 1004 } 1005 sym->val = strdup(val); 1006 if (sym->val == NULL) { 1007 free(sym->nam); 1008 free(sym); 1009 return (-1); 1010 } 1011 sym->used = 0; 1012 sym->persist = persist; 1013 TAILQ_INSERT_TAIL(&symhead, sym, entry); 1014 return (0); 1015 } 1016 1017 int 1018 cmdline_symset(char *s) 1019 { 1020 char *sym, *val; 1021 int ret; 1022 1023 if ((val = strrchr(s, '=')) == NULL) 1024 return (-1); 1025 sym = strndup(s, val - s); 1026 if (sym == NULL) 1027 errx(1, "%s: strndup", __func__); 1028 ret = symset(sym, val + 1, 1); 1029 free(sym); 1030 1031 return (ret); 1032 } 1033 1034 char * 1035 symget(const char *nam) 1036 { 1037 struct sym *sym; 1038 1039 TAILQ_FOREACH(sym, &symhead, entry) { 1040 if (strcmp(nam, sym->nam) == 0) { 1041 sym->used = 1; 1042 return (sym->val); 1043 } 1044 } 1045 return (NULL); 1046 } 1047 1048 struct ra_prefix_conf * 1049 conf_get_ra_prefix(struct in6_addr *addr, int prefixlen) 1050 { 1051 struct ra_prefix_conf *prefix; 1052 1053 if (addr == NULL) { 1054 if (ra_iface_conf->autoprefix != NULL) 1055 return (ra_iface_conf->autoprefix); 1056 } else { 1057 SIMPLEQ_FOREACH(prefix, &ra_iface_conf->ra_prefix_list, entry) { 1058 if (prefix->prefixlen == prefixlen && memcmp(addr, 1059 &prefix->prefix, sizeof(*addr)) == 0) 1060 return (prefix); 1061 } 1062 } 1063 1064 prefix = calloc(1, sizeof(*prefix)); 1065 if (prefix == NULL) 1066 err(1, "%s", __func__); 1067 prefix->prefixlen = prefixlen; 1068 prefix->vltime = ADV_VALID_LIFETIME; 1069 prefix->pltime = ADV_PREFERRED_LIFETIME; 1070 prefix->lflag = 1; 1071 prefix->aflag = 1; 1072 1073 if (addr == NULL) 1074 ra_iface_conf->autoprefix = prefix; 1075 else { 1076 prefix->prefix = *addr; 1077 SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, prefix, 1078 entry); 1079 } 1080 1081 return (prefix); 1082 } 1083 1084 struct ra_pref64_conf * 1085 conf_get_ra_pref64(struct in6_addr *addr, int prefixlen) 1086 { 1087 struct ra_pref64_conf *pref64; 1088 1089 SIMPLEQ_FOREACH(pref64, &ra_options->ra_pref64_list, entry) { 1090 if (pref64->prefixlen == prefixlen && memcmp(addr, 1091 &pref64->prefix, sizeof(*addr)) == 0) 1092 return (pref64); 1093 } 1094 1095 pref64 = calloc(1, sizeof(*pref64)); 1096 if (pref64 == NULL) 1097 err(1, "%s", __func__); 1098 pref64->prefixlen = prefixlen; 1099 pref64->ltime = ADV_DEFAULT_LIFETIME; 1100 pref64->prefix = *addr; 1101 SIMPLEQ_INSERT_TAIL(&ra_options->ra_pref64_list, pref64, entry); 1102 1103 return (pref64); 1104 } 1105 1106 struct ra_iface_conf * 1107 conf_get_ra_iface(char *name) 1108 { 1109 struct ra_iface_conf *iface; 1110 size_t n; 1111 1112 SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry) { 1113 if (strcmp(name, iface->name) == 0) 1114 return (iface); 1115 } 1116 1117 iface = calloc(1, sizeof(*iface)); 1118 if (iface == NULL) 1119 errx(1, "%s: calloc", __func__); 1120 n = strlcpy(iface->name, name, sizeof(iface->name)); 1121 if (n >= sizeof(iface->name)) 1122 errx(1, "%s: name too long", __func__); 1123 1124 /* Inherit attributes set in global section. */ 1125 iface->ra_options = conf->ra_options; 1126 1127 SIMPLEQ_INIT(&iface->ra_prefix_list); 1128 SIMPLEQ_INIT(&iface->ra_options.ra_rdnss_list); 1129 iface->ra_options.rdnss_count = 0; 1130 SIMPLEQ_INIT(&iface->ra_options.ra_dnssl_list); 1131 iface->ra_options.dnssl_len = 0; 1132 SIMPLEQ_INIT(&iface->ra_options.ra_pref64_list); 1133 1134 SIMPLEQ_INSERT_TAIL(&conf->ra_iface_list, iface, entry); 1135 1136 return (iface); 1137 } 1138 1139 void 1140 clear_config(struct rad_conf *xconf) 1141 { 1142 struct ra_iface_conf *iface; 1143 1144 free_dns_options(&xconf->ra_options); 1145 1146 while((iface = SIMPLEQ_FIRST(&xconf->ra_iface_list)) != NULL) { 1147 SIMPLEQ_REMOVE_HEAD(&xconf->ra_iface_list, entry); 1148 free_ra_iface_conf(iface); 1149 } 1150 1151 free(xconf); 1152 } 1153