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