xref: /openbsd-src/sbin/unwind/parse.y (revision cf9537f6b724ede0227e0e26a62491700c9cfa4c)
1*cf9537f6Sflorian /*	$OpenBSD: parse.y,v 1.29 2021/10/22 15:03:28 florian Exp $	*/
258b5b9b8Sflorian 
358b5b9b8Sflorian /*
458b5b9b8Sflorian  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
558b5b9b8Sflorian  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
658b5b9b8Sflorian  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
758b5b9b8Sflorian  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
858b5b9b8Sflorian  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
958b5b9b8Sflorian  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
1058b5b9b8Sflorian  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
1158b5b9b8Sflorian  *
1258b5b9b8Sflorian  * Permission to use, copy, modify, and distribute this software for any
1358b5b9b8Sflorian  * purpose with or without fee is hereby granted, provided that the above
1458b5b9b8Sflorian  * copyright notice and this permission notice appear in all copies.
1558b5b9b8Sflorian  *
1658b5b9b8Sflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1758b5b9b8Sflorian  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1858b5b9b8Sflorian  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1958b5b9b8Sflorian  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2058b5b9b8Sflorian  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2158b5b9b8Sflorian  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2258b5b9b8Sflorian  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2358b5b9b8Sflorian  */
2458b5b9b8Sflorian 
2558b5b9b8Sflorian %{
2658b5b9b8Sflorian #include <sys/queue.h>
2758b5b9b8Sflorian #include <sys/socket.h>
2858b5b9b8Sflorian #include <sys/stat.h>
2958b5b9b8Sflorian #include <sys/types.h>
3058b5b9b8Sflorian 
3158b5b9b8Sflorian #include <ctype.h>
3258b5b9b8Sflorian #include <err.h>
3358b5b9b8Sflorian #include <errno.h>
3458b5b9b8Sflorian #include <limits.h>
3558b5b9b8Sflorian #include <netdb.h>
3658b5b9b8Sflorian #include <stdarg.h>
3758b5b9b8Sflorian #include <stdint.h>
3858b5b9b8Sflorian #include <stdio.h>
3958b5b9b8Sflorian #include <syslog.h>
4058b5b9b8Sflorian #include <unistd.h>
4158b5b9b8Sflorian 
4258b5b9b8Sflorian #include "log.h"
4358b5b9b8Sflorian #include "unwind.h"
4458b5b9b8Sflorian 
4558b5b9b8Sflorian TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
4658b5b9b8Sflorian static struct file {
4758b5b9b8Sflorian 	TAILQ_ENTRY(file)	 entry;
4858b5b9b8Sflorian 	FILE			*stream;
4958b5b9b8Sflorian 	char			*name;
5058b5b9b8Sflorian 	size_t	 		 ungetpos;
5158b5b9b8Sflorian 	size_t			 ungetsize;
5258b5b9b8Sflorian 	u_char			*ungetbuf;
5358b5b9b8Sflorian 	int			 eof_reached;
5458b5b9b8Sflorian 	int			 lineno;
5558b5b9b8Sflorian 	int			 errors;
5658b5b9b8Sflorian } *file, *topfile;
5758b5b9b8Sflorian struct file	*pushfile(const char *, int);
5858b5b9b8Sflorian int		 popfile(void);
5958b5b9b8Sflorian int		 check_file_secrecy(int, const char *);
6058b5b9b8Sflorian int		 yyparse(void);
6158b5b9b8Sflorian int		 yylex(void);
6258b5b9b8Sflorian int		 yyerror(const char *, ...)
6358b5b9b8Sflorian     __attribute__((__format__ (printf, 1, 2)))
6458b5b9b8Sflorian     __attribute__((__nonnull__ (1)));
6558b5b9b8Sflorian int		 kw_cmp(const void *, const void *);
6658b5b9b8Sflorian int		 lookup(char *);
6758b5b9b8Sflorian int		 igetc(void);
6858b5b9b8Sflorian int		 lgetc(int);
6958b5b9b8Sflorian void		 lungetc(int);
7058b5b9b8Sflorian int		 findeol(void);
7158b5b9b8Sflorian 
7258b5b9b8Sflorian TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
7358b5b9b8Sflorian struct sym {
7458b5b9b8Sflorian 	TAILQ_ENTRY(sym)	 entry;
7558b5b9b8Sflorian 	int			 used;
7658b5b9b8Sflorian 	int			 persist;
7758b5b9b8Sflorian 	char			*nam;
7858b5b9b8Sflorian 	char			*val;
7958b5b9b8Sflorian };
8058b5b9b8Sflorian 
8158b5b9b8Sflorian int	 symset(const char *, const char *, int);
8258b5b9b8Sflorian char	*symget(const char *);
83fd873f7fSflorian int	 check_pref_uniq(enum uw_resolver_type);
8458b5b9b8Sflorian 
8558b5b9b8Sflorian static struct uw_conf		*conf;
8658b5b9b8Sflorian static int			 errors;
8758b5b9b8Sflorian 
8858b5b9b8Sflorian void			 clear_config(struct uw_conf *xconf);
8958b5b9b8Sflorian struct sockaddr_storage	*host_ip(const char *);
9058b5b9b8Sflorian 
9158b5b9b8Sflorian typedef struct {
9258b5b9b8Sflorian 	union {
9358b5b9b8Sflorian 		int64_t				 number;
9458b5b9b8Sflorian 		char				*string;
95dd16127bSotto 		struct force_tree		 force;
9658b5b9b8Sflorian 	} v;
9758b5b9b8Sflorian 	int lineno;
9858b5b9b8Sflorian } YYSTYPE;
9958b5b9b8Sflorian 
10058b5b9b8Sflorian %}
10158b5b9b8Sflorian 
102f3ea9bf1Sflorian %token	INCLUDE ERROR
10356fed3e1Skn %token	FORWARDER DOT PORT ODOT_FORWARDER ODOT_AUTOCONF ODOT_DHCP
10456fed3e1Skn %token	AUTHENTICATION NAME PREFERENCE RECURSOR AUTOCONF DHCP STUB
105dd16127bSotto %token	BLOCK LIST LOG FORCE ACCEPT BOGUS
10658b5b9b8Sflorian 
10758b5b9b8Sflorian %token	<v.string>	STRING
10858b5b9b8Sflorian %token	<v.number>	NUMBER
109dd16127bSotto %type	<v.number>	port dot prefopt log acceptbogus
1101463ff3cSotto %type	<v.string>	string authname
111dd16127bSotto %type	<v.force>	force_list
11258b5b9b8Sflorian 
11358b5b9b8Sflorian %%
11458b5b9b8Sflorian 
11558b5b9b8Sflorian grammar		: /* empty */
11658b5b9b8Sflorian 		| grammar include '\n'
11758b5b9b8Sflorian 		| grammar '\n'
11858b5b9b8Sflorian 		| grammar varset '\n'
119fd873f7fSflorian 		| grammar uw_pref '\n'
12058b5b9b8Sflorian 		| grammar uw_forwarder '\n'
1212d988276Sflorian 		| grammar block_list '\n'
122dd16127bSotto 		| grammar force '\n'
12358b5b9b8Sflorian 		| grammar error '\n'		{ file->errors++; }
12458b5b9b8Sflorian 		;
12558b5b9b8Sflorian 
12658b5b9b8Sflorian include		: INCLUDE STRING		{
12758b5b9b8Sflorian 			struct file	*nfile;
12858b5b9b8Sflorian 
12958b5b9b8Sflorian 			if ((nfile = pushfile($2, 0)) == NULL) {
13058b5b9b8Sflorian 				yyerror("failed to include file %s", $2);
13158b5b9b8Sflorian 				free($2);
13258b5b9b8Sflorian 				YYERROR;
13358b5b9b8Sflorian 			}
13458b5b9b8Sflorian 			free($2);
13558b5b9b8Sflorian 
13658b5b9b8Sflorian 			file = nfile;
13758b5b9b8Sflorian 			lungetc('\n');
13858b5b9b8Sflorian 		}
13958b5b9b8Sflorian 		;
14058b5b9b8Sflorian 
14158b5b9b8Sflorian string		: string STRING	{
14258b5b9b8Sflorian 			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
14358b5b9b8Sflorian 				free($1);
14458b5b9b8Sflorian 				free($2);
14558b5b9b8Sflorian 				yyerror("string: asprintf");
14658b5b9b8Sflorian 				YYERROR;
14758b5b9b8Sflorian 			}
14858b5b9b8Sflorian 			free($1);
14958b5b9b8Sflorian 			free($2);
15058b5b9b8Sflorian 		}
15158b5b9b8Sflorian 		| STRING
15258b5b9b8Sflorian 		;
15358b5b9b8Sflorian 
15458b5b9b8Sflorian varset		: STRING '=' string		{
15558b5b9b8Sflorian 			char *s = $1;
15658b5b9b8Sflorian 			if (cmd_opts & OPT_VERBOSE)
15758b5b9b8Sflorian 				printf("%s = \"%s\"\n", $1, $3);
15858b5b9b8Sflorian 			while (*s++) {
15958b5b9b8Sflorian 				if (isspace((unsigned char)*s)) {
16058b5b9b8Sflorian 					yyerror("macro name cannot contain "
16158b5b9b8Sflorian 					    "whitespace");
162570434efSotto 					free($1);
163570434efSotto 					free($3);
16458b5b9b8Sflorian 					YYERROR;
16558b5b9b8Sflorian 				}
16658b5b9b8Sflorian 			}
16758b5b9b8Sflorian 			if (symset($1, $3, 0) == -1)
16858b5b9b8Sflorian 				fatal("cannot store variable");
16958b5b9b8Sflorian 			free($1);
17058b5b9b8Sflorian 			free($3);
17158b5b9b8Sflorian 		}
17258b5b9b8Sflorian 		;
17358b5b9b8Sflorian 
17458b5b9b8Sflorian 
17558b5b9b8Sflorian optnl		: '\n' optnl		/* zero or more newlines */
17658b5b9b8Sflorian 		| /*empty*/
17758b5b9b8Sflorian 		;
17858b5b9b8Sflorian 
179ac71ec8eSflorian block_list		: BLOCK LIST STRING log {
1802d988276Sflorian 				if (conf->blocklist_file != NULL) {
1812d988276Sflorian 					yyerror("block list already "
1822d988276Sflorian 					    "configured");
1832d988276Sflorian 					free($3);
1842d988276Sflorian 					YYERROR;
1852d988276Sflorian 				} else {
1862d988276Sflorian 					conf->blocklist_file = strdup($3);
1872d988276Sflorian 					if (conf->blocklist_file == NULL)
1882d988276Sflorian 						err(1, "strdup");
1892d988276Sflorian 					free($3);
190ac71ec8eSflorian 					conf->blocklist_log = $4;
1912d988276Sflorian 				}
1922d988276Sflorian 			}
1932d988276Sflorian 			;
1942d988276Sflorian 
19561b17b6aSflorian uw_pref			: PREFERENCE {
19661b17b6aSflorian 				conf->res_pref.len = 0;
19761b17b6aSflorian 				memset(conf->enabled_resolvers, 0,
19861b17b6aSflorian 				    sizeof(conf->enabled_resolvers));
19961b17b6aSflorian 			} pref_block
200fd873f7fSflorian 			;
201fd873f7fSflorian 
202fd873f7fSflorian pref_block		: '{' optnl prefopts_l '}'
203fd873f7fSflorian 			| prefoptsl
204fd873f7fSflorian 			;
205fd873f7fSflorian 
206fd873f7fSflorian prefopts_l		: prefopts_l prefoptsl optnl
207fd873f7fSflorian 			| prefoptsl optnl
208fd873f7fSflorian 			;
209fd873f7fSflorian 
210eb720a37Sotto prefoptsl		: prefopt {
211eb720a37Sotto 				if (!check_pref_uniq($1))
212fd873f7fSflorian 					YYERROR;
213d032132bSflorian 				if (conf->res_pref.len >= UW_RES_NONE) {
214fd873f7fSflorian 					yyerror("preference list too long");
215fd873f7fSflorian 					YYERROR;
216fd873f7fSflorian 				}
217d032132bSflorian 				conf->res_pref.types[conf->res_pref.len++] = $1;
21861b17b6aSflorian 				conf->enabled_resolvers[$1] = 1;
219fd873f7fSflorian 			}
220eb720a37Sotto 			;
221eb720a37Sotto 
222eb720a37Sotto prefopt			: DOT			{ $$ = UW_RES_DOT; }
223eb720a37Sotto 			| FORWARDER		{ $$ = UW_RES_FORWARDER; }
22415fe126bSflorian 			| ODOT_FORWARDER	{ $$ = UW_RES_ODOT_FORWARDER; }
225eb720a37Sotto 			| RECURSOR		{ $$ = UW_RES_RECURSOR; }
22656fed3e1Skn 			| AUTOCONF		{ $$ = UW_RES_AUTOCONF; }
22756fed3e1Skn 			| DHCP			{ $$ = UW_RES_AUTOCONF; }
22856fed3e1Skn 			| ODOT_AUTOCONF		{ $$ = UW_RES_ODOT_AUTOCONF; }
22956fed3e1Skn 			| ODOT_DHCP		{ $$ = UW_RES_ODOT_AUTOCONF; }
230217b4d33Sflorian 			| STUB			{ $$ = UW_RES_ASR; }
231fd873f7fSflorian 			;
232fd873f7fSflorian 
23358b5b9b8Sflorian uw_forwarder		: FORWARDER forwarder_block
23458b5b9b8Sflorian 			;
23558b5b9b8Sflorian 
23658b5b9b8Sflorian forwarder_block		: '{' optnl forwarderopts_l '}'
23758b5b9b8Sflorian 			| forwarderoptsl
23858b5b9b8Sflorian 			;
23958b5b9b8Sflorian 
24058b5b9b8Sflorian forwarderopts_l		: forwarderopts_l forwarderoptsl optnl
24158b5b9b8Sflorian 			| forwarderoptsl optnl
24258b5b9b8Sflorian 			;
24358b5b9b8Sflorian 
2441463ff3cSotto forwarderoptsl		: STRING port authname dot {
245c4d4ad74Sotto 				struct uw_forwarder *uw_fwd;
24658b5b9b8Sflorian 				struct sockaddr_storage *ss;
247c4d4ad74Sotto 
24858b5b9b8Sflorian 				if ((ss = host_ip($1)) == NULL) {
24958b5b9b8Sflorian 					yyerror("%s is not an ip-address", $1);
25058b5b9b8Sflorian 					free($1);
25158b5b9b8Sflorian 					YYERROR;
25258b5b9b8Sflorian 				}
25358b5b9b8Sflorian 				free(ss);
25458b5b9b8Sflorian 
255838215f8Sflorian 				if ((uw_fwd = calloc(1, sizeof(*uw_fwd))) ==
256838215f8Sflorian 				    NULL)
257838215f8Sflorian 					err(1, NULL);
258838215f8Sflorian 
2591463ff3cSotto 				if ($2 < 0 || $2 > (int)USHRT_MAX) {
2601463ff3cSotto 					yyerror("invalid port: %lld", $2);
2611463ff3cSotto 					free($1);
262838215f8Sflorian 					free(uw_fwd);
2631463ff3cSotto 					YYERROR;
2641463ff3cSotto 				}
2651463ff3cSotto 				if ($2 == 0)
266838215f8Sflorian 					uw_fwd->port = $4 == DOT ? 853 : 53;
2671463ff3cSotto 				else
268838215f8Sflorian 					uw_fwd->port = $2;
2691463ff3cSotto 
270c4d4ad74Sotto 				if ($3 != NULL && $4 == 0) {
271c4d4ad74Sotto 					yyerror("authentication name can only "
272c4d4ad74Sotto 					    "be used with DoT");
273c4d4ad74Sotto 					free($1);
274838215f8Sflorian 					free(uw_fwd);
275c4d4ad74Sotto 					YYERROR;
276c4d4ad74Sotto 				}
277c4d4ad74Sotto 
278838215f8Sflorian 				if (strlcpy(uw_fwd->ip, $1, sizeof(uw_fwd->ip))
279838215f8Sflorian 				    >= sizeof(uw_fwd->ip)) {
280c4d4ad74Sotto 					free(uw_fwd);
28158b5b9b8Sflorian 					yyerror("forwarder %s too long", $1);
28258b5b9b8Sflorian 					free($1);
28358b5b9b8Sflorian 					YYERROR;
28458b5b9b8Sflorian 				}
28558b5b9b8Sflorian 
286838215f8Sflorian 				if ($4 == DOT && $3 != NULL) {
287838215f8Sflorian 					if (strlcpy(uw_fwd->auth_name, $3,
288838215f8Sflorian 					    sizeof(uw_fwd->auth_name))
289838215f8Sflorian 					    >= sizeof(uw_fwd->auth_name)) {
290838215f8Sflorian 						free(uw_fwd);
291838215f8Sflorian 						yyerror("authentication name "
292838215f8Sflorian 						    "%s too long", $3);
293838215f8Sflorian 						free($1);
294838215f8Sflorian 						YYERROR;
295838215f8Sflorian 					}
296838215f8Sflorian 				}
297838215f8Sflorian 
2981463ff3cSotto 				if ($4 == DOT)
2997d055805Sflorian 					TAILQ_INSERT_TAIL(
3001463ff3cSotto 					    &conf->uw_dot_forwarder_list,
301c4d4ad74Sotto 					    uw_fwd, entry);
302c4d4ad74Sotto 				else {
3037d055805Sflorian 					TAILQ_INSERT_TAIL(
3041463ff3cSotto 					    &conf->uw_forwarder_list,
305c4d4ad74Sotto 					    uw_fwd, entry);
306c4d4ad74Sotto 				}
307c4d4ad74Sotto 				free($1);
30858b5b9b8Sflorian 			}
3091463ff3cSotto 	;
31058b5b9b8Sflorian 
3111463ff3cSotto port	:	PORT NUMBER	{ $$ = $2; }
3121463ff3cSotto 	|	/* empty */	{ $$ = 0; }
3131463ff3cSotto 	;
31458b5b9b8Sflorian 
3151463ff3cSotto authname:	AUTHENTICATION NAME STRING	{ $$ = $3; }
3161463ff3cSotto 	|	/* empty */			{ $$ = NULL; }
3171463ff3cSotto 	;
31858b5b9b8Sflorian 
3191463ff3cSotto dot	:	DOT				{ $$ = DOT; }
3201463ff3cSotto 	|	/* empty */			{ $$ = 0; }
32158b5b9b8Sflorian 	;
322ac71ec8eSflorian 
323ac71ec8eSflorian log	:	LOG				{ $$ = 1; }
324ac71ec8eSflorian 	|	/* empty */			{ $$ = 0; }
325ac71ec8eSflorian 	;
326dd16127bSotto 
327dd16127bSotto force	:	FORCE acceptbogus prefopt '{' force_list optnl '}' {
328dd16127bSotto 			struct force_tree_entry *n, *nxt;
329dd16127bSotto 			int error = 0;
330dd16127bSotto 
3313bcff273Stb 			RB_FOREACH_SAFE(n, force_tree, &$5, nxt) {
332dd16127bSotto 				n->acceptbogus = $2;
333dd16127bSotto 				n->type = $3;
334dd16127bSotto 				RB_REMOVE(force_tree, &$5, n);
335dd16127bSotto 				if (RB_INSERT(force_tree, &conf->force,
336dd16127bSotto 				    n)) {
337dd16127bSotto 					yyerror("%s already in an force "
338dd16127bSotto 					    "list", n->domain);
339dd16127bSotto 					error = 1;
340dd16127bSotto 				}
341dd16127bSotto 			}
342dd16127bSotto 			if (error)
343dd16127bSotto 				YYERROR;
344dd16127bSotto 		}
345dd16127bSotto 	;
346dd16127bSotto 
347dd16127bSotto acceptbogus:	ACCEPT BOGUS	{ $$ = 1; }
348dd16127bSotto 	|	/* empty */	{ $$ = 0; }
349dd16127bSotto 	;
350dd16127bSotto 
351dd16127bSotto force_list:	force_list optnl STRING {
352dd16127bSotto 			struct force_tree_entry	*e;
353dd16127bSotto 			size_t				 len;
354dd16127bSotto 
355dd16127bSotto 			len = strlen($3);
356dd16127bSotto 			e = malloc(sizeof(*e));
357dd16127bSotto 			if (e == NULL)
358dd16127bSotto 				err(1, NULL);
359dd16127bSotto 			if (strlcpy(e->domain, $3, sizeof(e->domain)) >=
360dd16127bSotto 			    sizeof(e->domain)) {
361dd16127bSotto 				yyerror("force %s too long", $3);
362dd16127bSotto 				free($3);
363dd16127bSotto 				YYERROR;
364dd16127bSotto 			}
365dd16127bSotto 			free($3);
366dd16127bSotto 			if (len == 0 || e->domain[len-1] != '.') {
367dd16127bSotto 				if (strlcat(e->domain, ".",
368dd16127bSotto 				    sizeof((e->domain))) >=
369dd16127bSotto 				    sizeof((e->domain))) {
370dd16127bSotto 					yyerror("force %s too long", $3);
371dd16127bSotto 					YYERROR;
372dd16127bSotto 				}
373dd16127bSotto 			}
374dbebd753Stb 			if (RB_INSERT(force_tree, &$$, e) != NULL) {
375dbebd753Stb 				log_warnx("duplicate force %s", e->domain);
376dbebd753Stb 				free(e);
377dbebd753Stb 			}
378dd16127bSotto 		}
379dd16127bSotto 	|	/* empty */ {
380dd16127bSotto 			RB_INIT(&$$);
381dd16127bSotto 		}
382dd16127bSotto 	;
383dd16127bSotto 
38458b5b9b8Sflorian %%
38558b5b9b8Sflorian 
38658b5b9b8Sflorian struct keywords {
38758b5b9b8Sflorian 	const char	*k_name;
38858b5b9b8Sflorian 	int		 k_val;
38958b5b9b8Sflorian };
39058b5b9b8Sflorian 
39158b5b9b8Sflorian int
yyerror(const char * fmt,...)39258b5b9b8Sflorian yyerror(const char *fmt, ...)
39358b5b9b8Sflorian {
39458b5b9b8Sflorian 	va_list		 ap;
39558b5b9b8Sflorian 	char		*msg;
39658b5b9b8Sflorian 
39758b5b9b8Sflorian 	file->errors++;
39858b5b9b8Sflorian 	va_start(ap, fmt);
39958b5b9b8Sflorian 	if (vasprintf(&msg, fmt, ap) == -1)
40058b5b9b8Sflorian 		fatalx("yyerror vasprintf");
40158b5b9b8Sflorian 	va_end(ap);
40258b5b9b8Sflorian 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
40358b5b9b8Sflorian 	free(msg);
40458b5b9b8Sflorian 	return (0);
40558b5b9b8Sflorian }
40658b5b9b8Sflorian 
40758b5b9b8Sflorian int
kw_cmp(const void * k,const void * e)40858b5b9b8Sflorian kw_cmp(const void *k, const void *e)
40958b5b9b8Sflorian {
41058b5b9b8Sflorian 	return (strcmp(k, ((const struct keywords *)e)->k_name));
41158b5b9b8Sflorian }
41258b5b9b8Sflorian 
41358b5b9b8Sflorian int
lookup(char * s)41458b5b9b8Sflorian lookup(char *s)
41558b5b9b8Sflorian {
41658b5b9b8Sflorian 	/* This has to be sorted always. */
41758b5b9b8Sflorian 	static const struct keywords keywords[] = {
41858b5b9b8Sflorian 		{"DoT",			DOT},
419dd16127bSotto 		{"accept",		ACCEPT},
4203461bfbeSflorian 		{"authentication",	AUTHENTICATION},
42156fed3e1Skn 		{"autoconf",		AUTOCONF},
4222d988276Sflorian 		{"block",		BLOCK},
423dd16127bSotto 		{"bogus",		BOGUS},
424fd873f7fSflorian 		{"dhcp",		DHCP},
42558b5b9b8Sflorian 		{"dot",			DOT},
426dd16127bSotto 		{"force",		FORCE},
42758b5b9b8Sflorian 		{"forwarder",		FORWARDER},
42858b5b9b8Sflorian 		{"include",		INCLUDE},
4292d988276Sflorian 		{"list",		LIST},
430ac71ec8eSflorian 		{"log",			LOG},
4313461bfbeSflorian 		{"name",		NAME},
43256fed3e1Skn 		{"oDoT-autoconf",	ODOT_AUTOCONF},
43315fe126bSflorian 		{"oDoT-dhcp",		ODOT_DHCP},
43415fe126bSflorian 		{"oDoT-forwarder",	ODOT_FORWARDER},
43558b5b9b8Sflorian 		{"port",		PORT},
436fd873f7fSflorian 		{"preference",		PREFERENCE},
437fd873f7fSflorian 		{"recursor",		RECURSOR},
438217b4d33Sflorian 		{"stub",		STUB},
43958b5b9b8Sflorian 		{"tls",			DOT},
44058b5b9b8Sflorian 	};
44158b5b9b8Sflorian 	const struct keywords	*p;
44258b5b9b8Sflorian 
44358b5b9b8Sflorian 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
44458b5b9b8Sflorian 	    sizeof(keywords[0]), kw_cmp);
44558b5b9b8Sflorian 
44658b5b9b8Sflorian 	if (p)
44758b5b9b8Sflorian 		return (p->k_val);
44858b5b9b8Sflorian 	else
44958b5b9b8Sflorian 		return (STRING);
45058b5b9b8Sflorian }
45158b5b9b8Sflorian 
45258b5b9b8Sflorian #define START_EXPAND	1
45358b5b9b8Sflorian #define DONE_EXPAND	2
45458b5b9b8Sflorian 
45558b5b9b8Sflorian static int	expanding;
45658b5b9b8Sflorian 
45758b5b9b8Sflorian int
igetc(void)45858b5b9b8Sflorian igetc(void)
45958b5b9b8Sflorian {
46058b5b9b8Sflorian 	int	c;
46158b5b9b8Sflorian 
46258b5b9b8Sflorian 	while (1) {
46358b5b9b8Sflorian 		if (file->ungetpos > 0)
46458b5b9b8Sflorian 			c = file->ungetbuf[--file->ungetpos];
46558b5b9b8Sflorian 		else
46658b5b9b8Sflorian 			c = getc(file->stream);
46758b5b9b8Sflorian 
46858b5b9b8Sflorian 		if (c == START_EXPAND)
46958b5b9b8Sflorian 			expanding = 1;
47058b5b9b8Sflorian 		else if (c == DONE_EXPAND)
47158b5b9b8Sflorian 			expanding = 0;
47258b5b9b8Sflorian 		else
47358b5b9b8Sflorian 			break;
47458b5b9b8Sflorian 	}
47558b5b9b8Sflorian 	return (c);
47658b5b9b8Sflorian }
47758b5b9b8Sflorian 
47858b5b9b8Sflorian int
lgetc(int quotec)47958b5b9b8Sflorian lgetc(int quotec)
48058b5b9b8Sflorian {
48158b5b9b8Sflorian 	int		c, next;
48258b5b9b8Sflorian 
48358b5b9b8Sflorian 	if (quotec) {
48458b5b9b8Sflorian 		if ((c = igetc()) == EOF) {
48558b5b9b8Sflorian 			yyerror("reached end of file while parsing "
48658b5b9b8Sflorian 			    "quoted string");
48758b5b9b8Sflorian 			if (file == topfile || popfile() == EOF)
48858b5b9b8Sflorian 				return (EOF);
48958b5b9b8Sflorian 			return (quotec);
49058b5b9b8Sflorian 		}
49158b5b9b8Sflorian 		return (c);
49258b5b9b8Sflorian 	}
49358b5b9b8Sflorian 
49458b5b9b8Sflorian 	while ((c = igetc()) == '\\') {
49558b5b9b8Sflorian 		next = igetc();
49658b5b9b8Sflorian 		if (next != '\n') {
49758b5b9b8Sflorian 			c = next;
49858b5b9b8Sflorian 			break;
49958b5b9b8Sflorian 		}
50058b5b9b8Sflorian 		yylval.lineno = file->lineno;
50158b5b9b8Sflorian 		file->lineno++;
50258b5b9b8Sflorian 	}
50358b5b9b8Sflorian 
50458b5b9b8Sflorian 	if (c == EOF) {
50558b5b9b8Sflorian 		/*
50658b5b9b8Sflorian 		 * Fake EOL when hit EOF for the first time. This gets line
50758b5b9b8Sflorian 		 * count right if last line in included file is syntactically
50858b5b9b8Sflorian 		 * invalid and has no newline.
50958b5b9b8Sflorian 		 */
51058b5b9b8Sflorian 		if (file->eof_reached == 0) {
51158b5b9b8Sflorian 			file->eof_reached = 1;
51258b5b9b8Sflorian 			return ('\n');
51358b5b9b8Sflorian 		}
51458b5b9b8Sflorian 		while (c == EOF) {
51558b5b9b8Sflorian 			if (file == topfile || popfile() == EOF)
51658b5b9b8Sflorian 				return (EOF);
51758b5b9b8Sflorian 			c = igetc();
51858b5b9b8Sflorian 		}
51958b5b9b8Sflorian 	}
52058b5b9b8Sflorian 	return (c);
52158b5b9b8Sflorian }
52258b5b9b8Sflorian 
52358b5b9b8Sflorian void
lungetc(int c)52458b5b9b8Sflorian lungetc(int c)
52558b5b9b8Sflorian {
52658b5b9b8Sflorian 	if (c == EOF)
52758b5b9b8Sflorian 		return;
52858b5b9b8Sflorian 
52958b5b9b8Sflorian 	if (file->ungetpos >= file->ungetsize) {
53058b5b9b8Sflorian 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
53158b5b9b8Sflorian 		if (p == NULL)
53258b5b9b8Sflorian 			err(1, "lungetc");
53358b5b9b8Sflorian 		file->ungetbuf = p;
53458b5b9b8Sflorian 		file->ungetsize *= 2;
53558b5b9b8Sflorian 	}
53658b5b9b8Sflorian 	file->ungetbuf[file->ungetpos++] = c;
53758b5b9b8Sflorian }
53858b5b9b8Sflorian 
53958b5b9b8Sflorian int
findeol(void)54058b5b9b8Sflorian findeol(void)
54158b5b9b8Sflorian {
54258b5b9b8Sflorian 	int	c;
54358b5b9b8Sflorian 
54458b5b9b8Sflorian 	/* Skip to either EOF or the first real EOL. */
54558b5b9b8Sflorian 	while (1) {
54658b5b9b8Sflorian 		c = lgetc(0);
54758b5b9b8Sflorian 		if (c == '\n') {
54858b5b9b8Sflorian 			file->lineno++;
54958b5b9b8Sflorian 			break;
55058b5b9b8Sflorian 		}
55158b5b9b8Sflorian 		if (c == EOF)
55258b5b9b8Sflorian 			break;
55358b5b9b8Sflorian 	}
55458b5b9b8Sflorian 	return (ERROR);
55558b5b9b8Sflorian }
55658b5b9b8Sflorian 
55758b5b9b8Sflorian int
yylex(void)55858b5b9b8Sflorian yylex(void)
55958b5b9b8Sflorian {
56008f6ba19Snaddy 	char	 buf[8096];
56108f6ba19Snaddy 	char	*p, *val;
56258b5b9b8Sflorian 	int	 quotec, next, c;
56358b5b9b8Sflorian 	int	 token;
56458b5b9b8Sflorian 
56558b5b9b8Sflorian top:
56658b5b9b8Sflorian 	p = buf;
56758b5b9b8Sflorian 	while ((c = lgetc(0)) == ' ' || c == '\t')
56858b5b9b8Sflorian 		; /* nothing */
56958b5b9b8Sflorian 
57058b5b9b8Sflorian 	yylval.lineno = file->lineno;
57158b5b9b8Sflorian 	if (c == '#')
57258b5b9b8Sflorian 		while ((c = lgetc(0)) != '\n' && c != EOF)
57358b5b9b8Sflorian 			; /* nothing */
57458b5b9b8Sflorian 	if (c == '$' && !expanding) {
57558b5b9b8Sflorian 		while (1) {
57658b5b9b8Sflorian 			if ((c = lgetc(0)) == EOF)
57758b5b9b8Sflorian 				return (0);
57858b5b9b8Sflorian 
57958b5b9b8Sflorian 			if (p + 1 >= buf + sizeof(buf) - 1) {
58058b5b9b8Sflorian 				yyerror("string too long");
58158b5b9b8Sflorian 				return (findeol());
58258b5b9b8Sflorian 			}
58358b5b9b8Sflorian 			if (isalnum(c) || c == '_') {
58458b5b9b8Sflorian 				*p++ = c;
58558b5b9b8Sflorian 				continue;
58658b5b9b8Sflorian 			}
58758b5b9b8Sflorian 			*p = '\0';
58858b5b9b8Sflorian 			lungetc(c);
58958b5b9b8Sflorian 			break;
59058b5b9b8Sflorian 		}
59158b5b9b8Sflorian 		val = symget(buf);
59258b5b9b8Sflorian 		if (val == NULL) {
59358b5b9b8Sflorian 			yyerror("macro '%s' not defined", buf);
59458b5b9b8Sflorian 			return (findeol());
59558b5b9b8Sflorian 		}
59658b5b9b8Sflorian 		p = val + strlen(val) - 1;
59758b5b9b8Sflorian 		lungetc(DONE_EXPAND);
59858b5b9b8Sflorian 		while (p >= val) {
59908f6ba19Snaddy 			lungetc((unsigned char)*p);
60058b5b9b8Sflorian 			p--;
60158b5b9b8Sflorian 		}
60258b5b9b8Sflorian 		lungetc(START_EXPAND);
60358b5b9b8Sflorian 		goto top;
60458b5b9b8Sflorian 	}
60558b5b9b8Sflorian 
60658b5b9b8Sflorian 	switch (c) {
60758b5b9b8Sflorian 	case '\'':
60858b5b9b8Sflorian 	case '"':
60958b5b9b8Sflorian 		quotec = c;
61058b5b9b8Sflorian 		while (1) {
61158b5b9b8Sflorian 			if ((c = lgetc(quotec)) == EOF)
61258b5b9b8Sflorian 				return (0);
61358b5b9b8Sflorian 			if (c == '\n') {
61458b5b9b8Sflorian 				file->lineno++;
61558b5b9b8Sflorian 				continue;
61658b5b9b8Sflorian 			} else if (c == '\\') {
61758b5b9b8Sflorian 				if ((next = lgetc(quotec)) == EOF)
61858b5b9b8Sflorian 					return (0);
61958b5b9b8Sflorian 				if (next == quotec || next == ' ' ||
62058b5b9b8Sflorian 				    next == '\t')
62158b5b9b8Sflorian 					c = next;
62258b5b9b8Sflorian 				else if (next == '\n') {
62358b5b9b8Sflorian 					file->lineno++;
62458b5b9b8Sflorian 					continue;
62558b5b9b8Sflorian 				} else
62658b5b9b8Sflorian 					lungetc(next);
62758b5b9b8Sflorian 			} else if (c == quotec) {
62858b5b9b8Sflorian 				*p = '\0';
62958b5b9b8Sflorian 				break;
63058b5b9b8Sflorian 			} else if (c == '\0') {
63158b5b9b8Sflorian 				yyerror("syntax error");
63258b5b9b8Sflorian 				return (findeol());
63358b5b9b8Sflorian 			}
63458b5b9b8Sflorian 			if (p + 1 >= buf + sizeof(buf) - 1) {
63558b5b9b8Sflorian 				yyerror("string too long");
63658b5b9b8Sflorian 				return (findeol());
63758b5b9b8Sflorian 			}
63858b5b9b8Sflorian 			*p++ = c;
63958b5b9b8Sflorian 		}
64058b5b9b8Sflorian 		yylval.v.string = strdup(buf);
64158b5b9b8Sflorian 		if (yylval.v.string == NULL)
64258b5b9b8Sflorian 			err(1, "yylex: strdup");
64358b5b9b8Sflorian 		return (STRING);
64458b5b9b8Sflorian 	}
64558b5b9b8Sflorian 
64658b5b9b8Sflorian #define allowed_to_end_number(x) \
64758b5b9b8Sflorian 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
64858b5b9b8Sflorian 
64958b5b9b8Sflorian 	if (c == '-' || isdigit(c)) {
65058b5b9b8Sflorian 		do {
65158b5b9b8Sflorian 			*p++ = c;
65258b5b9b8Sflorian 			if ((size_t)(p-buf) >= sizeof(buf)) {
65358b5b9b8Sflorian 				yyerror("string too long");
65458b5b9b8Sflorian 				return (findeol());
65558b5b9b8Sflorian 			}
65658b5b9b8Sflorian 		} while ((c = lgetc(0)) != EOF && isdigit(c));
65758b5b9b8Sflorian 		lungetc(c);
65858b5b9b8Sflorian 		if (p == buf + 1 && buf[0] == '-')
65958b5b9b8Sflorian 			goto nodigits;
66058b5b9b8Sflorian 		if (c == EOF || allowed_to_end_number(c)) {
66158b5b9b8Sflorian 			const char *errstr = NULL;
66258b5b9b8Sflorian 
66358b5b9b8Sflorian 			*p = '\0';
66458b5b9b8Sflorian 			yylval.v.number = strtonum(buf, LLONG_MIN,
66558b5b9b8Sflorian 			    LLONG_MAX, &errstr);
66658b5b9b8Sflorian 			if (errstr) {
66758b5b9b8Sflorian 				yyerror("\"%s\" invalid number: %s",
66858b5b9b8Sflorian 				    buf, errstr);
66958b5b9b8Sflorian 				return (findeol());
67058b5b9b8Sflorian 			}
67158b5b9b8Sflorian 			return (NUMBER);
67258b5b9b8Sflorian 		} else {
67358b5b9b8Sflorian nodigits:
67458b5b9b8Sflorian 			while (p > buf + 1)
67508f6ba19Snaddy 				lungetc((unsigned char)*--p);
67608f6ba19Snaddy 			c = (unsigned char)*--p;
67758b5b9b8Sflorian 			if (c == '-')
67858b5b9b8Sflorian 				return (c);
67958b5b9b8Sflorian 		}
68058b5b9b8Sflorian 	}
68158b5b9b8Sflorian 
68258b5b9b8Sflorian #define allowed_in_string(x) \
68358b5b9b8Sflorian 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
68458b5b9b8Sflorian 	x != '{' && x != '}' && \
68558b5b9b8Sflorian 	x != '!' && x != '=' && x != '#' && \
68658b5b9b8Sflorian 	x != ','))
68758b5b9b8Sflorian 
68858b5b9b8Sflorian 	if (isalnum(c) || c == ':' || c == '_') {
68958b5b9b8Sflorian 		do {
69058b5b9b8Sflorian 			*p++ = c;
69158b5b9b8Sflorian 			if ((size_t)(p-buf) >= sizeof(buf)) {
69258b5b9b8Sflorian 				yyerror("string too long");
69358b5b9b8Sflorian 				return (findeol());
69458b5b9b8Sflorian 			}
69558b5b9b8Sflorian 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
69658b5b9b8Sflorian 		lungetc(c);
69758b5b9b8Sflorian 		*p = '\0';
69858b5b9b8Sflorian 		if ((token = lookup(buf)) == STRING)
69958b5b9b8Sflorian 			if ((yylval.v.string = strdup(buf)) == NULL)
70058b5b9b8Sflorian 				err(1, "yylex: strdup");
70158b5b9b8Sflorian 		return (token);
70258b5b9b8Sflorian 	}
70358b5b9b8Sflorian 	if (c == '\n') {
70458b5b9b8Sflorian 		yylval.lineno = file->lineno;
70558b5b9b8Sflorian 		file->lineno++;
70658b5b9b8Sflorian 	}
70758b5b9b8Sflorian 	if (c == EOF)
70858b5b9b8Sflorian 		return (0);
70958b5b9b8Sflorian 	return (c);
71058b5b9b8Sflorian }
71158b5b9b8Sflorian 
71258b5b9b8Sflorian int
check_file_secrecy(int fd,const char * fname)71358b5b9b8Sflorian check_file_secrecy(int fd, const char *fname)
71458b5b9b8Sflorian {
71558b5b9b8Sflorian 	struct stat	st;
71658b5b9b8Sflorian 
71758b5b9b8Sflorian 	if (fstat(fd, &st)) {
71858b5b9b8Sflorian 		log_warn("cannot stat %s", fname);
71958b5b9b8Sflorian 		return (-1);
72058b5b9b8Sflorian 	}
72158b5b9b8Sflorian 	if (st.st_uid != 0 && st.st_uid != getuid()) {
72258b5b9b8Sflorian 		log_warnx("%s: owner not root or current user", fname);
72358b5b9b8Sflorian 		return (-1);
72458b5b9b8Sflorian 	}
72558b5b9b8Sflorian 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
72658b5b9b8Sflorian 		log_warnx("%s: group writable or world read/writable", fname);
72758b5b9b8Sflorian 		return (-1);
72858b5b9b8Sflorian 	}
72958b5b9b8Sflorian 	return (0);
73058b5b9b8Sflorian }
73158b5b9b8Sflorian 
73258b5b9b8Sflorian struct file *
pushfile(const char * name,int secret)73358b5b9b8Sflorian pushfile(const char *name, int secret)
73458b5b9b8Sflorian {
73558b5b9b8Sflorian 	struct file	*nfile;
73658b5b9b8Sflorian 
73758b5b9b8Sflorian 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
73858b5b9b8Sflorian 		log_warn("calloc");
73958b5b9b8Sflorian 		return (NULL);
74058b5b9b8Sflorian 	}
74158b5b9b8Sflorian 	if ((nfile->name = strdup(name)) == NULL) {
74258b5b9b8Sflorian 		log_warn("strdup");
74358b5b9b8Sflorian 		free(nfile);
74458b5b9b8Sflorian 		return (NULL);
74558b5b9b8Sflorian 	}
74658b5b9b8Sflorian 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
74758b5b9b8Sflorian 		free(nfile->name);
74858b5b9b8Sflorian 		free(nfile);
74958b5b9b8Sflorian 		return (NULL);
75058b5b9b8Sflorian 	} else if (secret &&
75158b5b9b8Sflorian 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
75258b5b9b8Sflorian 		fclose(nfile->stream);
75358b5b9b8Sflorian 		free(nfile->name);
75458b5b9b8Sflorian 		free(nfile);
75558b5b9b8Sflorian 		return (NULL);
75658b5b9b8Sflorian 	}
75758b5b9b8Sflorian 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
75858b5b9b8Sflorian 	nfile->ungetsize = 16;
75958b5b9b8Sflorian 	nfile->ungetbuf = malloc(nfile->ungetsize);
76058b5b9b8Sflorian 	if (nfile->ungetbuf == NULL) {
76158b5b9b8Sflorian 		log_warn("malloc");
76258b5b9b8Sflorian 		fclose(nfile->stream);
76358b5b9b8Sflorian 		free(nfile->name);
76458b5b9b8Sflorian 		free(nfile);
76558b5b9b8Sflorian 		return (NULL);
76658b5b9b8Sflorian 	}
76758b5b9b8Sflorian 	TAILQ_INSERT_TAIL(&files, nfile, entry);
76858b5b9b8Sflorian 	return (nfile);
76958b5b9b8Sflorian }
77058b5b9b8Sflorian 
77158b5b9b8Sflorian int
popfile(void)77258b5b9b8Sflorian popfile(void)
77358b5b9b8Sflorian {
77458b5b9b8Sflorian 	struct file	*prev;
77558b5b9b8Sflorian 
77658b5b9b8Sflorian 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
77758b5b9b8Sflorian 		prev->errors += file->errors;
77858b5b9b8Sflorian 
77958b5b9b8Sflorian 	TAILQ_REMOVE(&files, file, entry);
78058b5b9b8Sflorian 	fclose(file->stream);
78158b5b9b8Sflorian 	free(file->name);
78258b5b9b8Sflorian 	free(file->ungetbuf);
78358b5b9b8Sflorian 	free(file);
78458b5b9b8Sflorian 	file = prev;
78558b5b9b8Sflorian 	return (file ? 0 : EOF);
78658b5b9b8Sflorian }
78758b5b9b8Sflorian 
78858b5b9b8Sflorian struct uw_conf *
parse_config(char * filename)789572e5ac0Skn parse_config(char *filename)
79058b5b9b8Sflorian {
791*cf9537f6Sflorian 	static enum uw_resolver_type	 default_res_pref[] = {
792*cf9537f6Sflorian 	    UW_RES_DOT,
793*cf9537f6Sflorian 	    UW_RES_ODOT_FORWARDER,
794*cf9537f6Sflorian 	    UW_RES_FORWARDER,
795*cf9537f6Sflorian 	    UW_RES_RECURSOR,
796*cf9537f6Sflorian 	    UW_RES_ODOT_AUTOCONF,
797*cf9537f6Sflorian 	    UW_RES_AUTOCONF,
798*cf9537f6Sflorian 	    UW_RES_ASR};
79958b5b9b8Sflorian 	struct sym			*sym, *next;
800*cf9537f6Sflorian 	int				 i;
80158b5b9b8Sflorian 
80258b5b9b8Sflorian 	conf = config_new_empty();
80358b5b9b8Sflorian 
804*cf9537f6Sflorian 	memcpy(&conf->res_pref.types, &default_res_pref,
805*cf9537f6Sflorian 	    sizeof(default_res_pref));
806*cf9537f6Sflorian 	conf->res_pref.len = nitems(default_res_pref);
807*cf9537f6Sflorian 	for (i = 0; i < conf->res_pref.len; i++)
808*cf9537f6Sflorian 		conf->enabled_resolvers[conf->res_pref.types[i]] = 1;
809*cf9537f6Sflorian 
810ee5be195Sflorian 	file = pushfile(filename != NULL ? filename : _PATH_CONF_FILE, 0);
81158b5b9b8Sflorian 	if (file == NULL) {
812572e5ac0Skn 		/* no default config file is fine */
813572e5ac0Skn 		if (errno == ENOENT && filename == NULL)
81458b5b9b8Sflorian 			return (conf);
81558b5b9b8Sflorian 		log_warn("%s", filename);
81658b5b9b8Sflorian 		free(conf);
81758b5b9b8Sflorian 		return (NULL);
81858b5b9b8Sflorian 	}
81958b5b9b8Sflorian 	topfile = file;
82058b5b9b8Sflorian 
82158b5b9b8Sflorian 	yyparse();
82258b5b9b8Sflorian 	errors = file->errors;
82358b5b9b8Sflorian 	popfile();
82458b5b9b8Sflorian 
82558b5b9b8Sflorian 	/* Free macros and check which have not been used. */
82658b5b9b8Sflorian 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
82758b5b9b8Sflorian 		if ((cmd_opts & OPT_VERBOSE2) && !sym->used)
82858b5b9b8Sflorian 			fprintf(stderr, "warning: macro '%s' not used\n",
82958b5b9b8Sflorian 			    sym->nam);
83058b5b9b8Sflorian 		if (!sym->persist) {
83158b5b9b8Sflorian 			free(sym->nam);
83258b5b9b8Sflorian 			free(sym->val);
83358b5b9b8Sflorian 			TAILQ_REMOVE(&symhead, sym, entry);
83458b5b9b8Sflorian 			free(sym);
83558b5b9b8Sflorian 		}
83658b5b9b8Sflorian 	}
83758b5b9b8Sflorian 
83858b5b9b8Sflorian 	if (errors) {
83958b5b9b8Sflorian 		clear_config(conf);
84058b5b9b8Sflorian 		return (NULL);
84158b5b9b8Sflorian 	}
84258b5b9b8Sflorian 
84358b5b9b8Sflorian 	return (conf);
84458b5b9b8Sflorian }
84558b5b9b8Sflorian 
84658b5b9b8Sflorian int
symset(const char * nam,const char * val,int persist)84758b5b9b8Sflorian symset(const char *nam, const char *val, int persist)
84858b5b9b8Sflorian {
84958b5b9b8Sflorian 	struct sym	*sym;
85058b5b9b8Sflorian 
85158b5b9b8Sflorian 	TAILQ_FOREACH(sym, &symhead, entry) {
85258b5b9b8Sflorian 		if (strcmp(nam, sym->nam) == 0)
85358b5b9b8Sflorian 			break;
85458b5b9b8Sflorian 	}
85558b5b9b8Sflorian 
85658b5b9b8Sflorian 	if (sym != NULL) {
85758b5b9b8Sflorian 		if (sym->persist == 1)
85858b5b9b8Sflorian 			return (0);
85958b5b9b8Sflorian 		else {
86058b5b9b8Sflorian 			free(sym->nam);
86158b5b9b8Sflorian 			free(sym->val);
86258b5b9b8Sflorian 			TAILQ_REMOVE(&symhead, sym, entry);
86358b5b9b8Sflorian 			free(sym);
86458b5b9b8Sflorian 		}
86558b5b9b8Sflorian 	}
86658b5b9b8Sflorian 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
86758b5b9b8Sflorian 		return (-1);
86858b5b9b8Sflorian 
86958b5b9b8Sflorian 	sym->nam = strdup(nam);
87058b5b9b8Sflorian 	if (sym->nam == NULL) {
87158b5b9b8Sflorian 		free(sym);
87258b5b9b8Sflorian 		return (-1);
87358b5b9b8Sflorian 	}
87458b5b9b8Sflorian 	sym->val = strdup(val);
87558b5b9b8Sflorian 	if (sym->val == NULL) {
87658b5b9b8Sflorian 		free(sym->nam);
87758b5b9b8Sflorian 		free(sym);
87858b5b9b8Sflorian 		return (-1);
87958b5b9b8Sflorian 	}
88058b5b9b8Sflorian 	sym->used = 0;
88158b5b9b8Sflorian 	sym->persist = persist;
88258b5b9b8Sflorian 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
88358b5b9b8Sflorian 	return (0);
88458b5b9b8Sflorian }
88558b5b9b8Sflorian 
88658b5b9b8Sflorian int
cmdline_symset(char * s)88758b5b9b8Sflorian cmdline_symset(char *s)
88858b5b9b8Sflorian {
88958b5b9b8Sflorian 	char	*sym, *val;
89058b5b9b8Sflorian 	int	ret;
89158b5b9b8Sflorian 
89258b5b9b8Sflorian 	if ((val = strrchr(s, '=')) == NULL)
89358b5b9b8Sflorian 		return (-1);
89458b5b9b8Sflorian 	sym = strndup(s, val - s);
89558b5b9b8Sflorian 	if (sym == NULL)
89658b5b9b8Sflorian 		errx(1, "%s: strndup", __func__);
89758b5b9b8Sflorian 	ret = symset(sym, val + 1, 1);
89858b5b9b8Sflorian 	free(sym);
89958b5b9b8Sflorian 
90058b5b9b8Sflorian 	return (ret);
90158b5b9b8Sflorian }
90258b5b9b8Sflorian 
90358b5b9b8Sflorian char *
symget(const char * nam)90458b5b9b8Sflorian symget(const char *nam)
90558b5b9b8Sflorian {
90658b5b9b8Sflorian 	struct sym	*sym;
90758b5b9b8Sflorian 
90858b5b9b8Sflorian 	TAILQ_FOREACH(sym, &symhead, entry) {
90958b5b9b8Sflorian 		if (strcmp(nam, sym->nam) == 0) {
91058b5b9b8Sflorian 			sym->used = 1;
91158b5b9b8Sflorian 			return (sym->val);
91258b5b9b8Sflorian 		}
91358b5b9b8Sflorian 	}
91458b5b9b8Sflorian 	return (NULL);
91558b5b9b8Sflorian }
91658b5b9b8Sflorian 
91758b5b9b8Sflorian void
clear_config(struct uw_conf * xconf)91858b5b9b8Sflorian clear_config(struct uw_conf *xconf)
91958b5b9b8Sflorian {
920c4d4ad74Sotto 	struct uw_forwarder	*uw_forwarder;
921c4d4ad74Sotto 
9227d055805Sflorian 	while ((uw_forwarder = TAILQ_FIRST(&xconf->uw_forwarder_list)) !=
92358b5b9b8Sflorian 	    NULL) {
9247d055805Sflorian 		TAILQ_REMOVE(&xconf->uw_forwarder_list, uw_forwarder, entry);
92558b5b9b8Sflorian 		free(uw_forwarder);
92658b5b9b8Sflorian 	}
9277d055805Sflorian 	while ((uw_forwarder = TAILQ_FIRST(&xconf->uw_dot_forwarder_list)) !=
92858b5b9b8Sflorian 	    NULL) {
9297d055805Sflorian 		TAILQ_REMOVE(&xconf->uw_dot_forwarder_list, uw_forwarder,
9307d055805Sflorian 		    entry);
93158b5b9b8Sflorian 		free(uw_forwarder);
93258b5b9b8Sflorian 	}
93358b5b9b8Sflorian 
93458b5b9b8Sflorian 	free(xconf);
93558b5b9b8Sflorian }
93658b5b9b8Sflorian 
93758b5b9b8Sflorian struct sockaddr_storage *
host_ip(const char * s)93858b5b9b8Sflorian host_ip(const char *s)
93958b5b9b8Sflorian {
94058b5b9b8Sflorian 	struct addrinfo	 hints, *res;
94158b5b9b8Sflorian 	struct sockaddr_storage	*ss = NULL;
94258b5b9b8Sflorian 
94358b5b9b8Sflorian 	memset(&hints, 0, sizeof(hints));
94458b5b9b8Sflorian 	hints.ai_family = AF_UNSPEC;
94558b5b9b8Sflorian 	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
94658b5b9b8Sflorian 	hints.ai_flags = AI_NUMERICHOST;
94758b5b9b8Sflorian 	if (getaddrinfo(s, "0", &hints, &res) == 0) {
94858b5b9b8Sflorian 		if (res->ai_family == AF_INET ||
94958b5b9b8Sflorian 		    res->ai_family == AF_INET6) {
95058b5b9b8Sflorian 			if ((ss = calloc(1, sizeof(*ss))) == NULL)
95158b5b9b8Sflorian 				fatal(NULL);
95258b5b9b8Sflorian 			memcpy(ss, res->ai_addr, res->ai_addrlen);
95358b5b9b8Sflorian 		}
95458b5b9b8Sflorian 		freeaddrinfo(res);
95558b5b9b8Sflorian 	}
95658b5b9b8Sflorian 
95758b5b9b8Sflorian 	return (ss);
95858b5b9b8Sflorian }
959fd873f7fSflorian 
960fd873f7fSflorian int
check_pref_uniq(enum uw_resolver_type type)961fd873f7fSflorian check_pref_uniq(enum uw_resolver_type type)
962fd873f7fSflorian {
963fd873f7fSflorian 	int	 i;
964fd873f7fSflorian 
965d032132bSflorian 	for (i = 0; i < conf->res_pref.len; i++)
966d032132bSflorian 		if (conf->res_pref.types[i] == type) {
967fd873f7fSflorian 			yyerror("%s is already in the preference list",
968fd873f7fSflorian 			    uw_resolver_type_str[type]);
969fd873f7fSflorian 			return (0);
970fd873f7fSflorian 		}
971fd873f7fSflorian 
972fd873f7fSflorian 	return (1);
973fd873f7fSflorian }
974