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