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