xref: /openbsd/usr.sbin/rad/parse.y (revision 3bef86f7)
1 /*	$OpenBSD: parse.y,v 1.21 2022/10/15 13:27:45 florian Exp $	*/
2 
3 /*
4  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
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/queue.h>
28 #include <sys/socket.h>
29 #include <sys/stat.h>
30 
31 #include <netinet/in.h>
32 #include <net/if.h>
33 
34 #include <arpa/inet.h>
35 
36 #include <ctype.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <event.h>
40 #include <imsg.h>
41 #include <limits.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <syslog.h>
46 #include <unistd.h>
47 
48 #include "log.h"
49 #include "rad.h"
50 #include "frontend.h"
51 
52 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
53 static struct file {
54 	TAILQ_ENTRY(file)	 entry;
55 	FILE			*stream;
56 	char			*name;
57 	size_t	 		 ungetpos;
58 	size_t			 ungetsize;
59 	u_char			*ungetbuf;
60 	int			 eof_reached;
61 	int			 lineno;
62 	int			 errors;
63 } *file, *topfile;
64 struct file	*pushfile(const char *, int);
65 int		 popfile(void);
66 int		 check_file_secrecy(int, const char *);
67 int		 yyparse(void);
68 int		 yylex(void);
69 int		 yyerror(const char *, ...)
70     __attribute__((__format__ (printf, 1, 2)))
71     __attribute__((__nonnull__ (1)));
72 int		 kw_cmp(const void *, const void *);
73 int		 lookup(char *);
74 int		 igetc(void);
75 int		 lgetc(int);
76 void		 lungetc(int);
77 int		 findeol(void);
78 
79 TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
80 struct sym {
81 	TAILQ_ENTRY(sym)	 entry;
82 	int			 used;
83 	int			 persist;
84 	char			*nam;
85 	char			*val;
86 };
87 
88 int	 symset(const char *, const char *, int);
89 char	*symget(const char *);
90 
91 void	 clear_config(struct rad_conf *xconf);
92 
93 static struct rad_conf		*conf;
94 static struct ra_options_conf	*ra_options;
95 static int			 errors;
96 
97 static struct ra_iface_conf	*ra_iface_conf;
98 static struct ra_prefix_conf	*ra_prefix_conf;
99 static struct ra_pref64_conf	*ra_pref64_conf;
100 
101 struct ra_prefix_conf	*conf_get_ra_prefix(struct in6_addr*, int);
102 struct ra_pref64_conf	*conf_get_ra_pref64(struct in6_addr*, int);
103 struct ra_iface_conf	*conf_get_ra_iface(char *);
104 void			 copy_dns_options(const struct ra_options_conf *,
105 			    struct ra_options_conf *);
106 void			 copy_pref64_options(const struct ra_options_conf *,
107 			    struct ra_options_conf *);
108 
109 typedef struct {
110 	union {
111 		int64_t		 number;
112 		char		*string;
113 	} v;
114 	int lineno;
115 } YYSTYPE;
116 
117 %}
118 
119 %token	RA_IFACE YES NO INCLUDE ERROR
120 %token	DEFAULT ROUTER HOP LIMIT MANAGED ADDRESS
121 %token	CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER
122 %token	AUTO PREFIX VALID PREFERRED LIFETIME ONLINK AUTONOMOUS
123 %token	ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU NAT64
124 
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 include '\n'
134 		| grammar '\n'
135 		| grammar { ra_options = &conf->ra_options; } conf_main '\n'
136 		| grammar varset '\n'
137 		| grammar ra_iface '\n'
138 		| grammar error '\n'		{ file->errors++; }
139 		;
140 
141 include		: INCLUDE STRING		{
142 			struct file	*nfile;
143 
144 			if ((nfile = pushfile($2, 0)) == NULL) {
145 				yyerror("failed to include file %s", $2);
146 				free($2);
147 				YYERROR;
148 			}
149 			free($2);
150 
151 			file = nfile;
152 			lungetc('\n');
153 		}
154 		;
155 
156 string		: string STRING	{
157 			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
158 				free($1);
159 				free($2);
160 				yyerror("string: asprintf");
161 				YYERROR;
162 			}
163 			free($1);
164 			free($2);
165 		}
166 		| STRING
167 		;
168 
169 yesno		: YES	{ $$ = 1; }
170 		| NO	{ $$ = 0; }
171 		;
172 
173 varset		: STRING '=' string		{
174 			char *s = $1;
175 			if (cmd_opts & OPT_VERBOSE)
176 				printf("%s = \"%s\"\n", $1, $3);
177 			while (*s++) {
178 				if (isspace((unsigned char)*s)) {
179 					yyerror("macro name cannot contain "
180 					    "whitespace");
181 					free($1);
182 					free($3);
183 					YYERROR;
184 				}
185 			}
186 			if (symset($1, $3, 0) == -1)
187 				fatal("cannot store variable");
188 			free($1);
189 			free($3);
190 		}
191 		;
192 
193 conf_main	: ra_opt_block {
194 			ra_options = &conf->ra_options;
195 		}
196 		;
197 
198 ra_opt_block	: DEFAULT ROUTER yesno {
199 			ra_options->dfr = $3;
200 		}
201 		| HOP LIMIT NUMBER {
202 			ra_options->cur_hl = $3;
203 		}
204 		| MANAGED ADDRESS CONFIGURATION yesno {
205 			ra_options->m_flag = $4;
206 		}
207 		| OTHER CONFIGURATION yesno {
208 			ra_options->o_flag = $3;
209 		}
210 		| ROUTER LIFETIME NUMBER {
211 			ra_options->router_lifetime = $3;
212 		}
213 		| REACHABLE TIME NUMBER {
214 			ra_options->reachable_time = $3;
215 		}
216 		| RETRANS TIMER NUMBER {
217 			ra_options->retrans_timer = $3;
218 		}
219 		| MTU NUMBER {
220 			ra_options->mtu = $2;
221 		}
222 		| NAT64 PREFIX STRING {
223 			struct in6_addr	 addr;
224 			int		 prefixlen;
225 			char		*p;
226 			const char	*errstr;
227 
228 			memset(&addr, 0, sizeof(addr));
229 			p = strchr($3, '/');
230 			if (p != NULL) {
231 				*p++ = '\0';
232 				prefixlen = strtonum(p, 0, 128, &errstr);
233 				if (errstr != NULL) {
234 					yyerror("error parsing prefix "
235 					    "\"%s/%s\"", $3, p);
236 					free($3);
237 					YYERROR;
238 				}
239 			} else
240 				prefixlen = 96;
241 
242 			switch (prefixlen) {
243 			case 96:
244 			case 64:
245 			case 56:
246 			case 48:
247 			case 40:
248 			case 32:
249 				break;
250 			default:
251 				yyerror("invalid nat64 prefix length: %d",
252 				    prefixlen);
253 				YYERROR;
254 				break;
255 			}
256 			if(inet_pton(AF_INET6, $3, &addr) == 0) {
257 				yyerror("error parsing prefix \"%s/%d\"", $3,
258 				    prefixlen);
259 				free($3);
260 				YYERROR;
261 			}
262 			mask_prefix(&addr, prefixlen);
263 			ra_pref64_conf = conf_get_ra_pref64(&addr, prefixlen);
264 		} ra_pref64_block {
265 			ra_pref64_conf = NULL;
266 		}
267 		| DNS dns_block
268 		;
269 
270 optnl		: '\n' optnl		/* zero or more newlines */
271 		| /*empty*/
272 		;
273 
274 nl		: '\n' optnl		/* one or more newlines */
275 		;
276 
277 ra_iface	: RA_IFACE STRING {
278 			ra_iface_conf = conf_get_ra_iface($2);
279 			/* set auto prefix defaults */
280 			ra_iface_conf->autoprefix = conf_get_ra_prefix(NULL, 0);
281 			ra_options = &ra_iface_conf->ra_options;
282 		} ra_iface_block {
283 			ra_iface_conf = NULL;
284 			ra_options = &conf->ra_options;
285 		}
286 		;
287 
288 ra_iface_block	: '{' optnl ra_ifaceopts_l '}'
289 		| '{' optnl '}'
290 		| /* empty */
291 		;
292 
293 ra_ifaceopts_l	: ra_ifaceopts_l ra_ifaceoptsl nl
294 		| ra_ifaceoptsl optnl
295 		;
296 
297 ra_ifaceoptsl	: NO AUTO PREFIX {
298 			free(ra_iface_conf->autoprefix);
299 			ra_iface_conf->autoprefix = NULL;
300 		}
301 		| AUTO PREFIX {
302 			if (ra_iface_conf->autoprefix == NULL)
303 				ra_iface_conf->autoprefix =
304 				    conf_get_ra_prefix(NULL, 0);
305 			ra_prefix_conf = ra_iface_conf->autoprefix;
306 		} ra_prefix_block {
307 			ra_prefix_conf = NULL;
308 		}
309 		| PREFIX STRING {
310 			struct in6_addr	 addr;
311 			int		 prefixlen;
312 			char		*p;
313 			const char	*errstr;
314 
315 			memset(&addr, 0, sizeof(addr));
316 			p = strchr($2, '/');
317 			if (p != NULL) {
318 				*p++ = '\0';
319 				prefixlen = strtonum(p, 0, 128, &errstr);
320 				if (errstr != NULL) {
321 					yyerror("error parsing prefix "
322 					    "\"%s/%s\"", $2, p);
323 					free($2);
324 					YYERROR;
325 				}
326 			} else
327 				prefixlen = 64;
328 			if(inet_pton(AF_INET6, $2, &addr) == 0) {
329 				yyerror("error parsing prefix \"%s/%d\"", $2,
330 				    prefixlen);
331 				free($2);
332 				YYERROR;
333 			}
334 			mask_prefix(&addr, prefixlen);
335 			ra_prefix_conf = conf_get_ra_prefix(&addr, prefixlen);
336 		} ra_prefix_block {
337 			ra_prefix_conf = NULL;
338 		}
339 		| ra_opt_block
340 		;
341 
342 ra_prefix_block	: '{' optnl ra_prefixopts_l '}'
343 		| '{' optnl '}'
344 		| /* empty */
345 		;
346 
347 ra_prefixopts_l	: ra_prefixopts_l ra_prefixoptsl nl
348 		| ra_prefixoptsl optnl
349 		;
350 
351 ra_prefixoptsl	: VALID LIFETIME NUMBER {
352 			ra_prefix_conf->vltime = $3;
353 		}
354 		| PREFERRED LIFETIME NUMBER {
355 			ra_prefix_conf->pltime = $3;
356 		}
357 		| ONLINK yesno {
358 			ra_prefix_conf->lflag = $2;
359 		}
360 		| AUTONOMOUS ADDRESS_CONFIGURATION yesno {
361 			ra_prefix_conf->aflag = $3;
362 		}
363 		;
364 
365 ra_pref64_block	: '{' optnl ra_pref64opts_l '}'
366 		| '{' optnl '}'
367 		| /* empty */
368 		;
369 
370 ra_pref64opts_l	: ra_pref64opts_l ra_pref64optsl nl
371 		| ra_pref64optsl optnl
372 		;
373 
374 ra_pref64optsl	: LIFETIME NUMBER {
375 			if ($2 < 0 || $2 > 65528) {
376 				yyerror("Invalid nat64 prefix lifetime: %lld",
377 				    $2);
378 				YYERROR;
379 			}
380 			ra_pref64_conf->ltime = $2;
381 		}
382 		;
383 
384 dns_block	: '{' optnl dnsopts_l '}'
385 		| '{' optnl '}'
386 		| /* empty */
387 		;
388 
389 dnsopts_l	: dnsopts_l dnsoptsl nl
390 		| dnsoptsl optnl
391 		;
392 
393 dnsoptsl	: LIFETIME NUMBER {
394 			ra_options->rdns_lifetime = $2;
395 		}
396 		| NAMESERVER nserver_block
397 		| SEARCH search_block
398 		;
399 nserver_block	: '{' optnl nserveropts_l '}'
400 			| '{' optnl '}'
401 			| nserveroptsl
402 			| /* empty */
403 			;
404 
405 nserveropts_l	: nserveropts_l nserveroptsl optnl
406 		| nserveroptsl optnl
407 		;
408 
409 nserveroptsl	: STRING {
410 			struct ra_rdnss_conf	*ra_rdnss_conf;
411 			struct in6_addr		 addr;
412 
413 			memset(&addr, 0, sizeof(addr));
414 			if (inet_pton(AF_INET6, $1, &addr)
415 			    != 1) {
416 				yyerror("error parsing nameserver address %s",
417 				    $1);
418 				free($1);
419 				YYERROR;
420 			}
421 			if ((ra_rdnss_conf = calloc(1, sizeof(*ra_rdnss_conf)))
422 			    == NULL)
423 				err(1, "%s", __func__);
424 			memcpy(&ra_rdnss_conf->rdnss, &addr, sizeof(addr));
425 			SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list,
426 			    ra_rdnss_conf, entry);
427 			ra_options->rdnss_count++;
428 		}
429 		;
430 search_block	: '{' optnl searchopts_l '}'
431 		| '{' optnl '}'
432 		| searchoptsl
433 		| /* empty */
434 		;
435 
436 searchopts_l	: searchopts_l searchoptsl optnl
437 		| searchoptsl optnl
438 		;
439 
440 searchoptsl	: STRING {
441 			struct ra_dnssl_conf	*ra_dnssl_conf;
442 			size_t			 len;
443 
444 			if ((ra_dnssl_conf = calloc(1,
445 			    sizeof(*ra_dnssl_conf))) == NULL)
446 				err(1, "%s", __func__);
447 
448 			if ((len = strlcpy(ra_dnssl_conf->search, $1,
449 			    sizeof(ra_dnssl_conf->search))) >=
450 			    sizeof(ra_dnssl_conf->search)) {
451 				yyerror("search string too long");
452 				free($1);
453 				YYERROR;
454 			}
455 			if (ra_dnssl_conf->search[len] != '.') {
456 				if ((len = strlcat(ra_dnssl_conf->search, ".",
457 				    sizeof(ra_dnssl_conf->search))) >
458 				    sizeof(ra_dnssl_conf->search)) {
459 					yyerror("search string too long");
460 					free($1);
461 					YYERROR;
462 				}
463 			}
464 			SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list,
465 			    ra_dnssl_conf, entry);
466 			ra_options->dnssl_len += len + 1;
467 		}
468 		;
469 %%
470 
471 struct keywords {
472 	const char	*k_name;
473 	int		 k_val;
474 };
475 
476 int
477 yyerror(const char *fmt, ...)
478 {
479 	va_list		 ap;
480 	char		*msg;
481 
482 	file->errors++;
483 	va_start(ap, fmt);
484 	if (vasprintf(&msg, fmt, ap) == -1)
485 		fatalx("yyerror vasprintf");
486 	va_end(ap);
487 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
488 	free(msg);
489 	return (0);
490 }
491 
492 int
493 kw_cmp(const void *k, const void *e)
494 {
495 	return (strcmp(k, ((const struct keywords *)e)->k_name));
496 }
497 
498 int
499 lookup(char *s)
500 {
501 	/* This has to be sorted always. */
502 	static const struct keywords keywords[] = {
503 		{"address",		ADDRESS},
504 		{"address-configuration",	ADDRESS_CONFIGURATION},
505 		{"auto",		AUTO},
506 		{"autonomous",		AUTONOMOUS},
507 		{"configuration",	CONFIGURATION},
508 		{"default",		DEFAULT},
509 		{"dns",			DNS},
510 		{"hop",			HOP},
511 		{"include",		INCLUDE},
512 		{"interface",		RA_IFACE},
513 		{"lifetime",		LIFETIME},
514 		{"limit",		LIMIT},
515 		{"managed",		MANAGED},
516 		{"mtu",			MTU},
517 		{"nameserver",		NAMESERVER},
518 		{"nat64",		NAT64},
519 		{"no",			NO},
520 		{"on-link",		ONLINK},
521 		{"other",		OTHER},
522 		{"preferred",		PREFERRED},
523 		{"prefix",		PREFIX},
524 		{"reachable",		REACHABLE},
525 		{"retrans",		RETRANS},
526 		{"router",		ROUTER},
527 		{"search",		SEARCH},
528 		{"time",		TIME},
529 		{"timer",		TIMER},
530 		{"valid",		VALID},
531 		{"yes",			YES},
532 	};
533 	const struct keywords	*p;
534 
535 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
536 	    sizeof(keywords[0]), kw_cmp);
537 
538 	if (p)
539 		return (p->k_val);
540 	else
541 		return (STRING);
542 }
543 
544 #define START_EXPAND	1
545 #define DONE_EXPAND	2
546 
547 static int	expanding;
548 
549 int
550 igetc(void)
551 {
552 	int	c;
553 
554 	while (1) {
555 		if (file->ungetpos > 0)
556 			c = file->ungetbuf[--file->ungetpos];
557 		else
558 			c = getc(file->stream);
559 
560 		if (c == START_EXPAND)
561 			expanding = 1;
562 		else if (c == DONE_EXPAND)
563 			expanding = 0;
564 		else
565 			break;
566 	}
567 	return (c);
568 }
569 
570 int
571 lgetc(int quotec)
572 {
573 	int		c, next;
574 
575 	if (quotec) {
576 		if ((c = igetc()) == EOF) {
577 			yyerror("reached end of file while parsing "
578 			    "quoted string");
579 			if (file == topfile || popfile() == EOF)
580 				return (EOF);
581 			return (quotec);
582 		}
583 		return (c);
584 	}
585 
586 	while ((c = igetc()) == '\\') {
587 		next = igetc();
588 		if (next != '\n') {
589 			c = next;
590 			break;
591 		}
592 		yylval.lineno = file->lineno;
593 		file->lineno++;
594 	}
595 
596 	if (c == EOF) {
597 		/*
598 		 * Fake EOL when hit EOF for the first time. This gets line
599 		 * count right if last line in included file is syntactically
600 		 * invalid and has no newline.
601 		 */
602 		if (file->eof_reached == 0) {
603 			file->eof_reached = 1;
604 			return ('\n');
605 		}
606 		while (c == EOF) {
607 			if (file == topfile || popfile() == EOF)
608 				return (EOF);
609 			c = igetc();
610 		}
611 	}
612 	return (c);
613 }
614 
615 void
616 lungetc(int c)
617 {
618 	if (c == EOF)
619 		return;
620 
621 	if (file->ungetpos >= file->ungetsize) {
622 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
623 		if (p == NULL)
624 			err(1, "lungetc");
625 		file->ungetbuf = p;
626 		file->ungetsize *= 2;
627 	}
628 	file->ungetbuf[file->ungetpos++] = c;
629 }
630 
631 int
632 findeol(void)
633 {
634 	int	c;
635 
636 	/* Skip to either EOF or the first real EOL. */
637 	while (1) {
638 		c = lgetc(0);
639 		if (c == '\n') {
640 			file->lineno++;
641 			break;
642 		}
643 		if (c == EOF)
644 			break;
645 	}
646 	return (ERROR);
647 }
648 
649 int
650 yylex(void)
651 {
652 	char	 buf[8096];
653 	char	*p, *val;
654 	int	 quotec, next, c;
655 	int	 token;
656 
657 top:
658 	p = buf;
659 	while ((c = lgetc(0)) == ' ' || c == '\t')
660 		; /* nothing */
661 
662 	yylval.lineno = file->lineno;
663 	if (c == '#')
664 		while ((c = lgetc(0)) != '\n' && c != EOF)
665 			; /* nothing */
666 	if (c == '$' && !expanding) {
667 		while (1) {
668 			if ((c = lgetc(0)) == EOF)
669 				return (0);
670 
671 			if (p + 1 >= buf + sizeof(buf) - 1) {
672 				yyerror("string too long");
673 				return (findeol());
674 			}
675 			if (isalnum(c) || c == '_') {
676 				*p++ = c;
677 				continue;
678 			}
679 			*p = '\0';
680 			lungetc(c);
681 			break;
682 		}
683 		val = symget(buf);
684 		if (val == NULL) {
685 			yyerror("macro '%s' not defined", buf);
686 			return (findeol());
687 		}
688 		p = val + strlen(val) - 1;
689 		lungetc(DONE_EXPAND);
690 		while (p >= val) {
691 			lungetc((unsigned char)*p);
692 			p--;
693 		}
694 		lungetc(START_EXPAND);
695 		goto top;
696 	}
697 
698 	switch (c) {
699 	case '\'':
700 	case '"':
701 		quotec = c;
702 		while (1) {
703 			if ((c = lgetc(quotec)) == EOF)
704 				return (0);
705 			if (c == '\n') {
706 				file->lineno++;
707 				continue;
708 			} else if (c == '\\') {
709 				if ((next = lgetc(quotec)) == EOF)
710 					return (0);
711 				if (next == quotec || next == ' ' ||
712 				    next == '\t')
713 					c = next;
714 				else if (next == '\n') {
715 					file->lineno++;
716 					continue;
717 				} else
718 					lungetc(next);
719 			} else if (c == quotec) {
720 				*p = '\0';
721 				break;
722 			} else if (c == '\0') {
723 				yyerror("syntax error");
724 				return (findeol());
725 			}
726 			if (p + 1 >= buf + sizeof(buf) - 1) {
727 				yyerror("string too long");
728 				return (findeol());
729 			}
730 			*p++ = c;
731 		}
732 		yylval.v.string = strdup(buf);
733 		if (yylval.v.string == NULL)
734 			err(1, "yylex: strdup");
735 		return (STRING);
736 	}
737 
738 #define allowed_to_end_number(x) \
739 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
740 
741 	if (c == '-' || isdigit(c)) {
742 		do {
743 			*p++ = c;
744 			if ((size_t)(p-buf) >= sizeof(buf)) {
745 				yyerror("string too long");
746 				return (findeol());
747 			}
748 		} while ((c = lgetc(0)) != EOF && isdigit(c));
749 		lungetc(c);
750 		if (p == buf + 1 && buf[0] == '-')
751 			goto nodigits;
752 		if (c == EOF || allowed_to_end_number(c)) {
753 			const char *errstr = NULL;
754 
755 			*p = '\0';
756 			yylval.v.number = strtonum(buf, LLONG_MIN,
757 			    LLONG_MAX, &errstr);
758 			if (errstr) {
759 				yyerror("\"%s\" invalid number: %s",
760 				    buf, errstr);
761 				return (findeol());
762 			}
763 			return (NUMBER);
764 		} else {
765 nodigits:
766 			while (p > buf + 1)
767 				lungetc((unsigned char)*--p);
768 			c = (unsigned char)*--p;
769 			if (c == '-')
770 				return (c);
771 		}
772 	}
773 
774 #define allowed_in_string(x) \
775 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
776 	x != '{' && x != '}' && \
777 	x != '!' && x != '=' && x != '#' && \
778 	x != ','))
779 
780 	if (isalnum(c) || c == ':' || c == '_') {
781 		do {
782 			*p++ = c;
783 			if ((size_t)(p-buf) >= sizeof(buf)) {
784 				yyerror("string too long");
785 				return (findeol());
786 			}
787 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
788 		lungetc(c);
789 		*p = '\0';
790 		if ((token = lookup(buf)) == STRING)
791 			if ((yylval.v.string = strdup(buf)) == NULL)
792 				err(1, "yylex: strdup");
793 		return (token);
794 	}
795 	if (c == '\n') {
796 		yylval.lineno = file->lineno;
797 		file->lineno++;
798 	}
799 	if (c == EOF)
800 		return (0);
801 	return (c);
802 }
803 
804 int
805 check_file_secrecy(int fd, const char *fname)
806 {
807 	struct stat	st;
808 
809 	if (fstat(fd, &st)) {
810 		log_warn("cannot stat %s", fname);
811 		return (-1);
812 	}
813 	if (st.st_uid != 0 && st.st_uid != getuid()) {
814 		log_warnx("%s: owner not root or current user", fname);
815 		return (-1);
816 	}
817 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
818 		log_warnx("%s: group writable or world read/writable", fname);
819 		return (-1);
820 	}
821 	return (0);
822 }
823 
824 struct file *
825 pushfile(const char *name, int secret)
826 {
827 	struct file	*nfile;
828 
829 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
830 		log_warn("calloc");
831 		return (NULL);
832 	}
833 	if ((nfile->name = strdup(name)) == NULL) {
834 		log_warn("strdup");
835 		free(nfile);
836 		return (NULL);
837 	}
838 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
839 		log_warn("%s", nfile->name);
840 		free(nfile->name);
841 		free(nfile);
842 		return (NULL);
843 	} else if (secret &&
844 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
845 		fclose(nfile->stream);
846 		free(nfile->name);
847 		free(nfile);
848 		return (NULL);
849 	}
850 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
851 	nfile->ungetsize = 16;
852 	nfile->ungetbuf = malloc(nfile->ungetsize);
853 	if (nfile->ungetbuf == NULL) {
854 		log_warn("malloc");
855 		fclose(nfile->stream);
856 		free(nfile->name);
857 		free(nfile);
858 		return (NULL);
859 	}
860 	TAILQ_INSERT_TAIL(&files, nfile, entry);
861 	return (nfile);
862 }
863 
864 int
865 popfile(void)
866 {
867 	struct file	*prev;
868 
869 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
870 		prev->errors += file->errors;
871 
872 	TAILQ_REMOVE(&files, file, entry);
873 	fclose(file->stream);
874 	free(file->name);
875 	free(file->ungetbuf);
876 	free(file);
877 	file = prev;
878 	return (file ? 0 : EOF);
879 }
880 
881 struct rad_conf *
882 parse_config(char *filename)
883 {
884 	struct sym		*sym, *next;
885 	struct ra_iface_conf	*iface;
886 
887 	conf = config_new_empty();
888 	ra_options = NULL;
889 
890 	file = pushfile(filename, 0);
891 	if (file == NULL) {
892 		free(conf);
893 		return (NULL);
894 	}
895 	topfile = file;
896 
897 	yyparse();
898 	errors = file->errors;
899 	popfile();
900 
901 	/* Free macros and check which have not been used. */
902 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
903 		if ((cmd_opts & OPT_VERBOSE2) && !sym->used)
904 			fprintf(stderr, "warning: macro '%s' not used\n",
905 			    sym->nam);
906 		if (!sym->persist) {
907 			free(sym->nam);
908 			free(sym->val);
909 			TAILQ_REMOVE(&symhead, sym, entry);
910 			free(sym);
911 		}
912 	}
913 
914 	if (errors) {
915 		clear_config(conf);
916 		return (NULL);
917 	}
918 
919 	if (!SIMPLEQ_EMPTY(&conf->ra_options.ra_rdnss_list) ||
920 	    !SIMPLEQ_EMPTY(&conf->ra_options.ra_dnssl_list)) {
921 		SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry)
922 			copy_dns_options(&conf->ra_options,
923 			    &iface->ra_options);
924 	}
925 
926 	if (!SIMPLEQ_EMPTY(&conf->ra_options.ra_pref64_list)) {
927 		SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry)
928 			copy_pref64_options(&conf->ra_options,
929 			    &iface->ra_options);
930 	}
931 
932 	return (conf);
933 }
934 
935 void
936 copy_dns_options(const struct ra_options_conf *src, struct ra_options_conf *dst)
937 {
938 	struct ra_rdnss_conf	*ra_rdnss, *nra_rdnss;
939 	struct ra_dnssl_conf	*ra_dnssl, *nra_dnssl;
940 
941 	if (SIMPLEQ_EMPTY(&dst->ra_rdnss_list)) {
942 		SIMPLEQ_FOREACH(ra_rdnss, &src->ra_rdnss_list, entry) {
943 			if ((nra_rdnss = calloc(1, sizeof(*nra_rdnss))) == NULL)
944 				err(1, "%s", __func__);
945 			memcpy(nra_rdnss, ra_rdnss, sizeof(*nra_rdnss));
946 			SIMPLEQ_INSERT_TAIL(&dst->ra_rdnss_list, nra_rdnss,
947 			    entry);
948 		}
949 		dst->rdnss_count = src->rdnss_count;
950 	}
951 	if (SIMPLEQ_EMPTY(&dst->ra_dnssl_list)) {
952 		SIMPLEQ_FOREACH(ra_dnssl, &src->ra_dnssl_list, entry) {
953 			if ((nra_dnssl = calloc(1, sizeof(*nra_dnssl))) == NULL)
954 				err(1, "%s", __func__);
955 			memcpy(nra_dnssl, ra_dnssl, sizeof(*nra_dnssl));
956 			SIMPLEQ_INSERT_TAIL(&dst->ra_dnssl_list, nra_dnssl,
957 			    entry);
958 		}
959 		dst->dnssl_len = src->dnssl_len;
960 	}
961 }
962 
963 void
964 copy_pref64_options(const struct ra_options_conf *src, struct ra_options_conf
965     *dst)
966 {
967 	struct ra_pref64_conf	*pref64, *npref64;
968 
969 	SIMPLEQ_FOREACH(pref64, &src->ra_pref64_list, entry) {
970 		if ((npref64 = calloc(1, sizeof(*npref64))) == NULL)
971 			err(1, "%s", __func__);
972 		memcpy(npref64, pref64, sizeof(*npref64));
973 		SIMPLEQ_INSERT_TAIL(&dst->ra_pref64_list, npref64, entry);
974 	}
975 }
976 
977 int
978 symset(const char *nam, const char *val, int persist)
979 {
980 	struct sym	*sym;
981 
982 	TAILQ_FOREACH(sym, &symhead, entry) {
983 		if (strcmp(nam, sym->nam) == 0)
984 			break;
985 	}
986 
987 	if (sym != NULL) {
988 		if (sym->persist == 1)
989 			return (0);
990 		else {
991 			free(sym->nam);
992 			free(sym->val);
993 			TAILQ_REMOVE(&symhead, sym, entry);
994 			free(sym);
995 		}
996 	}
997 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
998 		return (-1);
999 
1000 	sym->nam = strdup(nam);
1001 	if (sym->nam == NULL) {
1002 		free(sym);
1003 		return (-1);
1004 	}
1005 	sym->val = strdup(val);
1006 	if (sym->val == NULL) {
1007 		free(sym->nam);
1008 		free(sym);
1009 		return (-1);
1010 	}
1011 	sym->used = 0;
1012 	sym->persist = persist;
1013 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
1014 	return (0);
1015 }
1016 
1017 int
1018 cmdline_symset(char *s)
1019 {
1020 	char	*sym, *val;
1021 	int	ret;
1022 
1023 	if ((val = strrchr(s, '=')) == NULL)
1024 		return (-1);
1025 	sym = strndup(s, val - s);
1026 	if (sym == NULL)
1027 		errx(1, "%s: strndup", __func__);
1028 	ret = symset(sym, val + 1, 1);
1029 	free(sym);
1030 
1031 	return (ret);
1032 }
1033 
1034 char *
1035 symget(const char *nam)
1036 {
1037 	struct sym	*sym;
1038 
1039 	TAILQ_FOREACH(sym, &symhead, entry) {
1040 		if (strcmp(nam, sym->nam) == 0) {
1041 			sym->used = 1;
1042 			return (sym->val);
1043 		}
1044 	}
1045 	return (NULL);
1046 }
1047 
1048 struct ra_prefix_conf *
1049 conf_get_ra_prefix(struct in6_addr *addr, int prefixlen)
1050 {
1051 	struct ra_prefix_conf	*prefix;
1052 
1053 	if (addr == NULL) {
1054 		if (ra_iface_conf->autoprefix != NULL)
1055 			return (ra_iface_conf->autoprefix);
1056 	} else {
1057 		SIMPLEQ_FOREACH(prefix, &ra_iface_conf->ra_prefix_list, entry) {
1058 			if (prefix->prefixlen == prefixlen && memcmp(addr,
1059 			    &prefix->prefix, sizeof(*addr)) == 0)
1060 				return (prefix);
1061 		}
1062 	}
1063 
1064 	prefix = calloc(1, sizeof(*prefix));
1065 	if (prefix == NULL)
1066 		err(1, "%s", __func__);
1067 	prefix->prefixlen = prefixlen;
1068 	prefix->vltime = ADV_VALID_LIFETIME;
1069 	prefix->pltime = ADV_PREFERRED_LIFETIME;
1070 	prefix->lflag = 1;
1071 	prefix->aflag = 1;
1072 
1073 	if (addr == NULL)
1074 		ra_iface_conf->autoprefix = prefix;
1075 	else {
1076 		prefix->prefix = *addr;
1077 		SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, prefix,
1078 		    entry);
1079 	}
1080 
1081 	return (prefix);
1082 }
1083 
1084 struct ra_pref64_conf *
1085 conf_get_ra_pref64(struct in6_addr *addr, int prefixlen)
1086 {
1087 	struct ra_pref64_conf	*pref64;
1088 
1089 	SIMPLEQ_FOREACH(pref64, &ra_options->ra_pref64_list, entry) {
1090 		if (pref64->prefixlen == prefixlen && memcmp(addr,
1091 		    &pref64->prefix, sizeof(*addr)) == 0)
1092 			return (pref64);
1093 	}
1094 
1095 	pref64 = calloc(1, sizeof(*pref64));
1096 	if (pref64 == NULL)
1097 		err(1, "%s", __func__);
1098 	pref64->prefixlen = prefixlen;
1099 	pref64->ltime = ADV_DEFAULT_LIFETIME;
1100 	pref64->prefix = *addr;
1101 	SIMPLEQ_INSERT_TAIL(&ra_options->ra_pref64_list, pref64, entry);
1102 
1103 	return (pref64);
1104 }
1105 
1106 struct ra_iface_conf *
1107 conf_get_ra_iface(char *name)
1108 {
1109 	struct ra_iface_conf	*iface;
1110 	size_t			 n;
1111 
1112 	SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry) {
1113 		if (strcmp(name, iface->name) == 0)
1114 			return (iface);
1115 	}
1116 
1117 	iface = calloc(1, sizeof(*iface));
1118 	if (iface == NULL)
1119 		errx(1, "%s: calloc", __func__);
1120 	n = strlcpy(iface->name, name, sizeof(iface->name));
1121 	if (n >= sizeof(iface->name))
1122 		errx(1, "%s: name too long", __func__);
1123 
1124 	/* Inherit attributes set in global section. */
1125 	iface->ra_options = conf->ra_options;
1126 
1127 	SIMPLEQ_INIT(&iface->ra_prefix_list);
1128 	SIMPLEQ_INIT(&iface->ra_options.ra_rdnss_list);
1129 	iface->ra_options.rdnss_count = 0;
1130 	SIMPLEQ_INIT(&iface->ra_options.ra_dnssl_list);
1131 	iface->ra_options.dnssl_len = 0;
1132 	SIMPLEQ_INIT(&iface->ra_options.ra_pref64_list);
1133 
1134 	SIMPLEQ_INSERT_TAIL(&conf->ra_iface_list, iface, entry);
1135 
1136 	return (iface);
1137 }
1138 
1139 void
1140 clear_config(struct rad_conf *xconf)
1141 {
1142 	struct ra_iface_conf	*iface;
1143 
1144 	free_dns_options(&xconf->ra_options);
1145 
1146 	while((iface = SIMPLEQ_FIRST(&xconf->ra_iface_list)) != NULL) {
1147 		SIMPLEQ_REMOVE_HEAD(&xconf->ra_iface_list, entry);
1148 		free_ra_iface_conf(iface);
1149 	}
1150 
1151 	free(xconf);
1152 }
1153