parse.y revision 243730
1139825Simp%{
2148078Srwatson/*-
3148078Srwatson * Copyright (c) 2012 The FreeBSD Foundation
4148078Srwatson * All rights reserved.
592654Sjeff *
692654Sjeff * This software was developed by Pawel Jakub Dawidek under sponsorship from
792654Sjeff * the FreeBSD Foundation.
892654Sjeff *
992654Sjeff * Redistribution and use in source and binary forms, with or without
1092654Sjeff * modification, are permitted provided that the following conditions
1192654Sjeff * are met:
1292654Sjeff * 1. Redistributions of source code must retain the above copyright
1392654Sjeff *    notice, this list of conditions and the following disclaimer.
1492654Sjeff * 2. Redistributions in binary form must reproduce the above copyright
1592654Sjeff *    notice, this list of conditions and the following disclaimer in the
1692654Sjeff *    documentation and/or other materials provided with the distribution.
1792654Sjeff *
1892654Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1992654Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2092654Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2192654Sjeff * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2292654Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2392654Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2492654Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2592654Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2692654Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2792654Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2892654Sjeff * SUCH DAMAGE.
2992654Sjeff *
3092654Sjeff * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/parse.y#3 $
3192654Sjeff */
3292654Sjeff
3392654Sjeff#include "config.h"
3492654Sjeff
3592654Sjeff#include <sys/types.h>
3692654Sjeff#include <sys/queue.h>
3792654Sjeff#include <sys/sysctl.h>
3892654Sjeff
3992654Sjeff#include <arpa/inet.h>
4092654Sjeff
4192654Sjeff#include <err.h>
42184546Skeramida#include <errno.h>
4392654Sjeff#include <stdio.h>
4492654Sjeff#include <string.h>
4592654Sjeff#include <sysexits.h>
4692654Sjeff#include <unistd.h>
47129906Sbmilekic#ifndef HAVE_STRLCPY
4892654Sjeff#include <compat/strlcpy.h>
4992654Sjeff#endif
5092654Sjeff
51166213Smohans#include <pjdlog.h>
52166213Smohans
53244024Spjd#include "auditdistd.h"
5492654Sjeff
5592654Sjeffextern int depth;
5692654Sjeffextern int lineno;
5792654Sjeff
5892654Sjeffextern FILE *yyin;
5992654Sjeffextern char *yytext;
60132987Sgreen
61244024Spjdstatic struct adist_config *lconfig;
6292654Sjeffstatic struct adist_host *curhost;
63132987Sgreen#define	SECTION_GLOBAL		0
64132987Sgreen#define	SECTION_SENDER		1
6592654Sjeff#define	SECTION_RECEIVER	2
6692654Sjeffstatic int cursection;
6792654Sjeff
68105689Ssheldonh/* Sender section. */
6992654Sjeffstatic char depth1_source[ADIST_ADDRSIZE];
70132987Sgreenstatic int depth1_checksum;
7192654Sjeffstatic int depth1_compression;
7292654Sjeff/* Sender and receiver sections. */
7392654Sjeffstatic char depth1_directory[PATH_MAX];
7492654Sjeff
7592654Sjeffstatic bool adjust_directory(char *path);
7692654Sjeffstatic bool family_supported(int family);
7792654Sjeff
7892654Sjeffextern void yyrestart(FILE *);
79244024Spjd%}
8092654Sjeff
8192654Sjeff%token CB
8292654Sjeff%token CERTFILE
8392654Sjeff%token DIRECTORY
8492654Sjeff%token FINGERPRINT
8592654Sjeff%token HOST
8692654Sjeff%token KEYFILE
8792654Sjeff%token LISTEN
8892654Sjeff%token NAME
8992654Sjeff%token OB
90244024Spjd%token PASSWORD
9192654Sjeff%token PIDFILE
9292654Sjeff%token RECEIVER REMOTE
9392654Sjeff%token SENDER SOURCE
9492654Sjeff%token TIMEOUT
9592654Sjeff
96132987Sgreen/*
97244024Spjd%type <num> checksum_type
9892654Sjeff%type <num> compression_type
99132987Sgreen*/
100132987Sgreen
10192654Sjeff%union
10292654Sjeff{
103244024Spjd	int num;
104184546Skeramida	char *str;
105184546Skeramida}
10692654Sjeff
107132987Sgreen%token <num> NUM
10892654Sjeff%token <str> STR
10992654Sjeff
11092654Sjeff%%
11192654Sjeff
11292654Sjeffstatements:
113244024Spjd	|
11492654Sjeff	statements statement
11592654Sjeff	;
11692654Sjeff
11792654Sjeffstatement:
11892654Sjeff	name_statement
11992654Sjeff	|
12092654Sjeff	pidfile_statement
12192654Sjeff	|
122184546Skeramida	timeout_statement
12392654Sjeff	|
12492654Sjeff	sender_statement
12592654Sjeff	|
12692654Sjeff	receiver_statement
127251826Sjeff	;
128251826Sjeff
129251826Sjeffname_statement:	NAME STR
130251826Sjeff	{
131251826Sjeff		PJDLOG_RASSERT(depth == 0,
132251826Sjeff		    "The name variable can only be specificed in the global section.");
133251826Sjeff
134251826Sjeff		if (lconfig->adc_name[0] != '\0') {
135251826Sjeff			pjdlog_error("The name variable is specified twice.");
136251826Sjeff			free($2);
13792654Sjeff			return (1);
13892654Sjeff		}
139244024Spjd		if (strlcpy(lconfig->adc_name, $2,
14092654Sjeff		    sizeof(lconfig->adc_name)) >=
14192654Sjeff		    sizeof(lconfig->adc_name)) {
14292654Sjeff			pjdlog_error("The name value is too long.");
14392654Sjeff			free($2);
14492654Sjeff			return (1);
145184546Skeramida		}
14692654Sjeff		free($2);
147105689Ssheldonh	}
14892654Sjeff	;
14992654Sjeff
15092654Sjeffpidfile_statement:	PIDFILE STR
15192654Sjeff	{
15292654Sjeff		PJDLOG_RASSERT(depth == 0,
15392654Sjeff		    "The pidfile variable can only be specificed in the global section.");
15492654Sjeff
15592654Sjeff		if (lconfig->adc_pidfile[0] != '\0') {
15692654Sjeff			pjdlog_error("The pidfile variable is specified twice.");
15792654Sjeff			free($2);
15892654Sjeff			return (1);
15992654Sjeff		}
16092654Sjeff		if (strcmp($2, "none") != 0 && $2[0] != '/') {
16192654Sjeff			pjdlog_error("The pidfile variable must be set to absolute pathname or \"none\".");
162184546Skeramida			free($2);
16392654Sjeff			return (1);
16492654Sjeff		}
165184546Skeramida		if (strlcpy(lconfig->adc_pidfile, $2,
16692654Sjeff		    sizeof(lconfig->adc_pidfile)) >=
16792654Sjeff		    sizeof(lconfig->adc_pidfile)) {
16892654Sjeff			pjdlog_error("The pidfile value is too long.");
16992654Sjeff			free($2);
170184546Skeramida			return (1);
17192654Sjeff		}
172184546Skeramida		free($2);
17392654Sjeff	}
17492654Sjeff	;
17592654Sjeff
17692654Sjefftimeout_statement:	TIMEOUT NUM
17792654Sjeff	{
178242152Smdf		PJDLOG_ASSERT(depth == 0);
179242152Smdf
180249313Sglebius		lconfig->adc_timeout = $2;
18192654Sjeff	}
182120223Sjeff	;
183129906Sbmilekic
184129906Sbmilekicsender_statement:	SENDER sender_start sender_entries CB
185129906Sbmilekic	{
186184546Skeramida		PJDLOG_ASSERT(depth == 0);
187129906Sbmilekic		PJDLOG_ASSERT(cursection == SECTION_SENDER);
188184546Skeramida
189129906Sbmilekic		/* Configure defaults. */
190129906Sbmilekic		if (depth1_checksum == -1)
191129906Sbmilekic			depth1_checksum = ADIST_CHECKSUM_NONE;
192129906Sbmilekic		if (depth1_compression == -1)
193129906Sbmilekic			depth1_compression = ADIST_COMPRESSION_NONE;
194129906Sbmilekic		if (depth1_directory[0] == '\0') {
195129906Sbmilekic			(void)strlcpy(depth1_directory, ADIST_DIRECTORY_SENDER,
196129906Sbmilekic			    sizeof(depth1_directory));
197129906Sbmilekic		}
198129906Sbmilekic		/* Empty depth1_source is ok. */
199129906Sbmilekic		TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
200129906Sbmilekic			if (curhost->adh_role != ADIST_ROLE_SENDER)
201129906Sbmilekic				continue;
202129906Sbmilekic			if (curhost->adh_checksum == -1)
203129906Sbmilekic				curhost->adh_checksum = depth1_checksum;
204129906Sbmilekic			if (curhost->adh_compression == -1)
205129906Sbmilekic				curhost->adh_compression = depth1_compression;
206129913Sbmilekic			if (curhost->adh_directory[0] == '\0') {
207129913Sbmilekic				(void)strlcpy(curhost->adh_directory,
208129913Sbmilekic				    depth1_directory,
209129906Sbmilekic				    sizeof(curhost->adh_directory));
210129906Sbmilekic			}
211129906Sbmilekic			if (curhost->adh_localaddr[0] == '\0') {
212129906Sbmilekic				(void)strlcpy(curhost->adh_localaddr,
213129906Sbmilekic				    depth1_source,
214129906Sbmilekic				    sizeof(curhost->adh_localaddr));
215129906Sbmilekic			}
216129906Sbmilekic		}
217129906Sbmilekic		cursection = SECTION_GLOBAL;
218187681Sjeff	}
219187681Sjeff	;
220187681Sjeff
221187681Sjeffsender_start:	OB
222187681Sjeff	{
223187681Sjeff		PJDLOG_ASSERT(depth == 1);
224244024Spjd		PJDLOG_ASSERT(cursection == SECTION_GLOBAL);
225187681Sjeff
226187681Sjeff		cursection = SECTION_SENDER;
227187681Sjeff		depth1_checksum = -1;
228187681Sjeff		depth1_compression = -1;
229251826Sjeff		depth1_source[0] = '\0';
230251826Sjeff		depth1_directory[0] = '\0';
231251826Sjeff
232251826Sjeff#ifndef HAVE_AUDIT_SYSCALLS
233251826Sjeff		pjdlog_error("Sender functionality is not available.");
234251826Sjeff		return (1);
235251826Sjeff#endif
236251826Sjeff	}
237252040Sjeff	;
238251826Sjeff
239251826Sjeffsender_entries:
240251826Sjeff	|
241251826Sjeff	sender_entries sender_entry
242120223Sjeff	;
243120223Sjeff
244120223Sjeffsender_entry:
245148072Ssilby	source_statement
246120223Sjeff	|
24792654Sjeff	directory_statement
24892654Sjeff/*
24992654Sjeff	|
250184546Skeramida	checksum_statement
25192654Sjeff	|
25292654Sjeff	compression_statement
25392654Sjeff*/
25492654Sjeff	|
25595758Sjeff	sender_host_statement
256103531Sjeff	;
257103531Sjeff
258103531Sjeffreceiver_statement:	RECEIVER receiver_start receiver_entries CB
259103531Sjeff	{
260103531Sjeff		PJDLOG_ASSERT(depth == 0);
261103531Sjeff		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
262103531Sjeff
263103531Sjeff		/*
264129906Sbmilekic		 * If not listen addresses were specified,
265129906Sbmilekic		 * configure default ones.
266129906Sbmilekic		 */
267187681Sjeff		if (TAILQ_EMPTY(&lconfig->adc_listen)) {
268187681Sjeff			struct adist_listen *lst;
269187681Sjeff
270187681Sjeff			if (family_supported(AF_INET)) {
271187681Sjeff				lst = calloc(1, sizeof(*lst));
272187681Sjeff				if (lst == NULL) {
273187681Sjeff					pjdlog_error("Unable to allocate memory for listen address.");
274230623Skmacy					return (1);
275230623Skmacy				}
276230623Skmacy				(void)strlcpy(lst->adl_addr,
277230623Skmacy				    ADIST_LISTEN_TLS_TCP4,
278249264Sglebius				    sizeof(lst->adl_addr));
279249264Sglebius				TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
280249264Sglebius			} else {
281249264Sglebius				pjdlog_debug(1,
28292654Sjeff				    "No IPv4 support in the kernel, not listening on IPv4 address.");
283187681Sjeff			}
284187681Sjeff			if (family_supported(AF_INET6)) {
285187681Sjeff				lst = calloc(1, sizeof(*lst));
286187681Sjeff				if (lst == NULL) {
287187681Sjeff					pjdlog_error("Unable to allocate memory for listen address.");
288187681Sjeff					return (1);
289226313Sglebius				}
290249264Sglebius				(void)strlcpy(lst->adl_addr,
291187681Sjeff				    ADIST_LISTEN_TLS_TCP6,
29292654Sjeff				    sizeof(lst->adl_addr));
29392654Sjeff				TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
29492654Sjeff			} else {
29592654Sjeff				pjdlog_debug(1,
29692654Sjeff				    "No IPv6 support in the kernel, not listening on IPv6 address.");
29792654Sjeff			}
298166654Srwatson			if (TAILQ_EMPTY(&lconfig->adc_listen)) {
29992654Sjeff				pjdlog_error("No address to listen on.");
30092654Sjeff				return (1);
30194161Sjeff			}
30292654Sjeff		}
30392654Sjeff		/* Configure defaults. */
30492654Sjeff		if (depth1_directory[0] == '\0') {
30592654Sjeff			(void)strlcpy(depth1_directory,
30692654Sjeff			    ADIST_DIRECTORY_RECEIVER,
30794161Sjeff			    sizeof(depth1_directory));
30892654Sjeff		}
30992654Sjeff		TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
31092654Sjeff			if (curhost->adh_role != ADIST_ROLE_RECEIVER)
31192654Sjeff				continue;
31292654Sjeff			if (curhost->adh_directory[0] == '\0') {
31392654Sjeff				if (snprintf(curhost->adh_directory,
31492654Sjeff				    sizeof(curhost->adh_directory), "%s/%s",
31595766Sjeff				    depth1_directory, curhost->adh_name) >=
31692654Sjeff				    (ssize_t)sizeof(curhost->adh_directory)) {
31792654Sjeff					pjdlog_error("Directory value is too long.");
318184546Skeramida					return (1);
319184546Skeramida				}
320184546Skeramida			}
32192654Sjeff		}
32292654Sjeff		cursection = SECTION_GLOBAL;
32395766Sjeff	}
32492654Sjeff	;
32592654Sjeff
32692654Sjeffreceiver_start:	OB
32792654Sjeff	{
32892654Sjeff		PJDLOG_ASSERT(depth == 1);
32992654Sjeff		PJDLOG_ASSERT(cursection == SECTION_GLOBAL);
33092654Sjeff
33195766Sjeff		cursection = SECTION_RECEIVER;
33292654Sjeff		depth1_directory[0] = '\0';
33392654Sjeff	}
33495766Sjeff	;
33592654Sjeff
33695766Sjeffreceiver_entries:
33792654Sjeff	|
33892654Sjeff	receiver_entries receiver_entry
33992654Sjeff	;
34092654Sjeff
34192654Sjeffreceiver_entry:
34292654Sjeff	listen_statement
34392654Sjeff	|
34492654Sjeff	directory_statement
34592654Sjeff	|
34692654Sjeff	certfile_statement
34792654Sjeff	|
34892654Sjeff	keyfile_statement
34992654Sjeff	|
35092654Sjeff	receiver_host_statement
35192654Sjeff	;
35292654Sjeff
35392654Sjeff/*
35492654Sjeffchecksum_statement:	CHECKSUM checksum_type
35592654Sjeff	{
35692654Sjeff		PJDLOG_ASSERT(cursection == SECTION_SENDER);
35792654Sjeff
35892654Sjeff		switch (depth) {
35992654Sjeff		case 1:
36092654Sjeff			depth1_checksum = $2;
36192654Sjeff			break;
36292654Sjeff		case 2:
36392654Sjeff			PJDLOG_ASSERT(curhost != NULL);
364100326Smarkm			curhost->adh_checksum = $2;
36592654Sjeff			break;
36692654Sjeff		default:
36792654Sjeff			PJDLOG_ABORT("checksum at wrong depth level");
36892654Sjeff		}
36992654Sjeff	}
37092654Sjeff	;
37192654Sjeff
37292654Sjeffchecksum_type:
37392654Sjeff	NONE		{ $$ = ADIST_CHECKSUM_NONE; }
37492654Sjeff	|
37592654Sjeff	CRC32		{ $$ = ADIST_CHECKSUM_CRC32; }
376184546Skeramida	|
377184546Skeramida	SHA256		{ $$ = ADIST_CHECKSUM_SHA256; }
37892654Sjeff	;
37992654Sjeff
38092654Sjeffcompression_statement:	COMPRESSION compression_type
38192654Sjeff	{
382184546Skeramida		PJDLOG_ASSERT(cursection == SECTION_SENDER);
38392654Sjeff
38492654Sjeff		switch (depth) {
385249313Sglebius		case 1:
38692654Sjeff			depth1_compression = $2;
38792654Sjeff			break;
38892654Sjeff		case 2:
38992654Sjeff			PJDLOG_ASSERT(curhost != NULL);
39092654Sjeff			curhost->adh_compression = $2;
391184546Skeramida			break;
392184546Skeramida		default:
393184546Skeramida			PJDLOG_ABORT("compression at wrong depth level");
39492654Sjeff		}
39592654Sjeff	}
39692654Sjeff	;
39792654Sjeff
398249313Sglebiuscompression_type:
39992654Sjeff	NONE		{ $$ = ADIST_COMPRESSION_NONE; }
40092654Sjeff	|
40192654Sjeff	LZF		{ $$ = ADIST_COMPRESSION_LZF; }
40292654Sjeff	;
40392654Sjeff*/
40492654Sjeff
40592654Sjeffdirectory_statement:	DIRECTORY STR
40692654Sjeff	{
40792654Sjeff		PJDLOG_ASSERT(cursection == SECTION_SENDER ||
40892654Sjeff		    cursection == SECTION_RECEIVER);
40992654Sjeff
41092654Sjeff		switch (depth) {
41192654Sjeff		case 1:
41292654Sjeff			if (strlcpy(depth1_directory, $2,
41392654Sjeff			    sizeof(depth1_directory)) >=
414151104Sdes			    sizeof(depth1_directory)) {
41592654Sjeff				pjdlog_error("Directory value is too long.");
41692654Sjeff				free($2);
41792654Sjeff				return (1);
418151104Sdes			}
41992654Sjeff			if (!adjust_directory(depth1_directory))
42092654Sjeff				return (1);
42192654Sjeff			break;
42292654Sjeff		case 2:
42392654Sjeff			if (cursection == SECTION_SENDER || $2[0] == '/') {
42492654Sjeff				if (strlcpy(curhost->adh_directory, $2,
425103531Sjeff				    sizeof(curhost->adh_directory)) >=
42692654Sjeff				    sizeof(curhost->adh_directory)) {
42792654Sjeff					pjdlog_error("Directory value is too long.");
42892654Sjeff					free($2);
42992654Sjeff					return (1);
43092654Sjeff				}
431103531Sjeff			} else /* if (cursection == SECTION_RECEIVER) */ {
43292654Sjeff				if (depth1_directory[0] == '\0') {
433244024Spjd					pjdlog_error("Directory path must be absolute.");
434103531Sjeff					free($2);
43592654Sjeff					return (1);
43692654Sjeff				}
43792654Sjeff				if (snprintf(curhost->adh_directory,
43892654Sjeff				    sizeof(curhost->adh_directory), "%s/%s",
43992654Sjeff				    depth1_directory, $2) >=
44092654Sjeff				    (ssize_t)sizeof(curhost->adh_directory)) {
44192654Sjeff					pjdlog_error("Directory value is too long.");
44292654Sjeff					free($2);
44392654Sjeff					return (1);
44492654Sjeff				}
44592654Sjeff			}
44692654Sjeff			break;
44792654Sjeff		default:
44892654Sjeff			PJDLOG_ABORT("directory at wrong depth level");
44992654Sjeff		}
450166654Srwatson		free($2);
451166654Srwatson	}
452166654Srwatson	;
453166654Srwatson
454166654Srwatsonsource_statement:	SOURCE STR
455166654Srwatson	{
456166654Srwatson		PJDLOG_RASSERT(cursection == SECTION_SENDER,
457166654Srwatson		    "The source variable must be in sender section.");
458166654Srwatson
459166654Srwatson		switch (depth) {
460166654Srwatson		case 1:
461166654Srwatson			if (strlcpy(depth1_source, $2,
462247360Sattilio			    sizeof(depth1_source)) >=
463247360Sattilio			    sizeof(depth1_source)) {
46492654Sjeff				pjdlog_error("Source value is too long.");
46592654Sjeff				free($2);
466184546Skeramida				return (1);
467247360Sattilio			}
46892654Sjeff			break;
46992654Sjeff		case 2:
470247360Sattilio			if (strlcpy(curhost->adh_localaddr, $2,
47192654Sjeff			    sizeof(curhost->adh_localaddr)) >=
47292654Sjeff			    sizeof(curhost->adh_localaddr)) {
47392654Sjeff				pjdlog_error("Source value is too long.");
474247360Sattilio				free($2);
475247360Sattilio				return (1);
476247360Sattilio			}
47792654Sjeff			break;
478247360Sattilio		}
47992654Sjeff		free($2);
48092758Sjeff	}
48192758Sjeff	;
48292758Sjeff
48392758Sjefffingerprint_statement:	FINGERPRINT STR
48492758Sjeff	{
485213911Slstewart		PJDLOG_ASSERT(cursection == SECTION_SENDER);
48692758Sjeff		PJDLOG_ASSERT(depth == 2);
48792758Sjeff
488213911Slstewart		if (strncasecmp($2, "SHA256=", 7) != 0) {
48992758Sjeff			pjdlog_error("Invalid fingerprint value.");
490213911Slstewart			free($2);
49192654Sjeff			return (1);
49292654Sjeff		}
493211396Sandre		if (strlcpy(curhost->adh_fingerprint, $2,
494211396Sandre		    sizeof(curhost->adh_fingerprint)) >=
495211396Sandre		    sizeof(curhost->adh_fingerprint)) {
496211396Sandre			pjdlog_error("Fingerprint value is too long.");
497211396Sandre			free($2);
498211396Sandre			return (1);
499211396Sandre		}
500211396Sandre		free($2);
501211396Sandre	}
502211396Sandre	;
503211396Sandre
504211396Sandrepassword_statement:	PASSWORD STR
505243998Spjd	{
506243998Spjd		PJDLOG_ASSERT(cursection == SECTION_SENDER ||
507243998Spjd		    cursection == SECTION_RECEIVER);
508243998Spjd		PJDLOG_ASSERT(depth == 2);
509243998Spjd
510243998Spjd		if (strlcpy(curhost->adh_password, $2,
511243998Spjd		    sizeof(curhost->adh_password)) >=
512243998Spjd		    sizeof(curhost->adh_password)) {
513243998Spjd			pjdlog_error("Password value is too long.");
514243998Spjd			bzero($2, strlen($2));
515243998Spjd			free($2);
516243998Spjd			return (1);
517213910Slstewart		}
518213910Slstewart		bzero($2, strlen($2));
519213910Slstewart		free($2);
520213910Slstewart	}
521213910Slstewart	;
522213910Slstewart
523213910Slstewartcertfile_statement:	CERTFILE STR
524213910Slstewart	{
525213910Slstewart		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
526213910Slstewart		PJDLOG_ASSERT(depth == 1);
527213910Slstewart
528129906Sbmilekic		if (strlcpy(lconfig->adc_certfile, $2,
529129906Sbmilekic		    sizeof(lconfig->adc_certfile)) >=
530129906Sbmilekic		    sizeof(lconfig->adc_certfile)) {
531129906Sbmilekic			pjdlog_error("Certfile value is too long.");
532184546Skeramida			free($2);
533129906Sbmilekic			return (1);
534129906Sbmilekic		}
535129906Sbmilekic		free($2);
536129906Sbmilekic	}
537129906Sbmilekic	;
538129906Sbmilekic
539129906Sbmilekickeyfile_statement:	KEYFILE STR
540129906Sbmilekic	{
541129906Sbmilekic		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
542129906Sbmilekic		PJDLOG_ASSERT(depth == 1);
543184546Skeramida
544184546Skeramida		if (strlcpy(lconfig->adc_keyfile, $2,
545129906Sbmilekic		    sizeof(lconfig->adc_keyfile)) >=
546129906Sbmilekic		    sizeof(lconfig->adc_keyfile)) {
547129906Sbmilekic			pjdlog_error("Keyfile value is too long.");
548129906Sbmilekic			free($2);
549129906Sbmilekic			return (1);
550247360Sattilio		}
55192654Sjeff		free($2);
55292654Sjeff	}
553184546Skeramida	;
55492654Sjeff
55592654Sjefflisten_statement:	LISTEN STR
55692654Sjeff	{
55792654Sjeff		struct adist_listen *lst;
55892654Sjeff
55992654Sjeff		PJDLOG_ASSERT(depth == 1);
56092654Sjeff		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
56192654Sjeff
56292654Sjeff		lst = calloc(1, sizeof(*lst));
56392654Sjeff		if (lst == NULL) {
56492654Sjeff			pjdlog_error("Unable to allocate memory for listen address.");
56592654Sjeff			free($2);
56692654Sjeff			return (1);
56792654Sjeff		}
56892654Sjeff		if (strlcpy(lst->adl_addr, $2, sizeof(lst->adl_addr)) >=
56992654Sjeff		    sizeof(lst->adl_addr)) {
57092654Sjeff			pjdlog_error("listen argument is too long.");
57192654Sjeff			free($2);
57292654Sjeff			free(lst);
57392654Sjeff			return (1);
57492654Sjeff		}
57592654Sjeff		TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
57692654Sjeff		free($2);
57792654Sjeff	}
57892654Sjeff	;
57992654Sjeff
58092654Sjeffsender_host_statement:	HOST host_start OB sender_host_entries CB
581184546Skeramida	{
58292654Sjeff		/* Put it onto host list. */
58392654Sjeff		TAILQ_INSERT_TAIL(&lconfig->adc_hosts, curhost, adh_next);
58492654Sjeff		curhost = NULL;
585177921Salc	}
58692654Sjeff	;
58794157Sjeff
58892654Sjeffreceiver_host_statement:	HOST host_start OB receiver_host_entries CB
58992654Sjeff	{
59092654Sjeff		/* Put it onto host list. */
59192654Sjeff		TAILQ_INSERT_TAIL(&lconfig->adc_hosts, curhost, adh_next);
59292654Sjeff		curhost = NULL;
59392654Sjeff	}
59492654Sjeff	;
59592654Sjeff
59692654Sjeffhost_start:	STR
59792654Sjeff	{
59892654Sjeff		/* Check if there is no duplicate entry. */
59992654Sjeff		TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
60092654Sjeff			if (strcmp(curhost->adh_name, $1) != 0)
60192654Sjeff				continue;
60292654Sjeff			if (curhost->adh_role == ADIST_ROLE_SENDER &&
60392654Sjeff			    cursection == SECTION_RECEIVER) {
60492654Sjeff				continue;
605129906Sbmilekic			}
606129906Sbmilekic			if (curhost->adh_role == ADIST_ROLE_RECEIVER &&
607129906Sbmilekic			    cursection == SECTION_SENDER) {
608129906Sbmilekic				continue;
609129906Sbmilekic			}
610129906Sbmilekic			pjdlog_error("%s host %s is configured more than once.",
611129906Sbmilekic			    curhost->adh_role == ADIST_ROLE_SENDER ?
612244024Spjd			    "Sender" : "Receiver", curhost->adh_name);
613129906Sbmilekic			free($1);
614129906Sbmilekic			return (1);
615129906Sbmilekic		}
616249313Sglebius
617129906Sbmilekic		curhost = calloc(1, sizeof(*curhost));
618249313Sglebius		if (curhost == NULL) {
61992654Sjeff			pjdlog_error("Unable to allocate memory for host configuration.");
620147996Srwatson			free($1);
621165809Sjhb			return (1);
622165809Sjhb		}
623165809Sjhb		if (strlcpy(curhost->adh_name, $1, sizeof(curhost->adh_name)) >=
624165809Sjhb		    sizeof(curhost->adh_name)) {
625165809Sjhb			pjdlog_error("Host name is too long.");
626165809Sjhb			free($1);
627244024Spjd			return (1);
628165809Sjhb		}
629165809Sjhb		free($1);
630166213Smohans		curhost->adh_role = cursection == SECTION_SENDER ?
631165809Sjhb		    ADIST_ROLE_SENDER : ADIST_ROLE_RECEIVER;
632165809Sjhb		curhost->adh_version = ADIST_VERSION;
633147996Srwatson		curhost->adh_localaddr[0] = '\0';
634184546Skeramida		curhost->adh_remoteaddr[0] = '\0';
635184546Skeramida		curhost->adh_remote = NULL;
636147996Srwatson		curhost->adh_directory[0] = '\0';
637147996Srwatson		curhost->adh_password[0] = '\0';
638147996Srwatson		curhost->adh_fingerprint[0] = '\0';
639249313Sglebius		curhost->adh_worker_pid = 0;
640249313Sglebius		curhost->adh_conn = NULL;
641249313Sglebius	}
642249313Sglebius	;
643147996Srwatson
644147996Srwatsonsender_host_entries:
645148371Srwatson	|
646148371Srwatson	sender_host_entries sender_host_entry
647147996Srwatson	;
648147996Srwatson
649147996Srwatsonsender_host_entry:
650147996Srwatson	source_statement
651148371Srwatson	|
652249313Sglebius	remote_statement
653249313Sglebius	|
654249313Sglebius	directory_statement
655249313Sglebius	|
656249313Sglebius	fingerprint_statement
657147996Srwatson	|
658147996Srwatson	password_statement
659147996Srwatson/*
660147996Srwatson	|
661249313Sglebius	checksum_statement
662249313Sglebius	|
663249313Sglebius	compression_statement
664249313Sglebius*/
665249313Sglebius	;
666249313Sglebius
667249313Sglebiusreceiver_host_entries:
668249313Sglebius	|
669249313Sglebius	receiver_host_entries receiver_host_entry
670249313Sglebius	;
671147996Srwatson
672147996Srwatsonreceiver_host_entry:
673147996Srwatson	remote_statement
674249313Sglebius	|
675249313Sglebius	directory_statement
676249313Sglebius	|
677249313Sglebius	password_statement
678147996Srwatson	;
679147996Srwatson
68092654Sjeffremote_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
699static bool
700family_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
712static bool
713adjust_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
735static int
736my_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
761void
762yyerror(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
769struct adist_config *
770yy_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
841void
842yy_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}
858