1 /* $OpenBSD: parse.y,v 1.18 2021/03/01 08:05:40 jsg 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 100 struct ra_prefix_conf *conf_get_ra_prefix(struct in6_addr*, int); 101 struct ra_iface_conf *conf_get_ra_iface(char *); 102 void copy_dns_options(const struct ra_options_conf *, 103 struct ra_options_conf *); 104 105 typedef struct { 106 union { 107 int64_t number; 108 char *string; 109 } v; 110 int lineno; 111 } YYSTYPE; 112 113 %} 114 115 %token RA_IFACE YES NO INCLUDE ERROR 116 %token DEFAULT ROUTER HOP LIMIT MANAGED ADDRESS 117 %token CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER 118 %token AUTO PREFIX VALID PREFERRED LIFETIME ONLINK AUTONOMOUS 119 %token ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU 120 121 %token <v.string> STRING 122 %token <v.number> NUMBER 123 %type <v.number> yesno 124 %type <v.string> string 125 126 %% 127 128 grammar : /* empty */ 129 | grammar include '\n' 130 | grammar '\n' 131 | grammar { ra_options = &conf->ra_options; } conf_main '\n' 132 | grammar varset '\n' 133 | grammar ra_iface '\n' 134 | grammar error '\n' { file->errors++; } 135 ; 136 137 include : INCLUDE STRING { 138 struct file *nfile; 139 140 if ((nfile = pushfile($2, 0)) == NULL) { 141 yyerror("failed to include file %s", $2); 142 free($2); 143 YYERROR; 144 } 145 free($2); 146 147 file = nfile; 148 lungetc('\n'); 149 } 150 ; 151 152 string : string STRING { 153 if (asprintf(&$$, "%s %s", $1, $2) == -1) { 154 free($1); 155 free($2); 156 yyerror("string: asprintf"); 157 YYERROR; 158 } 159 free($1); 160 free($2); 161 } 162 | STRING 163 ; 164 165 yesno : YES { $$ = 1; } 166 | NO { $$ = 0; } 167 ; 168 169 varset : STRING '=' string { 170 char *s = $1; 171 if (cmd_opts & OPT_VERBOSE) 172 printf("%s = \"%s\"\n", $1, $3); 173 while (*s++) { 174 if (isspace((unsigned char)*s)) { 175 yyerror("macro name cannot contain " 176 "whitespace"); 177 free($1); 178 free($3); 179 YYERROR; 180 } 181 } 182 if (symset($1, $3, 0) == -1) 183 fatal("cannot store variable"); 184 free($1); 185 free($3); 186 } 187 ; 188 189 conf_main : ra_opt_block { 190 ra_options = &conf->ra_options; 191 } 192 ; 193 194 ra_opt_block : DEFAULT ROUTER yesno { 195 ra_options->dfr = $3; 196 } 197 | HOP LIMIT NUMBER { 198 ra_options->cur_hl = $3; 199 } 200 | MANAGED ADDRESS CONFIGURATION yesno { 201 ra_options->m_flag = $4; 202 } 203 | OTHER CONFIGURATION yesno { 204 ra_options->o_flag = $3; 205 } 206 | ROUTER LIFETIME NUMBER { 207 ra_options->router_lifetime = $3; 208 } 209 | REACHABLE TIME NUMBER { 210 ra_options->reachable_time = $3; 211 } 212 | RETRANS TIMER NUMBER { 213 ra_options->retrans_timer = $3; 214 } 215 | MTU NUMBER { 216 ra_options->mtu = $2; 217 } 218 | DNS dns_block 219 ; 220 221 optnl : '\n' optnl /* zero or more newlines */ 222 | /*empty*/ 223 ; 224 225 nl : '\n' optnl /* one or more newlines */ 226 ; 227 228 ra_iface : RA_IFACE STRING { 229 ra_iface_conf = conf_get_ra_iface($2); 230 /* set auto prefix defaults */ 231 ra_iface_conf->autoprefix = conf_get_ra_prefix(NULL, 0); 232 ra_options = &ra_iface_conf->ra_options; 233 } ra_iface_block { 234 ra_iface_conf = NULL; 235 ra_options = &conf->ra_options; 236 } 237 ; 238 239 ra_iface_block : '{' optnl ra_ifaceopts_l '}' 240 | '{' optnl '}' 241 | /* empty */ 242 ; 243 244 ra_ifaceopts_l : ra_ifaceopts_l ra_ifaceoptsl nl 245 | ra_ifaceoptsl optnl 246 ; 247 248 ra_ifaceoptsl : NO AUTO PREFIX { 249 free(ra_iface_conf->autoprefix); 250 ra_iface_conf->autoprefix = NULL; 251 } 252 | AUTO PREFIX { 253 if (ra_iface_conf->autoprefix == NULL) 254 ra_iface_conf->autoprefix = 255 conf_get_ra_prefix(NULL, 0); 256 ra_prefix_conf = ra_iface_conf->autoprefix; 257 } ra_prefix_block { 258 ra_prefix_conf = NULL; 259 } 260 | PREFIX STRING { 261 struct in6_addr addr; 262 int prefixlen; 263 char *p; 264 const char *errstr; 265 266 memset(&addr, 0, sizeof(addr)); 267 p = strchr($2, '/'); 268 if (p != NULL) { 269 *p++ = '\0'; 270 prefixlen = strtonum(p, 0, 128, &errstr); 271 if (errstr != NULL) { 272 yyerror("error parsing prefix " 273 "\"%s/%s\"", $2, p); 274 free($2); 275 YYERROR; 276 } 277 } else 278 prefixlen = 64; 279 if(inet_pton(AF_INET6, $2, &addr) == 0) { 280 yyerror("error parsing prefix \"%s/%d\"", $2, 281 prefixlen); 282 free($2); 283 YYERROR; 284 } 285 mask_prefix(&addr, prefixlen); 286 ra_prefix_conf = conf_get_ra_prefix(&addr, prefixlen); 287 } ra_prefix_block { 288 ra_prefix_conf = NULL; 289 } 290 | ra_opt_block 291 ; 292 293 ra_prefix_block : '{' optnl ra_prefixopts_l '}' 294 | '{' optnl '}' 295 | /* empty */ 296 ; 297 298 ra_prefixopts_l : ra_prefixopts_l ra_prefixoptsl nl 299 | ra_prefixoptsl optnl 300 ; 301 302 ra_prefixoptsl : VALID LIFETIME NUMBER { 303 ra_prefix_conf->vltime = $3; 304 } 305 | PREFERRED LIFETIME NUMBER { 306 ra_prefix_conf->pltime = $3; 307 } 308 | ONLINK yesno { 309 ra_prefix_conf->lflag = $2; 310 } 311 | AUTONOMOUS ADDRESS_CONFIGURATION yesno { 312 ra_prefix_conf->aflag = $3; 313 } 314 ; 315 dns_block : '{' optnl dnsopts_l '}' 316 | '{' optnl '}' 317 | /* empty */ 318 ; 319 320 dnsopts_l : dnsopts_l dnsoptsl nl 321 | dnsoptsl optnl 322 ; 323 324 dnsoptsl : LIFETIME NUMBER { 325 ra_options->rdns_lifetime = $2; 326 } 327 | NAMESERVER nserver_block 328 | SEARCH search_block 329 ; 330 nserver_block : '{' optnl nserveropts_l '}' 331 | '{' optnl '}' 332 | nserveroptsl 333 | /* empty */ 334 ; 335 336 nserveropts_l : nserveropts_l nserveroptsl optnl 337 | nserveroptsl optnl 338 ; 339 340 nserveroptsl : STRING { 341 struct ra_rdnss_conf *ra_rdnss_conf; 342 struct in6_addr addr; 343 344 memset(&addr, 0, sizeof(addr)); 345 if (inet_pton(AF_INET6, $1, &addr) 346 != 1) { 347 yyerror("error parsing nameserver address %s", 348 $1); 349 free($1); 350 YYERROR; 351 } 352 if ((ra_rdnss_conf = calloc(1, sizeof(*ra_rdnss_conf))) 353 == NULL) 354 err(1, "%s", __func__); 355 memcpy(&ra_rdnss_conf->rdnss, &addr, sizeof(addr)); 356 SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list, 357 ra_rdnss_conf, entry); 358 ra_options->rdnss_count++; 359 } 360 ; 361 search_block : '{' optnl searchopts_l '}' 362 | '{' optnl '}' 363 | searchoptsl 364 | /* empty */ 365 ; 366 367 searchopts_l : searchopts_l searchoptsl optnl 368 | searchoptsl optnl 369 ; 370 371 searchoptsl : STRING { 372 struct ra_dnssl_conf *ra_dnssl_conf; 373 size_t len; 374 375 if ((ra_dnssl_conf = calloc(1, 376 sizeof(*ra_dnssl_conf))) == NULL) 377 err(1, "%s", __func__); 378 379 if ((len = strlcpy(ra_dnssl_conf->search, $1, 380 sizeof(ra_dnssl_conf->search))) >= 381 sizeof(ra_dnssl_conf->search)) { 382 yyerror("search string too long"); 383 free($1); 384 YYERROR; 385 } 386 if (ra_dnssl_conf->search[len] != '.') { 387 if ((len = strlcat(ra_dnssl_conf->search, ".", 388 sizeof(ra_dnssl_conf->search))) > 389 sizeof(ra_dnssl_conf->search)) { 390 yyerror("search string too long"); 391 free($1); 392 YYERROR; 393 } 394 } 395 SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list, 396 ra_dnssl_conf, entry); 397 ra_options->dnssl_len += len + 1; 398 } 399 ; 400 %% 401 402 struct keywords { 403 const char *k_name; 404 int k_val; 405 }; 406 407 int 408 yyerror(const char *fmt, ...) 409 { 410 va_list ap; 411 char *msg; 412 413 file->errors++; 414 va_start(ap, fmt); 415 if (vasprintf(&msg, fmt, ap) == -1) 416 fatalx("yyerror vasprintf"); 417 va_end(ap); 418 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); 419 free(msg); 420 return (0); 421 } 422 423 int 424 kw_cmp(const void *k, const void *e) 425 { 426 return (strcmp(k, ((const struct keywords *)e)->k_name)); 427 } 428 429 int 430 lookup(char *s) 431 { 432 /* This has to be sorted always. */ 433 static const struct keywords keywords[] = { 434 {"address", ADDRESS}, 435 {"address-configuration", ADDRESS_CONFIGURATION}, 436 {"auto", AUTO}, 437 {"autonomous", AUTONOMOUS}, 438 {"configuration", CONFIGURATION}, 439 {"default", DEFAULT}, 440 {"dns", DNS}, 441 {"hop", HOP}, 442 {"include", INCLUDE}, 443 {"interface", RA_IFACE}, 444 {"lifetime", LIFETIME}, 445 {"limit", LIMIT}, 446 {"managed", MANAGED}, 447 {"mtu", MTU}, 448 {"nameserver", NAMESERVER}, 449 {"no", NO}, 450 {"on-link", ONLINK}, 451 {"other", OTHER}, 452 {"preferred", PREFERRED}, 453 {"prefix", PREFIX}, 454 {"reachable", REACHABLE}, 455 {"retrans", RETRANS}, 456 {"router", ROUTER}, 457 {"search", SEARCH}, 458 {"time", TIME}, 459 {"timer", TIMER}, 460 {"valid", VALID}, 461 {"yes", YES}, 462 }; 463 const struct keywords *p; 464 465 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 466 sizeof(keywords[0]), kw_cmp); 467 468 if (p) 469 return (p->k_val); 470 else 471 return (STRING); 472 } 473 474 #define START_EXPAND 1 475 #define DONE_EXPAND 2 476 477 static int expanding; 478 479 int 480 igetc(void) 481 { 482 int c; 483 484 while (1) { 485 if (file->ungetpos > 0) 486 c = file->ungetbuf[--file->ungetpos]; 487 else 488 c = getc(file->stream); 489 490 if (c == START_EXPAND) 491 expanding = 1; 492 else if (c == DONE_EXPAND) 493 expanding = 0; 494 else 495 break; 496 } 497 return (c); 498 } 499 500 int 501 lgetc(int quotec) 502 { 503 int c, next; 504 505 if (quotec) { 506 if ((c = igetc()) == EOF) { 507 yyerror("reached end of file while parsing " 508 "quoted string"); 509 if (file == topfile || popfile() == EOF) 510 return (EOF); 511 return (quotec); 512 } 513 return (c); 514 } 515 516 while ((c = igetc()) == '\\') { 517 next = igetc(); 518 if (next != '\n') { 519 c = next; 520 break; 521 } 522 yylval.lineno = file->lineno; 523 file->lineno++; 524 } 525 526 if (c == EOF) { 527 /* 528 * Fake EOL when hit EOF for the first time. This gets line 529 * count right if last line in included file is syntactically 530 * invalid and has no newline. 531 */ 532 if (file->eof_reached == 0) { 533 file->eof_reached = 1; 534 return ('\n'); 535 } 536 while (c == EOF) { 537 if (file == topfile || popfile() == EOF) 538 return (EOF); 539 c = igetc(); 540 } 541 } 542 return (c); 543 } 544 545 void 546 lungetc(int c) 547 { 548 if (c == EOF) 549 return; 550 551 if (file->ungetpos >= file->ungetsize) { 552 void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); 553 if (p == NULL) 554 err(1, "lungetc"); 555 file->ungetbuf = p; 556 file->ungetsize *= 2; 557 } 558 file->ungetbuf[file->ungetpos++] = c; 559 } 560 561 int 562 findeol(void) 563 { 564 int c; 565 566 /* Skip to either EOF or the first real EOL. */ 567 while (1) { 568 c = lgetc(0); 569 if (c == '\n') { 570 file->lineno++; 571 break; 572 } 573 if (c == EOF) 574 break; 575 } 576 return (ERROR); 577 } 578 579 int 580 yylex(void) 581 { 582 unsigned char buf[8096]; 583 unsigned char *p, *val; 584 int quotec, next, c; 585 int token; 586 587 top: 588 p = buf; 589 while ((c = lgetc(0)) == ' ' || c == '\t') 590 ; /* nothing */ 591 592 yylval.lineno = file->lineno; 593 if (c == '#') 594 while ((c = lgetc(0)) != '\n' && c != EOF) 595 ; /* nothing */ 596 if (c == '$' && !expanding) { 597 while (1) { 598 if ((c = lgetc(0)) == EOF) 599 return (0); 600 601 if (p + 1 >= buf + sizeof(buf) - 1) { 602 yyerror("string too long"); 603 return (findeol()); 604 } 605 if (isalnum(c) || c == '_') { 606 *p++ = c; 607 continue; 608 } 609 *p = '\0'; 610 lungetc(c); 611 break; 612 } 613 val = symget(buf); 614 if (val == NULL) { 615 yyerror("macro '%s' not defined", buf); 616 return (findeol()); 617 } 618 p = val + strlen(val) - 1; 619 lungetc(DONE_EXPAND); 620 while (p >= val) { 621 lungetc(*p); 622 p--; 623 } 624 lungetc(START_EXPAND); 625 goto top; 626 } 627 628 switch (c) { 629 case '\'': 630 case '"': 631 quotec = c; 632 while (1) { 633 if ((c = lgetc(quotec)) == EOF) 634 return (0); 635 if (c == '\n') { 636 file->lineno++; 637 continue; 638 } else if (c == '\\') { 639 if ((next = lgetc(quotec)) == EOF) 640 return (0); 641 if (next == quotec || next == ' ' || 642 next == '\t') 643 c = next; 644 else if (next == '\n') { 645 file->lineno++; 646 continue; 647 } else 648 lungetc(next); 649 } else if (c == quotec) { 650 *p = '\0'; 651 break; 652 } else if (c == '\0') { 653 yyerror("syntax error"); 654 return (findeol()); 655 } 656 if (p + 1 >= buf + sizeof(buf) - 1) { 657 yyerror("string too long"); 658 return (findeol()); 659 } 660 *p++ = c; 661 } 662 yylval.v.string = strdup(buf); 663 if (yylval.v.string == NULL) 664 err(1, "yylex: strdup"); 665 return (STRING); 666 } 667 668 #define allowed_to_end_number(x) \ 669 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 670 671 if (c == '-' || isdigit(c)) { 672 do { 673 *p++ = c; 674 if ((size_t)(p-buf) >= sizeof(buf)) { 675 yyerror("string too long"); 676 return (findeol()); 677 } 678 } while ((c = lgetc(0)) != EOF && isdigit(c)); 679 lungetc(c); 680 if (p == buf + 1 && buf[0] == '-') 681 goto nodigits; 682 if (c == EOF || allowed_to_end_number(c)) { 683 const char *errstr = NULL; 684 685 *p = '\0'; 686 yylval.v.number = strtonum(buf, LLONG_MIN, 687 LLONG_MAX, &errstr); 688 if (errstr) { 689 yyerror("\"%s\" invalid number: %s", 690 buf, errstr); 691 return (findeol()); 692 } 693 return (NUMBER); 694 } else { 695 nodigits: 696 while (p > buf + 1) 697 lungetc(*--p); 698 c = *--p; 699 if (c == '-') 700 return (c); 701 } 702 } 703 704 #define allowed_in_string(x) \ 705 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 706 x != '{' && x != '}' && \ 707 x != '!' && x != '=' && x != '#' && \ 708 x != ',')) 709 710 if (isalnum(c) || c == ':' || c == '_') { 711 do { 712 *p++ = c; 713 if ((size_t)(p-buf) >= sizeof(buf)) { 714 yyerror("string too long"); 715 return (findeol()); 716 } 717 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 718 lungetc(c); 719 *p = '\0'; 720 if ((token = lookup(buf)) == STRING) 721 if ((yylval.v.string = strdup(buf)) == NULL) 722 err(1, "yylex: strdup"); 723 return (token); 724 } 725 if (c == '\n') { 726 yylval.lineno = file->lineno; 727 file->lineno++; 728 } 729 if (c == EOF) 730 return (0); 731 return (c); 732 } 733 734 int 735 check_file_secrecy(int fd, const char *fname) 736 { 737 struct stat st; 738 739 if (fstat(fd, &st)) { 740 log_warn("cannot stat %s", fname); 741 return (-1); 742 } 743 if (st.st_uid != 0 && st.st_uid != getuid()) { 744 log_warnx("%s: owner not root or current user", fname); 745 return (-1); 746 } 747 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { 748 log_warnx("%s: group writable or world read/writable", fname); 749 return (-1); 750 } 751 return (0); 752 } 753 754 struct file * 755 pushfile(const char *name, int secret) 756 { 757 struct file *nfile; 758 759 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 760 log_warn("calloc"); 761 return (NULL); 762 } 763 if ((nfile->name = strdup(name)) == NULL) { 764 log_warn("strdup"); 765 free(nfile); 766 return (NULL); 767 } 768 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 769 log_warn("%s", nfile->name); 770 free(nfile->name); 771 free(nfile); 772 return (NULL); 773 } else if (secret && 774 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 775 fclose(nfile->stream); 776 free(nfile->name); 777 free(nfile); 778 return (NULL); 779 } 780 nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0; 781 nfile->ungetsize = 16; 782 nfile->ungetbuf = malloc(nfile->ungetsize); 783 if (nfile->ungetbuf == NULL) { 784 log_warn("malloc"); 785 fclose(nfile->stream); 786 free(nfile->name); 787 free(nfile); 788 return (NULL); 789 } 790 TAILQ_INSERT_TAIL(&files, nfile, entry); 791 return (nfile); 792 } 793 794 int 795 popfile(void) 796 { 797 struct file *prev; 798 799 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 800 prev->errors += file->errors; 801 802 TAILQ_REMOVE(&files, file, entry); 803 fclose(file->stream); 804 free(file->name); 805 free(file->ungetbuf); 806 free(file); 807 file = prev; 808 return (file ? 0 : EOF); 809 } 810 811 struct rad_conf * 812 parse_config(char *filename) 813 { 814 struct sym *sym, *next; 815 struct ra_iface_conf *iface; 816 817 conf = config_new_empty(); 818 ra_options = NULL; 819 820 file = pushfile(filename, 0); 821 if (file == NULL) { 822 free(conf); 823 return (NULL); 824 } 825 topfile = file; 826 827 yyparse(); 828 errors = file->errors; 829 popfile(); 830 831 /* Free macros and check which have not been used. */ 832 TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { 833 if ((cmd_opts & OPT_VERBOSE2) && !sym->used) 834 fprintf(stderr, "warning: macro '%s' not used\n", 835 sym->nam); 836 if (!sym->persist) { 837 free(sym->nam); 838 free(sym->val); 839 TAILQ_REMOVE(&symhead, sym, entry); 840 free(sym); 841 } 842 } 843 844 if (errors) { 845 clear_config(conf); 846 return (NULL); 847 } 848 849 if (!SIMPLEQ_EMPTY(&conf->ra_options.ra_rdnss_list) || 850 !SIMPLEQ_EMPTY(&conf->ra_options.ra_dnssl_list)) { 851 SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry) 852 copy_dns_options(&conf->ra_options, 853 &iface->ra_options); 854 } 855 856 return (conf); 857 } 858 859 void 860 copy_dns_options(const struct ra_options_conf *src, struct ra_options_conf *dst) 861 { 862 struct ra_rdnss_conf *ra_rdnss, *nra_rdnss; 863 struct ra_dnssl_conf *ra_dnssl, *nra_dnssl; 864 865 if (SIMPLEQ_EMPTY(&dst->ra_rdnss_list)) { 866 SIMPLEQ_FOREACH(ra_rdnss, &src->ra_rdnss_list, entry) { 867 if ((nra_rdnss = calloc(1, sizeof(*nra_rdnss))) == NULL) 868 errx(1, "%s", __func__); 869 memcpy(nra_rdnss, ra_rdnss, sizeof(*nra_rdnss)); 870 SIMPLEQ_INSERT_TAIL(&dst->ra_rdnss_list, nra_rdnss, 871 entry); 872 } 873 dst->rdnss_count = src->rdnss_count; 874 } 875 if (SIMPLEQ_EMPTY(&dst->ra_dnssl_list)) { 876 SIMPLEQ_FOREACH(ra_dnssl, &src->ra_dnssl_list, entry) { 877 if ((nra_dnssl = calloc(1, sizeof(*nra_dnssl))) == NULL) 878 errx(1, "%s", __func__); 879 memcpy(nra_dnssl, ra_dnssl, sizeof(*nra_dnssl)); 880 SIMPLEQ_INSERT_TAIL(&dst->ra_dnssl_list, nra_dnssl, 881 entry); 882 } 883 dst->dnssl_len = src->dnssl_len; 884 } 885 } 886 887 int 888 symset(const char *nam, const char *val, int persist) 889 { 890 struct sym *sym; 891 892 TAILQ_FOREACH(sym, &symhead, entry) { 893 if (strcmp(nam, sym->nam) == 0) 894 break; 895 } 896 897 if (sym != NULL) { 898 if (sym->persist == 1) 899 return (0); 900 else { 901 free(sym->nam); 902 free(sym->val); 903 TAILQ_REMOVE(&symhead, sym, entry); 904 free(sym); 905 } 906 } 907 if ((sym = calloc(1, sizeof(*sym))) == NULL) 908 return (-1); 909 910 sym->nam = strdup(nam); 911 if (sym->nam == NULL) { 912 free(sym); 913 return (-1); 914 } 915 sym->val = strdup(val); 916 if (sym->val == NULL) { 917 free(sym->nam); 918 free(sym); 919 return (-1); 920 } 921 sym->used = 0; 922 sym->persist = persist; 923 TAILQ_INSERT_TAIL(&symhead, sym, entry); 924 return (0); 925 } 926 927 int 928 cmdline_symset(char *s) 929 { 930 char *sym, *val; 931 int ret; 932 933 if ((val = strrchr(s, '=')) == NULL) 934 return (-1); 935 sym = strndup(s, val - s); 936 if (sym == NULL) 937 errx(1, "%s: strndup", __func__); 938 ret = symset(sym, val + 1, 1); 939 free(sym); 940 941 return (ret); 942 } 943 944 char * 945 symget(const char *nam) 946 { 947 struct sym *sym; 948 949 TAILQ_FOREACH(sym, &symhead, entry) { 950 if (strcmp(nam, sym->nam) == 0) { 951 sym->used = 1; 952 return (sym->val); 953 } 954 } 955 return (NULL); 956 } 957 958 struct ra_prefix_conf * 959 conf_get_ra_prefix(struct in6_addr *addr, int prefixlen) 960 { 961 struct ra_prefix_conf *prefix; 962 963 if (addr == NULL) { 964 if (ra_iface_conf->autoprefix != NULL) 965 return (ra_iface_conf->autoprefix); 966 } else { 967 SIMPLEQ_FOREACH(prefix, &ra_iface_conf->ra_prefix_list, entry) { 968 if (prefix->prefixlen == prefixlen && memcmp(addr, 969 &prefix->prefix, sizeof(*addr)) == 0) 970 return (prefix); 971 } 972 } 973 974 prefix = calloc(1, sizeof(*prefix)); 975 if (prefix == NULL) 976 errx(1, "%s: calloc", __func__); 977 prefix->prefixlen = prefixlen; 978 prefix->vltime = ADV_VALID_LIFETIME; 979 prefix->pltime = ADV_PREFERRED_LIFETIME; 980 prefix->lflag = 1; 981 prefix->aflag = 1; 982 983 if (addr == NULL) 984 ra_iface_conf->autoprefix = prefix; 985 else { 986 prefix->prefix = *addr; 987 SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, prefix, 988 entry); 989 } 990 991 return (prefix); 992 } 993 994 struct ra_iface_conf * 995 conf_get_ra_iface(char *name) 996 { 997 struct ra_iface_conf *iface; 998 size_t n; 999 1000 SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry) { 1001 if (strcmp(name, iface->name) == 0) 1002 return (iface); 1003 } 1004 1005 iface = calloc(1, sizeof(*iface)); 1006 if (iface == NULL) 1007 errx(1, "%s: calloc", __func__); 1008 n = strlcpy(iface->name, name, sizeof(iface->name)); 1009 if (n >= sizeof(iface->name)) 1010 errx(1, "%s: name too long", __func__); 1011 1012 /* Inherit attributes set in global section. */ 1013 iface->ra_options = conf->ra_options; 1014 1015 SIMPLEQ_INIT(&iface->ra_prefix_list); 1016 SIMPLEQ_INIT(&iface->ra_options.ra_rdnss_list); 1017 iface->ra_options.rdnss_count = 0; 1018 SIMPLEQ_INIT(&iface->ra_options.ra_dnssl_list); 1019 iface->ra_options.dnssl_len = 0; 1020 1021 SIMPLEQ_INSERT_TAIL(&conf->ra_iface_list, iface, entry); 1022 1023 return (iface); 1024 } 1025 1026 void 1027 clear_config(struct rad_conf *xconf) 1028 { 1029 struct ra_iface_conf *iface; 1030 1031 free_dns_options(&xconf->ra_options); 1032 1033 while((iface = SIMPLEQ_FIRST(&xconf->ra_iface_list)) != NULL) { 1034 SIMPLEQ_REMOVE_HEAD(&xconf->ra_iface_list, entry); 1035 free_ra_iface_conf(iface); 1036 } 1037 1038 free(xconf); 1039 } 1040