xref: /openbsd/usr.sbin/ldpd/parse.y (revision 8529ddd3)
1 /*	$OpenBSD: parse.y,v 1.23 2014/11/20 05:51:20 jsg Exp $ */
2 
3 /*
4  * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
5  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
6  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
7  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
8  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
9  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
10  *
11  * Permission to use, copy, modify, and distribute this software for any
12  * purpose with or without fee is hereby granted, provided that the above
13  * copyright notice and this permission notice appear in all copies.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23 
24 %{
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <ctype.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <unistd.h>
34 #include <ifaddrs.h>
35 #include <net/if_types.h>
36 #include <limits.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <syslog.h>
41 
42 #include "ldp.h"
43 #include "ldpd.h"
44 #include "ldpe.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		 check_file_secrecy(int, const char *);
58 int		 yyparse(void);
59 int		 yylex(void);
60 int		 yyerror(const char *, ...)
61     __attribute__((__format__ (printf, 1, 2)))
62     __attribute__((__nonnull__ (1)));
63 int		 kw_cmp(const void *, const void *);
64 int		 lookup(char *);
65 int		 lgetc(int);
66 int		 lungetc(int);
67 int		 findeol(void);
68 
69 TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
70 struct sym {
71 	TAILQ_ENTRY(sym)	 entry;
72 	int			 used;
73 	int			 persist;
74 	char			*nam;
75 	char			*val;
76 };
77 
78 int		 symset(const char *, const char *, int);
79 char		*symget(const char *);
80 
81 void		 clear_config(struct ldpd_conf *xconf);
82 u_int32_t	 get_rtr_id(void);
83 int		 host(const char *, struct in_addr *, struct in_addr *);
84 
85 static struct ldpd_conf	*conf;
86 static int			 errors = 0;
87 
88 struct iface	*iface = NULL;
89 struct tnbr	*tnbr = NULL;
90 
91 struct config_defaults {
92 	u_int16_t	lhello_holdtime;
93 	u_int16_t	lhello_interval;
94 	u_int16_t	thello_holdtime;
95 	u_int16_t	thello_interval;
96 };
97 
98 struct config_defaults	 globaldefs;
99 struct config_defaults	 ifacedefs;
100 struct config_defaults	 tnbrdefs;
101 struct config_defaults	*defs;
102 
103 struct iface	*conf_get_if(struct kif *);
104 struct tnbr	*conf_get_tnbr(struct in_addr);
105 
106 typedef struct {
107 	union {
108 		int64_t		 number;
109 		char		*string;
110 	} v;
111 	int lineno;
112 } YYSTYPE;
113 
114 %}
115 
116 %token	INTERFACE TNEIGHBOR ROUTERID FIBUPDATE
117 %token	LHELLOHOLDTIME LHELLOINTERVAL
118 %token	THELLOHOLDTIME THELLOINTERVAL
119 %token	THELLOACCEPT
120 %token	KEEPALIVE
121 %token	DISTRIBUTION RETENTION ADVERTISEMENT
122 %token	EXTTAG
123 %token	YES NO
124 %token	ERROR
125 %token	<v.string>	STRING
126 %token	<v.number>	NUMBER
127 %type	<v.number>	yesno
128 %type	<v.string>	string
129 
130 %%
131 
132 grammar		: /* empty */
133 		| grammar '\n'
134 		| grammar conf_main '\n'
135 		| grammar varset '\n'
136 		| grammar interface '\n'
137 		| grammar tneighbor '\n'
138 		| grammar error '\n'		{ file->errors++; }
139 		;
140 
141 string		: string STRING	{
142 			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
143 				free($1);
144 				free($2);
145 				yyerror("string: asprintf");
146 				YYERROR;
147 			}
148 			free($1);
149 			free($2);
150 		}
151 		| STRING
152 		;
153 
154 yesno		: YES	{ $$ = 1; }
155 		| NO	{ $$ = 0; }
156 		;
157 
158 varset		: STRING '=' string {
159 			if (conf->opts & LDPD_OPT_VERBOSE)
160 				printf("%s = \"%s\"\n", $1, $3);
161 			if (symset($1, $3, 0) == -1)
162 				fatal("cannot store variable");
163 			free($1);
164 			free($3);
165 		}
166 		;
167 
168 conf_main	: ROUTERID STRING {
169 			if (!inet_aton($2, &conf->rtr_id)) {
170 				yyerror("error parsing router-id");
171 				free($2);
172 				YYERROR;
173 			}
174 			free($2);
175 		}
176 		| FIBUPDATE yesno {
177 			if ($2 == 0)
178 				conf->flags |= LDPD_FLAG_NO_FIB_UPDATE;
179 			else
180 				conf->flags &= ~LDPD_FLAG_NO_FIB_UPDATE;
181 		}
182 		| DISTRIBUTION STRING {
183 			conf->mode &= ~(MODE_DIST_INDEPENDENT |
184 			    MODE_DIST_ORDERED);
185 
186 			if (!strcmp($2, "independent"))
187 				conf->mode |= MODE_DIST_INDEPENDENT;
188 			else if (!strcmp($2, "ordered"))
189 				conf->mode |= MODE_DIST_ORDERED;
190 			else {
191 				yyerror("unknown distribution type");
192 				free($2);
193 				YYERROR;
194 			}
195 		}
196 		| RETENTION STRING {
197 			conf->mode &= ~(MODE_RET_CONSERVATIVE |
198 			    MODE_RET_LIBERAL);
199 
200 			if (!strcmp($2, "conservative"))
201 				conf->mode |= MODE_RET_CONSERVATIVE;
202 			else if (!strcmp($2, "liberal"))
203 				conf->mode |= MODE_RET_LIBERAL;
204 			else {
205 				yyerror("unknown retention type");
206 				free($2);
207 				YYERROR;
208 			}
209 		}
210 		| ADVERTISEMENT STRING {
211 			conf->mode &= ~(MODE_ADV_ONDEMAND |
212 			    MODE_ADV_UNSOLICITED);
213 
214 			if (!strcmp($2, "ondemand"))
215 				conf->mode |= MODE_ADV_ONDEMAND;
216 			else if (!strcmp($2, "unsolicited"))
217 				conf->mode |= MODE_ADV_UNSOLICITED;
218 			else {
219 				yyerror("unknown retention type");
220 				free($2);
221 				YYERROR;
222 			}
223 		}
224 		| THELLOACCEPT yesno {
225 			if ($2 == 0)
226 				conf->flags &= ~LDPD_FLAG_TH_ACCEPT;
227 			else
228 				conf->flags |= LDPD_FLAG_TH_ACCEPT;
229 		}
230 		| KEEPALIVE NUMBER {
231 			if ($2 < MIN_KEEPALIVE ||
232 			    $2 > MAX_KEEPALIVE) {
233 				yyerror("keepalive out of range (%d-%d)",
234 				    MIN_KEEPALIVE, MAX_KEEPALIVE);
235 				YYERROR;
236 			}
237 			conf->keepalive = $2;
238 		}
239 		| iface_defaults
240 		| tnbr_defaults
241 		;
242 iface_defaults	: LHELLOHOLDTIME NUMBER {
243 			if ($2 < MIN_HOLDTIME ||
244 			    $2 > MAX_HOLDTIME) {
245 				yyerror("hello holdtime out of range (%d-%d)",
246 				    MIN_HOLDTIME, MAX_HOLDTIME);
247 				YYERROR;
248 			}
249 			defs->lhello_holdtime = $2;
250 		}
251 		| LHELLOINTERVAL NUMBER {
252 			if ($2 < MIN_HELLO_INTERVAL ||
253 			    $2 > MAX_HELLO_INTERVAL) {
254 				yyerror("hello-interval out of range (%d-%d)",
255 				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
256 				YYERROR;
257 			}
258 			defs->lhello_interval = $2;
259 		}
260 		;
261 
262 tnbr_defaults	: THELLOHOLDTIME NUMBER {
263 			if ($2 < MIN_HOLDTIME ||
264 			    $2 > MAX_HOLDTIME) {
265 				yyerror("hello holdtime out of range (%d-%d)",
266 				    MIN_HOLDTIME, MAX_HOLDTIME);
267 				YYERROR;
268 			}
269 			conf->thello_holdtime = $2;
270 			defs->thello_holdtime = $2;
271 		}
272 		| THELLOINTERVAL NUMBER {
273 			if ($2 < MIN_HELLO_INTERVAL ||
274 			    $2 > MAX_HELLO_INTERVAL) {
275 				yyerror("hello-interval out of range (%d-%d)",
276 				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
277 				YYERROR;
278 			}
279 			conf->thello_interval = $2;
280 			defs->thello_interval = $2;
281 		}
282 		;
283 
284 optnl		: '\n' optnl
285 		|
286 		;
287 
288 nl		: '\n' optnl		/* one newline or more */
289 		;
290 
291 interface	: INTERFACE STRING	{
292 			struct kif	*kif;
293 
294 			if ((kif = kif_findname($2)) == NULL) {
295 				yyerror("unknown interface %s", $2);
296 				free($2);
297 				YYERROR;
298 			}
299 			free($2);
300 			iface = conf_get_if(kif);
301 			if (iface == NULL)
302 				YYERROR;
303 			if (iface->media_type == IFT_LOOP ||
304 			    iface->media_type == IFT_CARP) {
305 				yyerror("unsupported interface type on "
306 				    "interface %s", iface->name);
307 				YYERROR;
308 			}
309 			LIST_INSERT_HEAD(&conf->iface_list, iface, entry);
310 
311 			memcpy(&ifacedefs, defs, sizeof(ifacedefs));
312 			defs = &ifacedefs;
313 		} interface_block {
314 			iface->hello_holdtime = defs->lhello_holdtime;
315 			iface->hello_interval = defs->lhello_interval;
316 			iface = NULL;
317 
318 			defs = &globaldefs;
319 		}
320 		;
321 
322 interface_block	: '{' optnl interfaceopts_l '}'
323 		| '{' optnl '}'
324 		| /* nothing */
325 		;
326 
327 interfaceopts_l	: interfaceopts_l iface_defaults nl
328 		| iface_defaults optnl
329 		;
330 
331 tneighbor	: TNEIGHBOR STRING	{
332 			struct in_addr	 addr;
333 
334 			if (inet_aton($2, &addr) == 0) {
335 				yyerror(
336 				    "error parsing neighbor address");
337 				free($2);
338 				YYERROR;
339 			}
340 			free($2);
341 
342 			tnbr = conf_get_tnbr(addr);
343 			if (tnbr == NULL)
344 				YYERROR;
345 			LIST_INSERT_HEAD(&conf->tnbr_list, tnbr, entry);
346 
347 			memcpy(&tnbrdefs, defs, sizeof(tnbrdefs));
348 			defs = &tnbrdefs;
349 		} tneighbor_block {
350 			tnbr->hello_holdtime = defs->thello_holdtime;
351 			tnbr->hello_interval = defs->thello_interval;
352 			tnbr = NULL;
353 
354 			defs = &globaldefs;
355 		}
356 		;
357 
358 tneighbor_block	: '{' optnl tneighboropts_l '}'
359 		| '{' optnl '}'
360 		| /* nothing */
361 		;
362 
363 tneighboropts_l	: tneighboropts_l tnbr_defaults nl
364 		| tnbr_defaults optnl
365 		;
366 
367 %%
368 
369 struct keywords {
370 	const char	*k_name;
371 	int		 k_val;
372 };
373 
374 int
375 yyerror(const char *fmt, ...)
376 {
377 	va_list		 ap;
378 	char		*msg;
379 
380 	file->errors++;
381 	va_start(ap, fmt);
382 	if (vasprintf(&msg, fmt, ap) == -1)
383 		fatalx("yyerror vasprintf");
384 	va_end(ap);
385 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
386 	free(msg);
387 	return (0);
388 }
389 
390 int
391 kw_cmp(const void *k, const void *e)
392 {
393 	return (strcmp(k, ((const struct keywords *)e)->k_name));
394 }
395 
396 int
397 lookup(char *s)
398 {
399 	/* this has to be sorted always */
400 	static const struct keywords keywords[] = {
401 		{"advertisement",		ADVERTISEMENT},
402 		{"distribution",		DISTRIBUTION},
403 		{"external-tag",		EXTTAG},
404 		{"fib-update",			FIBUPDATE},
405 		{"interface",			INTERFACE},
406 		{"keepalive",			KEEPALIVE},
407 		{"link-hello-holdtime",		LHELLOHOLDTIME},
408 		{"link-hello-interval",		LHELLOINTERVAL},
409 		{"no",				NO},
410 		{"retention",			RETENTION},
411 		{"router-id",			ROUTERID},
412 		{"targeted-hello-accept",	THELLOACCEPT},
413 		{"targeted-hello-holdtime",	THELLOHOLDTIME},
414 		{"targeted-hello-interval",	THELLOINTERVAL},
415 		{"targeted-neighbor",		TNEIGHBOR},
416 		{"yes",				YES}
417 	};
418 	const struct keywords	*p;
419 
420 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
421 	    sizeof(keywords[0]), kw_cmp);
422 
423 	if (p)
424 		return (p->k_val);
425 	else
426 		return (STRING);
427 }
428 
429 #define MAXPUSHBACK	128
430 
431 u_char	*parsebuf;
432 int	 parseindex;
433 u_char	 pushback_buffer[MAXPUSHBACK];
434 int	 pushback_index = 0;
435 
436 int
437 lgetc(int quotec)
438 {
439 	int		c, next;
440 
441 	if (parsebuf) {
442 		/* Read character from the parsebuffer instead of input. */
443 		if (parseindex >= 0) {
444 			c = parsebuf[parseindex++];
445 			if (c != '\0')
446 				return (c);
447 			parsebuf = NULL;
448 		} else
449 			parseindex++;
450 	}
451 
452 	if (pushback_index)
453 		return (pushback_buffer[--pushback_index]);
454 
455 	if (quotec) {
456 		if ((c = getc(file->stream)) == EOF) {
457 			yyerror("reached end of file while parsing "
458 			    "quoted string");
459 			if (file == topfile || popfile() == EOF)
460 				return (EOF);
461 			return (quotec);
462 		}
463 		return (c);
464 	}
465 
466 	while ((c = getc(file->stream)) == '\\') {
467 		next = getc(file->stream);
468 		if (next != '\n') {
469 			c = next;
470 			break;
471 		}
472 		yylval.lineno = file->lineno;
473 		file->lineno++;
474 	}
475 
476 	while (c == EOF) {
477 		if (file == topfile || popfile() == EOF)
478 			return (EOF);
479 		c = getc(file->stream);
480 	}
481 	return (c);
482 }
483 
484 int
485 lungetc(int c)
486 {
487 	if (c == EOF)
488 		return (EOF);
489 	if (parsebuf) {
490 		parseindex--;
491 		if (parseindex >= 0)
492 			return (c);
493 	}
494 	if (pushback_index < MAXPUSHBACK-1)
495 		return (pushback_buffer[pushback_index++] = c);
496 	else
497 		return (EOF);
498 }
499 
500 int
501 findeol(void)
502 {
503 	int	c;
504 
505 	parsebuf = NULL;
506 	pushback_index = 0;
507 
508 	/* skip to either EOF or the first real EOL */
509 	while (1) {
510 		c = lgetc(0);
511 		if (c == '\n') {
512 			file->lineno++;
513 			break;
514 		}
515 		if (c == EOF)
516 			break;
517 	}
518 	return (ERROR);
519 }
520 
521 int
522 yylex(void)
523 {
524 	u_char	 buf[8096];
525 	u_char	*p, *val;
526 	int	 quotec, next, c;
527 	int	 token;
528 
529 top:
530 	p = buf;
531 	while ((c = lgetc(0)) == ' ' || c == '\t')
532 		; /* nothing */
533 
534 	yylval.lineno = file->lineno;
535 	if (c == '#')
536 		while ((c = lgetc(0)) != '\n' && c != EOF)
537 			; /* nothing */
538 	if (c == '$' && parsebuf == NULL) {
539 		while (1) {
540 			if ((c = lgetc(0)) == EOF)
541 				return (0);
542 
543 			if (p + 1 >= buf + sizeof(buf) - 1) {
544 				yyerror("string too long");
545 				return (findeol());
546 			}
547 			if (isalnum(c) || c == '_') {
548 				*p++ = c;
549 				continue;
550 			}
551 			*p = '\0';
552 			lungetc(c);
553 			break;
554 		}
555 		val = symget(buf);
556 		if (val == NULL) {
557 			yyerror("macro '%s' not defined", buf);
558 			return (findeol());
559 		}
560 		parsebuf = val;
561 		parseindex = 0;
562 		goto top;
563 	}
564 
565 	switch (c) {
566 	case '\'':
567 	case '"':
568 		quotec = c;
569 		while (1) {
570 			if ((c = lgetc(quotec)) == EOF)
571 				return (0);
572 			if (c == '\n') {
573 				file->lineno++;
574 				continue;
575 			} else if (c == '\\') {
576 				if ((next = lgetc(quotec)) == EOF)
577 					return (0);
578 				if (next == quotec || c == ' ' || c == '\t')
579 					c = next;
580 				else if (next == '\n') {
581 					file->lineno++;
582 					continue;
583 				} else
584 					lungetc(next);
585 			} else if (c == quotec) {
586 				*p = '\0';
587 				break;
588 			} else if (c == '\0') {
589 				yyerror("syntax error");
590 				return (findeol());
591 			}
592 			if (p + 1 >= buf + sizeof(buf) - 1) {
593 				yyerror("string too long");
594 				return (findeol());
595 			}
596 			*p++ = c;
597 		}
598 		yylval.v.string = strdup(buf);
599 		if (yylval.v.string == NULL)
600 			err(1, "yylex: strdup");
601 		return (STRING);
602 	}
603 
604 #define allowed_to_end_number(x) \
605 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
606 
607 	if (c == '-' || isdigit(c)) {
608 		do {
609 			*p++ = c;
610 			if ((unsigned)(p-buf) >= sizeof(buf)) {
611 				yyerror("string too long");
612 				return (findeol());
613 			}
614 		} while ((c = lgetc(0)) != EOF && isdigit(c));
615 		lungetc(c);
616 		if (p == buf + 1 && buf[0] == '-')
617 			goto nodigits;
618 		if (c == EOF || allowed_to_end_number(c)) {
619 			const char *errstr = NULL;
620 
621 			*p = '\0';
622 			yylval.v.number = strtonum(buf, LLONG_MIN,
623 			    LLONG_MAX, &errstr);
624 			if (errstr) {
625 				yyerror("\"%s\" invalid number: %s",
626 				    buf, errstr);
627 				return (findeol());
628 			}
629 			return (NUMBER);
630 		} else {
631 nodigits:
632 			while (p > buf + 1)
633 				lungetc(*--p);
634 			c = *--p;
635 			if (c == '-')
636 				return (c);
637 		}
638 	}
639 
640 #define allowed_in_string(x) \
641 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
642 	x != '{' && x != '}' && \
643 	x != '!' && x != '=' && x != '#' && \
644 	x != ','))
645 
646 	if (isalnum(c) || c == ':' || c == '_') {
647 		do {
648 			*p++ = c;
649 			if ((unsigned)(p-buf) >= sizeof(buf)) {
650 				yyerror("string too long");
651 				return (findeol());
652 			}
653 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
654 		lungetc(c);
655 		*p = '\0';
656 		if ((token = lookup(buf)) == STRING)
657 			if ((yylval.v.string = strdup(buf)) == NULL)
658 				err(1, "yylex: strdup");
659 		return (token);
660 	}
661 	if (c == '\n') {
662 		yylval.lineno = file->lineno;
663 		file->lineno++;
664 	}
665 	if (c == EOF)
666 		return (0);
667 	return (c);
668 }
669 
670 int
671 check_file_secrecy(int fd, const char *fname)
672 {
673 	struct stat	st;
674 
675 	if (fstat(fd, &st)) {
676 		log_warn("cannot stat %s", fname);
677 		return (-1);
678 	}
679 	if (st.st_uid != 0 && st.st_uid != getuid()) {
680 		log_warnx("%s: owner not root or current user", fname);
681 		return (-1);
682 	}
683 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
684 		log_warnx("%s: group writable or world read/writable", fname);
685 		return (-1);
686 	}
687 	return (0);
688 }
689 
690 struct file *
691 pushfile(const char *name, int secret)
692 {
693 	struct file	*nfile;
694 
695 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
696 		log_warn("malloc");
697 		return (NULL);
698 	}
699 	if ((nfile->name = strdup(name)) == NULL) {
700 		log_warn("strdup");
701 		free(nfile);
702 		return (NULL);
703 	}
704 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
705 		log_warn("%s", nfile->name);
706 		free(nfile->name);
707 		free(nfile);
708 		return (NULL);
709 	} else if (secret &&
710 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
711 		fclose(nfile->stream);
712 		free(nfile->name);
713 		free(nfile);
714 		return (NULL);
715 	}
716 	nfile->lineno = 1;
717 	TAILQ_INSERT_TAIL(&files, nfile, entry);
718 	return (nfile);
719 }
720 
721 int
722 popfile(void)
723 {
724 	struct file	*prev;
725 
726 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
727 		prev->errors += file->errors;
728 
729 	TAILQ_REMOVE(&files, file, entry);
730 	fclose(file->stream);
731 	free(file->name);
732 	free(file);
733 	file = prev;
734 	return (file ? 0 : EOF);
735 }
736 
737 struct ldpd_conf *
738 parse_config(char *filename, int opts)
739 {
740 	struct sym	*sym, *next;
741 
742 	if ((conf = calloc(1, sizeof(struct ldpd_conf))) == NULL)
743 		fatal("parse_config");
744 	conf->opts = opts;
745 	conf->keepalive = DEFAULT_KEEPALIVE;
746 
747 	bzero(&globaldefs, sizeof(globaldefs));
748 	defs = &globaldefs;
749 	defs->lhello_holdtime = LINK_DFLT_HOLDTIME;
750 	defs->lhello_interval = DEFAULT_HELLO_INTERVAL;
751 	defs->thello_holdtime = TARGETED_DFLT_HOLDTIME;
752 	defs->thello_interval = DEFAULT_HELLO_INTERVAL;
753 	conf->thello_holdtime = TARGETED_DFLT_HOLDTIME;
754 	conf->thello_interval = DEFAULT_HELLO_INTERVAL;
755 
756 	conf->mode = (MODE_DIST_INDEPENDENT | MODE_RET_LIBERAL |
757 	    MODE_ADV_UNSOLICITED);
758 
759 	if ((file = pushfile(filename, !(conf->opts & LDPD_OPT_NOACTION))) == NULL) {
760 		free(conf);
761 		return (NULL);
762 	}
763 	topfile = file;
764 
765 	yyparse();
766 	errors = file->errors;
767 	popfile();
768 
769 	/* Free macros and check which have not been used. */
770 	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
771 		next = TAILQ_NEXT(sym, entry);
772 		if ((conf->opts & LDPD_OPT_VERBOSE2) && !sym->used)
773 			fprintf(stderr, "warning: macro '%s' not "
774 			    "used\n", sym->nam);
775 		if (!sym->persist) {
776 			free(sym->nam);
777 			free(sym->val);
778 			TAILQ_REMOVE(&symhead, sym, entry);
779 			free(sym);
780 		}
781 	}
782 
783 	/* free global config defaults */
784 	if (errors) {
785 		clear_config(conf);
786 		return (NULL);
787 	}
788 
789 	if (conf->rtr_id.s_addr == 0)
790 		conf->rtr_id.s_addr = get_rtr_id();
791 
792 	return (conf);
793 }
794 
795 int
796 symset(const char *nam, const char *val, int persist)
797 {
798 	struct sym	*sym;
799 
800 	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
801 	    sym = TAILQ_NEXT(sym, entry))
802 		;	/* nothing */
803 
804 	if (sym != NULL) {
805 		if (sym->persist == 1)
806 			return (0);
807 		else {
808 			free(sym->nam);
809 			free(sym->val);
810 			TAILQ_REMOVE(&symhead, sym, entry);
811 			free(sym);
812 		}
813 	}
814 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
815 		return (-1);
816 
817 	sym->nam = strdup(nam);
818 	if (sym->nam == NULL) {
819 		free(sym);
820 		return (-1);
821 	}
822 	sym->val = strdup(val);
823 	if (sym->val == NULL) {
824 		free(sym->nam);
825 		free(sym);
826 		return (-1);
827 	}
828 	sym->used = 0;
829 	sym->persist = persist;
830 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
831 	return (0);
832 }
833 
834 int
835 cmdline_symset(char *s)
836 {
837 	char	*sym, *val;
838 	int	ret;
839 	size_t	len;
840 
841 	if ((val = strrchr(s, '=')) == NULL)
842 		return (-1);
843 
844 	len = strlen(s) - strlen(val) + 1;
845 	if ((sym = malloc(len)) == NULL)
846 		errx(1, "cmdline_symset: malloc");
847 
848 	strlcpy(sym, s, len);
849 
850 	ret = symset(sym, val + 1, 1);
851 	free(sym);
852 
853 	return (ret);
854 }
855 
856 char *
857 symget(const char *nam)
858 {
859 	struct sym	*sym;
860 
861 	TAILQ_FOREACH(sym, &symhead, entry)
862 		if (strcmp(nam, sym->nam) == 0) {
863 			sym->used = 1;
864 			return (sym->val);
865 		}
866 	return (NULL);
867 }
868 
869 struct iface *
870 conf_get_if(struct kif *kif)
871 {
872 	struct iface	*i;
873 
874 	LIST_FOREACH(i, &conf->iface_list, entry) {
875 		if (i->ifindex == kif->ifindex) {
876 			yyerror("interface %s already configured",
877 			    kif->ifname);
878 			return (NULL);
879 		}
880 	}
881 
882 	i = if_new(kif);
883 
884 	return (i);
885 }
886 
887 struct tnbr *
888 conf_get_tnbr(struct in_addr addr)
889 {
890 	struct tnbr	*t;
891 
892 	LIST_FOREACH(t, &conf->tnbr_list, entry) {
893 		if (t->addr.s_addr == addr.s_addr) {
894 			yyerror("targeted neighbor %s already configured",
895 			    inet_ntoa(addr));
896 			return (NULL);
897 		}
898 	}
899 
900 	t = tnbr_new(conf, addr, 1);
901 
902 	return (t);
903 }
904 
905 void
906 clear_config(struct ldpd_conf *xconf)
907 {
908 	struct iface	*i;
909 
910 	while ((i = LIST_FIRST(&conf->iface_list)) != NULL) {
911 		LIST_REMOVE(i, entry);
912 		if_del(i);
913 	}
914 
915 	free(xconf);
916 }
917 
918 u_int32_t
919 get_rtr_id(void)
920 {
921 	struct ifaddrs		*ifap, *ifa;
922 	u_int32_t		 ip = 0, cur, localnet;
923 
924 	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
925 
926 	if (getifaddrs(&ifap) == -1)
927 		fatal("getifaddrs");
928 
929 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
930 		if (strncmp(ifa->ifa_name, "carp", 4) == 0)
931 			continue;
932 		if (ifa->ifa_addr->sa_family != AF_INET)
933 			continue;
934 		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
935 		if ((cur & localnet) == localnet)	/* skip 127/8 */
936 			continue;
937 		if (cur > ip || ip == 0)
938 			ip = cur;
939 	}
940 	freeifaddrs(ifap);
941 
942 	if (ip == 0)
943 		fatal("router-id is 0.0.0.0");
944 
945 	return (ip);
946 }
947 
948 int
949 host(const char *s, struct in_addr *addr, struct in_addr *mask)
950 {
951 	struct in_addr		 ina;
952 	int			 bits = 32;
953 
954 	bzero(&ina, sizeof(struct in_addr));
955 	if (strrchr(s, '/') != NULL) {
956 		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
957 			return (0);
958 	} else {
959 		if (inet_pton(AF_INET, s, &ina) != 1)
960 			return (0);
961 	}
962 
963 	addr->s_addr = ina.s_addr;
964 	mask->s_addr = prefixlen2mask(bits);
965 
966 	return (1);
967 }
968