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