]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/openbsm/bin/auditdistd/parse.y
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / contrib / openbsm / bin / auditdistd / parse.y
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 }