xref: /freebsd/contrib/openbsm/bin/auditdistd/parse.y (revision b740c88bfb6453416926271c089262e7164dace3)
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 
54 extern int depth;
55 extern int lineno;
56 
57 extern FILE *yyin;
58 extern char *yytext;
59 
60 static struct adist_config *lconfig;
61 static struct adist_host *curhost;
62 #define	SECTION_GLOBAL		0
63 #define	SECTION_SENDER		1
64 #define	SECTION_RECEIVER	2
65 static int cursection;
66 
67 /* Sender section. */
68 static char depth1_source[ADIST_ADDRSIZE];
69 static int depth1_checksum;
70 static int depth1_compression;
71 /* Sender and receiver sections. */
72 static char depth1_directory[PATH_MAX];
73 
74 static bool adjust_directory(char *path);
75 static bool family_supported(int family);
76 
77 extern 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 
111 statements:
112 	|
113 	statements statement
114 	;
115 
116 statement:
117 	name_statement
118 	|
119 	pidfile_statement
120 	|
121 	timeout_statement
122 	|
123 	sender_statement
124 	|
125 	receiver_statement
126 	;
127 
128 name_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 
149 pidfile_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 
175 timeout_statement:	TIMEOUT NUM
176 	{
177 		PJDLOG_ASSERT(depth == 0);
178 
179 		lconfig->adc_timeout = $2;
180 	}
181 	;
182 
183 sender_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 
220 sender_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 
238 sender_entries:
239 	|
240 	sender_entries sender_entry
241 	;
242 
243 sender_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 
257 receiver_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 
325 receiver_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 
335 receiver_entries:
336 	|
337 	receiver_entries receiver_entry
338 	;
339 
340 receiver_entry:
341 	listen_statement
342 	|
343 	directory_statement
344 	|
345 	certfile_statement
346 	|
347 	keyfile_statement
348 	|
349 	receiver_host_statement
350 	;
351 
352 /*
353 checksum_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 
371 checksum_type:
372 	NONE		{ $$ = ADIST_CHECKSUM_NONE; }
373 	|
374 	CRC32		{ $$ = ADIST_CHECKSUM_CRC32; }
375 	|
376 	SHA256		{ $$ = ADIST_CHECKSUM_SHA256; }
377 	;
378 
379 compression_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 
397 compression_type:
398 	NONE		{ $$ = ADIST_COMPRESSION_NONE; }
399 	|
400 	LZF		{ $$ = ADIST_COMPRESSION_LZF; }
401 	;
402 */
403 
404 directory_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 
453 source_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 
482 fingerprint_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 
503 password_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 
522 certfile_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 
538 keyfile_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 
554 listen_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 
579 sender_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 
587 receiver_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 
595 host_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 
643 sender_host_entries:
644 	|
645 	sender_host_entries sender_host_entry
646 	;
647 
648 sender_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 
666 receiver_host_entries:
667 	|
668 	receiver_host_entries receiver_host_entry
669 	;
670 
671 receiver_host_entry:
672 	remote_statement
673 	|
674 	directory_statement
675 	|
676 	password_statement
677 	;
678 
679 remote_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 
698 static bool
699 family_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 
711 static bool
712 adjust_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 
734 static int
735 my_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 
760 void
761 yyerror(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 
768 struct adist_config *
769 yy_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 
840 void
841 yy_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