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