xref: /openbsd/usr.sbin/ripd/parse.y (revision 8529ddd3)
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