3 * Copyright (c) 2012 The FreeBSD Foundation
6 * This software was developed by Pawel Jakub Dawidek under sponsorship from
7 * the FreeBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
30 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/parse.y#5 $
33 #include <config/config.h>
35 #include <sys/types.h>
36 #include <sys/queue.h>
37 #include <sys/sysctl.h>
39 #include <arpa/inet.h>
48 #include <compat/strlcpy.h>
51 #include "auditdistd.h"
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;
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];
74 static bool adjust_directory(char *path);
75 static bool family_supported(int family);
77 extern void yyrestart(FILE *);
91 %token RECEIVER REMOTE
96 %type <num> checksum_type
97 %type <num> compression_type
128 name_statement: NAME STR
130 PJDLOG_RASSERT(depth == 0,
131 "The name variable can only be specificed in the global section.");
133 if (lconfig->adc_name[0] != '\0') {
134 pjdlog_error("The name variable is specified twice.");
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.");
149 pidfile_statement: PIDFILE STR
151 PJDLOG_RASSERT(depth == 0,
152 "The pidfile variable can only be specificed in the global section.");
154 if (lconfig->adc_pidfile[0] != '\0') {
155 pjdlog_error("The pidfile variable is specified twice.");
159 if (strcmp($2, "none") != 0 && $2[0] != '/') {
160 pjdlog_error("The pidfile variable must be set to absolute pathname or \"none\".");
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.");
175 timeout_statement: TIMEOUT NUM
177 PJDLOG_ASSERT(depth == 0);
179 lconfig->adc_timeout = $2;
183 sender_statement: SENDER sender_start sender_entries CB
185 PJDLOG_ASSERT(depth == 0);
186 PJDLOG_ASSERT(cursection == SECTION_SENDER);
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));
197 /* Empty depth1_source is ok. */
198 TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
199 if (curhost->adh_role != ADIST_ROLE_SENDER)
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,
208 sizeof(curhost->adh_directory));
210 if (curhost->adh_localaddr[0] == '\0') {
211 (void)strlcpy(curhost->adh_localaddr,
213 sizeof(curhost->adh_localaddr));
216 cursection = SECTION_GLOBAL;
222 PJDLOG_ASSERT(depth == 1);
223 PJDLOG_ASSERT(cursection == SECTION_GLOBAL);
225 cursection = SECTION_SENDER;
226 depth1_checksum = -1;
227 depth1_compression = -1;
228 depth1_source[0] = '\0';
229 depth1_directory[0] = '\0';
231 #ifndef HAVE_AUDIT_SYSCALLS
232 pjdlog_error("Sender functionality is not available.");
240 sender_entries sender_entry
251 compression_statement
254 sender_host_statement
257 receiver_statement: RECEIVER receiver_start receiver_entries CB
259 PJDLOG_ASSERT(depth == 0);
260 PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
263 * If not listen addresses were specified,
264 * configure default ones.
266 if (TAILQ_EMPTY(&lconfig->adc_listen)) {
267 struct adist_listen *lst;
269 if (family_supported(AF_INET)) {
270 lst = calloc(1, sizeof(*lst));
272 pjdlog_error("Unable to allocate memory for listen address.");
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);
281 "No IPv4 support in the kernel, not listening on IPv4 address.");
283 if (family_supported(AF_INET6)) {
284 lst = calloc(1, sizeof(*lst));
286 pjdlog_error("Unable to allocate memory for listen address.");
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);
295 "No IPv6 support in the kernel, not listening on IPv6 address.");
297 if (TAILQ_EMPTY(&lconfig->adc_listen)) {
298 pjdlog_error("No address to listen on.");
302 /* Configure defaults. */
303 if (depth1_directory[0] == '\0') {
304 (void)strlcpy(depth1_directory,
305 ADIST_DIRECTORY_RECEIVER,
306 sizeof(depth1_directory));
308 TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
309 if (curhost->adh_role != ADIST_ROLE_RECEIVER)
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.");
321 cursection = SECTION_GLOBAL;
327 PJDLOG_ASSERT(depth == 1);
328 PJDLOG_ASSERT(cursection == SECTION_GLOBAL);
330 cursection = SECTION_RECEIVER;
331 depth1_directory[0] = '\0';
337 receiver_entries receiver_entry
349 receiver_host_statement
353 checksum_statement: CHECKSUM checksum_type
355 PJDLOG_ASSERT(cursection == SECTION_SENDER);
359 depth1_checksum = $2;
362 PJDLOG_ASSERT(curhost != NULL);
363 curhost->adh_checksum = $2;
366 PJDLOG_ABORT("checksum at wrong depth level");
372 NONE { $$ = ADIST_CHECKSUM_NONE; }
374 CRC32 { $$ = ADIST_CHECKSUM_CRC32; }
376 SHA256 { $$ = ADIST_CHECKSUM_SHA256; }
379 compression_statement: COMPRESSION compression_type
381 PJDLOG_ASSERT(cursection == SECTION_SENDER);
385 depth1_compression = $2;
388 PJDLOG_ASSERT(curhost != NULL);
389 curhost->adh_compression = $2;
392 PJDLOG_ABORT("compression at wrong depth level");
398 NONE { $$ = ADIST_COMPRESSION_NONE; }
400 LZF { $$ = ADIST_COMPRESSION_LZF; }
404 directory_statement: DIRECTORY STR
406 PJDLOG_ASSERT(cursection == SECTION_SENDER ||
407 cursection == SECTION_RECEIVER);
411 if (strlcpy(depth1_directory, $2,
412 sizeof(depth1_directory)) >=
413 sizeof(depth1_directory)) {
414 pjdlog_error("Directory value is too long.");
418 if (!adjust_directory(depth1_directory))
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.");
430 } else /* if (cursection == SECTION_RECEIVER) */ {
431 if (depth1_directory[0] == '\0') {
432 pjdlog_error("Directory path must be absolute.");
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.");
447 PJDLOG_ABORT("directory at wrong depth level");
453 source_statement: SOURCE STR
455 PJDLOG_RASSERT(cursection == SECTION_SENDER,
456 "The source variable must be in sender section.");
460 if (strlcpy(depth1_source, $2,
461 sizeof(depth1_source)) >=
462 sizeof(depth1_source)) {
463 pjdlog_error("Source value is too long.");
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.");
482 fingerprint_statement: FINGERPRINT STR
484 PJDLOG_ASSERT(cursection == SECTION_SENDER);
485 PJDLOG_ASSERT(depth == 2);
487 if (strncasecmp($2, "SHA256=", 7) != 0) {
488 pjdlog_error("Invalid fingerprint value.");
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.");
503 password_statement: PASSWORD STR
505 PJDLOG_ASSERT(cursection == SECTION_SENDER ||
506 cursection == SECTION_RECEIVER);
507 PJDLOG_ASSERT(depth == 2);
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));
517 bzero($2, strlen($2));
522 certfile_statement: CERTFILE STR
524 PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
525 PJDLOG_ASSERT(depth == 1);
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.");
538 keyfile_statement: KEYFILE STR
540 PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
541 PJDLOG_ASSERT(depth == 1);
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.");
554 listen_statement: LISTEN STR
556 struct adist_listen *lst;
558 PJDLOG_ASSERT(depth == 1);
559 PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
561 lst = calloc(1, sizeof(*lst));
563 pjdlog_error("Unable to allocate memory for listen address.");
567 if (strlcpy(lst->adl_addr, $2, sizeof(lst->adl_addr)) >=
568 sizeof(lst->adl_addr)) {
569 pjdlog_error("listen argument is too long.");
574 TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
579 sender_host_statement: HOST host_start OB sender_host_entries CB
581 /* Put it onto host list. */
582 TAILQ_INSERT_TAIL(&lconfig->adc_hosts, curhost, adh_next);
587 receiver_host_statement: HOST host_start OB receiver_host_entries CB
589 /* Put it onto host list. */
590 TAILQ_INSERT_TAIL(&lconfig->adc_hosts, curhost, adh_next);
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)
601 if (curhost->adh_role == ADIST_ROLE_SENDER &&
602 cursection == SECTION_RECEIVER) {
605 if (curhost->adh_role == ADIST_ROLE_RECEIVER &&
606 cursection == SECTION_SENDER) {
609 pjdlog_error("%s host %s is configured more than once.",
610 curhost->adh_role == ADIST_ROLE_SENDER ?
611 "Sender" : "Receiver", curhost->adh_name);
616 curhost = calloc(1, sizeof(*curhost));
617 if (curhost == NULL) {
618 pjdlog_error("Unable to allocate memory for host configuration.");
622 if (strlcpy(curhost->adh_name, $1, sizeof(curhost->adh_name)) >=
623 sizeof(curhost->adh_name)) {
624 pjdlog_error("Host name is too long.");
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;
645 sender_host_entries sender_host_entry
655 fingerprint_statement
662 compression_statement
666 receiver_host_entries:
668 receiver_host_entries receiver_host_entry
679 remote_statement: REMOTE STR
681 PJDLOG_ASSERT(depth == 2);
682 PJDLOG_ASSERT(cursection == SECTION_SENDER ||
683 cursection == SECTION_RECEIVER);
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.");
699 family_supported(int family)
703 sock = socket(family, SOCK_STREAM, 0);
704 if (sock == -1 && errno == EPROTONOSUPPORT)
712 adjust_directory(char *path)
719 pjdlog_error("Directory path is empty.");
722 if (path[len - 1] != '/')
727 if (path[0] != '/') {
728 pjdlog_error("Directory path must be absolute.");
735 my_name(char *name, size_t size)
737 char buf[MAXHOSTNAMELEN];
740 if (gethostname(buf, sizeof(buf)) < 0) {
741 pjdlog_errno(LOG_ERR, "gethostname() failed");
745 /* First component of the host name. */
746 pos = strchr(buf, '.');
748 (void)strlcpy(name, buf, size);
750 (void)strlcpy(name, buf, MIN((size_t)(pos - buf + 1), size));
752 if (name[0] == '\0') {
753 pjdlog_error("Empty host name.");
761 yyerror(const char *str)
764 pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
765 lineno, yytext, str);
768 struct adist_config *
769 yy_config_parse(const char *config, bool exitonerror)
774 cursection = SECTION_GLOBAL;
778 lconfig = calloc(1, sizeof(*lconfig));
779 if (lconfig == NULL) {
780 pjdlog_error("Unable to allocate memory for configuration.");
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';
793 yyin = fopen(config, "r");
795 pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
797 yy_config_free(lconfig);
806 yy_config_free(lconfig);
813 * Let's see if everything is set up.
815 if (lconfig->adc_name[0] == '\0' && my_name(lconfig->adc_name,
816 sizeof(lconfig->adc_name)) == -1) {
817 yy_config_free(lconfig);
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));
828 if (lconfig->adc_certfile[0] == '\0') {
829 (void)strlcpy(lconfig->adc_certfile, ADIST_CERTFILE,
830 sizeof(lconfig->adc_certfile));
832 if (lconfig->adc_keyfile[0] == '\0') {
833 (void)strlcpy(lconfig->adc_keyfile, ADIST_KEYFILE,
834 sizeof(lconfig->adc_keyfile));
841 yy_config_free(struct adist_config *config)
843 struct adist_host *adhost;
844 struct adist_listen *lst;
846 while ((lst = TAILQ_FIRST(&config->adc_listen)) != NULL) {
847 TAILQ_REMOVE(&config->adc_listen, lst, adl_next);
850 while ((adhost = TAILQ_FIRST(&config->adc_hosts)) != NULL) {
851 TAILQ_REMOVE(&config->adc_hosts, adhost, adh_next);
852 bzero(adhost, sizeof(*adhost));