1%{
2/*-
3 * Copyright (c) 2012 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * This software was developed by Pawel Jakub Dawidek under sponsorship from
7 * the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/parse.y#5 $
31 */
32
33#include <config/config.h>
34
35#include <sys/types.h>
36#include <sys/queue.h>
37#include <sys/sysctl.h>
38
39#include <arpa/inet.h>
40
41#include <err.h>
42#include <errno.h>
43#include <stdio.h>
44#include <string.h>
45#include <sysexits.h>
46#include <unistd.h>
47#ifndef HAVE_STRLCPY
48#include <compat/strlcpy.h>
49#endif
50
51#include "auditdistd.h"
52#include "pjdlog.h"
53
54extern int depth;
55extern int lineno;
56
57extern FILE *yyin;
58extern char *yytext;
59
60static struct adist_config *lconfig;
61static struct adist_host *curhost;
62#define	SECTION_GLOBAL		0
63#define	SECTION_SENDER		1
64#define	SECTION_RECEIVER	2
65static int cursection;
66
67/* Sender section. */
68static char depth1_source[ADIST_ADDRSIZE];
69static int depth1_checksum;
70static int depth1_compression;
71/* Sender and receiver sections. */
72static char depth1_directory[PATH_MAX];
73
74static bool adjust_directory(char *path);
75static bool family_supported(int family);
76
77extern void yyrestart(FILE *);
78%}
79
80%token CB
81%token CERTFILE
82%token DIRECTORY
83%token FINGERPRINT
84%token HOST
85%token KEYFILE
86%token LISTEN
87%token NAME
88%token OB
89%token PASSWORD
90%token PIDFILE
91%token RECEIVER REMOTE
92%token SENDER SOURCE
93%token TIMEOUT
94
95/*
96%type <num> checksum_type
97%type <num> compression_type
98*/
99
100%union
101{
102	int num;
103	char *str;
104}
105
106%token <num> NUM
107%token <str> STR
108
109%%
110
111statements:
112	|
113	statements statement
114	;
115
116statement:
117	name_statement
118	|
119	pidfile_statement
120	|
121	timeout_statement
122	|
123	sender_statement
124	|
125	receiver_statement
126	;
127
128name_statement:	NAME STR
129	{
130		PJDLOG_RASSERT(depth == 0,
131		    "The name variable can only be specificed in the global section.");
132
133		if (lconfig->adc_name[0] != '\0') {
134			pjdlog_error("The name variable is specified twice.");
135			free($2);
136			return (1);
137		}
138		if (strlcpy(lconfig->adc_name, $2,
139		    sizeof(lconfig->adc_name)) >=
140		    sizeof(lconfig->adc_name)) {
141			pjdlog_error("The name value is too long.");
142			free($2);
143			return (1);
144		}
145		free($2);
146	}
147	;
148
149pidfile_statement:	PIDFILE STR
150	{
151		PJDLOG_RASSERT(depth == 0,
152		    "The pidfile variable can only be specificed in the global section.");
153
154		if (lconfig->adc_pidfile[0] != '\0') {
155			pjdlog_error("The pidfile variable is specified twice.");
156			free($2);
157			return (1);
158		}
159		if (strcmp($2, "none") != 0 && $2[0] != '/') {
160			pjdlog_error("The pidfile variable must be set to absolute pathname or \"none\".");
161			free($2);
162			return (1);
163		}
164		if (strlcpy(lconfig->adc_pidfile, $2,
165		    sizeof(lconfig->adc_pidfile)) >=
166		    sizeof(lconfig->adc_pidfile)) {
167			pjdlog_error("The pidfile value is too long.");
168			free($2);
169			return (1);
170		}
171		free($2);
172	}
173	;
174
175timeout_statement:	TIMEOUT NUM
176	{
177		PJDLOG_ASSERT(depth == 0);
178
179		lconfig->adc_timeout = $2;
180	}
181	;
182
183sender_statement:	SENDER sender_start sender_entries CB
184	{
185		PJDLOG_ASSERT(depth == 0);
186		PJDLOG_ASSERT(cursection == SECTION_SENDER);
187
188		/* Configure defaults. */
189		if (depth1_checksum == -1)
190			depth1_checksum = ADIST_CHECKSUM_NONE;
191		if (depth1_compression == -1)
192			depth1_compression = ADIST_COMPRESSION_NONE;
193		if (depth1_directory[0] == '\0') {
194			(void)strlcpy(depth1_directory, ADIST_DIRECTORY_SENDER,
195			    sizeof(depth1_directory));
196		}
197		/* Empty depth1_source is ok. */
198		TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
199			if (curhost->adh_role != ADIST_ROLE_SENDER)
200				continue;
201			if (curhost->adh_checksum == -1)
202				curhost->adh_checksum = depth1_checksum;
203			if (curhost->adh_compression == -1)
204				curhost->adh_compression = depth1_compression;
205			if (curhost->adh_directory[0] == '\0') {
206				(void)strlcpy(curhost->adh_directory,
207				    depth1_directory,
208				    sizeof(curhost->adh_directory));
209			}
210			if (curhost->adh_localaddr[0] == '\0') {
211				(void)strlcpy(curhost->adh_localaddr,
212				    depth1_source,
213				    sizeof(curhost->adh_localaddr));
214			}
215		}
216		cursection = SECTION_GLOBAL;
217	}
218	;
219
220sender_start:	OB
221	{
222		PJDLOG_ASSERT(depth == 1);
223		PJDLOG_ASSERT(cursection == SECTION_GLOBAL);
224
225		cursection = SECTION_SENDER;
226		depth1_checksum = -1;
227		depth1_compression = -1;
228		depth1_source[0] = '\0';
229		depth1_directory[0] = '\0';
230
231#ifndef HAVE_AUDIT_SYSCALLS
232		pjdlog_error("Sender functionality is not available.");
233		return (1);
234#endif
235	}
236	;
237
238sender_entries:
239	|
240	sender_entries sender_entry
241	;
242
243sender_entry:
244	source_statement
245	|
246	directory_statement
247/*
248	|
249	checksum_statement
250	|
251	compression_statement
252*/
253	|
254	sender_host_statement
255	;
256
257receiver_statement:	RECEIVER receiver_start receiver_entries CB
258	{
259		PJDLOG_ASSERT(depth == 0);
260		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
261
262		/*
263		 * If not listen addresses were specified,
264		 * configure default ones.
265		 */
266		if (TAILQ_EMPTY(&lconfig->adc_listen)) {
267			struct adist_listen *lst;
268
269			if (family_supported(AF_INET)) {
270				lst = calloc(1, sizeof(*lst));
271				if (lst == NULL) {
272					pjdlog_error("Unable to allocate memory for listen address.");
273					return (1);
274				}
275				(void)strlcpy(lst->adl_addr,
276				    ADIST_LISTEN_TLS_TCP4,
277				    sizeof(lst->adl_addr));
278				TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
279			} else {
280				pjdlog_debug(1,
281				    "No IPv4 support in the kernel, not listening on IPv4 address.");
282			}
283			if (family_supported(AF_INET6)) {
284				lst = calloc(1, sizeof(*lst));
285				if (lst == NULL) {
286					pjdlog_error("Unable to allocate memory for listen address.");
287					return (1);
288				}
289				(void)strlcpy(lst->adl_addr,
290				    ADIST_LISTEN_TLS_TCP6,
291				    sizeof(lst->adl_addr));
292				TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
293			} else {
294				pjdlog_debug(1,
295				    "No IPv6 support in the kernel, not listening on IPv6 address.");
296			}
297			if (TAILQ_EMPTY(&lconfig->adc_listen)) {
298				pjdlog_error("No address to listen on.");
299				return (1);
300			}
301		}
302		/* Configure defaults. */
303		if (depth1_directory[0] == '\0') {
304			(void)strlcpy(depth1_directory,
305			    ADIST_DIRECTORY_RECEIVER,
306			    sizeof(depth1_directory));
307		}
308		TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
309			if (curhost->adh_role != ADIST_ROLE_RECEIVER)
310				continue;
311			if (curhost->adh_directory[0] == '\0') {
312				if (snprintf(curhost->adh_directory,
313				    sizeof(curhost->adh_directory), "%s/%s",
314				    depth1_directory, curhost->adh_name) >=
315				    (ssize_t)sizeof(curhost->adh_directory)) {
316					pjdlog_error("Directory value is too long.");
317					return (1);
318				}
319			}
320		}
321		cursection = SECTION_GLOBAL;
322	}
323	;
324
325receiver_start:	OB
326	{
327		PJDLOG_ASSERT(depth == 1);
328		PJDLOG_ASSERT(cursection == SECTION_GLOBAL);
329
330		cursection = SECTION_RECEIVER;
331		depth1_directory[0] = '\0';
332	}
333	;
334
335receiver_entries:
336	|
337	receiver_entries receiver_entry
338	;
339
340receiver_entry:
341	listen_statement
342	|
343	directory_statement
344	|
345	certfile_statement
346	|
347	keyfile_statement
348	|
349	receiver_host_statement
350	;
351
352/*
353checksum_statement:	CHECKSUM checksum_type
354	{
355		PJDLOG_ASSERT(cursection == SECTION_SENDER);
356
357		switch (depth) {
358		case 1:
359			depth1_checksum = $2;
360			break;
361		case 2:
362			PJDLOG_ASSERT(curhost != NULL);
363			curhost->adh_checksum = $2;
364			break;
365		default:
366			PJDLOG_ABORT("checksum at wrong depth level");
367		}
368	}
369	;
370
371checksum_type:
372	NONE		{ $$ = ADIST_CHECKSUM_NONE; }
373	|
374	CRC32		{ $$ = ADIST_CHECKSUM_CRC32; }
375	|
376	SHA256		{ $$ = ADIST_CHECKSUM_SHA256; }
377	;
378
379compression_statement:	COMPRESSION compression_type
380	{
381		PJDLOG_ASSERT(cursection == SECTION_SENDER);
382
383		switch (depth) {
384		case 1:
385			depth1_compression = $2;
386			break;
387		case 2:
388			PJDLOG_ASSERT(curhost != NULL);
389			curhost->adh_compression = $2;
390			break;
391		default:
392			PJDLOG_ABORT("compression at wrong depth level");
393		}
394	}
395	;
396
397compression_type:
398	NONE		{ $$ = ADIST_COMPRESSION_NONE; }
399	|
400	LZF		{ $$ = ADIST_COMPRESSION_LZF; }
401	;
402*/
403
404directory_statement:	DIRECTORY STR
405	{
406		PJDLOG_ASSERT(cursection == SECTION_SENDER ||
407		    cursection == SECTION_RECEIVER);
408
409		switch (depth) {
410		case 1:
411			if (strlcpy(depth1_directory, $2,
412			    sizeof(depth1_directory)) >=
413			    sizeof(depth1_directory)) {
414				pjdlog_error("Directory value is too long.");
415				free($2);
416				return (1);
417			}
418			if (!adjust_directory(depth1_directory))
419				return (1);
420			break;
421		case 2:
422			if (cursection == SECTION_SENDER || $2[0] == '/') {
423				if (strlcpy(curhost->adh_directory, $2,
424				    sizeof(curhost->adh_directory)) >=
425				    sizeof(curhost->adh_directory)) {
426					pjdlog_error("Directory value is too long.");
427					free($2);
428					return (1);
429				}
430			} else /* if (cursection == SECTION_RECEIVER) */ {
431				if (depth1_directory[0] == '\0') {
432					pjdlog_error("Directory path must be absolute.");
433					free($2);
434					return (1);
435				}
436				if (snprintf(curhost->adh_directory,
437				    sizeof(curhost->adh_directory), "%s/%s",
438				    depth1_directory, $2) >=
439				    (ssize_t)sizeof(curhost->adh_directory)) {
440					pjdlog_error("Directory value is too long.");
441					free($2);
442					return (1);
443				}
444			}
445			break;
446		default:
447			PJDLOG_ABORT("directory at wrong depth level");
448		}
449		free($2);
450	}
451	;
452
453source_statement:	SOURCE STR
454	{
455		PJDLOG_RASSERT(cursection == SECTION_SENDER,
456		    "The source variable must be in sender section.");
457
458		switch (depth) {
459		case 1:
460			if (strlcpy(depth1_source, $2,
461			    sizeof(depth1_source)) >=
462			    sizeof(depth1_source)) {
463				pjdlog_error("Source value is too long.");
464				free($2);
465				return (1);
466			}
467			break;
468		case 2:
469			if (strlcpy(curhost->adh_localaddr, $2,
470			    sizeof(curhost->adh_localaddr)) >=
471			    sizeof(curhost->adh_localaddr)) {
472				pjdlog_error("Source value is too long.");
473				free($2);
474				return (1);
475			}
476			break;
477		}
478		free($2);
479	}
480	;
481
482fingerprint_statement:	FINGERPRINT STR
483	{
484		PJDLOG_ASSERT(cursection == SECTION_SENDER);
485		PJDLOG_ASSERT(depth == 2);
486
487		if (strncasecmp($2, "SHA256=", 7) != 0) {
488			pjdlog_error("Invalid fingerprint value.");
489			free($2);
490			return (1);
491		}
492		if (strlcpy(curhost->adh_fingerprint, $2,
493		    sizeof(curhost->adh_fingerprint)) >=
494		    sizeof(curhost->adh_fingerprint)) {
495			pjdlog_error("Fingerprint value is too long.");
496			free($2);
497			return (1);
498		}
499		free($2);
500	}
501	;
502
503password_statement:	PASSWORD STR
504	{
505		PJDLOG_ASSERT(cursection == SECTION_SENDER ||
506		    cursection == SECTION_RECEIVER);
507		PJDLOG_ASSERT(depth == 2);
508
509		if (strlcpy(curhost->adh_password, $2,
510		    sizeof(curhost->adh_password)) >=
511		    sizeof(curhost->adh_password)) {
512			pjdlog_error("Password value is too long.");
513			bzero($2, strlen($2));
514			free($2);
515			return (1);
516		}
517		bzero($2, strlen($2));
518		free($2);
519	}
520	;
521
522certfile_statement:	CERTFILE STR
523	{
524		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
525		PJDLOG_ASSERT(depth == 1);
526
527		if (strlcpy(lconfig->adc_certfile, $2,
528		    sizeof(lconfig->adc_certfile)) >=
529		    sizeof(lconfig->adc_certfile)) {
530			pjdlog_error("Certfile value is too long.");
531			free($2);
532			return (1);
533		}
534		free($2);
535	}
536	;
537
538keyfile_statement:	KEYFILE STR
539	{
540		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
541		PJDLOG_ASSERT(depth == 1);
542
543		if (strlcpy(lconfig->adc_keyfile, $2,
544		    sizeof(lconfig->adc_keyfile)) >=
545		    sizeof(lconfig->adc_keyfile)) {
546			pjdlog_error("Keyfile value is too long.");
547			free($2);
548			return (1);
549		}
550		free($2);
551	}
552	;
553
554listen_statement:	LISTEN STR
555	{
556		struct adist_listen *lst;
557
558		PJDLOG_ASSERT(depth == 1);
559		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
560
561		lst = calloc(1, sizeof(*lst));
562		if (lst == NULL) {
563			pjdlog_error("Unable to allocate memory for listen address.");
564			free($2);
565			return (1);
566		}
567		if (strlcpy(lst->adl_addr, $2, sizeof(lst->adl_addr)) >=
568		    sizeof(lst->adl_addr)) {
569			pjdlog_error("listen argument is too long.");
570			free($2);
571			free(lst);
572			return (1);
573		}
574		TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
575		free($2);
576	}
577	;
578
579sender_host_statement:	HOST host_start OB sender_host_entries CB
580	{
581		/* Put it onto host list. */
582		TAILQ_INSERT_TAIL(&lconfig->adc_hosts, curhost, adh_next);
583		curhost = NULL;
584	}
585	;
586
587receiver_host_statement:	HOST host_start OB receiver_host_entries CB
588	{
589		/* Put it onto host list. */
590		TAILQ_INSERT_TAIL(&lconfig->adc_hosts, curhost, adh_next);
591		curhost = NULL;
592	}
593	;
594
595host_start:	STR
596	{
597		/* Check if there is no duplicate entry. */
598		TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
599			if (strcmp(curhost->adh_name, $1) != 0)
600				continue;
601			if (curhost->adh_role == ADIST_ROLE_SENDER &&
602			    cursection == SECTION_RECEIVER) {
603				continue;
604			}
605			if (curhost->adh_role == ADIST_ROLE_RECEIVER &&
606			    cursection == SECTION_SENDER) {
607				continue;
608			}
609			pjdlog_error("%s host %s is configured more than once.",
610			    curhost->adh_role == ADIST_ROLE_SENDER ?
611			    "Sender" : "Receiver", curhost->adh_name);
612			free($1);
613			return (1);
614		}
615
616		curhost = calloc(1, sizeof(*curhost));
617		if (curhost == NULL) {
618			pjdlog_error("Unable to allocate memory for host configuration.");
619			free($1);
620			return (1);
621		}
622		if (strlcpy(curhost->adh_name, $1, sizeof(curhost->adh_name)) >=
623		    sizeof(curhost->adh_name)) {
624			pjdlog_error("Host name is too long.");
625			free($1);
626			return (1);
627		}
628		free($1);
629		curhost->adh_role = cursection == SECTION_SENDER ?
630		    ADIST_ROLE_SENDER : ADIST_ROLE_RECEIVER;
631		curhost->adh_version = ADIST_VERSION;
632		curhost->adh_localaddr[0] = '\0';
633		curhost->adh_remoteaddr[0] = '\0';
634		curhost->adh_remote = NULL;
635		curhost->adh_directory[0] = '\0';
636		curhost->adh_password[0] = '\0';
637		curhost->adh_fingerprint[0] = '\0';
638		curhost->adh_worker_pid = 0;
639		curhost->adh_conn = NULL;
640	}
641	;
642
643sender_host_entries:
644	|
645	sender_host_entries sender_host_entry
646	;
647
648sender_host_entry:
649	source_statement
650	|
651	remote_statement
652	|
653	directory_statement
654	|
655	fingerprint_statement
656	|
657	password_statement
658/*
659	|
660	checksum_statement
661	|
662	compression_statement
663*/
664	;
665
666receiver_host_entries:
667	|
668	receiver_host_entries receiver_host_entry
669	;
670
671receiver_host_entry:
672	remote_statement
673	|
674	directory_statement
675	|
676	password_statement
677	;
678
679remote_statement:	REMOTE STR
680	{
681		PJDLOG_ASSERT(depth == 2);
682		PJDLOG_ASSERT(cursection == SECTION_SENDER ||
683		    cursection == SECTION_RECEIVER);
684
685		if (strlcpy(curhost->adh_remoteaddr, $2,
686		    sizeof(curhost->adh_remoteaddr)) >=
687		    sizeof(curhost->adh_remoteaddr)) {
688			pjdlog_error("Remote value is too long.");
689			free($2);
690			return (1);
691		}
692		free($2);
693	}
694	;
695
696%%
697
698static bool
699family_supported(int family)
700{
701	int sock;
702
703	sock = socket(family, SOCK_STREAM, 0);
704	if (sock == -1 && errno == EPROTONOSUPPORT)
705		return (false);
706	if (sock >= 0)
707		(void)close(sock);
708	return (true);
709}
710
711static bool
712adjust_directory(char *path)
713{
714	size_t len;
715
716	len = strlen(path);
717	for (;;) {
718		if (len == 0) {
719			pjdlog_error("Directory path is empty.");
720			return (false);
721		}
722		if (path[len - 1] != '/')
723			break;
724		len--;
725		path[len] = '\0';
726	}
727	if (path[0] != '/') {
728		pjdlog_error("Directory path must be absolute.");
729		return (false);
730	}
731	return (true);
732}
733
734static int
735my_name(char *name, size_t size)
736{
737	char buf[MAXHOSTNAMELEN];
738	char *pos;
739
740	if (gethostname(buf, sizeof(buf)) < 0) {
741		pjdlog_errno(LOG_ERR, "gethostname() failed");
742		return (-1);
743	}
744
745	/* First component of the host name. */
746	pos = strchr(buf, '.');
747	if (pos == NULL)
748		(void)strlcpy(name, buf, size);
749	else
750		(void)strlcpy(name, buf, MIN((size_t)(pos - buf + 1), size));
751
752	if (name[0] == '\0') {
753		pjdlog_error("Empty host name.");
754		return (-1);
755	}
756
757	return (0);
758}
759
760void
761yyerror(const char *str)
762{
763
764	pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
765	    lineno, yytext, str);
766}
767
768struct adist_config *
769yy_config_parse(const char *config, bool exitonerror)
770{
771	int ret;
772
773	curhost = NULL;
774	cursection = SECTION_GLOBAL;
775	depth = 0;
776	lineno = 0;
777
778	lconfig = calloc(1, sizeof(*lconfig));
779	if (lconfig == NULL) {
780		pjdlog_error("Unable to allocate memory for configuration.");
781		if (exitonerror)
782			exit(EX_TEMPFAIL);
783		return (NULL);
784	}
785	TAILQ_INIT(&lconfig->adc_hosts);
786	TAILQ_INIT(&lconfig->adc_listen);
787	lconfig->adc_name[0] = '\0';
788	lconfig->adc_timeout = -1;
789	lconfig->adc_pidfile[0] = '\0';
790	lconfig->adc_certfile[0] = '\0';
791	lconfig->adc_keyfile[0] = '\0';
792
793	yyin = fopen(config, "r");
794	if (yyin == NULL) {
795		pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
796		    config);
797		yy_config_free(lconfig);
798		if (exitonerror)
799			exit(EX_OSFILE);
800		return (NULL);
801	}
802	yyrestart(yyin);
803	ret = yyparse();
804	fclose(yyin);
805	if (ret != 0) {
806		yy_config_free(lconfig);
807		if (exitonerror)
808			exit(EX_CONFIG);
809		return (NULL);
810	}
811
812	/*
813	 * Let's see if everything is set up.
814	 */
815	if (lconfig->adc_name[0] == '\0' && my_name(lconfig->adc_name,
816	    sizeof(lconfig->adc_name)) == -1) {
817		yy_config_free(lconfig);
818		if (exitonerror)
819			exit(EX_CONFIG);
820		return (NULL);
821	}
822	if (lconfig->adc_timeout == -1)
823		lconfig->adc_timeout = ADIST_TIMEOUT;
824	if (lconfig->adc_pidfile[0] == '\0') {
825		(void)strlcpy(lconfig->adc_pidfile, ADIST_PIDFILE,
826		    sizeof(lconfig->adc_pidfile));
827	}
828	if (lconfig->adc_certfile[0] == '\0') {
829		(void)strlcpy(lconfig->adc_certfile, ADIST_CERTFILE,
830		    sizeof(lconfig->adc_certfile));
831	}
832	if (lconfig->adc_keyfile[0] == '\0') {
833		(void)strlcpy(lconfig->adc_keyfile, ADIST_KEYFILE,
834		    sizeof(lconfig->adc_keyfile));
835	}
836
837	return (lconfig);
838}
839
840void
841yy_config_free(struct adist_config *config)
842{
843	struct adist_host *adhost;
844	struct adist_listen *lst;
845
846	while ((lst = TAILQ_FIRST(&config->adc_listen)) != NULL) {
847		TAILQ_REMOVE(&config->adc_listen, lst, adl_next);
848		free(lst);
849	}
850	while ((adhost = TAILQ_FIRST(&config->adc_hosts)) != NULL) {
851		TAILQ_REMOVE(&config->adc_hosts, adhost, adh_next);
852		bzero(adhost, sizeof(*adhost));
853		free(adhost);
854	}
855	free(config);
856}
857