xref: /openbsd/usr.sbin/rad/parse.y (revision cea17583)
1*cea17583Sbket /*	$OpenBSD: parse.y,v 1.6 2018/07/20 17:55:09 bket Exp $	*/
253293e44Sflorian 
353293e44Sflorian /*
453293e44Sflorian  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
553293e44Sflorian  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
653293e44Sflorian  * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
753293e44Sflorian  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
853293e44Sflorian  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
953293e44Sflorian  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
1053293e44Sflorian  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
1153293e44Sflorian  *
1253293e44Sflorian  * Permission to use, copy, modify, and distribute this software for any
1353293e44Sflorian  * purpose with or without fee is hereby granted, provided that the above
1453293e44Sflorian  * copyright notice and this permission notice appear in all copies.
1553293e44Sflorian  *
1653293e44Sflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1753293e44Sflorian  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1853293e44Sflorian  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1953293e44Sflorian  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2053293e44Sflorian  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2153293e44Sflorian  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2253293e44Sflorian  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2353293e44Sflorian  */
2453293e44Sflorian 
2553293e44Sflorian %{
2653293e44Sflorian #include <sys/types.h>
2753293e44Sflorian #include <sys/queue.h>
2853293e44Sflorian #include <sys/socket.h>
2953293e44Sflorian #include <sys/stat.h>
3053293e44Sflorian 
3153293e44Sflorian #include <netinet/in.h>
3253293e44Sflorian #include <net/if.h>
3353293e44Sflorian 
3453293e44Sflorian #include <arpa/inet.h>
3553293e44Sflorian 
3653293e44Sflorian #include <ctype.h>
3753293e44Sflorian #include <err.h>
3853293e44Sflorian #include <errno.h>
3953293e44Sflorian #include <event.h>
4053293e44Sflorian #include <ifaddrs.h>
4153293e44Sflorian #include <imsg.h>
4253293e44Sflorian #include <limits.h>
4353293e44Sflorian #include <stdarg.h>
4453293e44Sflorian #include <stdio.h>
4553293e44Sflorian #include <string.h>
4653293e44Sflorian #include <syslog.h>
4753293e44Sflorian #include <unistd.h>
4853293e44Sflorian 
4953293e44Sflorian #include "log.h"
5053293e44Sflorian #include "rad.h"
5153293e44Sflorian #include "frontend.h"
5253293e44Sflorian 
5353293e44Sflorian TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
5453293e44Sflorian static struct file {
5553293e44Sflorian 	TAILQ_ENTRY(file)	 entry;
5653293e44Sflorian 	FILE			*stream;
5753293e44Sflorian 	char			*name;
5853293e44Sflorian 	size_t	 		 ungetpos;
5953293e44Sflorian 	size_t			 ungetsize;
6053293e44Sflorian 	u_char			*ungetbuf;
6153293e44Sflorian 	int			 eof_reached;
6253293e44Sflorian 	int			 lineno;
6353293e44Sflorian 	int			 errors;
6453293e44Sflorian } *file, *topfile;
6553293e44Sflorian struct file	*pushfile(const char *, int);
6653293e44Sflorian int		 popfile(void);
6753293e44Sflorian int		 check_file_secrecy(int, const char *);
6853293e44Sflorian int		 yyparse(void);
6953293e44Sflorian int		 yylex(void);
7053293e44Sflorian int		 yyerror(const char *, ...)
7153293e44Sflorian     __attribute__((__format__ (printf, 1, 2)))
7253293e44Sflorian     __attribute__((__nonnull__ (1)));
7353293e44Sflorian int		 kw_cmp(const void *, const void *);
7453293e44Sflorian int		 lookup(char *);
7553293e44Sflorian int		 igetc(void);
7653293e44Sflorian int		 lgetc(int);
7753293e44Sflorian void		 lungetc(int);
7853293e44Sflorian int		 findeol(void);
7953293e44Sflorian 
8053293e44Sflorian TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
8153293e44Sflorian struct sym {
8253293e44Sflorian 	TAILQ_ENTRY(sym)	 entry;
8353293e44Sflorian 	int			 used;
8453293e44Sflorian 	int			 persist;
8553293e44Sflorian 	char			*nam;
8653293e44Sflorian 	char			*val;
8753293e44Sflorian };
8853293e44Sflorian 
8953293e44Sflorian int	 symset(const char *, const char *, int);
9053293e44Sflorian char	*symget(const char *);
9153293e44Sflorian 
9253293e44Sflorian void	 clear_config(struct rad_conf *xconf);
9353293e44Sflorian 
9453293e44Sflorian static struct rad_conf		*conf;
9553293e44Sflorian static struct ra_options_conf	*ra_options;
9653293e44Sflorian static int			 errors;
9753293e44Sflorian 
9853293e44Sflorian static struct ra_iface_conf	*ra_iface_conf;
9953293e44Sflorian static struct ra_prefix_conf	*ra_prefix_conf;
10053293e44Sflorian 
10153293e44Sflorian struct ra_prefix_conf	*conf_get_ra_prefix(struct in6_addr*, int);
10253293e44Sflorian struct ra_iface_conf	*conf_get_ra_iface(char *);
10353293e44Sflorian 
10453293e44Sflorian typedef struct {
10553293e44Sflorian 	union {
10653293e44Sflorian 		int64_t		 number;
10753293e44Sflorian 		char		*string;
10853293e44Sflorian 	} v;
10953293e44Sflorian 	int lineno;
11053293e44Sflorian } YYSTYPE;
11153293e44Sflorian 
11253293e44Sflorian %}
11353293e44Sflorian 
11453293e44Sflorian %token	RA_IFACE YES NO INCLUDE ERROR
11553293e44Sflorian %token	DEFAULT ROUTER HOP LIMIT MANAGED ADDRESS
11653293e44Sflorian %token	CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER
11753293e44Sflorian %token	AUTO PREFIX VALID PREFERRED LIFETIME ONLINK AUTONOMOUS
118*cea17583Sbket %token	ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU
11953293e44Sflorian 
12053293e44Sflorian %token	<v.string>	STRING
12153293e44Sflorian %token	<v.number>	NUMBER
12253293e44Sflorian %type	<v.number>	yesno
12353293e44Sflorian %type	<v.string>	string
12453293e44Sflorian 
12553293e44Sflorian %%
12653293e44Sflorian 
12753293e44Sflorian grammar		: /* empty */
12853293e44Sflorian 		| grammar include '\n'
12953293e44Sflorian 		| grammar '\n'
13053293e44Sflorian 		| grammar { ra_options = &conf->ra_options; } conf_main '\n'
13153293e44Sflorian 		| grammar varset '\n'
13253293e44Sflorian 		| grammar ra_iface '\n'
13353293e44Sflorian 		| grammar error '\n'		{ file->errors++; }
13453293e44Sflorian 		;
13553293e44Sflorian 
13653293e44Sflorian include		: INCLUDE STRING		{
13753293e44Sflorian 			struct file	*nfile;
13853293e44Sflorian 
1393a682461Sflorian 			if ((nfile = pushfile($2, 0)) == NULL) {
14053293e44Sflorian 				yyerror("failed to include file %s", $2);
14153293e44Sflorian 				free($2);
14253293e44Sflorian 				YYERROR;
14353293e44Sflorian 			}
14453293e44Sflorian 			free($2);
14553293e44Sflorian 
14653293e44Sflorian 			file = nfile;
14753293e44Sflorian 			lungetc('\n');
14853293e44Sflorian 		}
14953293e44Sflorian 		;
15053293e44Sflorian 
15153293e44Sflorian string		: string STRING	{
15253293e44Sflorian 			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
15353293e44Sflorian 				free($1);
15453293e44Sflorian 				free($2);
15553293e44Sflorian 				yyerror("string: asprintf");
15653293e44Sflorian 				YYERROR;
15753293e44Sflorian 			}
15853293e44Sflorian 			free($1);
15953293e44Sflorian 			free($2);
16053293e44Sflorian 		}
16153293e44Sflorian 		| STRING
16253293e44Sflorian 		;
16353293e44Sflorian 
16453293e44Sflorian yesno		: YES	{ $$ = 1; }
16553293e44Sflorian 		| NO	{ $$ = 0; }
16653293e44Sflorian 		;
16753293e44Sflorian 
16853293e44Sflorian varset		: STRING '=' string		{
16953293e44Sflorian 			char *s = $1;
17053293e44Sflorian 			if (cmd_opts & OPT_VERBOSE)
17153293e44Sflorian 				printf("%s = \"%s\"\n", $1, $3);
17253293e44Sflorian 			while (*s++) {
17353293e44Sflorian 				if (isspace((unsigned char)*s)) {
17453293e44Sflorian 					yyerror("macro name cannot contain "
17553293e44Sflorian 					    "whitespace");
17653293e44Sflorian 					YYERROR;
17753293e44Sflorian 				}
17853293e44Sflorian 			}
17953293e44Sflorian 			if (symset($1, $3, 0) == -1)
18053293e44Sflorian 				fatal("cannot store variable");
18153293e44Sflorian 			free($1);
18253293e44Sflorian 			free($3);
18353293e44Sflorian 		}
18453293e44Sflorian 		;
18553293e44Sflorian 
18653293e44Sflorian conf_main	: ra_opt_block {
18753293e44Sflorian 			ra_options = &conf->ra_options;
18853293e44Sflorian 		}
18953293e44Sflorian 		;
19053293e44Sflorian 
19153293e44Sflorian ra_opt_block	: DEFAULT ROUTER yesno {
19253293e44Sflorian 			ra_options->dfr = $3;
19353293e44Sflorian 		}
19453293e44Sflorian 		| HOP LIMIT NUMBER {
19553293e44Sflorian 			ra_options->cur_hl = $3;
19653293e44Sflorian 		}
19753293e44Sflorian 		| MANAGED ADDRESS CONFIGURATION yesno {
19853293e44Sflorian 			ra_options->m_flag = $4;
19953293e44Sflorian 		}
20053293e44Sflorian 		| OTHER CONFIGURATION yesno {
20153293e44Sflorian 			ra_options->o_flag = $3;
20253293e44Sflorian 		}
20353293e44Sflorian 		| ROUTER LIFETIME NUMBER {
20453293e44Sflorian 			ra_options->router_lifetime = $3;
20553293e44Sflorian 		}
20653293e44Sflorian 		| REACHABLE TIME NUMBER {
20753293e44Sflorian 			ra_options->reachable_time = $3;
20853293e44Sflorian 		}
20953293e44Sflorian 		| RETRANS TIMER NUMBER {
21053293e44Sflorian 			ra_options->retrans_timer = $3;
21153293e44Sflorian 		}
212*cea17583Sbket 		| MTU NUMBER {
213*cea17583Sbket 			ra_options->mtu = $2;
214*cea17583Sbket 		}
21553293e44Sflorian 		;
21653293e44Sflorian 
21753293e44Sflorian optnl		: '\n' optnl		/* zero or more newlines */
21853293e44Sflorian 		| /*empty*/
21953293e44Sflorian 		;
22053293e44Sflorian 
22153293e44Sflorian nl		: '\n' optnl		/* one or more newlines */
22253293e44Sflorian 		;
22353293e44Sflorian 
22453293e44Sflorian ra_iface	: RA_IFACE STRING {
22553293e44Sflorian 			ra_iface_conf = conf_get_ra_iface($2);
22653293e44Sflorian 			/* set auto prefix defaults */
22753293e44Sflorian 			ra_iface_conf->autoprefix = conf_get_ra_prefix(NULL, 0);
22853293e44Sflorian 			ra_options = &ra_iface_conf->ra_options;
22953293e44Sflorian 		} ra_iface_block {
23053293e44Sflorian 			ra_iface_conf = NULL;
23153293e44Sflorian 		}
23253293e44Sflorian 		;
23353293e44Sflorian 
23453293e44Sflorian ra_iface_block	: '{' optnl ra_ifaceopts_l '}'
23553293e44Sflorian 		| '{' optnl '}'
23653293e44Sflorian 		| /* empty */
23753293e44Sflorian 		;
23853293e44Sflorian 
23953293e44Sflorian ra_ifaceopts_l	: ra_ifaceopts_l ra_ifaceoptsl nl
24053293e44Sflorian 		| ra_ifaceoptsl optnl
24153293e44Sflorian 		;
24253293e44Sflorian 
24353293e44Sflorian ra_ifaceoptsl	: NO AUTO PREFIX {
24453293e44Sflorian 			free(ra_iface_conf->autoprefix);
24553293e44Sflorian 			ra_iface_conf->autoprefix = NULL;
24653293e44Sflorian 		}
24753293e44Sflorian 		| AUTO PREFIX {
24853293e44Sflorian 			if (ra_iface_conf->autoprefix == NULL)
24953293e44Sflorian 				ra_iface_conf->autoprefix =
250cddacf98Sflorian 				    conf_get_ra_prefix(NULL, 0);
251cddacf98Sflorian 			ra_prefix_conf = ra_iface_conf->autoprefix;
25253293e44Sflorian 		} ra_prefix_block {
25353293e44Sflorian 			ra_prefix_conf = NULL;
25453293e44Sflorian 		}
25553293e44Sflorian 		| PREFIX STRING {
25653293e44Sflorian 			struct in6_addr	 addr;
25753293e44Sflorian 			int		 prefixlen;
25853293e44Sflorian 
25953293e44Sflorian 			memset(&addr, 0, sizeof(addr));
26053293e44Sflorian 			prefixlen = inet_net_pton(AF_INET6, $2, &addr,
26153293e44Sflorian 			    sizeof(addr));
26253293e44Sflorian 			if (prefixlen == -1) {
26353293e44Sflorian 				yyerror("error parsing prefix");
26453293e44Sflorian 				free($2);
26553293e44Sflorian 				YYERROR;
26653293e44Sflorian 			}
26753293e44Sflorian 			mask_prefix(&addr, prefixlen);
26853293e44Sflorian 			ra_prefix_conf = conf_get_ra_prefix(&addr, prefixlen);
26953293e44Sflorian 		} ra_prefix_block {
27053293e44Sflorian 			ra_prefix_conf = NULL;
27153293e44Sflorian 		}
2724c40b7e8Sflorian 		| DNS dns_block
27353293e44Sflorian 		| ra_opt_block
27453293e44Sflorian 		;
27553293e44Sflorian 
27653293e44Sflorian ra_prefix_block	: '{' optnl ra_prefixopts_l '}'
27753293e44Sflorian 		| '{' optnl '}'
27853293e44Sflorian 		| /* empty */
27953293e44Sflorian 		;
28053293e44Sflorian 
28153293e44Sflorian ra_prefixopts_l	: ra_prefixopts_l ra_prefixoptsl nl
28253293e44Sflorian 		| ra_prefixoptsl optnl
28353293e44Sflorian 		;
28453293e44Sflorian 
28553293e44Sflorian ra_prefixoptsl	: VALID LIFETIME NUMBER {
28653293e44Sflorian 			ra_prefix_conf->vltime = $3;
28753293e44Sflorian 		}
28853293e44Sflorian 		| PREFERRED LIFETIME NUMBER {
28953293e44Sflorian 			ra_prefix_conf->pltime = $3;
29053293e44Sflorian 		}
29153293e44Sflorian 		| ONLINK yesno {
29253293e44Sflorian 			ra_prefix_conf->lflag = $2;
29353293e44Sflorian 		}
29453293e44Sflorian 		| AUTONOMOUS ADDRESS_CONFIGURATION yesno {
29553293e44Sflorian 			ra_prefix_conf->aflag = $3;
29653293e44Sflorian 		}
29753293e44Sflorian 		;
2984c40b7e8Sflorian dns_block	: '{' optnl dnsopts_l '}'
2994c40b7e8Sflorian 		| '{' optnl '}'
3004c40b7e8Sflorian 		| /* empty */
3014c40b7e8Sflorian 		;
30253293e44Sflorian 
3034c40b7e8Sflorian dnsopts_l	: dnsopts_l dnsoptsl nl
3044c40b7e8Sflorian 		| dnsoptsl optnl
3054c40b7e8Sflorian 		;
3064c40b7e8Sflorian 
3074c40b7e8Sflorian dnsoptsl	: LIFETIME NUMBER {
3084c40b7e8Sflorian 			ra_iface_conf->rdns_lifetime = $2;
3094c40b7e8Sflorian 		}
3108fe22fd3Sflorian 		| NAMESERVER nserver_block
3114c40b7e8Sflorian 		| SEARCH search_block
3124c40b7e8Sflorian 		;
3138fe22fd3Sflorian nserver_block	: '{' optnl nserveropts_l '}'
3144c40b7e8Sflorian 			| '{' optnl '}'
3158fe22fd3Sflorian 			| nserveroptsl
3164c40b7e8Sflorian 			| /* empty */
3174c40b7e8Sflorian 			;
3184c40b7e8Sflorian 
3198fe22fd3Sflorian nserveropts_l	: nserveropts_l nserveroptsl optnl
3208fe22fd3Sflorian 		| nserveroptsl optnl
3214c40b7e8Sflorian 		;
3224c40b7e8Sflorian 
3238fe22fd3Sflorian nserveroptsl	: STRING {
3244c40b7e8Sflorian 			struct ra_rdnss_conf	*ra_rdnss_conf;
3254c40b7e8Sflorian 			struct in6_addr		 addr;
3264c40b7e8Sflorian 
3274c40b7e8Sflorian 			memset(&addr, 0, sizeof(addr));
3284c40b7e8Sflorian 			if (inet_pton(AF_INET6, $1, &addr)
3294c40b7e8Sflorian 			    != 1) {
3308fe22fd3Sflorian 				yyerror("error parsing nameserver address %s",
3314c40b7e8Sflorian 				    $1);
3324c40b7e8Sflorian 				free($1);
3334c40b7e8Sflorian 				YYERROR;
3344c40b7e8Sflorian 			}
3354c40b7e8Sflorian 			if ((ra_rdnss_conf = calloc(1, sizeof(*ra_rdnss_conf)))
3364c40b7e8Sflorian 			    == NULL)
3374c40b7e8Sflorian 				err(1, "%s", __func__);
3384c40b7e8Sflorian 			memcpy(&ra_rdnss_conf->rdnss, &addr, sizeof(addr));
3394c40b7e8Sflorian 			SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_rdnss_list,
3404c40b7e8Sflorian 			    ra_rdnss_conf, entry);
3414c40b7e8Sflorian 			ra_iface_conf->rdnss_count++;
3424c40b7e8Sflorian 		}
3434c40b7e8Sflorian 		;
3444c40b7e8Sflorian search_block	: '{' optnl searchopts_l '}'
3454c40b7e8Sflorian 		| '{' optnl '}'
3464c40b7e8Sflorian 		| searchoptsl
3474c40b7e8Sflorian 		| /* empty */
3484c40b7e8Sflorian 		;
3494c40b7e8Sflorian 
3504c40b7e8Sflorian searchopts_l	: searchopts_l searchoptsl optnl
3514c40b7e8Sflorian 		| searchoptsl optnl
3524c40b7e8Sflorian 		;
3534c40b7e8Sflorian 
3544c40b7e8Sflorian searchoptsl	: STRING {
3554c40b7e8Sflorian 			struct ra_dnssl_conf	*ra_dnssl_conf;
3564c40b7e8Sflorian 			size_t			 len;
3574c40b7e8Sflorian 
3584c40b7e8Sflorian 			if ((ra_dnssl_conf = calloc(1,
3594c40b7e8Sflorian 			    sizeof(*ra_dnssl_conf))) == NULL)
3604c40b7e8Sflorian 				err(1, "%s", __func__);
3614c40b7e8Sflorian 
3624c40b7e8Sflorian 			if ((len = strlcpy(ra_dnssl_conf->search, $1,
3634c40b7e8Sflorian 			    sizeof(ra_dnssl_conf->search))) >
3644c40b7e8Sflorian 			    sizeof(ra_dnssl_conf->search)) {
3654c40b7e8Sflorian 				yyerror("search string too long");
3664c40b7e8Sflorian 				free($1);
3674c40b7e8Sflorian 				YYERROR;
3684c40b7e8Sflorian 			}
3694c40b7e8Sflorian 			if (ra_dnssl_conf->search[len] != '.') {
3704c40b7e8Sflorian 				if ((len = strlcat(ra_dnssl_conf->search, ".",
3714c40b7e8Sflorian 				    sizeof(ra_dnssl_conf->search))) >
3724c40b7e8Sflorian 				    sizeof(ra_dnssl_conf->search)) {
3734c40b7e8Sflorian 					yyerror("search string too long");
3744c40b7e8Sflorian 					free($1);
3754c40b7e8Sflorian 					YYERROR;
3764c40b7e8Sflorian 				}
3774c40b7e8Sflorian 			}
3784c40b7e8Sflorian 			SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_dnssl_list,
3794c40b7e8Sflorian 			    ra_dnssl_conf, entry);
3804c40b7e8Sflorian 			ra_iface_conf->dnssl_len += len + 1;
3814c40b7e8Sflorian 		}
3824c40b7e8Sflorian 		;
38353293e44Sflorian %%
38453293e44Sflorian 
38553293e44Sflorian struct keywords {
38653293e44Sflorian 	const char	*k_name;
38753293e44Sflorian 	int		 k_val;
38853293e44Sflorian };
38953293e44Sflorian 
39053293e44Sflorian int
39153293e44Sflorian yyerror(const char *fmt, ...)
39253293e44Sflorian {
39353293e44Sflorian 	va_list		 ap;
39453293e44Sflorian 	char		*msg;
39553293e44Sflorian 
39653293e44Sflorian 	file->errors++;
39753293e44Sflorian 	va_start(ap, fmt);
39853293e44Sflorian 	if (vasprintf(&msg, fmt, ap) == -1)
39953293e44Sflorian 		fatalx("yyerror vasprintf");
40053293e44Sflorian 	va_end(ap);
40153293e44Sflorian 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
40253293e44Sflorian 	free(msg);
40353293e44Sflorian 	return (0);
40453293e44Sflorian }
40553293e44Sflorian 
40653293e44Sflorian int
40753293e44Sflorian kw_cmp(const void *k, const void *e)
40853293e44Sflorian {
40953293e44Sflorian 	return (strcmp(k, ((const struct keywords *)e)->k_name));
41053293e44Sflorian }
41153293e44Sflorian 
41253293e44Sflorian int
41353293e44Sflorian lookup(char *s)
41453293e44Sflorian {
41553293e44Sflorian 	/* This has to be sorted always. */
41653293e44Sflorian 	static const struct keywords keywords[] = {
41753293e44Sflorian 		{"address",		ADDRESS},
41853293e44Sflorian 		{"address-configuration",	ADDRESS_CONFIGURATION},
41953293e44Sflorian 		{"auto",		AUTO},
42053293e44Sflorian 		{"autonomous",		AUTONOMOUS},
42153293e44Sflorian 		{"configuration",	CONFIGURATION},
42253293e44Sflorian 		{"default",		DEFAULT},
4234c40b7e8Sflorian 		{"dns",			DNS},
42453293e44Sflorian 		{"hop",			HOP},
42553293e44Sflorian 		{"include",		INCLUDE},
42653293e44Sflorian 		{"interface",		RA_IFACE},
42753293e44Sflorian 		{"lifetime",		LIFETIME},
42853293e44Sflorian 		{"limit",		LIMIT},
42953293e44Sflorian 		{"managed",		MANAGED},
430*cea17583Sbket 		{"mtu",			MTU},
4318fe22fd3Sflorian 		{"nameserver",		NAMESERVER},
43253293e44Sflorian 		{"no",			NO},
43353293e44Sflorian 		{"on-link",		ONLINK},
43453293e44Sflorian 		{"other",		OTHER},
43553293e44Sflorian 		{"preferred",		PREFERRED},
43653293e44Sflorian 		{"prefix",		PREFIX},
43753293e44Sflorian 		{"reachable",		REACHABLE},
43853293e44Sflorian 		{"retrans",		RETRANS},
43953293e44Sflorian 		{"router",		ROUTER},
4404c40b7e8Sflorian 		{"search",		SEARCH},
44153293e44Sflorian 		{"time",		TIME},
44253293e44Sflorian 		{"timer",		TIMER},
44353293e44Sflorian 		{"valid",		VALID},
44453293e44Sflorian 		{"yes",			YES},
44553293e44Sflorian 	};
44653293e44Sflorian 	const struct keywords	*p;
44753293e44Sflorian 
44853293e44Sflorian 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
44953293e44Sflorian 	    sizeof(keywords[0]), kw_cmp);
45053293e44Sflorian 
45153293e44Sflorian 	if (p)
45253293e44Sflorian 		return (p->k_val);
45353293e44Sflorian 	else
45453293e44Sflorian 		return (STRING);
45553293e44Sflorian }
45653293e44Sflorian 
45753293e44Sflorian #define START_EXPAND	1
45853293e44Sflorian #define DONE_EXPAND	2
45953293e44Sflorian 
46053293e44Sflorian static int	expanding;
46153293e44Sflorian 
46253293e44Sflorian int
46353293e44Sflorian igetc(void)
46453293e44Sflorian {
46553293e44Sflorian 	int	c;
46653293e44Sflorian 
46753293e44Sflorian 	while (1) {
46853293e44Sflorian 		if (file->ungetpos > 0)
46953293e44Sflorian 			c = file->ungetbuf[--file->ungetpos];
47053293e44Sflorian 		else
47153293e44Sflorian 			c = getc(file->stream);
47253293e44Sflorian 
47353293e44Sflorian 		if (c == START_EXPAND)
47453293e44Sflorian 			expanding = 1;
47553293e44Sflorian 		else if (c == DONE_EXPAND)
47653293e44Sflorian 			expanding = 0;
47753293e44Sflorian 		else
47853293e44Sflorian 			break;
47953293e44Sflorian 	}
48053293e44Sflorian 	return (c);
48153293e44Sflorian }
48253293e44Sflorian 
48353293e44Sflorian int
48453293e44Sflorian lgetc(int quotec)
48553293e44Sflorian {
48653293e44Sflorian 	int		c, next;
48753293e44Sflorian 
48853293e44Sflorian 	if (quotec) {
48953293e44Sflorian 		if ((c = igetc()) == EOF) {
49053293e44Sflorian 			yyerror("reached end of file while parsing "
49153293e44Sflorian 			    "quoted string");
49253293e44Sflorian 			if (file == topfile || popfile() == EOF)
49353293e44Sflorian 				return (EOF);
49453293e44Sflorian 			return (quotec);
49553293e44Sflorian 		}
49653293e44Sflorian 		return (c);
49753293e44Sflorian 	}
49853293e44Sflorian 
49953293e44Sflorian 	while ((c = igetc()) == '\\') {
50053293e44Sflorian 		next = igetc();
50153293e44Sflorian 		if (next != '\n') {
50253293e44Sflorian 			c = next;
50353293e44Sflorian 			break;
50453293e44Sflorian 		}
50553293e44Sflorian 		yylval.lineno = file->lineno;
50653293e44Sflorian 		file->lineno++;
50753293e44Sflorian 	}
50853293e44Sflorian 
50953293e44Sflorian 	if (c == EOF) {
51053293e44Sflorian 		/*
51153293e44Sflorian 		 * Fake EOL when hit EOF for the first time. This gets line
51253293e44Sflorian 		 * count right if last line in included file is syntactically
51353293e44Sflorian 		 * invalid and has no newline.
51453293e44Sflorian 		 */
51553293e44Sflorian 		if (file->eof_reached == 0) {
51653293e44Sflorian 			file->eof_reached = 1;
51753293e44Sflorian 			return ('\n');
51853293e44Sflorian 		}
51953293e44Sflorian 		while (c == EOF) {
52053293e44Sflorian 			if (file == topfile || popfile() == EOF)
52153293e44Sflorian 				return (EOF);
52253293e44Sflorian 			c = igetc();
52353293e44Sflorian 		}
52453293e44Sflorian 	}
52553293e44Sflorian 	return (c);
52653293e44Sflorian }
52753293e44Sflorian 
52853293e44Sflorian void
52953293e44Sflorian lungetc(int c)
53053293e44Sflorian {
53153293e44Sflorian 	if (c == EOF)
53253293e44Sflorian 		return;
53353293e44Sflorian 
53453293e44Sflorian 	if (file->ungetpos >= file->ungetsize) {
53553293e44Sflorian 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
53653293e44Sflorian 		if (p == NULL)
53753293e44Sflorian 			err(1, "lungetc");
53853293e44Sflorian 		file->ungetbuf = p;
53953293e44Sflorian 		file->ungetsize *= 2;
54053293e44Sflorian 	}
54153293e44Sflorian 	file->ungetbuf[file->ungetpos++] = c;
54253293e44Sflorian }
54353293e44Sflorian 
54453293e44Sflorian int
54553293e44Sflorian findeol(void)
54653293e44Sflorian {
54753293e44Sflorian 	int	c;
54853293e44Sflorian 
54953293e44Sflorian 	/* Skip to either EOF or the first real EOL. */
55053293e44Sflorian 	while (1) {
55153293e44Sflorian 		c = lgetc(0);
55253293e44Sflorian 		if (c == '\n') {
55353293e44Sflorian 			file->lineno++;
55453293e44Sflorian 			break;
55553293e44Sflorian 		}
55653293e44Sflorian 		if (c == EOF)
55753293e44Sflorian 			break;
55853293e44Sflorian 	}
55953293e44Sflorian 	return (ERROR);
56053293e44Sflorian }
56153293e44Sflorian 
56253293e44Sflorian int
56353293e44Sflorian yylex(void)
56453293e44Sflorian {
56553293e44Sflorian 	unsigned char	 buf[8096];
56653293e44Sflorian 	unsigned char	*p, *val;
56753293e44Sflorian 	int		 quotec, next, c;
56853293e44Sflorian 	int		 token;
56953293e44Sflorian 
57053293e44Sflorian top:
57153293e44Sflorian 	p = buf;
57253293e44Sflorian 	while ((c = lgetc(0)) == ' ' || c == '\t')
57353293e44Sflorian 		; /* nothing */
57453293e44Sflorian 
57553293e44Sflorian 	yylval.lineno = file->lineno;
57653293e44Sflorian 	if (c == '#')
57753293e44Sflorian 		while ((c = lgetc(0)) != '\n' && c != EOF)
57853293e44Sflorian 			; /* nothing */
57953293e44Sflorian 	if (c == '$' && !expanding) {
58053293e44Sflorian 		while (1) {
58153293e44Sflorian 			if ((c = lgetc(0)) == EOF)
58253293e44Sflorian 				return (0);
58353293e44Sflorian 
58453293e44Sflorian 			if (p + 1 >= buf + sizeof(buf) - 1) {
58553293e44Sflorian 				yyerror("string too long");
58653293e44Sflorian 				return (findeol());
58753293e44Sflorian 			}
58853293e44Sflorian 			if (isalnum(c) || c == '_') {
58953293e44Sflorian 				*p++ = c;
59053293e44Sflorian 				continue;
59153293e44Sflorian 			}
59253293e44Sflorian 			*p = '\0';
59353293e44Sflorian 			lungetc(c);
59453293e44Sflorian 			break;
59553293e44Sflorian 		}
59653293e44Sflorian 		val = symget(buf);
59753293e44Sflorian 		if (val == NULL) {
59853293e44Sflorian 			yyerror("macro '%s' not defined", buf);
59953293e44Sflorian 			return (findeol());
60053293e44Sflorian 		}
60153293e44Sflorian 		p = val + strlen(val) - 1;
60253293e44Sflorian 		lungetc(DONE_EXPAND);
60353293e44Sflorian 		while (p >= val) {
60453293e44Sflorian 			lungetc(*p);
60553293e44Sflorian 			p--;
60653293e44Sflorian 		}
60753293e44Sflorian 		lungetc(START_EXPAND);
60853293e44Sflorian 		goto top;
60953293e44Sflorian 	}
61053293e44Sflorian 
61153293e44Sflorian 	switch (c) {
61253293e44Sflorian 	case '\'':
61353293e44Sflorian 	case '"':
61453293e44Sflorian 		quotec = c;
61553293e44Sflorian 		while (1) {
61653293e44Sflorian 			if ((c = lgetc(quotec)) == EOF)
61753293e44Sflorian 				return (0);
61853293e44Sflorian 			if (c == '\n') {
61953293e44Sflorian 				file->lineno++;
62053293e44Sflorian 				continue;
62153293e44Sflorian 			} else if (c == '\\') {
62253293e44Sflorian 				if ((next = lgetc(quotec)) == EOF)
62353293e44Sflorian 					return (0);
62453293e44Sflorian 				if (next == quotec || c == ' ' || c == '\t')
62553293e44Sflorian 					c = next;
62653293e44Sflorian 				else if (next == '\n') {
62753293e44Sflorian 					file->lineno++;
62853293e44Sflorian 					continue;
62953293e44Sflorian 				} else
63053293e44Sflorian 					lungetc(next);
63153293e44Sflorian 			} else if (c == quotec) {
63253293e44Sflorian 				*p = '\0';
63353293e44Sflorian 				break;
63453293e44Sflorian 			} else if (c == '\0') {
63553293e44Sflorian 				yyerror("syntax error");
63653293e44Sflorian 				return (findeol());
63753293e44Sflorian 			}
63853293e44Sflorian 			if (p + 1 >= buf + sizeof(buf) - 1) {
63953293e44Sflorian 				yyerror("string too long");
64053293e44Sflorian 				return (findeol());
64153293e44Sflorian 			}
64253293e44Sflorian 			*p++ = c;
64353293e44Sflorian 		}
64453293e44Sflorian 		yylval.v.string = strdup(buf);
64553293e44Sflorian 		if (yylval.v.string == NULL)
64653293e44Sflorian 			err(1, "yylex: strdup");
64753293e44Sflorian 		return (STRING);
64853293e44Sflorian 	}
64953293e44Sflorian 
65053293e44Sflorian #define allowed_to_end_number(x) \
65153293e44Sflorian 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
65253293e44Sflorian 
65353293e44Sflorian 	if (c == '-' || isdigit(c)) {
65453293e44Sflorian 		do {
65553293e44Sflorian 			*p++ = c;
65653293e44Sflorian 			if ((unsigned)(p-buf) >= sizeof(buf)) {
65753293e44Sflorian 				yyerror("string too long");
65853293e44Sflorian 				return (findeol());
65953293e44Sflorian 			}
66053293e44Sflorian 		} while ((c = lgetc(0)) != EOF && isdigit(c));
66153293e44Sflorian 		lungetc(c);
66253293e44Sflorian 		if (p == buf + 1 && buf[0] == '-')
66353293e44Sflorian 			goto nodigits;
66453293e44Sflorian 		if (c == EOF || allowed_to_end_number(c)) {
66553293e44Sflorian 			const char *errstr = NULL;
66653293e44Sflorian 
66753293e44Sflorian 			*p = '\0';
66853293e44Sflorian 			yylval.v.number = strtonum(buf, LLONG_MIN,
66953293e44Sflorian 			    LLONG_MAX, &errstr);
67053293e44Sflorian 			if (errstr) {
67153293e44Sflorian 				yyerror("\"%s\" invalid number: %s",
67253293e44Sflorian 				    buf, errstr);
67353293e44Sflorian 				return (findeol());
67453293e44Sflorian 			}
67553293e44Sflorian 			return (NUMBER);
67653293e44Sflorian 		} else {
67753293e44Sflorian nodigits:
67853293e44Sflorian 			while (p > buf + 1)
67953293e44Sflorian 				lungetc(*--p);
68053293e44Sflorian 			c = *--p;
68153293e44Sflorian 			if (c == '-')
68253293e44Sflorian 				return (c);
68353293e44Sflorian 		}
68453293e44Sflorian 	}
68553293e44Sflorian 
68653293e44Sflorian #define allowed_in_string(x) \
68753293e44Sflorian 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
68853293e44Sflorian 	x != '{' && x != '}' && \
68953293e44Sflorian 	x != '!' && x != '=' && x != '#' && \
69053293e44Sflorian 	x != ','))
69153293e44Sflorian 
69253293e44Sflorian 	if (isalnum(c) || c == ':' || c == '_') {
69353293e44Sflorian 		do {
69453293e44Sflorian 			*p++ = c;
69553293e44Sflorian 			if ((unsigned)(p-buf) >= sizeof(buf)) {
69653293e44Sflorian 				yyerror("string too long");
69753293e44Sflorian 				return (findeol());
69853293e44Sflorian 			}
69953293e44Sflorian 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
70053293e44Sflorian 		lungetc(c);
70153293e44Sflorian 		*p = '\0';
70253293e44Sflorian 		if ((token = lookup(buf)) == STRING)
70353293e44Sflorian 			if ((yylval.v.string = strdup(buf)) == NULL)
70453293e44Sflorian 				err(1, "yylex: strdup");
70553293e44Sflorian 		return (token);
70653293e44Sflorian 	}
70753293e44Sflorian 	if (c == '\n') {
70853293e44Sflorian 		yylval.lineno = file->lineno;
70953293e44Sflorian 		file->lineno++;
71053293e44Sflorian 	}
71153293e44Sflorian 	if (c == EOF)
71253293e44Sflorian 		return (0);
71353293e44Sflorian 	return (c);
71453293e44Sflorian }
71553293e44Sflorian 
71653293e44Sflorian int
71753293e44Sflorian check_file_secrecy(int fd, const char *fname)
71853293e44Sflorian {
71953293e44Sflorian 	struct stat	st;
72053293e44Sflorian 
72153293e44Sflorian 	if (fstat(fd, &st)) {
72253293e44Sflorian 		log_warn("cannot stat %s", fname);
72353293e44Sflorian 		return (-1);
72453293e44Sflorian 	}
72553293e44Sflorian 	if (st.st_uid != 0 && st.st_uid != getuid()) {
72653293e44Sflorian 		log_warnx("%s: owner not root or current user", fname);
72753293e44Sflorian 		return (-1);
72853293e44Sflorian 	}
72953293e44Sflorian 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
73053293e44Sflorian 		log_warnx("%s: group writable or world read/writable", fname);
73153293e44Sflorian 		return (-1);
73253293e44Sflorian 	}
73353293e44Sflorian 	return (0);
73453293e44Sflorian }
73553293e44Sflorian 
73653293e44Sflorian struct file *
73753293e44Sflorian pushfile(const char *name, int secret)
73853293e44Sflorian {
73953293e44Sflorian 	struct file	*nfile;
74053293e44Sflorian 
74153293e44Sflorian 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
74253293e44Sflorian 		log_warn("calloc");
74353293e44Sflorian 		return (NULL);
74453293e44Sflorian 	}
74553293e44Sflorian 	if ((nfile->name = strdup(name)) == NULL) {
74653293e44Sflorian 		log_warn("strdup");
74753293e44Sflorian 		free(nfile);
74853293e44Sflorian 		return (NULL);
74953293e44Sflorian 	}
75053293e44Sflorian 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
75153293e44Sflorian 		log_warn("%s", nfile->name);
75253293e44Sflorian 		free(nfile->name);
75353293e44Sflorian 		free(nfile);
75453293e44Sflorian 		return (NULL);
75553293e44Sflorian 	} else if (secret &&
75653293e44Sflorian 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
75753293e44Sflorian 		fclose(nfile->stream);
75853293e44Sflorian 		free(nfile->name);
75953293e44Sflorian 		free(nfile);
76053293e44Sflorian 		return (NULL);
76153293e44Sflorian 	}
76253293e44Sflorian 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
76353293e44Sflorian 	nfile->ungetsize = 16;
76453293e44Sflorian 	nfile->ungetbuf = malloc(nfile->ungetsize);
76553293e44Sflorian 	if (nfile->ungetbuf == NULL) {
76653293e44Sflorian 		log_warn("malloc");
76753293e44Sflorian 		fclose(nfile->stream);
76853293e44Sflorian 		free(nfile->name);
76953293e44Sflorian 		free(nfile);
77053293e44Sflorian 		return (NULL);
77153293e44Sflorian 	}
77253293e44Sflorian 	TAILQ_INSERT_TAIL(&files, nfile, entry);
77353293e44Sflorian 	return (nfile);
77453293e44Sflorian }
77553293e44Sflorian 
77653293e44Sflorian int
77753293e44Sflorian popfile(void)
77853293e44Sflorian {
77953293e44Sflorian 	struct file	*prev;
78053293e44Sflorian 
78153293e44Sflorian 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
78253293e44Sflorian 		prev->errors += file->errors;
78353293e44Sflorian 
78453293e44Sflorian 	TAILQ_REMOVE(&files, file, entry);
78553293e44Sflorian 	fclose(file->stream);
78653293e44Sflorian 	free(file->name);
78753293e44Sflorian 	free(file->ungetbuf);
78853293e44Sflorian 	free(file);
78953293e44Sflorian 	file = prev;
79053293e44Sflorian 	return (file ? 0 : EOF);
79153293e44Sflorian }
79253293e44Sflorian 
79353293e44Sflorian struct rad_conf *
79453293e44Sflorian parse_config(char *filename)
79553293e44Sflorian {
79653293e44Sflorian 	struct sym	*sym, *next;
79753293e44Sflorian 
79853293e44Sflorian 	conf = config_new_empty();
79953293e44Sflorian 	ra_options = NULL;
80053293e44Sflorian 
8013a682461Sflorian 	file = pushfile(filename, 0);
80253293e44Sflorian 	if (file == NULL) {
80353293e44Sflorian 		free(conf);
80453293e44Sflorian 		return (NULL);
80553293e44Sflorian 	}
80653293e44Sflorian 	topfile = file;
80753293e44Sflorian 
80853293e44Sflorian 	yyparse();
80953293e44Sflorian 	errors = file->errors;
81053293e44Sflorian 	popfile();
81153293e44Sflorian 
81253293e44Sflorian 	/* Free macros and check which have not been used. */
81353293e44Sflorian 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
81453293e44Sflorian 		if ((cmd_opts & OPT_VERBOSE2) && !sym->used)
81553293e44Sflorian 			fprintf(stderr, "warning: macro '%s' not used\n",
81653293e44Sflorian 			    sym->nam);
81753293e44Sflorian 		if (!sym->persist) {
81853293e44Sflorian 			free(sym->nam);
81953293e44Sflorian 			free(sym->val);
82053293e44Sflorian 			TAILQ_REMOVE(&symhead, sym, entry);
82153293e44Sflorian 			free(sym);
82253293e44Sflorian 		}
82353293e44Sflorian 	}
82453293e44Sflorian 
82553293e44Sflorian 	if (errors) {
82653293e44Sflorian 		clear_config(conf);
82753293e44Sflorian 		return (NULL);
82853293e44Sflorian 	}
82953293e44Sflorian 
83053293e44Sflorian 	return (conf);
83153293e44Sflorian }
83253293e44Sflorian 
83353293e44Sflorian int
83453293e44Sflorian symset(const char *nam, const char *val, int persist)
83553293e44Sflorian {
83653293e44Sflorian 	struct sym	*sym;
83753293e44Sflorian 
83853293e44Sflorian 	TAILQ_FOREACH(sym, &symhead, entry) {
83953293e44Sflorian 		if (strcmp(nam, sym->nam) == 0)
84053293e44Sflorian 			break;
84153293e44Sflorian 	}
84253293e44Sflorian 
84353293e44Sflorian 	if (sym != NULL) {
84453293e44Sflorian 		if (sym->persist == 1)
84553293e44Sflorian 			return (0);
84653293e44Sflorian 		else {
84753293e44Sflorian 			free(sym->nam);
84853293e44Sflorian 			free(sym->val);
84953293e44Sflorian 			TAILQ_REMOVE(&symhead, sym, entry);
85053293e44Sflorian 			free(sym);
85153293e44Sflorian 		}
85253293e44Sflorian 	}
85353293e44Sflorian 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
85453293e44Sflorian 		return (-1);
85553293e44Sflorian 
85653293e44Sflorian 	sym->nam = strdup(nam);
85753293e44Sflorian 	if (sym->nam == NULL) {
85853293e44Sflorian 		free(sym);
85953293e44Sflorian 		return (-1);
86053293e44Sflorian 	}
86153293e44Sflorian 	sym->val = strdup(val);
86253293e44Sflorian 	if (sym->val == NULL) {
86353293e44Sflorian 		free(sym->nam);
86453293e44Sflorian 		free(sym);
86553293e44Sflorian 		return (-1);
86653293e44Sflorian 	}
86753293e44Sflorian 	sym->used = 0;
86853293e44Sflorian 	sym->persist = persist;
86953293e44Sflorian 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
87053293e44Sflorian 	return (0);
87153293e44Sflorian }
87253293e44Sflorian 
87353293e44Sflorian int
87453293e44Sflorian cmdline_symset(char *s)
87553293e44Sflorian {
87653293e44Sflorian 	char	*sym, *val;
87753293e44Sflorian 	int	ret;
87853293e44Sflorian 	size_t	len;
87953293e44Sflorian 
88053293e44Sflorian 	if ((val = strrchr(s, '=')) == NULL)
88153293e44Sflorian 		return (-1);
88253293e44Sflorian 
88353293e44Sflorian 	len = strlen(s) - strlen(val) + 1;
88453293e44Sflorian 	if ((sym = malloc(len)) == NULL)
88553293e44Sflorian 		errx(1, "cmdline_symset: malloc");
88653293e44Sflorian 
88753293e44Sflorian 	strlcpy(sym, s, len);
88853293e44Sflorian 
88953293e44Sflorian 	ret = symset(sym, val + 1, 1);
89053293e44Sflorian 	free(sym);
89153293e44Sflorian 
89253293e44Sflorian 	return (ret);
89353293e44Sflorian }
89453293e44Sflorian 
89553293e44Sflorian char *
89653293e44Sflorian symget(const char *nam)
89753293e44Sflorian {
89853293e44Sflorian 	struct sym	*sym;
89953293e44Sflorian 
90053293e44Sflorian 	TAILQ_FOREACH(sym, &symhead, entry) {
90153293e44Sflorian 		if (strcmp(nam, sym->nam) == 0) {
90253293e44Sflorian 			sym->used = 1;
90353293e44Sflorian 			return (sym->val);
90453293e44Sflorian 		}
90553293e44Sflorian 	}
90653293e44Sflorian 	return (NULL);
90753293e44Sflorian }
90853293e44Sflorian 
90953293e44Sflorian struct ra_prefix_conf *
91053293e44Sflorian conf_get_ra_prefix(struct in6_addr *addr, int prefixlen)
91153293e44Sflorian {
91253293e44Sflorian 	struct ra_prefix_conf	*prefix;
91353293e44Sflorian 
91453293e44Sflorian 	if (addr == NULL) {
91553293e44Sflorian 		if (ra_iface_conf->autoprefix != NULL)
91653293e44Sflorian 			return (ra_iface_conf->autoprefix);
91753293e44Sflorian 	} else {
91853293e44Sflorian 		SIMPLEQ_FOREACH(prefix, &ra_iface_conf->ra_prefix_list, entry) {
91953293e44Sflorian 			if (prefix->prefixlen == prefixlen && memcmp(addr,
92053293e44Sflorian 			    &prefix->prefix, sizeof(*addr)) == 0)
92153293e44Sflorian 				return (prefix);
92253293e44Sflorian 		}
92353293e44Sflorian 	}
92453293e44Sflorian 
92553293e44Sflorian 	prefix = calloc(1, sizeof(*prefix));
92653293e44Sflorian 	if (prefix == NULL)
92753293e44Sflorian 		errx(1, "%s: calloc", __func__);
92853293e44Sflorian 	prefix->prefixlen = prefixlen;
92953293e44Sflorian 	prefix->vltime = 2592000;	/* 30 days */
93053293e44Sflorian 	prefix->pltime = 604800;	/* 7 days */
93153293e44Sflorian 	prefix->lflag = 1;
93253293e44Sflorian 	prefix->aflag = 1;
93353293e44Sflorian 
93453293e44Sflorian 	if (addr == NULL)
93553293e44Sflorian 		ra_iface_conf->autoprefix = prefix;
93653293e44Sflorian 	else {
93753293e44Sflorian 		prefix->prefix = *addr;
93853293e44Sflorian 		SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, prefix,
93953293e44Sflorian 		    entry);
94053293e44Sflorian 	}
94153293e44Sflorian 
94253293e44Sflorian 	return (prefix);
94353293e44Sflorian }
94453293e44Sflorian 
94553293e44Sflorian struct ra_iface_conf *
94653293e44Sflorian conf_get_ra_iface(char *name)
94753293e44Sflorian {
94853293e44Sflorian 	struct ra_iface_conf	*iface;
94953293e44Sflorian 	size_t			 n;
95053293e44Sflorian 
95153293e44Sflorian 	SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry) {
95253293e44Sflorian 		if (strcmp(name, iface->name) == 0)
95353293e44Sflorian 			return (iface);
95453293e44Sflorian 	}
95553293e44Sflorian 
95653293e44Sflorian 	iface = calloc(1, sizeof(*iface));
95753293e44Sflorian 	if (iface == NULL)
95853293e44Sflorian 		errx(1, "%s: calloc", __func__);
95953293e44Sflorian 	n = strlcpy(iface->name, name, sizeof(iface->name));
96053293e44Sflorian 	if (n >= sizeof(iface->name))
96153293e44Sflorian 		errx(1, "%s: name too long", __func__);
96253293e44Sflorian 
96353293e44Sflorian 	/* Inherit attributes set in global section. */
96453293e44Sflorian 	iface->ra_options = conf->ra_options;
96553293e44Sflorian 
9664c40b7e8Sflorian 	iface->rdns_lifetime = DEFAULT_RDNS_LIFETIME;
9674c40b7e8Sflorian 
96853293e44Sflorian 	SIMPLEQ_INIT(&iface->ra_prefix_list);
9694c40b7e8Sflorian 	SIMPLEQ_INIT(&iface->ra_rdnss_list);
9704c40b7e8Sflorian 	SIMPLEQ_INIT(&iface->ra_dnssl_list);
97153293e44Sflorian 
97253293e44Sflorian 	SIMPLEQ_INSERT_TAIL(&conf->ra_iface_list, iface, entry);
97353293e44Sflorian 
97453293e44Sflorian 	return (iface);
97553293e44Sflorian }
97653293e44Sflorian 
97753293e44Sflorian void
97853293e44Sflorian clear_config(struct rad_conf *xconf)
97953293e44Sflorian {
98053293e44Sflorian 	struct ra_iface_conf	*iface;
98153293e44Sflorian 
98253293e44Sflorian 	while((iface = SIMPLEQ_FIRST(&xconf->ra_iface_list)) != NULL) {
98353293e44Sflorian 		SIMPLEQ_REMOVE_HEAD(&xconf->ra_iface_list, entry);
98453293e44Sflorian 		free(iface);
98553293e44Sflorian 	}
98653293e44Sflorian 
98753293e44Sflorian 	free(xconf);
98853293e44Sflorian }
989