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