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