xref: /openbsd/usr.sbin/ospfd/parse.y (revision 46bca67b)
1 /*	$OpenBSD: parse.y,v 1.83 2017/01/05 13:53:09 krw Exp $ */
2 
3 /*
4  * Copyright (c) 2004, 2005 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 <limits.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <syslog.h>
40 
41 #include "ospf.h"
42 #include "ospfd.h"
43 #include "ospfe.h"
44 #include "log.h"
45 
46 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
47 static struct file {
48 	TAILQ_ENTRY(file)	 entry;
49 	FILE			*stream;
50 	char			*name;
51 	int			 lineno;
52 	int			 errors;
53 } *file, *topfile;
54 struct file	*pushfile(const char *, int);
55 int		 popfile(void);
56 int		 check_file_secrecy(int, const char *);
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 void		 clear_config(struct ospfd_conf *xconf);
80 u_int32_t	 get_rtr_id(void);
81 int		 host(const char *, struct in_addr *, struct in_addr *);
82 
83 static struct ospfd_conf	*conf;
84 static int			 errors = 0;
85 
86 struct area	*area = NULL;
87 struct iface	*iface = NULL;
88 
89 struct config_defaults {
90 	char		auth_key[MAX_SIMPLE_AUTH_LEN];
91 	struct auth_md_head	 md_list;
92 	u_int32_t	dead_interval;
93 	u_int32_t	fast_hello_interval;
94 	u_int16_t	transmit_delay;
95 	u_int16_t	hello_interval;
96 	u_int16_t	rxmt_interval;
97 	u_int16_t	metric;
98 	enum auth_type	auth_type;
99 	u_int8_t	auth_keyid;
100 	u_int8_t	priority;
101 };
102 
103 struct config_defaults	 globaldefs;
104 struct config_defaults	 areadefs;
105 struct config_defaults	 ifacedefs;
106 struct config_defaults	*defs;
107 
108 struct area	*conf_get_area(struct in_addr);
109 struct iface	*conf_get_if(struct kif *, struct kif_addr *);
110 int		 conf_check_rdomain(unsigned int);
111 
112 typedef struct {
113 	union {
114 		int64_t		 number;
115 		char		*string;
116 		struct redistribute *redist;
117 	} v;
118 	int lineno;
119 } YYSTYPE;
120 
121 %}
122 
123 %token	AREA INTERFACE ROUTERID FIBUPDATE REDISTRIBUTE RTLABEL RDOMAIN
124 %token	RFC1583COMPAT STUB ROUTER SPFDELAY SPFHOLDTIME EXTTAG
125 %token	AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID
126 %token	METRIC PASSIVE
127 %token	HELLOINTERVAL FASTHELLOINTERVAL TRANSMITDELAY
128 %token	RETRANSMITINTERVAL ROUTERDEADTIME ROUTERPRIORITY
129 %token	SET TYPE
130 %token	YES NO
131 %token	MSEC MINIMAL
132 %token	DEMOTE
133 %token	INCLUDE
134 %token	ERROR
135 %token	<v.string>	STRING
136 %token	<v.number>	NUMBER
137 %type	<v.number>	yesno no optlist optlist_l option demotecount msec
138 %type	<v.number>	deadtime
139 %type	<v.string>	string
140 %type	<v.redist>	redistribute
141 
142 %%
143 
144 grammar		: /* empty */
145 		| grammar include '\n'
146 		| grammar '\n'
147 		| grammar conf_main '\n'
148 		| grammar varset '\n'
149 		| grammar area '\n'
150 		| grammar error '\n'		{ file->errors++; }
151 		;
152 
153 include		: INCLUDE STRING		{
154 			struct file	*nfile;
155 
156 			if ((nfile = pushfile($2, 1)) == NULL) {
157 				yyerror("failed to include file %s", $2);
158 				free($2);
159 				YYERROR;
160 			}
161 			free($2);
162 
163 			file = nfile;
164 			lungetc('\n');
165 		}
166 		;
167 
168 string		: string STRING	{
169 			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
170 				free($1);
171 				free($2);
172 				yyerror("string: asprintf");
173 				YYERROR;
174 			}
175 			free($1);
176 			free($2);
177 		}
178 		| STRING
179 		;
180 
181 yesno		: YES	{ $$ = 1; }
182 		| NO	{ $$ = 0; }
183 		;
184 
185 no		: /* empty */	{ $$ = 0; }
186 		| NO		{ $$ = 1; }
187 		;
188 
189 msec		: MSEC NUMBER {
190 			$$ = $2;
191 		}
192 		| NUMBER {
193 			$$ = $1 * 1000;
194 		}
195 		;
196 
197 varset		: STRING '=' string		{
198 			char *s = $1;
199 			if (conf->opts & OSPFD_OPT_VERBOSE)
200 				printf("%s = \"%s\"\n", $1, $3);
201 			while (*s++) {
202 				if (isspace((unsigned char)*s)) {
203 					yyerror("macro name cannot contain "
204 					    "whitespace");
205 					YYERROR;
206 				}
207 			}
208 			if (symset($1, $3, 0) == -1)
209 				fatal("cannot store variable");
210 			free($1);
211 			free($3);
212 		}
213 		;
214 
215 conf_main	: ROUTERID STRING {
216 			if (!inet_aton($2, &conf->rtr_id)) {
217 				yyerror("error parsing router-id");
218 				free($2);
219 				YYERROR;
220 			}
221 			free($2);
222 		}
223 		| FIBUPDATE yesno {
224 			if ($2 == 0)
225 				conf->flags |= OSPFD_FLAG_NO_FIB_UPDATE;
226 			else
227 				conf->flags &= ~OSPFD_FLAG_NO_FIB_UPDATE;
228 		}
229 		| redistribute {
230 			SIMPLEQ_INSERT_TAIL(&conf->redist_list, $1, entry);
231 			conf->redistribute = 1;
232 		}
233 		| RTLABEL STRING EXTTAG NUMBER {
234 			if ($4 < 0 || $4 > UINT_MAX) {
235 				yyerror("invalid external route tag");
236 				free($2);
237 				YYERROR;
238 			}
239 			rtlabel_tag(rtlabel_name2id($2), $4);
240 			free($2);
241 		}
242 		| RDOMAIN NUMBER {
243 			if ($2 < 0 || $2 > RT_TABLEID_MAX) {
244 				yyerror("invalid rdomain");
245 				YYERROR;
246 			}
247 			conf->rdomain = $2;
248 		}
249 		| RFC1583COMPAT yesno {
250 			conf->rfc1583compat = $2;
251 		}
252 		| SPFDELAY msec {
253 			if ($2 < MIN_SPF_DELAY || $2 > MAX_SPF_DELAY) {
254 				yyerror("spf-delay out of range "
255 				    "(%d-%d)", MIN_SPF_DELAY,
256 				    MAX_SPF_DELAY);
257 				YYERROR;
258 			}
259 			conf->spf_delay = $2;
260 		}
261 		| SPFHOLDTIME msec {
262 			if ($2 < MIN_SPF_HOLDTIME || $2 > MAX_SPF_HOLDTIME) {
263 				yyerror("spf-holdtime out of range "
264 				    "(%d-%d)", MIN_SPF_HOLDTIME,
265 				    MAX_SPF_HOLDTIME);
266 				YYERROR;
267 			}
268 			conf->spf_hold_time = $2;
269 		}
270 		| STUB ROUTER yesno {
271 			if ($3)
272 				conf->flags |= OSPFD_FLAG_STUB_ROUTER;
273 			else
274 				/* allow to force non stub mode */
275 				conf->flags &= ~OSPFD_FLAG_STUB_ROUTER;
276 		}
277 		| defaults
278 		;
279 
280 
281 redistribute	: no REDISTRIBUTE NUMBER '/' NUMBER optlist {
282 			struct redistribute	*r;
283 
284 			if ((r = calloc(1, sizeof(*r))) == NULL)
285 				fatal(NULL);
286 			r->type = REDIST_ADDR;
287 			if ($3 < 0 || $3 > 255 || $5 < 1 || $5 > 32) {
288 				yyerror("bad network: %llu/%llu", $3, $5);
289 				free(r);
290 				YYERROR;
291 			}
292 			r->addr.s_addr = htonl($3 << IN_CLASSA_NSHIFT);
293 			r->mask.s_addr = prefixlen2mask($5);
294 
295 			if ($1)
296 				r->type |= REDIST_NO;
297 			r->metric = $6;
298 			$$ = r;
299 		}
300 		| no REDISTRIBUTE STRING optlist {
301 			struct redistribute	*r;
302 
303 			if ((r = calloc(1, sizeof(*r))) == NULL)
304 				fatal(NULL);
305 			if (!strcmp($3, "default"))
306 				r->type = REDIST_DEFAULT;
307 			else if (!strcmp($3, "static"))
308 				r->type = REDIST_STATIC;
309 			else if (!strcmp($3, "connected"))
310 				r->type = REDIST_CONNECTED;
311 			else if (host($3, &r->addr, &r->mask))
312 				r->type = REDIST_ADDR;
313 			else {
314 				yyerror("unknown redistribute type");
315 				free($3);
316 				free(r);
317 				YYERROR;
318 			}
319 
320 			if ($1)
321 				r->type |= REDIST_NO;
322 			r->metric = $4;
323 			free($3);
324 			$$ = r;
325 		}
326 		| no REDISTRIBUTE RTLABEL STRING optlist {
327 			struct redistribute	*r;
328 
329 			if ((r = calloc(1, sizeof(*r))) == NULL)
330 				fatal(NULL);
331 			r->type = REDIST_LABEL;
332 			r->label = rtlabel_name2id($4);
333 			if ($1)
334 				r->type |= REDIST_NO;
335 			r->metric = $5;
336 			free($4);
337 
338 			$$ = r;
339 		}
340 		;
341 
342 optlist		: /* empty */ 			{ $$ = DEFAULT_REDIST_METRIC; }
343 		| SET option			{
344 			$$ = $2;
345 			if (($$ & LSA_METRIC_MASK) == 0)
346 				$$ |= DEFAULT_REDIST_METRIC;
347 		}
348 		| SET optnl '{' optnl optlist_l optnl '}'	{
349 			$$ = $5;
350 			if (($$ & LSA_METRIC_MASK) == 0)
351 				$$ |= DEFAULT_REDIST_METRIC;
352 		}
353 		;
354 
355 optlist_l	: optlist_l comma option {
356 			if ($1 & LSA_ASEXT_E_FLAG && $3 & LSA_ASEXT_E_FLAG) {
357 				yyerror("redistribute type already defined");
358 				YYERROR;
359 			}
360 			if ($1 & LSA_METRIC_MASK && $3 & LSA_METRIC_MASK) {
361 				yyerror("redistribute metric already defined");
362 				YYERROR;
363 			}
364 			$$ = $1 | $3;
365 		}
366 		| option { $$ = $1; }
367 		;
368 
369 option		: METRIC NUMBER {
370 			if ($2 == 0 || $2 > MAX_METRIC) {
371 				yyerror("invalid redistribute metric");
372 				YYERROR;
373 			}
374 			$$ = $2;
375 		}
376 		| TYPE NUMBER {
377 			switch ($2) {
378 			case 1:
379 				$$ = 0;
380 				break;
381 			case 2:
382 				$$ = LSA_ASEXT_E_FLAG;
383 				break;
384 			default:
385 				yyerror("only external type 1 and 2 allowed");
386 				YYERROR;
387 			}
388 		}
389 		;
390 
391 authmd		: AUTHMD NUMBER STRING {
392 			if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
393 				yyerror("auth-md key-id out of range "
394 				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
395 				free($3);
396 				YYERROR;
397 			}
398 			if (strlen($3) > MD5_DIGEST_LENGTH) {
399 				yyerror("auth-md key length out of range "
400 				    "(max length %d)",
401 				    MD5_DIGEST_LENGTH);
402 				free($3);
403 				YYERROR;
404 			}
405 			md_list_add(&defs->md_list, $2, $3);
406 			free($3);
407 		}
408 
409 authmdkeyid	: AUTHMDKEYID NUMBER {
410 			if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
411 				yyerror("auth-md-keyid out of range "
412 				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
413 				YYERROR;
414 			}
415 			defs->auth_keyid = $2;
416 		}
417 
418 authtype	: AUTHTYPE STRING {
419 			enum auth_type	type;
420 
421 			if (!strcmp($2, "none"))
422 				type = AUTH_NONE;
423 			else if (!strcmp($2, "simple"))
424 				type = AUTH_SIMPLE;
425 			else if (!strcmp($2, "crypt"))
426 				type = AUTH_CRYPT;
427 			else {
428 				yyerror("unknown auth-type");
429 				free($2);
430 				YYERROR;
431 			}
432 			free($2);
433 			defs->auth_type = type;
434 		}
435 		;
436 
437 authkey		: AUTHKEY STRING {
438 			if (strlen($2) > MAX_SIMPLE_AUTH_LEN) {
439 				yyerror("auth-key too long (max length %d)",
440 				    MAX_SIMPLE_AUTH_LEN);
441 					free($2);
442 					YYERROR;
443 			}
444 			strncpy(defs->auth_key, $2,
445 			    sizeof(defs->auth_key));
446 			free($2);
447 		}
448 		;
449 
450 defaults	: METRIC NUMBER {
451 			if ($2 < MIN_METRIC || $2 > MAX_METRIC) {
452 				yyerror("metric out of range (%d-%d)",
453 				    MIN_METRIC, MAX_METRIC);
454 				YYERROR;
455 			}
456 			defs->metric = $2;
457 		}
458 		| ROUTERPRIORITY NUMBER {
459 			if ($2 < MIN_PRIORITY || $2 > MAX_PRIORITY) {
460 				yyerror("router-priority out of range (%d-%d)",
461 				    MIN_PRIORITY, MAX_PRIORITY);
462 				YYERROR;
463 			}
464 			defs->priority = $2;
465 		}
466 		| ROUTERDEADTIME deadtime {
467 			defs->dead_interval = $2;
468 		}
469 		| TRANSMITDELAY NUMBER {
470 			if ($2 < MIN_TRANSMIT_DELAY ||
471 			    $2 > MAX_TRANSMIT_DELAY) {
472 				yyerror("transmit-delay out of range (%d-%d)",
473 				    MIN_TRANSMIT_DELAY, MAX_TRANSMIT_DELAY);
474 				YYERROR;
475 			}
476 			defs->transmit_delay = $2;
477 		}
478 		| HELLOINTERVAL NUMBER {
479 			if ($2 < MIN_HELLO_INTERVAL ||
480 			    $2 > MAX_HELLO_INTERVAL) {
481 				yyerror("hello-interval out of range (%d-%d)",
482 				    MIN_HELLO_INTERVAL, MAX_HELLO_INTERVAL);
483 				YYERROR;
484 			}
485 			defs->hello_interval = $2;
486 		}
487 		| FASTHELLOINTERVAL MSEC NUMBER {
488 			if ($3 < MIN_FAST_INTERVAL ||
489 			    $3 > MAX_FAST_INTERVAL) {
490 				yyerror("fast-hello-interval msec out of "
491 				    "range (%d-%d)", MIN_FAST_INTERVAL,
492 				    MAX_FAST_INTERVAL);
493 				YYERROR;
494 			}
495 			defs->fast_hello_interval = $3;
496 		}
497 		| RETRANSMITINTERVAL NUMBER {
498 			if ($2 < MIN_RXMT_INTERVAL || $2 > MAX_RXMT_INTERVAL) {
499 				yyerror("retransmit-interval out of range "
500 				    "(%d-%d)", MIN_RXMT_INTERVAL,
501 				    MAX_RXMT_INTERVAL);
502 				YYERROR;
503 			}
504 			defs->rxmt_interval = $2;
505 		}
506 		| authtype
507 		| authkey
508 		| authmdkeyid
509 		| authmd
510 		;
511 
512 deadtime	: NUMBER {
513 			if ($1 < MIN_RTR_DEAD_TIME || $1 > MAX_RTR_DEAD_TIME) {
514 				yyerror("router-dead-time out of range (%d-%d)",
515 				    MIN_RTR_DEAD_TIME, MAX_RTR_DEAD_TIME);
516 				YYERROR;
517 			}
518 			$$ = $1;
519 		}
520 		| MINIMAL {
521 			$$ = FAST_RTR_DEAD_TIME;
522 		}
523 
524 optnl		: '\n' optnl
525 		|
526 		;
527 
528 nl		: '\n' optnl		/* one newline or more */
529 		;
530 
531 comma		: ','
532 		| /*empty*/
533 		;
534 
535 area		: AREA STRING {
536 			struct in_addr	id;
537 			if (inet_aton($2, &id) == 0) {
538 				yyerror("error parsing area");
539 				free($2);
540 				YYERROR;
541 			}
542 			free($2);
543 			area = conf_get_area(id);
544 
545 			memcpy(&areadefs, defs, sizeof(areadefs));
546 			md_list_copy(&areadefs.md_list, &defs->md_list);
547 			defs = &areadefs;
548 		} '{' optnl areaopts_l '}' {
549 			area = NULL;
550 			md_list_clr(&defs->md_list);
551 			defs = &globaldefs;
552 		}
553 		;
554 
555 demotecount	: NUMBER	{ $$ = $1; }
556 		| /*empty*/	{ $$ = 1; }
557 		;
558 
559 areaopts_l	: areaopts_l areaoptsl nl
560 		| areaoptsl optnl
561 		;
562 
563 areaoptsl	: interface
564 		| DEMOTE STRING	demotecount {
565 			if ($3 < 1 || $3 > 255) {
566 				yyerror("demote count out of range (1-255)");
567 				free($2);
568 				YYERROR;
569 			}
570 			area->demote_level = $3;
571 			if (strlcpy(area->demote_group, $2,
572 			    sizeof(area->demote_group)) >=
573 			    sizeof(area->demote_group)) {
574 				yyerror("demote group name \"%s\" too long",
575 				    $2);
576 				free($2);
577 				YYERROR;
578 			}
579 			free($2);
580 			if (carp_demote_init(area->demote_group,
581 			    conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
582 				yyerror("error initializing group \"%s\"",
583 				    area->demote_group);
584 				YYERROR;
585 			}
586 		}
587 		| defaults
588 		| STUB 			{ area->stub = 1; }
589 		| STUB redistribute {
590 			area->stub = 1;
591 			if ($2->type != REDIST_DEFAULT) {
592 				yyerror("bad redistribute option");
593 				YYERROR;
594 			}
595 			if (!SIMPLEQ_EMPTY(&area->redist_list)) {
596 				yyerror("area redistribute option only "
597 				    "allowed once");
598 				YYERROR;
599 			}
600 			SIMPLEQ_INSERT_TAIL(&area->redist_list, $2, entry);
601 		}
602 		;
603 
604 interface	: INTERFACE STRING	{
605 			struct kif	*kif;
606 			struct kif_addr	*ka = NULL;
607 			char		*s;
608 			struct in_addr	 addr;
609 
610 			s = strchr($2, ':');
611 			if (s) {
612 				*s++ = '\0';
613 				if (inet_aton(s, &addr) == 0) {
614 					yyerror(
615 					    "error parsing interface address");
616 					free($2);
617 					YYERROR;
618 				}
619 			} else
620 				addr.s_addr = 0;
621 
622 			if ((kif = kif_findname($2, addr, &ka)) == NULL) {
623 				yyerror("unknown interface %s", $2);
624 				free($2);
625 				YYERROR;
626 			}
627 			if (ka == NULL) {
628 				if (s)
629 					yyerror("address %s not configured on "
630 					    "interface %s", s, $2);
631 				else
632 					yyerror("unnumbered interface %s", $2);
633 				free($2);
634 				YYERROR;
635 			}
636 			free($2);
637 			iface = conf_get_if(kif, ka);
638 			if (iface == NULL)
639 				YYERROR;
640 			iface->area = area;
641 			LIST_INSERT_HEAD(&area->iface_list, iface, entry);
642 
643 			memcpy(&ifacedefs, defs, sizeof(ifacedefs));
644 			md_list_copy(&ifacedefs.md_list, &defs->md_list);
645 			defs = &ifacedefs;
646 		} interface_block {
647 			iface->dead_interval = defs->dead_interval;
648 			iface->fast_hello_interval = defs->fast_hello_interval;
649 			iface->transmit_delay = defs->transmit_delay;
650 			if (iface->dead_interval == FAST_RTR_DEAD_TIME)
651 				iface->hello_interval = 0;
652 			else
653 				iface->hello_interval = defs->hello_interval;
654 			iface->rxmt_interval = defs->rxmt_interval;
655 			iface->metric = defs->metric;
656 			iface->priority = defs->priority;
657 			iface->auth_type = defs->auth_type;
658 			iface->auth_keyid = defs->auth_keyid;
659 			memcpy(iface->auth_key, defs->auth_key,
660 			    sizeof(iface->auth_key));
661 			md_list_copy(&iface->auth_md_list, &defs->md_list);
662 			md_list_clr(&defs->md_list);
663 			iface = NULL;
664 			/* interface is always part of an area */
665 			defs = &areadefs;
666 		}
667 		;
668 
669 interface_block	: '{' optnl interfaceopts_l '}'
670 		| '{' optnl '}'
671 		|
672 		;
673 
674 interfaceopts_l	: interfaceopts_l interfaceoptsl nl
675 		| interfaceoptsl optnl
676 		;
677 
678 interfaceoptsl	: PASSIVE		{ iface->passive = 1; }
679 		| DEMOTE STRING		{
680 			if (strlcpy(iface->demote_group, $2,
681 			    sizeof(iface->demote_group)) >=
682 			    sizeof(iface->demote_group)) {
683 				yyerror("demote group name \"%s\" too long",
684 				    $2);
685 				free($2);
686 				YYERROR;
687 			}
688 			free($2);
689 			if (carp_demote_init(iface->demote_group,
690 			    conf->opts & OSPFD_OPT_FORCE_DEMOTE) == -1) {
691 				yyerror("error initializing group \"%s\"",
692 				    iface->demote_group);
693 				YYERROR;
694 			}
695 		}
696 		| defaults
697 		;
698 
699 %%
700 
701 struct keywords {
702 	const char	*k_name;
703 	int		 k_val;
704 };
705 
706 int
707 yyerror(const char *fmt, ...)
708 {
709 	va_list		 ap;
710 	char		*msg;
711 
712 	file->errors++;
713 	va_start(ap, fmt);
714 	if (vasprintf(&msg, fmt, ap) == -1)
715 		fatalx("yyerror vasprintf");
716 	va_end(ap);
717 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
718 	free(msg);
719 	return (0);
720 }
721 
722 int
723 kw_cmp(const void *k, const void *e)
724 {
725 	return (strcmp(k, ((const struct keywords *)e)->k_name));
726 }
727 
728 int
729 lookup(char *s)
730 {
731 	/* this has to be sorted always */
732 	static const struct keywords keywords[] = {
733 		{"area",		AREA},
734 		{"auth-key",		AUTHKEY},
735 		{"auth-md",		AUTHMD},
736 		{"auth-md-keyid",	AUTHMDKEYID},
737 		{"auth-type",		AUTHTYPE},
738 		{"demote",		DEMOTE},
739 		{"external-tag",	EXTTAG},
740 		{"fast-hello-interval",	FASTHELLOINTERVAL},
741 		{"fib-update",		FIBUPDATE},
742 		{"hello-interval",	HELLOINTERVAL},
743 		{"include",		INCLUDE},
744 		{"interface",		INTERFACE},
745 		{"metric",		METRIC},
746 		{"minimal",		MINIMAL},
747 		{"msec",		MSEC},
748 		{"no",			NO},
749 		{"passive",		PASSIVE},
750 		{"rdomain",		RDOMAIN},
751 		{"redistribute",	REDISTRIBUTE},
752 		{"retransmit-interval",	RETRANSMITINTERVAL},
753 		{"rfc1583compat",	RFC1583COMPAT},
754 		{"router",		ROUTER},
755 		{"router-dead-time",	ROUTERDEADTIME},
756 		{"router-id",		ROUTERID},
757 		{"router-priority",	ROUTERPRIORITY},
758 		{"rtlabel",		RTLABEL},
759 		{"set",			SET},
760 		{"spf-delay",		SPFDELAY},
761 		{"spf-holdtime",	SPFHOLDTIME},
762 		{"stub",		STUB},
763 		{"transmit-delay",	TRANSMITDELAY},
764 		{"type",		TYPE},
765 		{"yes",			YES}
766 	};
767 	const struct keywords	*p;
768 
769 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
770 	    sizeof(keywords[0]), kw_cmp);
771 
772 	if (p)
773 		return (p->k_val);
774 	else
775 		return (STRING);
776 }
777 
778 #define MAXPUSHBACK	128
779 
780 u_char	*parsebuf;
781 int	 parseindex;
782 u_char	 pushback_buffer[MAXPUSHBACK];
783 int	 pushback_index = 0;
784 
785 int
786 lgetc(int quotec)
787 {
788 	int		c, next;
789 
790 	if (parsebuf) {
791 		/* Read character from the parsebuffer instead of input. */
792 		if (parseindex >= 0) {
793 			c = parsebuf[parseindex++];
794 			if (c != '\0')
795 				return (c);
796 			parsebuf = NULL;
797 		} else
798 			parseindex++;
799 	}
800 
801 	if (pushback_index)
802 		return (pushback_buffer[--pushback_index]);
803 
804 	if (quotec) {
805 		if ((c = getc(file->stream)) == EOF) {
806 			yyerror("reached end of file while parsing "
807 			    "quoted string");
808 			if (file == topfile || popfile() == EOF)
809 				return (EOF);
810 			return (quotec);
811 		}
812 		return (c);
813 	}
814 
815 	while ((c = getc(file->stream)) == '\\') {
816 		next = getc(file->stream);
817 		if (next != '\n') {
818 			c = next;
819 			break;
820 		}
821 		yylval.lineno = file->lineno;
822 		file->lineno++;
823 	}
824 
825 	while (c == EOF) {
826 		if (file == topfile || popfile() == EOF)
827 			return (EOF);
828 		c = getc(file->stream);
829 	}
830 	return (c);
831 }
832 
833 int
834 lungetc(int c)
835 {
836 	if (c == EOF)
837 		return (EOF);
838 	if (parsebuf) {
839 		parseindex--;
840 		if (parseindex >= 0)
841 			return (c);
842 	}
843 	if (pushback_index < MAXPUSHBACK-1)
844 		return (pushback_buffer[pushback_index++] = c);
845 	else
846 		return (EOF);
847 }
848 
849 int
850 findeol(void)
851 {
852 	int	c;
853 
854 	parsebuf = NULL;
855 
856 	/* skip to either EOF or the first real EOL */
857 	while (1) {
858 		if (pushback_index)
859 			c = pushback_buffer[--pushback_index];
860 		else
861 			c = lgetc(0);
862 		if (c == '\n') {
863 			file->lineno++;
864 			break;
865 		}
866 		if (c == EOF)
867 			break;
868 	}
869 	return (ERROR);
870 }
871 
872 int
873 yylex(void)
874 {
875 	u_char	 buf[8096];
876 	u_char	*p, *val;
877 	int	 quotec, next, c;
878 	int	 token;
879 
880 top:
881 	p = buf;
882 	while ((c = lgetc(0)) == ' ' || c == '\t')
883 		; /* nothing */
884 
885 	yylval.lineno = file->lineno;
886 	if (c == '#')
887 		while ((c = lgetc(0)) != '\n' && c != EOF)
888 			; /* nothing */
889 	if (c == '$' && parsebuf == NULL) {
890 		while (1) {
891 			if ((c = lgetc(0)) == EOF)
892 				return (0);
893 
894 			if (p + 1 >= buf + sizeof(buf) - 1) {
895 				yyerror("string too long");
896 				return (findeol());
897 			}
898 			if (isalnum(c) || c == '_') {
899 				*p++ = c;
900 				continue;
901 			}
902 			*p = '\0';
903 			lungetc(c);
904 			break;
905 		}
906 		val = symget(buf);
907 		if (val == NULL) {
908 			yyerror("macro '%s' not defined", buf);
909 			return (findeol());
910 		}
911 		parsebuf = val;
912 		parseindex = 0;
913 		goto top;
914 	}
915 
916 	switch (c) {
917 	case '\'':
918 	case '"':
919 		quotec = c;
920 		while (1) {
921 			if ((c = lgetc(quotec)) == EOF)
922 				return (0);
923 			if (c == '\n') {
924 				file->lineno++;
925 				continue;
926 			} else if (c == '\\') {
927 				if ((next = lgetc(quotec)) == EOF)
928 					return (0);
929 				if (next == quotec || c == ' ' || c == '\t')
930 					c = next;
931 				else if (next == '\n') {
932 					file->lineno++;
933 					continue;
934 				} else
935 					lungetc(next);
936 			} else if (c == quotec) {
937 				*p = '\0';
938 				break;
939 			} else if (c == '\0') {
940 				yyerror("syntax error");
941 				return (findeol());
942 			}
943 			if (p + 1 >= buf + sizeof(buf) - 1) {
944 				yyerror("string too long");
945 				return (findeol());
946 			}
947 			*p++ = c;
948 		}
949 		yylval.v.string = strdup(buf);
950 		if (yylval.v.string == NULL)
951 			err(1, "yylex: strdup");
952 		return (STRING);
953 	}
954 
955 #define allowed_to_end_number(x) \
956 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
957 
958 	if (c == '-' || isdigit(c)) {
959 		do {
960 			*p++ = c;
961 			if ((unsigned)(p-buf) >= sizeof(buf)) {
962 				yyerror("string too long");
963 				return (findeol());
964 			}
965 		} while ((c = lgetc(0)) != EOF && isdigit(c));
966 		lungetc(c);
967 		if (p == buf + 1 && buf[0] == '-')
968 			goto nodigits;
969 		if (c == EOF || allowed_to_end_number(c)) {
970 			const char *errstr = NULL;
971 
972 			*p = '\0';
973 			yylval.v.number = strtonum(buf, LLONG_MIN,
974 			    LLONG_MAX, &errstr);
975 			if (errstr) {
976 				yyerror("\"%s\" invalid number: %s",
977 				    buf, errstr);
978 				return (findeol());
979 			}
980 			return (NUMBER);
981 		} else {
982 nodigits:
983 			while (p > buf + 1)
984 				lungetc(*--p);
985 			c = *--p;
986 			if (c == '-')
987 				return (c);
988 		}
989 	}
990 
991 #define allowed_in_string(x) \
992 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
993 	x != '{' && x != '}' && \
994 	x != '!' && x != '=' && x != '#' && \
995 	x != ','))
996 
997 	if (isalnum(c) || c == ':' || c == '_') {
998 		do {
999 			*p++ = c;
1000 			if ((unsigned)(p-buf) >= sizeof(buf)) {
1001 				yyerror("string too long");
1002 				return (findeol());
1003 			}
1004 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
1005 		lungetc(c);
1006 		*p = '\0';
1007 		if ((token = lookup(buf)) == STRING)
1008 			if ((yylval.v.string = strdup(buf)) == NULL)
1009 				err(1, "yylex: strdup");
1010 		return (token);
1011 	}
1012 	if (c == '\n') {
1013 		yylval.lineno = file->lineno;
1014 		file->lineno++;
1015 	}
1016 	if (c == EOF)
1017 		return (0);
1018 	return (c);
1019 }
1020 
1021 int
1022 check_file_secrecy(int fd, const char *fname)
1023 {
1024 	struct stat	st;
1025 
1026 	if (fstat(fd, &st)) {
1027 		log_warn("cannot stat %s", fname);
1028 		return (-1);
1029 	}
1030 	if (st.st_uid != 0 && st.st_uid != getuid()) {
1031 		log_warnx("%s: owner not root or current user", fname);
1032 		return (-1);
1033 	}
1034 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
1035 		log_warnx("%s: group writable or world read/writable", fname);
1036 		return (-1);
1037 	}
1038 	return (0);
1039 }
1040 
1041 struct file *
1042 pushfile(const char *name, int secret)
1043 {
1044 	struct file	*nfile;
1045 
1046 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
1047 		log_warn("malloc");
1048 		return (NULL);
1049 	}
1050 	if ((nfile->name = strdup(name)) == NULL) {
1051 		log_warn("malloc");
1052 		free(nfile);
1053 		return (NULL);
1054 	}
1055 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
1056 		log_warn("%s", nfile->name);
1057 		free(nfile->name);
1058 		free(nfile);
1059 		return (NULL);
1060 	} else if (secret &&
1061 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
1062 		fclose(nfile->stream);
1063 		free(nfile->name);
1064 		free(nfile);
1065 		return (NULL);
1066 	}
1067 	nfile->lineno = 1;
1068 	TAILQ_INSERT_TAIL(&files, nfile, entry);
1069 	return (nfile);
1070 }
1071 
1072 int
1073 popfile(void)
1074 {
1075 	struct file	*prev;
1076 
1077 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
1078 		prev->errors += file->errors;
1079 
1080 	TAILQ_REMOVE(&files, file, entry);
1081 	fclose(file->stream);
1082 	free(file->name);
1083 	free(file);
1084 	file = prev;
1085 	return (file ? 0 : EOF);
1086 }
1087 
1088 struct ospfd_conf *
1089 parse_config(char *filename, int opts)
1090 {
1091 	struct sym	*sym, *next;
1092 
1093 	if ((conf = calloc(1, sizeof(struct ospfd_conf))) == NULL)
1094 		fatal("parse_config");
1095 	conf->opts = opts;
1096 	if (conf->opts & OSPFD_OPT_STUB_ROUTER)
1097 		conf->flags |= OSPFD_FLAG_STUB_ROUTER;
1098 
1099 	bzero(&globaldefs, sizeof(globaldefs));
1100 	defs = &globaldefs;
1101 	TAILQ_INIT(&defs->md_list);
1102 	defs->dead_interval = DEFAULT_RTR_DEAD_TIME;
1103 	defs->fast_hello_interval = DEFAULT_FAST_INTERVAL;
1104 	defs->transmit_delay = DEFAULT_TRANSMIT_DELAY;
1105 	defs->hello_interval = DEFAULT_HELLO_INTERVAL;
1106 	defs->rxmt_interval = DEFAULT_RXMT_INTERVAL;
1107 	defs->metric = DEFAULT_METRIC;
1108 	defs->priority = DEFAULT_PRIORITY;
1109 
1110 	conf->spf_delay = DEFAULT_SPF_DELAY;
1111 	conf->spf_hold_time = DEFAULT_SPF_HOLDTIME;
1112 	conf->spf_state = SPF_IDLE;
1113 
1114 	if ((file = pushfile(filename, !(conf->opts & OSPFD_OPT_NOACTION))) == NULL) {
1115 		free(conf);
1116 		return (NULL);
1117 	}
1118 	topfile = file;
1119 
1120 	LIST_INIT(&conf->area_list);
1121 	LIST_INIT(&conf->cand_list);
1122 	SIMPLEQ_INIT(&conf->redist_list);
1123 
1124 	yyparse();
1125 	errors = file->errors;
1126 	popfile();
1127 
1128 	/* Free macros and check which have not been used. */
1129 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
1130 		if ((conf->opts & OSPFD_OPT_VERBOSE2) && !sym->used)
1131 			fprintf(stderr, "warning: macro '%s' not "
1132 			    "used\n", sym->nam);
1133 		if (!sym->persist) {
1134 			free(sym->nam);
1135 			free(sym->val);
1136 			TAILQ_REMOVE(&symhead, sym, entry);
1137 			free(sym);
1138 		}
1139 	}
1140 
1141 	/* free global config defaults */
1142 	md_list_clr(&globaldefs.md_list);
1143 
1144 	/* check that all interfaces belong to the configured rdomain */
1145 	errors += conf_check_rdomain(conf->rdomain);
1146 
1147 	if (errors) {
1148 		clear_config(conf);
1149 		return (NULL);
1150 	}
1151 
1152 	if (conf->rtr_id.s_addr == 0)
1153 		conf->rtr_id.s_addr = get_rtr_id();
1154 
1155 	return (conf);
1156 }
1157 
1158 int
1159 symset(const char *nam, const char *val, int persist)
1160 {
1161 	struct sym	*sym;
1162 
1163 	TAILQ_FOREACH(sym, &symhead, entry) {
1164 		if (strcmp(nam, sym->nam) == 0)
1165 			break;
1166 	}
1167 
1168 	if (sym != NULL) {
1169 		if (sym->persist == 1)
1170 			return (0);
1171 		else {
1172 			free(sym->nam);
1173 			free(sym->val);
1174 			TAILQ_REMOVE(&symhead, sym, entry);
1175 			free(sym);
1176 		}
1177 	}
1178 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
1179 		return (-1);
1180 
1181 	sym->nam = strdup(nam);
1182 	if (sym->nam == NULL) {
1183 		free(sym);
1184 		return (-1);
1185 	}
1186 	sym->val = strdup(val);
1187 	if (sym->val == NULL) {
1188 		free(sym->nam);
1189 		free(sym);
1190 		return (-1);
1191 	}
1192 	sym->used = 0;
1193 	sym->persist = persist;
1194 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
1195 	return (0);
1196 }
1197 
1198 int
1199 cmdline_symset(char *s)
1200 {
1201 	char	*sym, *val;
1202 	int	ret;
1203 	size_t	len;
1204 
1205 	if ((val = strrchr(s, '=')) == NULL)
1206 		return (-1);
1207 
1208 	len = strlen(s) - strlen(val) + 1;
1209 	if ((sym = malloc(len)) == NULL)
1210 		errx(1, "cmdline_symset: malloc");
1211 
1212 	strlcpy(sym, s, len);
1213 
1214 	ret = symset(sym, val + 1, 1);
1215 	free(sym);
1216 
1217 	return (ret);
1218 }
1219 
1220 char *
1221 symget(const char *nam)
1222 {
1223 	struct sym	*sym;
1224 
1225 	TAILQ_FOREACH(sym, &symhead, entry) {
1226 		if (strcmp(nam, sym->nam) == 0) {
1227 			sym->used = 1;
1228 			return (sym->val);
1229 		}
1230 	}
1231 	return (NULL);
1232 }
1233 
1234 struct area *
1235 conf_get_area(struct in_addr id)
1236 {
1237 	struct area	*a;
1238 
1239 	a = area_find(conf, id);
1240 	if (a)
1241 		return (a);
1242 	a = area_new();
1243 	LIST_INSERT_HEAD(&conf->area_list, a, entry);
1244 
1245 	a->id.s_addr = id.s_addr;
1246 
1247 	return (a);
1248 }
1249 
1250 struct iface *
1251 conf_get_if(struct kif *kif, struct kif_addr *ka)
1252 {
1253 	struct area	*a;
1254 	struct iface	*i;
1255 
1256 	LIST_FOREACH(a, &conf->area_list, entry)
1257 		LIST_FOREACH(i, &a->iface_list, entry)
1258 			if (i->ifindex == kif->ifindex &&
1259 			    i->addr.s_addr == ka->addr.s_addr) {
1260 				yyerror("interface %s already configured",
1261 				    kif->ifname);
1262 				return (NULL);
1263 			}
1264 
1265 	i = if_new(kif, ka);
1266 	i->auth_keyid = 1;
1267 
1268 	return (i);
1269 }
1270 
1271 int
1272 conf_check_rdomain(unsigned int rdomain)
1273 {
1274 	struct area	*a;
1275 	struct iface	*i;
1276 	int		 errs = 0;
1277 
1278 	LIST_FOREACH(a, &conf->area_list, entry)
1279 		LIST_FOREACH(i, &a->iface_list, entry)
1280 			if (i->rdomain != rdomain) {
1281 				logit(LOG_CRIT,
1282 				    "interface %s not in rdomain %u",
1283 				    i->name, rdomain);
1284 				errs++;
1285 			}
1286 
1287 	return (errs);
1288 }
1289 
1290 void
1291 clear_config(struct ospfd_conf *xconf)
1292 {
1293 	struct area	*a;
1294 
1295 	while ((a = LIST_FIRST(&xconf->area_list)) != NULL) {
1296 		LIST_REMOVE(a, entry);
1297 		area_del(a);
1298 	}
1299 
1300 	free(xconf);
1301 }
1302 
1303 u_int32_t
1304 get_rtr_id(void)
1305 {
1306 	struct ifaddrs		*ifap, *ifa;
1307 	u_int32_t		 ip = 0, cur, localnet;
1308 
1309 	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
1310 
1311 	if (getifaddrs(&ifap) == -1)
1312 		fatal("getifaddrs");
1313 
1314 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1315 		if (strncmp(ifa->ifa_name, "carp", 4) == 0)
1316 			continue;
1317 		if (ifa->ifa_addr->sa_family != AF_INET)
1318 			continue;
1319 		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
1320 		if ((cur & localnet) == localnet)	/* skip 127/8 */
1321 			continue;
1322 		if (ntohl(cur) < ntohl(ip) || ip == 0)
1323 			ip = cur;
1324 	}
1325 	freeifaddrs(ifap);
1326 
1327 	if (ip == 0)
1328 		fatal("router-id is 0.0.0.0");
1329 
1330 	return (ip);
1331 }
1332 
1333 int
1334 host(const char *s, struct in_addr *addr, struct in_addr *mask)
1335 {
1336 	struct in_addr		 ina;
1337 	int			 bits = 32;
1338 
1339 	bzero(&ina, sizeof(struct in_addr));
1340 	if (strrchr(s, '/') != NULL) {
1341 		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
1342 			return (0);
1343 	} else {
1344 		if (inet_pton(AF_INET, s, &ina) != 1)
1345 			return (0);
1346 	}
1347 
1348 	addr->s_addr = ina.s_addr;
1349 	mask->s_addr = prefixlen2mask(bits);
1350 
1351 	return (1);
1352 }
1353