xref: /openbsd/usr.sbin/radiusd/parse.y (revision 09467b48)
1 /*	$OpenBSD: parse.y,v 1.12 2019/04/01 11:05:41 yasuoka Exp $	*/
2 
3 /*
4  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
5  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
6  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
7  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 %{
23 #include <sys/types.h>
24 #include <sys/queue.h>
25 #include <sys/socket.h>
26 
27 #include <ctype.h>
28 #include <errno.h>
29 #include <limits.h>
30 #include <netdb.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <syslog.h>
34 
35 #include "radiusd.h"
36 #include "radiusd_local.h"
37 #include "log.h"
38 
39 static struct	 radiusd *conf;
40 static struct	 radiusd_authentication authen;
41 static struct	 radiusd_client client;
42 
43 static struct	 radiusd_module *find_module (const char *);
44 static void	 free_str_l (void *);
45 static struct	 radiusd_module_ref *create_module_ref (const char *);
46 static void	 radiusd_authentication_init (struct radiusd_authentication *);
47 static void	 radiusd_client_init (struct radiusd_client *);
48 
49 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
50 static struct file {
51 	TAILQ_ENTRY(file)	 entry;
52 	FILE			*stream;
53 	char			*name;
54 	int			 lineno;
55 	int			 errors;
56 } *file, *topfile;
57 struct file	*pushfile(const char *);
58 int		 popfile(void);
59 int		 yyparse(void);
60 int		 yylex(void);
61 int		 yyerror(const char *, ...)
62     __attribute__((__format__ (printf, 1, 2)))
63     __attribute__((__nonnull__ (1)));
64 int		 kw_cmp(const void *, const void *);
65 int		 lookup(char *);
66 int		 lgetc(int);
67 int		 lungetc(int);
68 int		 findeol(void);
69 
70 typedef struct {
71 	union {
72 		int64_t				  number;
73 		char				 *string;
74 		struct radiusd_listen		  listen;
75 		int				  yesno;
76 		struct {
77 			char			**v;
78 			int			  c;
79 		} str_l;
80 		struct {
81 			int			 af;
82 			struct radiusd_addr	 addr;
83 			struct radiusd_addr	 mask;
84 		} prefix;
85 	} v;
86 	int lineno;
87 } YYSTYPE;
88 
89 %}
90 
91 %token	INCLUDE LISTEN ON PORT CLIENT SECRET LOAD MODULE MSGAUTH_REQUIRED
92 %token	AUTHENTICATE AUTHENTICATE_BY DECORATE_BY SET
93 %token	ERROR YES NO
94 %token	<v.string>		STRING
95 %token	<v.number>		NUMBER
96 %type	<v.number>		optport
97 %type	<v.listen>		listen_addr
98 %type	<v.str_l>		str_l
99 %type	<v.prefix>		prefix
100 %type	<v.yesno>		yesno
101 %type	<v.string>		strnum
102 %%
103 
104 grammar		: /* empty */
105 		| grammar '\n'
106 		| grammar include '\n'
107 		| grammar listen '\n'
108 		| grammar client '\n'
109 		| grammar module '\n'
110 		| grammar authenticate '\n'
111 		| grammar error '\n'
112 		;
113 
114 include		: INCLUDE STRING		{
115 			struct file	*nfile;
116 
117 			if ((nfile = pushfile($2)) == NULL) {
118 				yyerror("failed to include file %s", $2);
119 				free($2);
120 				YYERROR;
121 			}
122 			free($2);
123 
124 			file = nfile;
125 			lungetc('\n');
126 			nfile->lineno--;
127 		}
128 		;
129 listen		: LISTEN ON listen_addr {
130 			struct radiusd_listen *n;
131 
132 			if ((n = malloc(sizeof(struct radiusd_listen)))
133 			    == NULL) {
134 outofmemory:
135 				yyerror("Out of memory: %s", strerror(errno));
136 				YYERROR;
137 			}
138 			*n = $3;
139 			TAILQ_INSERT_TAIL(&conf->listen, n, next);
140 		}
141 listen_addr	: STRING optport {
142 			int		 gai_errno;
143 			struct addrinfo hints, *res;
144 
145 			memset(&hints, 0, sizeof(hints));
146 			hints.ai_family = PF_UNSPEC;
147 			hints.ai_socktype = SOCK_DGRAM;
148 			hints.ai_flags = AI_PASSIVE;
149 			hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
150 
151 			if ((gai_errno =
152 				    getaddrinfo($1, NULL, &hints, &res)) != 0 ||
153 			    res->ai_addrlen > sizeof($$.addr)) {
154 				yyerror("Could not parse the address: %s: %s",
155 				    $1, gai_strerror(gai_errno));
156 				free($1);
157 				YYERROR;
158 			}
159 			free($1);
160 			$$.stype = res->ai_socktype;
161 			$$.sproto = res->ai_protocol;
162 			memcpy(&$$.addr, res->ai_addr, res->ai_addrlen);
163 			$$.addr.ipv4.sin_port = ($2 == 0)?
164 			    htons(RADIUS_DEFAULT_PORT) : htons($2);
165 			freeaddrinfo(res);
166 		}
167 optport		: { $$ = 0; }
168 		| PORT NUMBER	{ $$ = $2; }
169 		;
170 client		: CLIENT prefix optnl clientopts_b {
171 			struct radiusd_client *client0;
172 
173 			if (client.secret[0] == '\0') {
174 				yyerror("secret is required for client");
175 				YYERROR;
176 			}
177 
178 			client0 = calloc(1, sizeof(struct radiusd_client));
179 			if (client0 == NULL)
180 				goto outofmemory;
181 			strlcpy(client0->secret, client.secret,
182 			    sizeof(client0->secret));
183 			client0->msgauth_required = client.msgauth_required;
184 			client0->af = $2.af;
185 			client0->addr = $2.addr;
186 			client0->mask = $2.mask;
187 			TAILQ_INSERT_TAIL(&conf->client, client0, next);
188 			radiusd_client_init(&client);
189 		}
190 
191 clientopts_b	: '{' optnl_l clientopts_l optnl_l '}'
192 		| '{' optnl_l '}'	/* allow empty block */
193 		;
194 
195 clientopts_l	: clientopts_l nl clientopts
196 		| clientopts
197 		;
198 
199 clientopts	: SECRET STRING {
200 			if (strlcpy(client.secret, $2, sizeof(client.secret))
201 			    >= sizeof(client.secret)) {
202 				yyerror("secret is too long");
203 				YYERROR;
204 			}
205 		}
206 		| MSGAUTH_REQUIRED yesno {
207 			client.msgauth_required = $2;
208 		}
209 		;
210 
211 prefix		: STRING '/' NUMBER {
212 			int		 gai_errno, q, r;
213 			struct addrinfo	 hints, *res;
214 
215 			memset(&hints, 0, sizeof(hints));
216 			hints.ai_family = PF_UNSPEC;
217 			hints.ai_socktype = SOCK_DGRAM;	/* dummy */
218 			hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
219 
220 			if ((gai_errno = getaddrinfo($1, NULL, &hints, &res))
221 			    != 0) {
222 				yyerror("Could not parse the address: %s: %s",
223 				    $1, gai_strerror(gai_errno));
224 				free($1);
225 				YYERROR;
226 			}
227 			free($1);
228 			q = $3 >> 3;
229 			r = $3 & 7;
230 			switch (res->ai_family) {
231 			case AF_INET:
232 				if ($3 < 0 || 32 < $3) {
233 					yyerror("mask len %lld is out of range",
234 					    (long long)$3);
235 					YYERROR;
236 				}
237 				$$.addr.addr.ipv4 = ((struct sockaddr_in *)
238 				    res->ai_addr)->sin_addr;
239 				$$.mask.addr.ipv4.s_addr = htonl((uint32_t)
240 				    ((0xffffffffffULL) << (32 - $3)));
241 				break;
242 			case AF_INET6:
243 				if ($3 < 0 || 128 < $3) {
244 					yyerror("mask len %lld is out of range",
245 					    (long long)$3);
246 					YYERROR;
247 				}
248 				$$.addr.addr.ipv6 = ((struct sockaddr_in6 *)
249 				    res->ai_addr)->sin6_addr;
250 				memset(&$$.mask.addr.ipv6, 0,
251 				    sizeof($$.mask.addr.ipv6));
252 				if (q > 0)
253 					memset(&$$.mask.addr.ipv6, 0xff, q);
254 				if (r > 0)
255 					*((u_char *)&$$.mask.addr.ipv6 + q) =
256 					    (0xff00 >> r) & 0xff;
257 				break;
258 			}
259 			$$.af = res->ai_family;
260 			freeaddrinfo(res);
261 		}
262 		;
263 module		: MODULE LOAD STRING STRING {
264 			struct radiusd_module *module;
265 			if ((module = radiusd_module_load(conf, $4, $3))
266 			    == NULL) {
267 				free($3);
268 				free($4);
269 				YYERROR;
270 			}
271 			free($3);
272 			free($4);
273 			TAILQ_INSERT_TAIL(&conf->module, module, next);
274 		}
275 		| MODULE SET STRING STRING str_l {
276 			struct radiusd_module	*module;
277 
278 			module = find_module($3);
279 			if (module == NULL) {
280 				yyerror("module `%s' is not found", $3);
281 setstrerr:
282 				free($3);
283 				free($4);
284 				free_str_l(&$5);
285 				YYERROR;
286 			}
287 			if ($4[0] == '_') {
288 				yyerror("setting `%s' is not allowed", $4);
289 				goto setstrerr;
290 			}
291 			if (radiusd_module_set(module, $4, $5.c, $5.v)) {
292 				yyerror("syntax error by module `%s'", $3);
293 				goto setstrerr;
294 			}
295 			free($3);
296 			free($4);
297 			free_str_l(&$5);
298 		}
299 		;
300 authenticate	: AUTHENTICATE str_l optnl authopts_b {
301 			struct radiusd_authentication *a;
302 
303 			if ((a = calloc(1,
304 			    sizeof(struct radiusd_authentication))) == NULL) {
305 				free_str_l(&$2);
306 				goto outofmemory;
307 			}
308 			a->auth = authen.auth;
309 			a->deco = authen.deco;
310 			a->username = $2.v;
311 
312 			TAILQ_INSERT_TAIL(&conf->authen, a, next);
313 			radiusd_authentication_init(&authen);
314 		}
315 		;
316 
317 authopts_b	: '{' optnl_l authopts_l optnl_l '}'
318 		| '{' optnl_l '}'	/* empty options */
319 		;
320 
321 authopts_l	: authopts_l nl authopts
322 		| authopts
323 		;
324 
325 authopts	: AUTHENTICATE_BY STRING {
326 			struct radiusd_module_ref	*modref;
327 
328 			modref = create_module_ref($2);
329 			free($2);
330 			if (modref == NULL)
331 				YYERROR;
332 			authen.auth = modref;
333 		}
334 		/* XXX decoration doesn't work for this moment.  */
335 		| DECORATE_BY str_l {
336 			int				 i;
337 			struct radiusd_module_ref	*modref;
338 
339 			for (i = 0; i < $2.c; i++) {
340 				if ((modref = create_module_ref($2.v[i]))
341 				    == NULL) {
342 					free_str_l(&$2);
343 					YYERROR;
344 				}
345 				TAILQ_INSERT_TAIL(&authen.deco, modref, next);
346 			}
347 			free_str_l(&$2);
348 		}
349 		;
350 str_l		: str_l strnum {
351 			int	  i;
352 			char	**v;
353 			if ((v = calloc(sizeof(char **), $$.c + 2)) == NULL)
354 				goto outofmemory;
355 			for (i = 0; i < $$.c; i++)
356 				v[i] = $$.v[i];
357 			v[i++] = $2;
358 			v[i] = NULL;
359 			$$.c++;
360 			free($$.v);
361 			$$.v = v;
362 		}
363 		| strnum {
364 			if (($$.v = calloc(sizeof(char **), 2)) == NULL)
365 				goto outofmemory;
366 			$$.v[0] = $1;
367 			$$.v[1] = NULL;
368 			$$.c = 1;
369 		}
370 		;
371 strnum		: STRING	{ $$ = $1; }
372 		| NUMBER {
373 			/* Treat number as a string */
374 			asprintf(&($$), "%jd", (intmax_t)$1);
375 			if ($$ == NULL)
376 				goto outofmemory;
377 		}
378 		;
379 optnl		:
380 		| '\n'
381 		;
382 nl		: '\n' optnl		/* one new line or more */
383 		;
384 optnl_l		:
385 		| '\n' optnl_l
386 		;
387 yesno		: YES { $$ = true; }
388 		| NO  { $$ = false; }
389 		;
390 %%
391 
392 struct keywords {
393 	const char	*k_name;
394 	int		 k_val;
395 };
396 
397 int
398 yyerror(const char *fmt, ...)
399 {
400 	va_list		 ap;
401 	char		*msg;
402 
403 	file->errors++;
404 	va_start(ap, fmt);
405 	if (vasprintf(&msg, fmt, ap) == -1)
406 		fatalx("yyerror vasprintf");
407 	va_end(ap);
408 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
409 	free(msg);
410 	return (0);
411 }
412 
413 int
414 kw_cmp(const void *k, const void *e)
415 {
416 	return (strcmp(k, ((const struct keywords *)e)->k_name));
417 }
418 
419 int
420 lookup(char *s)
421 {
422 	/* this has to be sorted always */
423 	static const struct keywords keywords[] = {
424 		{ "authenticate",		AUTHENTICATE},
425 		{ "authenticate-by",		AUTHENTICATE_BY},
426 		{ "client",			CLIENT},
427 		{ "decorate-by",		DECORATE_BY},
428 		{ "include",			INCLUDE},
429 		{ "listen",			LISTEN},
430 		{ "load",			LOAD},
431 		{ "module",			MODULE},
432 		{ "msgauth-required",		MSGAUTH_REQUIRED},
433 		{ "no",				NO},
434 		{ "on",				ON},
435 		{ "port",			PORT},
436 		{ "secret",			SECRET},
437 		{ "set",			SET},
438 		{ "yes",			YES},
439 	};
440 	const struct keywords	*p;
441 
442 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
443 	    sizeof(keywords[0]), kw_cmp);
444 
445 	if (p)
446 		return (p->k_val);
447 	else
448 		return (STRING);
449 }
450 
451 #define MAXPUSHBACK	128
452 
453 u_char	*parsebuf;
454 int	 parseindex;
455 u_char	 pushback_buffer[MAXPUSHBACK];
456 int	 pushback_index = 0;
457 
458 int
459 lgetc(int quotec)
460 {
461 	int		c, next;
462 
463 	if (parsebuf) {
464 		/* Read character from the parsebuffer instead of input. */
465 		if (parseindex >= 0) {
466 			c = parsebuf[parseindex++];
467 			if (c != '\0')
468 				return (c);
469 			parsebuf = NULL;
470 		} else
471 			parseindex++;
472 	}
473 
474 	if (pushback_index)
475 		return (pushback_buffer[--pushback_index]);
476 
477 	if (quotec) {
478 		if ((c = getc(file->stream)) == EOF) {
479 			yyerror("reached end of file while parsing "
480 			    "quoted string");
481 			if (file == topfile || popfile() == EOF)
482 				return (EOF);
483 			return (quotec);
484 		}
485 		return (c);
486 	}
487 
488 	while ((c = getc(file->stream)) == '\\') {
489 		next = getc(file->stream);
490 		if (next != '\n') {
491 			c = next;
492 			break;
493 		}
494 		yylval.lineno = file->lineno;
495 		file->lineno++;
496 	}
497 
498 	while (c == EOF) {
499 		if (file == topfile || popfile() == EOF)
500 			return (EOF);
501 		c = getc(file->stream);
502 	}
503 	return (c);
504 }
505 
506 int
507 lungetc(int c)
508 {
509 	if (c == EOF)
510 		return (EOF);
511 	if (parsebuf) {
512 		parseindex--;
513 		if (parseindex >= 0)
514 			return (c);
515 	}
516 	if (pushback_index < MAXPUSHBACK-1)
517 		return (pushback_buffer[pushback_index++] = c);
518 	else
519 		return (EOF);
520 }
521 
522 int
523 findeol(void)
524 {
525 	int	c;
526 
527 	parsebuf = NULL;
528 
529 	/* skip to either EOF or the first real EOL */
530 	while (1) {
531 		if (pushback_index)
532 			c = pushback_buffer[--pushback_index];
533 		else
534 			c = lgetc(0);
535 		if (c == '\n') {
536 			file->lineno++;
537 			break;
538 		}
539 		if (c == EOF)
540 			break;
541 	}
542 	return (ERROR);
543 }
544 
545 int
546 yylex(void)
547 {
548 	u_char	 buf[8096];
549 	u_char	*p;
550 	int	 quotec, next, c;
551 	int	 token;
552 
553 	p = buf;
554 	while ((c = lgetc(0)) == ' ' || c == '\t')
555 		; /* nothing */
556 
557 	yylval.lineno = file->lineno;
558 	if (c == '#')
559 		while ((c = lgetc(0)) != '\n' && c != EOF)
560 			; /* nothing */
561 
562 	switch (c) {
563 	case '\'':
564 	case '"':
565 		quotec = c;
566 		while (1) {
567 			if ((c = lgetc(quotec)) == EOF)
568 				return (0);
569 			if (c == '\n') {
570 				file->lineno++;
571 				continue;
572 			} else if (c == '\\') {
573 				if ((next = lgetc(quotec)) == EOF)
574 					return (0);
575 				if (next == quotec || next == ' ' ||
576 				    next == '\t')
577 					c = next;
578 				else if (next == '\n') {
579 					file->lineno++;
580 					continue;
581 				} else
582 					lungetc(next);
583 			} else if (c == quotec) {
584 				*p = '\0';
585 				break;
586 			} else if (c == '\0') {
587 				yyerror("syntax error");
588 				return (findeol());
589 			}
590 			if (p + 1 >= buf + sizeof(buf) - 1) {
591 				yyerror("string too long");
592 				return (findeol());
593 			}
594 			*p++ = c;
595 		}
596 		yylval.v.string = strdup(buf);
597 		if (yylval.v.string == NULL)
598 			fatal("yylex: strdup");
599 		return (STRING);
600 	}
601 
602 #define allowed_to_end_number(x) \
603 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
604 
605 	if (c == '-' || isdigit(c)) {
606 		do {
607 			*p++ = c;
608 			if ((size_t)(p-buf) >= sizeof(buf)) {
609 				yyerror("string too long");
610 				return (findeol());
611 			}
612 		} while ((c = lgetc(0)) != EOF && isdigit(c));
613 		lungetc(c);
614 		if (p == buf + 1 && buf[0] == '-')
615 			goto nodigits;
616 		if (c == EOF || allowed_to_end_number(c)) {
617 			const char *errstr = NULL;
618 
619 			*p = '\0';
620 			yylval.v.number = strtonum(buf, LLONG_MIN,
621 			    LLONG_MAX, &errstr);
622 			if (errstr) {
623 				yyerror("\"%s\" invalid number: %s",
624 				    buf, errstr);
625 				return (findeol());
626 			}
627 			return (NUMBER);
628 		} else {
629 nodigits:
630 			while (p > buf + 1)
631 				lungetc(*--p);
632 			c = *--p;
633 			if (c == '-')
634 				return (c);
635 		}
636 	}
637 
638 #define allowed_in_string(x) \
639 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
640 	x != '{' && x != '}' && x != '<' && x != '>' && \
641 	x != '!' && x != '=' && x != '/' && x != '#' && \
642 	x != ','))
643 
644 	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
645 		do {
646 			*p++ = c;
647 			if ((size_t)(p-buf) >= sizeof(buf)) {
648 				yyerror("string too long");
649 				return (findeol());
650 			}
651 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
652 		lungetc(c);
653 		*p = '\0';
654 		if ((token = lookup(buf)) == STRING)
655 			if ((yylval.v.string = strdup(buf)) == NULL)
656 				fatal("yylex: strdup");
657 		return (token);
658 	}
659 	if (c == '\n') {
660 		yylval.lineno = file->lineno;
661 		file->lineno++;
662 	}
663 	if (c == EOF)
664 		return (0);
665 	return (c);
666 }
667 
668 struct file *
669 pushfile(const char *name)
670 {
671 	struct file	*nfile;
672 
673 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
674 		log_warn("%s", __func__);
675 		return (NULL);
676 	}
677 	if ((nfile->name = strdup(name)) == NULL) {
678 		log_warn("%s", __func__);
679 		free(nfile);
680 		return (NULL);
681 	}
682 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
683 		log_warn("%s: %s", __func__, nfile->name);
684 		free(nfile->name);
685 		free(nfile);
686 		return (NULL);
687 	}
688 	nfile->lineno = 1;
689 	TAILQ_INSERT_TAIL(&files, nfile, entry);
690 	return (nfile);
691 }
692 
693 int
694 popfile(void)
695 {
696 	struct file	*prev;
697 
698 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
699 		prev->errors += file->errors;
700 
701 	TAILQ_REMOVE(&files, file, entry);
702 	fclose(file->stream);
703 	free(file->name);
704 	free(file);
705 	file = prev;
706 	return (file ? 0 : EOF);
707 }
708 
709 int
710 parse_config(const char *filename, struct radiusd *radiusd)
711 {
712 	int				 errors = 0;
713 	struct radiusd_listen		*l;
714 	struct radiusd_module_ref	*m, *mt;
715 
716 	conf = radiusd;
717 	radiusd_conf_init(conf);
718 	radiusd_authentication_init(&authen);
719 	radiusd_client_init(&client);
720 	authen.auth = NULL;
721 
722 	if ((file = pushfile(filename)) == NULL) {
723 		errors++;
724 		goto out;
725 	}
726 	topfile = file;
727 
728 	yyparse();
729 	errors = file->errors;
730 	popfile();
731 
732 	if (TAILQ_EMPTY(&conf->listen)) {
733 		if ((l = malloc(sizeof(struct radiusd_listen))) == NULL) {
734 			log_warn("Out of memory");
735 			return (-1);
736 		}
737 		l->stype = SOCK_DGRAM;
738 		l->sproto = IPPROTO_UDP;
739 		l->addr.ipv4.sin_family = AF_INET;
740 		l->addr.ipv4.sin_len = sizeof(struct sockaddr_in);
741 		l->addr.ipv4.sin_addr.s_addr = htonl(0x7F000001L);
742 		l->addr.ipv4.sin_port = htons(RADIUS_DEFAULT_PORT);
743 		TAILQ_INSERT_TAIL(&conf->listen, l, next);
744 	}
745 	TAILQ_FOREACH(l, &conf->listen, next) {
746 		l->sock = -1;
747 	}
748 	if (authen.auth != NULL)
749 		free(authen.auth);
750 	TAILQ_FOREACH_SAFE(m, &authen.deco, next, mt) {
751 		TAILQ_REMOVE(&authen.deco, m, next);
752 		free(m);
753 	}
754 out:
755 	conf = NULL;
756 	return (errors ? -1 : 0);
757 }
758 
759 static struct radiusd_module *
760 find_module(const char *name)
761 {
762 	struct radiusd_module	*module;
763 
764 	TAILQ_FOREACH(module, &conf->module, next) {
765 		if (strcmp(name, module->name) == 0)
766 			return (module);
767 	}
768 
769 	return (NULL);
770 }
771 
772 static void
773 free_str_l(void *str_l0)
774 {
775 	int				  i;
776 	struct {
777 		char			**v;
778 		int			  c;
779 	}				 *str_l = str_l0;
780 
781 	for (i = 0; i < str_l->c; i++)
782 		free(str_l->v[i]);
783 	free(str_l->v);
784 }
785 
786 static struct radiusd_module_ref *
787 create_module_ref(const char *modulename)
788 {
789 	struct radiusd_module		*module;
790 	struct radiusd_module_ref	*modref;
791 
792 	if ((module = find_module(modulename)) == NULL) {
793 		yyerror("module `%s' is not found", modulename);
794 		return (NULL);
795 	}
796 	if ((modref = calloc(1, sizeof(struct radiusd_module_ref))) == NULL) {
797 		yyerror("Out of memory: %s", strerror(errno));
798 		return (NULL);
799 	}
800 	modref->module = module;
801 
802 	return (modref);
803 }
804 
805 static void
806 radiusd_authentication_init(struct radiusd_authentication *auth)
807 {
808 	memset(auth, 0, sizeof(struct radiusd_authentication));
809 	TAILQ_INIT(&auth->deco);
810 }
811 
812 static void
813 radiusd_client_init(struct radiusd_client *clnt)
814 {
815 	memset(clnt, 0, sizeof(struct radiusd_client));
816 	clnt->msgauth_required = true;
817 }
818