1 /* $OpenBSD: parse.y,v 1.48 2021/10/15 15:01:28 naddy Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it> 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/socket.h> 28 #include <sys/stat.h> 29 #include <net/route.h> 30 #include <netinet/in.h> 31 #include <arpa/inet.h> 32 #include <ctype.h> 33 #include <err.h> 34 #include <errno.h> 35 #include <unistd.h> 36 #include <limits.h> 37 #include <stdarg.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <syslog.h> 41 42 #include "ripd.h" 43 #include "rip.h" 44 #include "ripe.h" 45 #include "log.h" 46 47 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 48 static struct file { 49 TAILQ_ENTRY(file) entry; 50 FILE *stream; 51 char *name; 52 int lineno; 53 int errors; 54 } *file, *topfile; 55 struct file *pushfile(const char *, int); 56 int popfile(void); 57 int yyparse(void); 58 int yylex(void); 59 int yyerror(const char *, ...) 60 __attribute__((__format__ (printf, 1, 2))) 61 __attribute__((__nonnull__ (1))); 62 int kw_cmp(const void *, const void *); 63 int lookup(char *); 64 int lgetc(int); 65 int lungetc(int); 66 int findeol(void); 67 68 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 69 struct sym { 70 TAILQ_ENTRY(sym) entry; 71 int used; 72 int persist; 73 char *nam; 74 char *val; 75 }; 76 int symset(const char *, const char *, int); 77 char *symget(const char *); 78 79 static struct { 80 u_int8_t auth_key[MAX_SIMPLE_AUTH_LEN]; 81 struct auth_md_head md_list; 82 enum auth_type auth_type; 83 u_int8_t auth_keyid; 84 u_int8_t cost; 85 } *defs, globaldefs, ifacedefs; 86 87 struct iface *iface = NULL; 88 static struct ripd_conf *conf; 89 static int errors = 0; 90 91 struct iface *conf_get_if(struct kif *); 92 void clear_config(struct ripd_conf *); 93 int check_file_secrecy(int, const char *); 94 u_int32_t get_rtr_id(void); 95 int host(const char *, struct in_addr *, struct in_addr *); 96 97 typedef struct { 98 union { 99 int64_t number; 100 char *string; 101 } v; 102 int lineno; 103 } YYSTYPE; 104 105 %} 106 107 %token SPLIT_HORIZON TRIGGERED_UPDATES FIBPRIORITY FIBUPDATE 108 %token REDISTRIBUTE RDOMAIN 109 %token AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID 110 %token INTERFACE RTLABEL 111 %token COST PASSIVE 112 %token YES NO 113 %token DEMOTE 114 %token ERROR 115 %token <v.string> STRING 116 %token <v.number> NUMBER 117 %type <v.number> yesno no 118 %type <v.string> string 119 120 %% 121 122 grammar : /* empty */ 123 | grammar '\n' 124 | grammar conf_main '\n' 125 | grammar varset '\n' 126 | grammar interface '\n' 127 | grammar error '\n' { file->errors++; } 128 ; 129 130 string : string STRING { 131 if (asprintf(&$$, "%s %s", $1, $2) == -1) { 132 free($1); 133 free($2); 134 yyerror("string: asprintf"); 135 YYERROR; 136 } 137 free($1); 138 free($2); 139 } 140 | STRING 141 ; 142 143 yesno : YES { $$ = 1; } 144 | NO { $$ = 0; } 145 ; 146 147 no : /* empty */ { $$ = 0; } 148 | NO { $$ = 1; } 149 150 varset : STRING '=' string { 151 char *s = $1; 152 if (conf->opts & RIPD_OPT_VERBOSE) 153 printf("%s = \"%s\"\n", $1, $3); 154 while (*s++) { 155 if (isspace((unsigned char)*s)) { 156 yyerror("macro name cannot contain " 157 "whitespace"); 158 free($1); 159 free($3); 160 YYERROR; 161 } 162 } 163 if (symset($1, $3, 0) == -1) 164 fatal("cannot store variable"); 165 free($1); 166 free($3); 167 } 168 ; 169 170 conf_main : SPLIT_HORIZON STRING { 171 /* clean flags first */ 172 conf->options &= ~(OPT_SPLIT_HORIZON | 173 OPT_SPLIT_POISONED); 174 if (!strcmp($2, "none")) 175 /* nothing */ ; 176 else if (!strcmp($2, "simple")) 177 conf->options |= OPT_SPLIT_HORIZON; 178 else if (!strcmp($2, "poisoned")) 179 conf->options |= OPT_SPLIT_POISONED; 180 else { 181 yyerror("unknown split horizon type"); 182 free($2); 183 YYERROR; 184 } 185 free($2); 186 } 187 | TRIGGERED_UPDATES yesno { 188 if ($2 == 1) 189 conf->options |= OPT_TRIGGERED_UPDATES; 190 else 191 conf->options &= ~OPT_TRIGGERED_UPDATES; 192 } 193 | RDOMAIN NUMBER { 194 if ($2 < 0 || $2 > RT_TABLEID_MAX) { 195 yyerror("invalid rdomain"); 196 YYERROR; 197 } 198 conf->rdomain = $2; 199 } 200 | FIBPRIORITY NUMBER { 201 if ($2 <= RTP_NONE || $2 > RTP_MAX) { 202 yyerror("invalid fib-priority"); 203 YYERROR; 204 } 205 conf->fib_priority = $2; 206 } 207 | FIBUPDATE yesno { 208 if ($2 == 0) 209 conf->flags |= RIPD_FLAG_NO_FIB_UPDATE; 210 else 211 conf->flags &= ~RIPD_FLAG_NO_FIB_UPDATE; 212 } 213 | no REDISTRIBUTE STRING { 214 struct redistribute *r; 215 216 if ((r = calloc(1, sizeof(*r))) == NULL) 217 fatal(NULL); 218 if (!strcmp($3, "static")) 219 r->type = REDIST_STATIC; 220 else if (!strcmp($3, "connected")) 221 r->type = REDIST_CONNECTED; 222 else if (!strcmp($3, "default")) 223 r->type = REDIST_DEFAULT; 224 else if (host($3, &r->addr, &r->mask)) 225 r->type = REDIST_ADDR; 226 else { 227 yyerror("unknown redistribute type"); 228 free($3); 229 free(r); 230 YYERROR; 231 } 232 233 if ($1) 234 r->type |= REDIST_NO; 235 236 SIMPLEQ_INSERT_TAIL(&conf->redist_list, r, 237 entry); 238 239 conf->redistribute |= REDISTRIBUTE_ON; 240 free($3); 241 } 242 | no REDISTRIBUTE RTLABEL STRING { 243 struct redistribute *r; 244 245 if ((r = calloc(1, sizeof(*r))) == NULL) 246 fatal(NULL); 247 r->type = REDIST_LABEL; 248 r->label = rtlabel_name2id($4); 249 if ($1) 250 r->type |= REDIST_NO; 251 free($4); 252 253 SIMPLEQ_INSERT_TAIL(&conf->redist_list, r, entry); 254 conf->redistribute |= REDISTRIBUTE_ON; 255 } 256 | defaults 257 ; 258 259 authmd : AUTHMD NUMBER STRING { 260 if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) { 261 yyerror("auth-md key-id out of range " 262 "(%d-%d)", MIN_MD_ID, MAX_MD_ID); 263 free($3); 264 YYERROR; 265 } 266 if (md_list_add(&defs->md_list, $2, $3) == -1) { 267 yyerror("auth-md key length out of range " 268 "(max length %d)", MD5_DIGEST_LENGTH); 269 free($3); 270 YYERROR; 271 } 272 free($3); 273 } 274 275 authmdkeyid : AUTHMDKEYID NUMBER { 276 if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) { 277 yyerror("auth-md-keyid out of range " 278 "(%d-%d)", MIN_MD_ID, MAX_MD_ID); 279 YYERROR; 280 } 281 defs->auth_keyid = $2; 282 } 283 284 authtype : AUTHTYPE STRING { 285 enum auth_type type; 286 287 if (!strcmp($2, "none")) 288 type = AUTH_NONE; 289 else if (!strcmp($2, "simple")) 290 type = AUTH_SIMPLE; 291 else if (!strcmp($2, "crypt")) 292 type = AUTH_CRYPT; 293 else { 294 yyerror("unknown auth-type"); 295 free($2); 296 YYERROR; 297 } 298 free($2); 299 defs->auth_type = type; 300 } 301 ; 302 303 authkey : AUTHKEY STRING { 304 if (strlen($2) > MAX_SIMPLE_AUTH_LEN) { 305 yyerror("auth-key too long (max length %d)", 306 MAX_SIMPLE_AUTH_LEN); 307 free($2); 308 YYERROR; 309 } 310 bzero(defs->auth_key, MAX_SIMPLE_AUTH_LEN); 311 memcpy(defs->auth_key, $2, strlen($2)); 312 free($2); 313 } 314 ; 315 316 defaults : COST NUMBER { 317 if ($2 < 1 || $2 > INFINITY) { 318 yyerror("cost out of range (%d-%d)", 1, 319 INFINITY); 320 YYERROR; 321 } 322 defs->cost = $2; 323 } 324 | authtype 325 | authkey 326 | authmdkeyid 327 | authmd 328 ; 329 330 optnl : '\n' optnl 331 | 332 ; 333 334 nl : '\n' optnl 335 ; 336 337 interface : INTERFACE STRING { 338 struct kif *kif; 339 340 if ((kif = kif_findname($2)) == NULL) { 341 yyerror("unknown interface %s", $2); 342 free($2); 343 YYERROR; 344 } 345 free($2); 346 iface = conf_get_if(kif); 347 if (iface == NULL) 348 YYERROR; 349 LIST_INSERT_HEAD(&conf->iface_list, iface, entry); 350 memcpy(&ifacedefs, defs, sizeof(ifacedefs)); 351 md_list_copy(&ifacedefs.md_list, &defs->md_list); 352 defs = &ifacedefs; 353 } interface_block { 354 iface->cost = defs->cost; 355 iface->auth_type = defs->auth_type; 356 iface->auth_keyid = defs->auth_keyid; 357 memcpy(iface->auth_key, defs->auth_key, 358 sizeof(iface->auth_key)); 359 md_list_copy(&iface->auth_md_list, &defs->md_list); 360 md_list_clr(&defs->md_list); 361 defs = &globaldefs; 362 } 363 ; 364 365 interface_block : /* empty */ 366 | '{' optnl interfaceopts_l '}' 367 | '{' optnl '}' 368 ; 369 370 interfaceopts_l : interfaceopts_l interfaceoptsl nl 371 | interfaceoptsl optnl 372 ; 373 374 interfaceoptsl : PASSIVE { iface->passive = 1; } 375 | DEMOTE STRING { 376 if (strlcpy(iface->demote_group, $2, 377 sizeof(iface->demote_group)) >= 378 sizeof(iface->demote_group)) { 379 yyerror("demote group name \"%s\" too long", 380 $2); 381 free($2); 382 YYERROR; 383 } 384 free($2); 385 if (carp_demote_init(iface->demote_group, 386 conf->opts & RIPD_OPT_FORCE_DEMOTE) == -1) { 387 yyerror("error initializing group \"%s\"", 388 iface->demote_group); 389 YYERROR; 390 } 391 } 392 | defaults 393 ; 394 %% 395 396 struct keywords { 397 const char *k_name; 398 int k_val; 399 }; 400 401 int 402 yyerror(const char *fmt, ...) 403 { 404 va_list ap; 405 char *msg; 406 407 file->errors++; 408 va_start(ap, fmt); 409 if (vasprintf(&msg, fmt, ap) == -1) 410 fatalx("yyerror vasprintf"); 411 va_end(ap); 412 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); 413 free(msg); 414 return (0); 415 } 416 417 int 418 kw_cmp(const void *k, const void *e) 419 { 420 return (strcmp(k, ((const struct keywords *)e)->k_name)); 421 } 422 423 int 424 lookup(char *s) 425 { 426 /* this has to be sorted always */ 427 static const struct keywords keywords[] = { 428 {"auth-key", AUTHKEY}, 429 {"auth-md", AUTHMD}, 430 {"auth-md-keyid", AUTHMDKEYID}, 431 {"auth-type", AUTHTYPE}, 432 {"cost", COST}, 433 {"demote", DEMOTE}, 434 {"fib-priority", FIBPRIORITY}, 435 {"fib-update", FIBUPDATE}, 436 {"interface", INTERFACE}, 437 {"no", NO}, 438 {"passive", PASSIVE}, 439 {"rdomain", RDOMAIN}, 440 {"redistribute", REDISTRIBUTE}, 441 {"rtlabel", RTLABEL}, 442 {"split-horizon", SPLIT_HORIZON}, 443 {"triggered-updates", TRIGGERED_UPDATES}, 444 {"yes", YES} 445 }; 446 const struct keywords *p; 447 448 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 449 sizeof(keywords[0]), kw_cmp); 450 451 if (p) 452 return (p->k_val); 453 else 454 return (STRING); 455 } 456 457 #define MAXPUSHBACK 128 458 459 char *parsebuf; 460 int parseindex; 461 char pushback_buffer[MAXPUSHBACK]; 462 int pushback_index = 0; 463 464 int 465 lgetc(int quotec) 466 { 467 int c, next; 468 469 if (parsebuf) { 470 /* Read character from the parsebuffer instead of input. */ 471 if (parseindex >= 0) { 472 c = (unsigned char)parsebuf[parseindex++]; 473 if (c != '\0') 474 return (c); 475 parsebuf = NULL; 476 } else 477 parseindex++; 478 } 479 480 if (pushback_index) 481 return ((unsigned char)pushback_buffer[--pushback_index]); 482 483 if (quotec) { 484 if ((c = getc(file->stream)) == EOF) { 485 yyerror("reached end of file while parsing " 486 "quoted string"); 487 if (file == topfile || popfile() == EOF) 488 return (EOF); 489 return (quotec); 490 } 491 return (c); 492 } 493 494 while ((c = getc(file->stream)) == '\\') { 495 next = getc(file->stream); 496 if (next != '\n') { 497 c = next; 498 break; 499 } 500 yylval.lineno = file->lineno; 501 file->lineno++; 502 } 503 504 while (c == EOF) { 505 if (file == topfile || popfile() == EOF) 506 return (EOF); 507 c = getc(file->stream); 508 } 509 return (c); 510 } 511 512 int 513 lungetc(int c) 514 { 515 if (c == EOF) 516 return (EOF); 517 if (parsebuf) { 518 parseindex--; 519 if (parseindex >= 0) 520 return (c); 521 } 522 if (pushback_index + 1 >= MAXPUSHBACK) 523 return (EOF); 524 pushback_buffer[pushback_index++] = c; 525 return (c); 526 } 527 528 int 529 findeol(void) 530 { 531 int c; 532 533 parsebuf = NULL; 534 535 /* skip to either EOF or the first real EOL */ 536 while (1) { 537 if (pushback_index) 538 c = (unsigned char)pushback_buffer[--pushback_index]; 539 else 540 c = lgetc(0); 541 if (c == '\n') { 542 file->lineno++; 543 break; 544 } 545 if (c == EOF) 546 break; 547 } 548 return (ERROR); 549 } 550 551 int 552 yylex(void) 553 { 554 char buf[8096]; 555 char *p, *val; 556 int quotec, next, c; 557 int token; 558 559 top: 560 p = buf; 561 while ((c = lgetc(0)) == ' ' || c == '\t') 562 ; /* nothing */ 563 564 yylval.lineno = file->lineno; 565 if (c == '#') 566 while ((c = lgetc(0)) != '\n' && c != EOF) 567 ; /* nothing */ 568 if (c == '$' && parsebuf == NULL) { 569 while (1) { 570 if ((c = lgetc(0)) == EOF) 571 return (0); 572 573 if (p + 1 >= buf + sizeof(buf) - 1) { 574 yyerror("string too long"); 575 return (findeol()); 576 } 577 if (isalnum(c) || c == '_') { 578 *p++ = c; 579 continue; 580 } 581 *p = '\0'; 582 lungetc(c); 583 break; 584 } 585 val = symget(buf); 586 if (val == NULL) { 587 yyerror("macro '%s' not defined", buf); 588 return (findeol()); 589 } 590 parsebuf = val; 591 parseindex = 0; 592 goto top; 593 } 594 595 switch (c) { 596 case '\'': 597 case '"': 598 quotec = c; 599 while (1) { 600 if ((c = lgetc(quotec)) == EOF) 601 return (0); 602 if (c == '\n') { 603 file->lineno++; 604 continue; 605 } else if (c == '\\') { 606 if ((next = lgetc(quotec)) == EOF) 607 return (0); 608 if (next == quotec || next == ' ' || 609 next == '\t') 610 c = next; 611 else if (next == '\n') { 612 file->lineno++; 613 continue; 614 } else 615 lungetc(next); 616 } else if (c == quotec) { 617 *p = '\0'; 618 break; 619 } else if (c == '\0') { 620 yyerror("syntax error"); 621 return (findeol()); 622 } 623 if (p + 1 >= buf + sizeof(buf) - 1) { 624 yyerror("string too long"); 625 return (findeol()); 626 } 627 *p++ = c; 628 } 629 yylval.v.string = strdup(buf); 630 if (yylval.v.string == NULL) 631 err(1, "%s", __func__); 632 return (STRING); 633 } 634 635 #define allowed_to_end_number(x) \ 636 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 637 638 if (c == '-' || isdigit(c)) { 639 do { 640 *p++ = c; 641 if ((size_t)(p-buf) >= sizeof(buf)) { 642 yyerror("string too long"); 643 return (findeol()); 644 } 645 } while ((c = lgetc(0)) != EOF && isdigit(c)); 646 lungetc(c); 647 if (p == buf + 1 && buf[0] == '-') 648 goto nodigits; 649 if (c == EOF || allowed_to_end_number(c)) { 650 const char *errstr = NULL; 651 652 *p = '\0'; 653 yylval.v.number = strtonum(buf, LLONG_MIN, 654 LLONG_MAX, &errstr); 655 if (errstr) { 656 yyerror("\"%s\" invalid number: %s", 657 buf, errstr); 658 return (findeol()); 659 } 660 return (NUMBER); 661 } else { 662 nodigits: 663 while (p > buf + 1) 664 lungetc((unsigned char)*--p); 665 c = (unsigned char)*--p; 666 if (c == '-') 667 return (c); 668 } 669 } 670 671 #define allowed_in_string(x) \ 672 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 673 x != '{' && x != '}' && \ 674 x != '!' && x != '=' && x != '#' && \ 675 x != ',')) 676 677 if (isalnum(c) || c == ':' || c == '_') { 678 do { 679 *p++ = c; 680 if ((size_t)(p-buf) >= sizeof(buf)) { 681 yyerror("string too long"); 682 return (findeol()); 683 } 684 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 685 lungetc(c); 686 *p = '\0'; 687 if ((token = lookup(buf)) == STRING) 688 if ((yylval.v.string = strdup(buf)) == NULL) 689 err(1, "%s", __func__); 690 return (token); 691 } 692 if (c == '\n') { 693 yylval.lineno = file->lineno; 694 file->lineno++; 695 } 696 if (c == EOF) 697 return (0); 698 return (c); 699 } 700 701 int 702 check_file_secrecy(int fd, const char *fname) 703 { 704 struct stat st; 705 706 if (fstat(fd, &st)) { 707 log_warn("cannot stat %s", fname); 708 return (-1); 709 } 710 if (st.st_uid != 0 && st.st_uid != getuid()) { 711 log_warnx("%s: owner not root or current user", fname); 712 return (-1); 713 } 714 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { 715 log_warnx("%s: group writable or world read/writable", fname); 716 return (-1); 717 } 718 return (0); 719 } 720 721 struct file * 722 pushfile(const char *name, int secret) 723 { 724 struct file *nfile; 725 726 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 727 log_warn("%s", __func__); 728 return (NULL); 729 } 730 if ((nfile->name = strdup(name)) == NULL) { 731 log_warn("%s", __func__); 732 free(nfile); 733 return (NULL); 734 } 735 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 736 log_warn("%s: %s", __func__, nfile->name); 737 free(nfile->name); 738 free(nfile); 739 return (NULL); 740 } else if (secret && 741 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 742 fclose(nfile->stream); 743 free(nfile->name); 744 free(nfile); 745 return (NULL); 746 } 747 nfile->lineno = 1; 748 TAILQ_INSERT_TAIL(&files, nfile, entry); 749 return (nfile); 750 } 751 752 int 753 popfile(void) 754 { 755 struct file *prev; 756 757 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 758 prev->errors += file->errors; 759 760 TAILQ_REMOVE(&files, file, entry); 761 fclose(file->stream); 762 free(file->name); 763 free(file); 764 file = prev; 765 return (file ? 0 : EOF); 766 } 767 768 struct ripd_conf * 769 parse_config(char *filename, int opts) 770 { 771 struct sym *sym, *next; 772 773 if ((conf = calloc(1, sizeof(struct ripd_conf))) == NULL) 774 fatal("parse_config"); 775 776 bzero(&globaldefs, sizeof(globaldefs)); 777 defs = &globaldefs; 778 TAILQ_INIT(&defs->md_list); 779 defs->cost = DEFAULT_COST; 780 defs->auth_type = AUTH_NONE; 781 conf->opts = opts; 782 conf->options = OPT_SPLIT_POISONED; 783 conf->fib_priority = RTP_RIP; 784 SIMPLEQ_INIT(&conf->redist_list); 785 786 if ((file = pushfile(filename, !(conf->opts & RIPD_OPT_NOACTION))) == NULL) { 787 free(conf); 788 return (NULL); 789 } 790 topfile = file; 791 792 yyparse(); 793 errors = file->errors; 794 popfile(); 795 796 /* Free macros and check which have not been used. */ 797 TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) { 798 if ((conf->opts & RIPD_OPT_VERBOSE2) && !sym->used) 799 fprintf(stderr, "warning: macro '%s' not " 800 "used\n", sym->nam); 801 if (!sym->persist) { 802 free(sym->nam); 803 free(sym->val); 804 TAILQ_REMOVE(&symhead, sym, entry); 805 free(sym); 806 } 807 } 808 809 /* free global config defaults */ 810 md_list_clr(&globaldefs.md_list); 811 812 if (errors) { 813 clear_config(conf); 814 return (NULL); 815 } 816 817 return (conf); 818 } 819 820 int 821 symset(const char *nam, const char *val, int persist) 822 { 823 struct sym *sym; 824 825 TAILQ_FOREACH(sym, &symhead, entry) { 826 if (strcmp(nam, sym->nam) == 0) 827 break; 828 } 829 830 if (sym != NULL) { 831 if (sym->persist == 1) 832 return (0); 833 else { 834 free(sym->nam); 835 free(sym->val); 836 TAILQ_REMOVE(&symhead, sym, entry); 837 free(sym); 838 } 839 } 840 if ((sym = calloc(1, sizeof(*sym))) == NULL) 841 return (-1); 842 843 sym->nam = strdup(nam); 844 if (sym->nam == NULL) { 845 free(sym); 846 return (-1); 847 } 848 sym->val = strdup(val); 849 if (sym->val == NULL) { 850 free(sym->nam); 851 free(sym); 852 return (-1); 853 } 854 sym->used = 0; 855 sym->persist = persist; 856 TAILQ_INSERT_TAIL(&symhead, sym, entry); 857 return (0); 858 } 859 860 int 861 cmdline_symset(char *s) 862 { 863 char *sym, *val; 864 int ret; 865 866 if ((val = strrchr(s, '=')) == NULL) 867 return (-1); 868 sym = strndup(s, val - s); 869 if (sym == NULL) 870 errx(1, "%s: strndup", __func__); 871 ret = symset(sym, val + 1, 1); 872 free(sym); 873 874 return (ret); 875 } 876 877 char * 878 symget(const char *nam) 879 { 880 struct sym *sym; 881 882 TAILQ_FOREACH(sym, &symhead, entry) { 883 if (strcmp(nam, sym->nam) == 0) { 884 sym->used = 1; 885 return (sym->val); 886 } 887 } 888 return (NULL); 889 } 890 891 struct iface * 892 conf_get_if(struct kif *kif) 893 { 894 struct iface *i; 895 896 LIST_FOREACH(i, &conf->iface_list, entry) 897 if (i->ifindex == kif->ifindex) { 898 yyerror("interface %s already configured", 899 kif->ifname); 900 return (NULL); 901 } 902 903 i = if_new(kif); 904 i->auth_keyid = 1; 905 i->passive = 0; 906 907 return (i); 908 } 909 910 void 911 clear_config(struct ripd_conf *xconf) 912 { 913 struct iface *i; 914 915 while ((i = LIST_FIRST(&conf->iface_list)) != NULL) { 916 LIST_REMOVE(i, entry); 917 if_del(i); 918 } 919 920 free(xconf); 921 } 922 923 int 924 host(const char *s, struct in_addr *addr, struct in_addr *mask) 925 { 926 struct in_addr ina; 927 int bits = 32; 928 929 bzero(&ina, sizeof(struct in_addr)); 930 if (strrchr(s, '/') != NULL) { 931 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) 932 return (0); 933 } else { 934 if (inet_pton(AF_INET, s, &ina) != 1) 935 return (0); 936 } 937 938 addr->s_addr = ina.s_addr; 939 mask->s_addr = prefixlen2mask(bits); 940 941 return (1); 942 } 943