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