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
yyerror(const char * fmt,...)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
kw_cmp(const void * k,const void * e)418 kw_cmp(const void *k, const void *e)
419 {
420 return (strcmp(k, ((const struct keywords *)e)->k_name));
421 }
422
423 int
lookup(char * s)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
lgetc(int quotec)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
lungetc(int c)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
findeol(void)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
yylex(void)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
check_file_secrecy(int fd,const char * fname)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 *
pushfile(const char * name,int secret)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
popfile(void)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 *
parse_config(char * filename,int opts)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
symset(const char * nam,const char * val,int persist)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
cmdline_symset(char * s)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 *
symget(const char * nam)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 *
conf_get_if(struct kif * kif)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
clear_config(struct ripd_conf * xconf)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
host(const char * s,struct in_addr * addr,struct in_addr * mask)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