parse.y revision 1.29
1/*	$OpenBSD: parse.y,v 1.29 2015/07/21 04:52:29 renato 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 "lde.h"
45#include "ldpe.h"
46#include "log.h"
47
48TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
49static struct file {
50	TAILQ_ENTRY(file)	 entry;
51	FILE			*stream;
52	char			*name;
53	int			 lineno;
54	int			 errors;
55} *file, *topfile;
56struct file	*pushfile(const char *, int);
57int		 popfile(void);
58int		 check_file_secrecy(int, const char *);
59int		 yyparse(void);
60int		 yylex(void);
61int		 yyerror(const char *, ...)
62    __attribute__((__format__ (printf, 1, 2)))
63    __attribute__((__nonnull__ (1)));
64int		 kw_cmp(const void *, const void *);
65int		 lookup(char *);
66int		 lgetc(int);
67int		 lungetc(int);
68int		 findeol(void);
69
70TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
71struct sym {
72	TAILQ_ENTRY(sym)	 entry;
73	int			 used;
74	int			 persist;
75	char			*nam;
76	char			*val;
77};
78
79int		 symset(const char *, const char *, int);
80char		*symget(const char *);
81
82void		 clear_config(struct ldpd_conf *xconf);
83u_int32_t	 get_rtr_id(void);
84int		 host(const char *, struct in_addr *, struct in_addr *);
85
86static struct ldpd_conf	*conf;
87static int			 errors = 0;
88
89struct iface		*iface = NULL;
90struct tnbr		*tnbr = NULL;
91struct nbr_params	*nbrp = NULL;
92struct l2vpn		*l2vpn = NULL;
93struct l2vpn_pw		*pw = NULL;
94
95struct config_defaults {
96	u_int16_t	lhello_holdtime;
97	u_int16_t	lhello_interval;
98	u_int16_t	thello_holdtime;
99	u_int16_t	thello_interval;
100	u_int8_t	pwflags;
101};
102
103struct config_defaults	 globaldefs;
104struct config_defaults	 ifacedefs;
105struct config_defaults	 tnbrdefs;
106struct config_defaults	 pwdefs;
107struct config_defaults	*defs;
108
109struct iface		*conf_get_if(struct kif *);
110struct tnbr		*conf_get_tnbr(struct in_addr);
111struct nbr_params	*conf_get_nbrp(struct in_addr);
112struct l2vpn		*conf_get_l2vpn(char *);
113struct l2vpn_if		*conf_get_l2vpn_if(struct l2vpn *, struct kif *);
114struct l2vpn_pw		*conf_get_l2vpn_pw(struct l2vpn *, struct kif *);
115
116typedef struct {
117	union {
118		int64_t		 number;
119		char		*string;
120	} v;
121	int lineno;
122} YYSTYPE;
123
124%}
125
126%token	INTERFACE TNEIGHBOR ROUTERID FIBUPDATE
127%token	LHELLOHOLDTIME LHELLOINTERVAL
128%token	THELLOHOLDTIME THELLOINTERVAL
129%token	THELLOACCEPT
130%token	KEEPALIVE
131%token	NEIGHBOR PASSWORD
132%token	L2VPN TYPE VPLS PWTYPE MTU BRIDGE
133%token	ETHERNET ETHERNETTAGGED STATUSTLV CONTROLWORD
134%token	PSEUDOWIRE NEIGHBOR PWID
135%token	EXTTAG
136%token	YES NO
137%token	ERROR
138%token	<v.string>	STRING
139%token	<v.number>	NUMBER
140%type	<v.number>	yesno
141%type	<v.number>	l2vpn_type
142%type	<v.number>	pw_type
143%type	<v.string>	string
144
145%%
146
147grammar		: /* empty */
148		| grammar '\n'
149		| grammar conf_main '\n'
150		| grammar varset '\n'
151		| grammar interface '\n'
152		| grammar tneighbor '\n'
153		| grammar neighbor '\n'
154		| grammar l2vpn '\n'
155		| grammar error '\n'		{ file->errors++; }
156		;
157
158string		: string STRING	{
159			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
160				free($1);
161				free($2);
162				yyerror("string: asprintf");
163				YYERROR;
164			}
165			free($1);
166			free($2);
167		}
168		| STRING
169		;
170
171yesno		: YES	{ $$ = 1; }
172		| NO	{ $$ = 0; }
173		;
174
175l2vpn_type	: VPLS	{ $$ = L2VPN_TYPE_VPLS; }
176		;
177
178pw_type		: ETHERNET		{ $$ = PW_TYPE_ETHERNET; }
179		| ETHERNETTAGGED	{ $$ = PW_TYPE_ETHERNET_TAGGED; }
180		;
181
182varset		: STRING '=' string {
183			if (conf->opts & LDPD_OPT_VERBOSE)
184				printf("%s = \"%s\"\n", $1, $3);
185			if (symset($1, $3, 0) == -1)
186				fatal("cannot store variable");
187			free($1);
188			free($3);
189		}
190		;
191
192conf_main	: ROUTERID STRING {
193			if (!inet_aton($2, &conf->rtr_id)) {
194				yyerror("error parsing router-id");
195				free($2);
196				YYERROR;
197			}
198			free($2);
199		}
200		| FIBUPDATE yesno {
201			if ($2 == 0)
202				conf->flags |= LDPD_FLAG_NO_FIB_UPDATE;
203			else
204				conf->flags &= ~LDPD_FLAG_NO_FIB_UPDATE;
205		}
206		| THELLOACCEPT yesno {
207			if ($2 == 0)
208				conf->flags &= ~LDPD_FLAG_TH_ACCEPT;
209			else
210				conf->flags |= LDPD_FLAG_TH_ACCEPT;
211		}
212		| KEEPALIVE NUMBER {
213			if ($2 < MIN_KEEPALIVE ||
214			    $2 > MAX_KEEPALIVE) {
215				yyerror("keepalive out of range (%d-%d)",
216				    MIN_KEEPALIVE, MAX_KEEPALIVE);
217				YYERROR;
218			}
219			conf->keepalive = $2;
220		}
221		| iface_defaults
222		| tnbr_defaults
223		;
224
225iface_defaults	: LHELLOHOLDTIME NUMBER {
226			if ($2 < MIN_HOLDTIME ||
227			    $2 > MAX_HOLDTIME) {
228				yyerror("hello holdtime out of range (%d-%d)",
229				    MIN_HOLDTIME, MAX_HOLDTIME);
230				YYERROR;
231			}
232			defs->lhello_holdtime = $2;
233		}
234		| LHELLOINTERVAL NUMBER {
235			if ($2 < MIN_HELLO_INTERVAL ||
236			    $2 > MAX_HELLO_INTERVAL) {
237				yyerror("hello-interval out of range (%d-%d)",
238				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
239				YYERROR;
240			}
241			defs->lhello_interval = $2;
242		}
243		;
244
245tnbr_defaults	: THELLOHOLDTIME NUMBER {
246			if ($2 < MIN_HOLDTIME ||
247			    $2 > MAX_HOLDTIME) {
248				yyerror("hello holdtime out of range (%d-%d)",
249				    MIN_HOLDTIME, MAX_HOLDTIME);
250				YYERROR;
251			}
252			conf->thello_holdtime = $2;
253			defs->thello_holdtime = $2;
254		}
255		| THELLOINTERVAL NUMBER {
256			if ($2 < MIN_HELLO_INTERVAL ||
257			    $2 > MAX_HELLO_INTERVAL) {
258				yyerror("hello-interval out of range (%d-%d)",
259				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
260				YYERROR;
261			}
262			conf->thello_interval = $2;
263			defs->thello_interval = $2;
264		}
265		;
266
267nbr_opts	: PASSWORD STRING {
268			if (strlcpy(nbrp->auth.md5key, $2,
269			    sizeof(nbrp->auth.md5key)) >=
270			    sizeof(nbrp->auth.md5key)) {
271				yyerror("tcp md5sig password too long: max %zu",
272				    sizeof(nbrp->auth.md5key) - 1);
273				free($2);
274				YYERROR;
275			}
276			nbrp->auth.md5key_len = strlen($2);
277			nbrp->auth.method = AUTH_MD5SIG;
278			free($2);
279		}
280		;
281
282pw_defaults	: STATUSTLV yesno {
283			if ($2 == 1) {
284				defs->pwflags |= F_PW_STATUSTLV_CONF;
285				defs->pwflags |= F_PW_STATUSTLV;
286			} else {
287				defs->pwflags &= ~F_PW_STATUSTLV_CONF;
288				defs->pwflags &= ~F_PW_STATUSTLV;
289			}
290		}
291		| CONTROLWORD yesno {
292			if ($2 == 1) {
293				defs->pwflags |= F_PW_CONTROLWORD_CONF;
294				defs->pwflags |= F_PW_CONTROLWORD;
295			} else {
296				defs->pwflags &= ~F_PW_CONTROLWORD_CONF;
297				defs->pwflags &= ~F_PW_CONTROLWORD;
298			}
299		}
300		;
301
302pwopts		: PWID NUMBER {
303			if ($2 < MIN_PWID_ID ||
304			    $2 > MAX_PWID_ID) {
305				yyerror("pw-id out of range (%d-%d)",
306				    MIN_PWID_ID, MAX_PWID_ID);
307				YYERROR;
308			}
309
310			pw->pwid = $2;
311		}
312		| NEIGHBOR STRING {
313			struct in_addr	 addr;
314			struct tnbr	*t;
315
316			if (inet_aton($2, &addr) == 0) {
317				yyerror(
318				    "error parsing neighbor address");
319				free($2);
320				YYERROR;
321			}
322			free($2);
323
324			pw->addr.s_addr = addr.s_addr;
325
326			t = tnbr_find(conf, addr);
327			if (t == NULL) {
328				t = tnbr_new(conf, addr);
329				LIST_INSERT_HEAD(&conf->tnbr_list, t, entry);
330			}
331
332			t->pw_count++;
333		}
334		| pw_defaults
335		;
336
337pseudowire	: PSEUDOWIRE 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
347			if (kif->media_type != IFT_MPLSTUNNEL) {
348				yyerror("unsupported interface type on "
349				    "interface %s", kif->ifname);
350				YYERROR;
351			}
352
353			pw = conf_get_l2vpn_pw(l2vpn, kif);
354			if (pw == NULL)
355				YYERROR;
356			LIST_INSERT_HEAD(&l2vpn->pw_list, pw, entry);
357
358			memcpy(&pwdefs, defs, sizeof(pwdefs));
359			defs = &pwdefs;
360		} pw_block {
361			struct l2vpn	*l;
362			struct l2vpn_pw *p;
363
364			LIST_FOREACH(l, &conf->l2vpn_list, entry)
365				LIST_FOREACH(p, &l->pw_list, entry)
366					if (pw != p &&
367					    pw->pwid == p->pwid &&
368					    pw->addr.s_addr == p->addr.s_addr) {
369						yyerror("pseudowire already "
370						    "configured");
371						YYERROR;
372					}
373
374			pw->flags = defs->pwflags;
375			defs = &globaldefs;
376			pw = NULL;
377		}
378		;
379
380pw_block	: '{' optnl pwopts_l '}'
381		| '{' optnl '}'
382		| /* nothing */
383		;
384
385pwopts_l	: pwopts_l pwopts nl
386		| pwopts optnl
387		;
388
389l2vpnopts	: PWTYPE pw_type {
390			l2vpn->pw_type = $2;
391		}
392		| MTU NUMBER {
393			if ($2 < MIN_L2VPN_MTU ||
394			    $2 > MAX_L2VPN_MTU) {
395				yyerror("l2vpn mtu out of range (%d-%d)",
396				    MIN_L2VPN_MTU, MAX_L2VPN_MTU);
397				YYERROR;
398			}
399			l2vpn->mtu = $2;
400		}
401		| pw_defaults
402		| BRIDGE STRING {
403			struct l2vpn	 *l;
404			struct kif	 *kif;
405
406			if ((kif = kif_findname($2)) == NULL) {
407				yyerror("unknown interface %s", $2);
408				free($2);
409				YYERROR;
410			}
411			free($2);
412
413			if (l2vpn->br_ifindex != 0) {
414				yyerror("bridge interface cannot be "
415				    "redefined on l2vpn %s", l2vpn->name);
416				YYERROR;
417			}
418
419			if (kif->media_type != IFT_BRIDGE) {
420				yyerror("unsupported interface type on "
421				    "interface %s", kif->ifname);
422				YYERROR;
423			}
424
425			LIST_FOREACH(l, &conf->l2vpn_list, entry) {
426				if (l->br_ifindex == kif->ifindex) {
427					yyerror("bridge %s is already being "
428					    "used by l2vpn %s", kif->ifname,
429					    l->name);
430					YYERROR;
431				}
432			}
433
434			l2vpn->br_ifindex = kif->ifindex;
435			strlcpy(l2vpn->br_ifname, kif->ifname,
436			    sizeof(l2vpn->br_ifname));
437		}
438		| INTERFACE STRING {
439			struct kif	*kif;
440			struct l2vpn_if	*lif;
441
442			if ((kif = kif_findname($2)) == NULL) {
443				yyerror("unknown interface %s", $2);
444				free($2);
445				YYERROR;
446			}
447			free($2);
448
449			if (kif->media_type == IFT_BRIDGE
450			    || kif->media_type == IFT_LOOP
451			    || kif->media_type == IFT_CARP) {
452				yyerror("unsupported interface type on "
453				    "interface %s", kif->ifname);
454				YYERROR;
455			}
456
457			lif = conf_get_l2vpn_if(l2vpn, kif);
458			if (lif == NULL)
459				YYERROR;
460			LIST_INSERT_HEAD(&l2vpn->if_list, lif, entry);
461		}
462		| pseudowire
463		;
464
465optnl		: '\n' optnl
466		|
467		;
468
469nl		: '\n' optnl		/* one newline or more */
470		;
471
472interface	: INTERFACE STRING	{
473			struct kif	*kif;
474
475			if ((kif = kif_findname($2)) == NULL) {
476				yyerror("unknown interface %s", $2);
477				free($2);
478				YYERROR;
479			}
480			free($2);
481			iface = conf_get_if(kif);
482			if (iface == NULL)
483				YYERROR;
484			if (iface->media_type == IFT_LOOP ||
485			    iface->media_type == IFT_CARP ||
486			    iface->media_type == IFT_MPLSTUNNEL) {
487				yyerror("unsupported interface type on "
488				    "interface %s", iface->name);
489				YYERROR;
490			}
491			LIST_INSERT_HEAD(&conf->iface_list, iface, entry);
492
493			memcpy(&ifacedefs, defs, sizeof(ifacedefs));
494			defs = &ifacedefs;
495		} interface_block {
496			iface->hello_holdtime = defs->lhello_holdtime;
497			iface->hello_interval = defs->lhello_interval;
498			iface = NULL;
499
500			defs = &globaldefs;
501		}
502		;
503
504interface_block	: '{' optnl interfaceopts_l '}'
505		| '{' optnl '}'
506		| /* nothing */
507		;
508
509interfaceopts_l	: interfaceopts_l iface_defaults nl
510		| iface_defaults optnl
511		;
512
513tneighbor	: TNEIGHBOR STRING	{
514			struct in_addr	 addr;
515
516			if (inet_aton($2, &addr) == 0) {
517				yyerror(
518				    "error parsing neighbor address");
519				free($2);
520				YYERROR;
521			}
522			free($2);
523
524			tnbr = conf_get_tnbr(addr);
525			if (tnbr == NULL)
526				YYERROR;
527
528			tnbr->flags |= F_TNBR_CONFIGURED;
529			LIST_INSERT_HEAD(&conf->tnbr_list, tnbr, entry);
530
531			memcpy(&tnbrdefs, defs, sizeof(tnbrdefs));
532			defs = &tnbrdefs;
533		} tneighbor_block {
534			tnbr->hello_holdtime = defs->thello_holdtime;
535			tnbr->hello_interval = defs->thello_interval;
536			tnbr = NULL;
537
538			defs = &globaldefs;
539		}
540		;
541
542tneighbor_block	: '{' optnl tneighboropts_l '}'
543		| '{' optnl '}'
544		| /* nothing */
545		;
546
547tneighboropts_l	: tneighboropts_l tnbr_defaults nl
548		| tnbr_defaults optnl
549		;
550
551neighbor	: NEIGHBOR STRING	{
552			struct in_addr	 addr;
553
554			if (inet_aton($2, &addr) == 0) {
555				yyerror(
556				    "error parsing neighbor address");
557				free($2);
558				YYERROR;
559			}
560			free($2);
561
562			nbrp = conf_get_nbrp(addr);
563			if (nbrp == NULL)
564				YYERROR;
565			LIST_INSERT_HEAD(&conf->nbrp_list, nbrp, entry);
566		} neighbor_block {
567			nbrp = NULL;
568		}
569		;
570
571neighbor_block	: '{' optnl neighboropts_l '}'
572		| '{' optnl '}'
573		| /* nothing */
574		;
575
576neighboropts_l	: neighboropts_l nbr_opts nl
577		| nbr_opts optnl
578		;
579
580l2vpn		: L2VPN STRING TYPE l2vpn_type {
581			l2vpn = conf_get_l2vpn($2);
582			if (l2vpn == NULL)
583				YYERROR;
584			l2vpn->type = $4;
585			LIST_INSERT_HEAD(&conf->l2vpn_list, l2vpn, entry);
586		} l2vpn_block {
587			l2vpn = NULL;
588		}
589		;
590
591l2vpn_block	: '{' optnl l2vpnopts_l '}'
592		| '{' optnl '}'
593		| /* nothing */
594		;
595
596l2vpnopts_l	: l2vpnopts_l l2vpnopts nl
597		| l2vpnopts optnl
598		;
599
600%%
601
602struct keywords {
603	const char	*k_name;
604	int		 k_val;
605};
606
607int
608yyerror(const char *fmt, ...)
609{
610	va_list		 ap;
611	char		*msg;
612
613	file->errors++;
614	va_start(ap, fmt);
615	if (vasprintf(&msg, fmt, ap) == -1)
616		fatalx("yyerror vasprintf");
617	va_end(ap);
618	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
619	free(msg);
620	return (0);
621}
622
623int
624kw_cmp(const void *k, const void *e)
625{
626	return (strcmp(k, ((const struct keywords *)e)->k_name));
627}
628
629int
630lookup(char *s)
631{
632	/* this has to be sorted always */
633	static const struct keywords keywords[] = {
634		{"bridge",			BRIDGE},
635		{"control-word",		CONTROLWORD},
636		{"ethernet",			ETHERNET},
637		{"ethernet-tagged",		ETHERNETTAGGED},
638		{"fib-update",			FIBUPDATE},
639		{"interface",			INTERFACE},
640		{"keepalive",			KEEPALIVE},
641		{"l2vpn",			L2VPN},
642		{"link-hello-holdtime",		LHELLOHOLDTIME},
643		{"link-hello-interval",		LHELLOINTERVAL},
644		{"mtu",				MTU},
645		{"neighbor",			NEIGHBOR},
646		{"no",				NO},
647		{"password",			PASSWORD},
648		{"pseudowire",			PSEUDOWIRE},
649		{"pw-id",			PWID},
650		{"pw-type",			PWTYPE},
651		{"router-id",			ROUTERID},
652		{"status-tlv",			STATUSTLV},
653		{"targeted-hello-accept",	THELLOACCEPT},
654		{"targeted-hello-holdtime",	THELLOHOLDTIME},
655		{"targeted-hello-interval",	THELLOINTERVAL},
656		{"targeted-neighbor",		TNEIGHBOR},
657		{"type",			TYPE},
658		{"vpls",			VPLS},
659		{"yes",				YES}
660	};
661	const struct keywords	*p;
662
663	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
664	    sizeof(keywords[0]), kw_cmp);
665
666	if (p)
667		return (p->k_val);
668	else
669		return (STRING);
670}
671
672#define MAXPUSHBACK	128
673
674u_char	*parsebuf;
675int	 parseindex;
676u_char	 pushback_buffer[MAXPUSHBACK];
677int	 pushback_index = 0;
678
679int
680lgetc(int quotec)
681{
682	int		c, next;
683
684	if (parsebuf) {
685		/* Read character from the parsebuffer instead of input. */
686		if (parseindex >= 0) {
687			c = parsebuf[parseindex++];
688			if (c != '\0')
689				return (c);
690			parsebuf = NULL;
691		} else
692			parseindex++;
693	}
694
695	if (pushback_index)
696		return (pushback_buffer[--pushback_index]);
697
698	if (quotec) {
699		if ((c = getc(file->stream)) == EOF) {
700			yyerror("reached end of file while parsing "
701			    "quoted string");
702			if (file == topfile || popfile() == EOF)
703				return (EOF);
704			return (quotec);
705		}
706		return (c);
707	}
708
709	while ((c = getc(file->stream)) == '\\') {
710		next = getc(file->stream);
711		if (next != '\n') {
712			c = next;
713			break;
714		}
715		yylval.lineno = file->lineno;
716		file->lineno++;
717	}
718
719	while (c == EOF) {
720		if (file == topfile || popfile() == EOF)
721			return (EOF);
722		c = getc(file->stream);
723	}
724	return (c);
725}
726
727int
728lungetc(int c)
729{
730	if (c == EOF)
731		return (EOF);
732	if (parsebuf) {
733		parseindex--;
734		if (parseindex >= 0)
735			return (c);
736	}
737	if (pushback_index < MAXPUSHBACK-1)
738		return (pushback_buffer[pushback_index++] = c);
739	else
740		return (EOF);
741}
742
743int
744findeol(void)
745{
746	int	c;
747
748	parsebuf = NULL;
749	pushback_index = 0;
750
751	/* skip to either EOF or the first real EOL */
752	while (1) {
753		c = lgetc(0);
754		if (c == '\n') {
755			file->lineno++;
756			break;
757		}
758		if (c == EOF)
759			break;
760	}
761	return (ERROR);
762}
763
764int
765yylex(void)
766{
767	u_char	 buf[8096];
768	u_char	*p, *val;
769	int	 quotec, next, c;
770	int	 token;
771
772top:
773	p = buf;
774	while ((c = lgetc(0)) == ' ' || c == '\t')
775		; /* nothing */
776
777	yylval.lineno = file->lineno;
778	if (c == '#')
779		while ((c = lgetc(0)) != '\n' && c != EOF)
780			; /* nothing */
781	if (c == '$' && parsebuf == NULL) {
782		while (1) {
783			if ((c = lgetc(0)) == EOF)
784				return (0);
785
786			if (p + 1 >= buf + sizeof(buf) - 1) {
787				yyerror("string too long");
788				return (findeol());
789			}
790			if (isalnum(c) || c == '_') {
791				*p++ = c;
792				continue;
793			}
794			*p = '\0';
795			lungetc(c);
796			break;
797		}
798		val = symget(buf);
799		if (val == NULL) {
800			yyerror("macro '%s' not defined", buf);
801			return (findeol());
802		}
803		parsebuf = val;
804		parseindex = 0;
805		goto top;
806	}
807
808	switch (c) {
809	case '\'':
810	case '"':
811		quotec = c;
812		while (1) {
813			if ((c = lgetc(quotec)) == EOF)
814				return (0);
815			if (c == '\n') {
816				file->lineno++;
817				continue;
818			} else if (c == '\\') {
819				if ((next = lgetc(quotec)) == EOF)
820					return (0);
821				if (next == quotec || c == ' ' || c == '\t')
822					c = next;
823				else if (next == '\n') {
824					file->lineno++;
825					continue;
826				} else
827					lungetc(next);
828			} else if (c == quotec) {
829				*p = '\0';
830				break;
831			} else if (c == '\0') {
832				yyerror("syntax error");
833				return (findeol());
834			}
835			if (p + 1 >= buf + sizeof(buf) - 1) {
836				yyerror("string too long");
837				return (findeol());
838			}
839			*p++ = c;
840		}
841		yylval.v.string = strdup(buf);
842		if (yylval.v.string == NULL)
843			err(1, "yylex: strdup");
844		return (STRING);
845	}
846
847#define allowed_to_end_number(x) \
848	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
849
850	if (c == '-' || isdigit(c)) {
851		do {
852			*p++ = c;
853			if ((unsigned)(p-buf) >= sizeof(buf)) {
854				yyerror("string too long");
855				return (findeol());
856			}
857		} while ((c = lgetc(0)) != EOF && isdigit(c));
858		lungetc(c);
859		if (p == buf + 1 && buf[0] == '-')
860			goto nodigits;
861		if (c == EOF || allowed_to_end_number(c)) {
862			const char *errstr = NULL;
863
864			*p = '\0';
865			yylval.v.number = strtonum(buf, LLONG_MIN,
866			    LLONG_MAX, &errstr);
867			if (errstr) {
868				yyerror("\"%s\" invalid number: %s",
869				    buf, errstr);
870				return (findeol());
871			}
872			return (NUMBER);
873		} else {
874nodigits:
875			while (p > buf + 1)
876				lungetc(*--p);
877			c = *--p;
878			if (c == '-')
879				return (c);
880		}
881	}
882
883#define allowed_in_string(x) \
884	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
885	x != '{' && x != '}' && \
886	x != '!' && x != '=' && x != '#' && \
887	x != ','))
888
889	if (isalnum(c) || c == ':' || c == '_') {
890		do {
891			*p++ = c;
892			if ((unsigned)(p-buf) >= sizeof(buf)) {
893				yyerror("string too long");
894				return (findeol());
895			}
896		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
897		lungetc(c);
898		*p = '\0';
899		if ((token = lookup(buf)) == STRING)
900			if ((yylval.v.string = strdup(buf)) == NULL)
901				err(1, "yylex: strdup");
902		return (token);
903	}
904	if (c == '\n') {
905		yylval.lineno = file->lineno;
906		file->lineno++;
907	}
908	if (c == EOF)
909		return (0);
910	return (c);
911}
912
913int
914check_file_secrecy(int fd, const char *fname)
915{
916	struct stat	st;
917
918	if (fstat(fd, &st)) {
919		log_warn("cannot stat %s", fname);
920		return (-1);
921	}
922	if (st.st_uid != 0 && st.st_uid != getuid()) {
923		log_warnx("%s: owner not root or current user", fname);
924		return (-1);
925	}
926	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
927		log_warnx("%s: group writable or world read/writable", fname);
928		return (-1);
929	}
930	return (0);
931}
932
933struct file *
934pushfile(const char *name, int secret)
935{
936	struct file	*nfile;
937
938	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
939		log_warn("malloc");
940		return (NULL);
941	}
942	if ((nfile->name = strdup(name)) == NULL) {
943		log_warn("strdup");
944		free(nfile);
945		return (NULL);
946	}
947	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
948		log_warn("%s", nfile->name);
949		free(nfile->name);
950		free(nfile);
951		return (NULL);
952	} else if (secret &&
953	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
954		fclose(nfile->stream);
955		free(nfile->name);
956		free(nfile);
957		return (NULL);
958	}
959	nfile->lineno = 1;
960	TAILQ_INSERT_TAIL(&files, nfile, entry);
961	return (nfile);
962}
963
964int
965popfile(void)
966{
967	struct file	*prev;
968
969	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
970		prev->errors += file->errors;
971
972	TAILQ_REMOVE(&files, file, entry);
973	fclose(file->stream);
974	free(file->name);
975	free(file);
976	file = prev;
977	return (file ? 0 : EOF);
978}
979
980struct ldpd_conf *
981parse_config(char *filename, int opts)
982{
983	struct sym	*sym, *next;
984
985	if ((conf = calloc(1, sizeof(struct ldpd_conf))) == NULL)
986		fatal("parse_config");
987	conf->opts = opts;
988	conf->keepalive = DEFAULT_KEEPALIVE;
989
990	bzero(&globaldefs, sizeof(globaldefs));
991	defs = &globaldefs;
992	defs->lhello_holdtime = LINK_DFLT_HOLDTIME;
993	defs->lhello_interval = DEFAULT_HELLO_INTERVAL;
994	defs->thello_holdtime = TARGETED_DFLT_HOLDTIME;
995	defs->thello_interval = DEFAULT_HELLO_INTERVAL;
996	conf->thello_holdtime = TARGETED_DFLT_HOLDTIME;
997	conf->thello_interval = DEFAULT_HELLO_INTERVAL;
998	defs->pwflags |= F_PW_STATUSTLV_CONF;
999	defs->pwflags |= F_PW_STATUSTLV;
1000	defs->pwflags |= F_PW_CONTROLWORD_CONF;
1001	defs->pwflags |= F_PW_CONTROLWORD;
1002
1003	if ((file = pushfile(filename, !(conf->opts & LDPD_OPT_NOACTION))) == NULL) {
1004		free(conf);
1005		return (NULL);
1006	}
1007	topfile = file;
1008
1009	LIST_INIT(&conf->iface_list);
1010	LIST_INIT(&conf->addr_list);
1011	LIST_INIT(&conf->tnbr_list);
1012	LIST_INIT(&conf->nbrp_list);
1013	LIST_INIT(&conf->l2vpn_list);
1014
1015	yyparse();
1016	errors = file->errors;
1017	popfile();
1018
1019	/* Free macros and check which have not been used. */
1020	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
1021		next = TAILQ_NEXT(sym, entry);
1022		if ((conf->opts & LDPD_OPT_VERBOSE2) && !sym->used)
1023			fprintf(stderr, "warning: macro '%s' not "
1024			    "used\n", sym->nam);
1025		if (!sym->persist) {
1026			free(sym->nam);
1027			free(sym->val);
1028			TAILQ_REMOVE(&symhead, sym, entry);
1029			free(sym);
1030		}
1031	}
1032
1033	/* free global config defaults */
1034	if (errors) {
1035		clear_config(conf);
1036		return (NULL);
1037	}
1038
1039	if (conf->rtr_id.s_addr == 0)
1040		conf->rtr_id.s_addr = get_rtr_id();
1041
1042	return (conf);
1043}
1044
1045int
1046symset(const char *nam, const char *val, int persist)
1047{
1048	struct sym	*sym;
1049
1050	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
1051	    sym = TAILQ_NEXT(sym, entry))
1052		;	/* nothing */
1053
1054	if (sym != NULL) {
1055		if (sym->persist == 1)
1056			return (0);
1057		else {
1058			free(sym->nam);
1059			free(sym->val);
1060			TAILQ_REMOVE(&symhead, sym, entry);
1061			free(sym);
1062		}
1063	}
1064	if ((sym = calloc(1, sizeof(*sym))) == NULL)
1065		return (-1);
1066
1067	sym->nam = strdup(nam);
1068	if (sym->nam == NULL) {
1069		free(sym);
1070		return (-1);
1071	}
1072	sym->val = strdup(val);
1073	if (sym->val == NULL) {
1074		free(sym->nam);
1075		free(sym);
1076		return (-1);
1077	}
1078	sym->used = 0;
1079	sym->persist = persist;
1080	TAILQ_INSERT_TAIL(&symhead, sym, entry);
1081	return (0);
1082}
1083
1084int
1085cmdline_symset(char *s)
1086{
1087	char	*sym, *val;
1088	int	ret;
1089	size_t	len;
1090
1091	if ((val = strrchr(s, '=')) == NULL)
1092		return (-1);
1093
1094	len = strlen(s) - strlen(val) + 1;
1095	if ((sym = malloc(len)) == NULL)
1096		errx(1, "cmdline_symset: malloc");
1097
1098	strlcpy(sym, s, len);
1099
1100	ret = symset(sym, val + 1, 1);
1101	free(sym);
1102
1103	return (ret);
1104}
1105
1106char *
1107symget(const char *nam)
1108{
1109	struct sym	*sym;
1110
1111	TAILQ_FOREACH(sym, &symhead, entry)
1112		if (strcmp(nam, sym->nam) == 0) {
1113			sym->used = 1;
1114			return (sym->val);
1115		}
1116	return (NULL);
1117}
1118
1119struct iface *
1120conf_get_if(struct kif *kif)
1121{
1122	struct iface	*i;
1123
1124	LIST_FOREACH(i, &conf->iface_list, entry) {
1125		if (i->ifindex == kif->ifindex) {
1126			yyerror("interface %s already configured",
1127			    kif->ifname);
1128			return (NULL);
1129		}
1130	}
1131
1132	i = if_new(kif);
1133
1134	return (i);
1135}
1136
1137struct tnbr *
1138conf_get_tnbr(struct in_addr addr)
1139{
1140	struct tnbr	*t;
1141
1142	t = tnbr_find(conf, addr);
1143	if (t && (t->flags & F_TNBR_CONFIGURED)) {
1144		yyerror("targeted neighbor %s already configured",
1145		    inet_ntoa(addr));
1146		return (NULL);
1147	}
1148
1149	t = tnbr_new(conf, addr);
1150
1151	return (t);
1152}
1153
1154struct nbr_params *
1155conf_get_nbrp(struct in_addr addr)
1156{
1157	struct nbr_params	*n;
1158
1159	LIST_FOREACH(n, &conf->nbrp_list, entry) {
1160		if (n->addr.s_addr == addr.s_addr) {
1161			yyerror("neighbor %s already configured",
1162			    inet_ntoa(addr));
1163			return (NULL);
1164		}
1165	}
1166
1167	n = nbr_params_new(addr);
1168
1169	return (n);
1170}
1171
1172struct l2vpn *
1173conf_get_l2vpn(char *name)
1174{
1175	struct l2vpn	 *l;
1176
1177	if (l2vpn_find(conf, name)) {
1178		yyerror("l2vpn %s already configured", name);
1179		return (NULL);
1180	}
1181
1182	l = l2vpn_new(name);
1183
1184	return (l);
1185}
1186
1187struct l2vpn_if *
1188conf_get_l2vpn_if(struct l2vpn *l, struct kif *kif)
1189{
1190	struct iface	*i;
1191	struct l2vpn	*ltmp;
1192
1193	LIST_FOREACH(i, &conf->iface_list, entry) {
1194		if (i->ifindex == kif->ifindex) {
1195			yyerror("interface %s already configured",
1196			    kif->ifname);
1197			return (NULL);
1198		}
1199	}
1200
1201	LIST_FOREACH(ltmp, &conf->l2vpn_list, entry)
1202		if (l2vpn_if_find(ltmp, kif->ifindex)) {
1203			yyerror("interface %s is already being "
1204			    "used by l2vpn %s", kif->ifname, ltmp->name);
1205			return (NULL);
1206		}
1207
1208	return (l2vpn_if_new(l, kif));
1209}
1210
1211struct l2vpn_pw *
1212conf_get_l2vpn_pw(struct l2vpn *l, struct kif *kif)
1213{
1214	struct l2vpn	*ltmp;
1215
1216	LIST_FOREACH(ltmp, &conf->l2vpn_list, entry) {
1217		if (l2vpn_pw_find(ltmp, kif->ifindex)) {
1218			yyerror("pseudowire %s is already being "
1219			    "used by l2vpn %s", kif->ifname, ltmp->name);
1220			return (NULL);
1221		}
1222	}
1223
1224	return (l2vpn_pw_new(l, kif));
1225}
1226
1227void
1228clear_config(struct ldpd_conf *xconf)
1229{
1230	struct iface		*i;
1231	struct tnbr		*t;
1232	struct nbr_params	*n;
1233	struct l2vpn		*l;
1234	struct l2vpn_if		*f;
1235	struct l2vpn_pw		*p;
1236
1237	while ((i = LIST_FIRST(&xconf->iface_list)) != NULL) {
1238		LIST_REMOVE(i, entry);
1239		if_del(i);
1240	}
1241
1242	while ((t = LIST_FIRST(&xconf->tnbr_list)) != NULL) {
1243		LIST_REMOVE(t, entry);
1244		tnbr_del(t);
1245	}
1246
1247	while ((n = LIST_FIRST(&xconf->nbrp_list)) != NULL) {
1248		LIST_REMOVE(n, entry);
1249		free(n);
1250	}
1251
1252	while ((l = LIST_FIRST(&xconf->l2vpn_list)) != NULL) {
1253		while ((f = LIST_FIRST(&l->if_list)) != NULL) {
1254			LIST_REMOVE(f, entry);
1255			free(f);
1256		}
1257		while ((p = LIST_FIRST(&l->pw_list)) != NULL) {
1258			LIST_REMOVE(p, entry);
1259			free(p);
1260		}
1261		LIST_REMOVE(l, entry);
1262		free(l);
1263	}
1264
1265	free(xconf);
1266}
1267
1268u_int32_t
1269get_rtr_id(void)
1270{
1271	struct ifaddrs		*ifap, *ifa;
1272	u_int32_t		 ip = 0, cur, localnet;
1273
1274	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
1275
1276	if (getifaddrs(&ifap) == -1)
1277		fatal("getifaddrs");
1278
1279	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1280		if (strncmp(ifa->ifa_name, "carp", 4) == 0)
1281			continue;
1282		if (ifa->ifa_addr->sa_family != AF_INET)
1283			continue;
1284		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
1285		if ((cur & localnet) == localnet)	/* skip 127/8 */
1286			continue;
1287		if (cur > ip || ip == 0)
1288			ip = cur;
1289	}
1290	freeifaddrs(ifap);
1291
1292	if (ip == 0)
1293		fatal("router-id is 0.0.0.0");
1294
1295	return (ip);
1296}
1297
1298int
1299host(const char *s, struct in_addr *addr, struct in_addr *mask)
1300{
1301	struct in_addr		 ina;
1302	int			 bits = 32;
1303
1304	bzero(&ina, sizeof(struct in_addr));
1305	if (strrchr(s, '/') != NULL) {
1306		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
1307			return (0);
1308	} else {
1309		if (inet_pton(AF_INET, s, &ina) != 1)
1310			return (0);
1311	}
1312
1313	addr->s_addr = ina.s_addr;
1314	mask->s_addr = prefixlen2mask(bits);
1315
1316	return (1);
1317}
1318