1243730Srwatson%{
2243730Srwatson/*-
3243730Srwatson * Copyright (c) 2012 The FreeBSD Foundation
4243730Srwatson * All rights reserved.
5243730Srwatson *
6243730Srwatson * This software was developed by Pawel Jakub Dawidek under sponsorship from
7243730Srwatson * the FreeBSD Foundation.
8243730Srwatson *
9243730Srwatson * Redistribution and use in source and binary forms, with or without
10243730Srwatson * modification, are permitted provided that the following conditions
11243730Srwatson * are met:
12243730Srwatson * 1. Redistributions of source code must retain the above copyright
13243730Srwatson *    notice, this list of conditions and the following disclaimer.
14243730Srwatson * 2. Redistributions in binary form must reproduce the above copyright
15243730Srwatson *    notice, this list of conditions and the following disclaimer in the
16243730Srwatson *    documentation and/or other materials provided with the distribution.
17243730Srwatson *
18243730Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19243730Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20243730Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21243730Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22243730Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23243730Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24243730Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25243730Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26243730Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27243730Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28243730Srwatson * SUCH DAMAGE.
29243730Srwatson *
30243734Srwatson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/parse.y#5 $
31243730Srwatson */
32243730Srwatson
33243734Srwatson#include <config/config.h>
34243730Srwatson
35243730Srwatson#include <sys/types.h>
36243730Srwatson#include <sys/queue.h>
37243730Srwatson#include <sys/sysctl.h>
38243730Srwatson
39243730Srwatson#include <arpa/inet.h>
40243730Srwatson
41243730Srwatson#include <err.h>
42243730Srwatson#include <errno.h>
43243730Srwatson#include <stdio.h>
44243730Srwatson#include <string.h>
45243730Srwatson#include <sysexits.h>
46243730Srwatson#include <unistd.h>
47243730Srwatson#ifndef HAVE_STRLCPY
48243730Srwatson#include <compat/strlcpy.h>
49243730Srwatson#endif
50243730Srwatson
51243730Srwatson#include "auditdistd.h"
52243734Srwatson#include "pjdlog.h"
53243730Srwatson
54243730Srwatsonextern int depth;
55243730Srwatsonextern int lineno;
56243730Srwatson
57243730Srwatsonextern FILE *yyin;
58243730Srwatsonextern char *yytext;
59243730Srwatson
60243730Srwatsonstatic struct adist_config *lconfig;
61243730Srwatsonstatic struct adist_host *curhost;
62243730Srwatson#define	SECTION_GLOBAL		0
63243730Srwatson#define	SECTION_SENDER		1
64243730Srwatson#define	SECTION_RECEIVER	2
65243730Srwatsonstatic int cursection;
66243730Srwatson
67243730Srwatson/* Sender section. */
68243730Srwatsonstatic char depth1_source[ADIST_ADDRSIZE];
69243730Srwatsonstatic int depth1_checksum;
70243730Srwatsonstatic int depth1_compression;
71243730Srwatson/* Sender and receiver sections. */
72243730Srwatsonstatic char depth1_directory[PATH_MAX];
73243730Srwatson
74243730Srwatsonstatic bool adjust_directory(char *path);
75243730Srwatsonstatic bool family_supported(int family);
76243730Srwatson
77243730Srwatsonextern void yyrestart(FILE *);
78243730Srwatson%}
79243730Srwatson
80243730Srwatson%token CB
81243730Srwatson%token CERTFILE
82243730Srwatson%token DIRECTORY
83243730Srwatson%token FINGERPRINT
84243730Srwatson%token HOST
85243730Srwatson%token KEYFILE
86243730Srwatson%token LISTEN
87243730Srwatson%token NAME
88243730Srwatson%token OB
89243730Srwatson%token PASSWORD
90243730Srwatson%token PIDFILE
91243730Srwatson%token RECEIVER REMOTE
92243730Srwatson%token SENDER SOURCE
93243730Srwatson%token TIMEOUT
94243730Srwatson
95243730Srwatson/*
96243730Srwatson%type <num> checksum_type
97243730Srwatson%type <num> compression_type
98243730Srwatson*/
99243730Srwatson
100243730Srwatson%union
101243730Srwatson{
102243730Srwatson	int num;
103243730Srwatson	char *str;
104243730Srwatson}
105243730Srwatson
106243730Srwatson%token <num> NUM
107243730Srwatson%token <str> STR
108243730Srwatson
109243730Srwatson%%
110243730Srwatson
111243730Srwatsonstatements:
112243730Srwatson	|
113243730Srwatson	statements statement
114243730Srwatson	;
115243730Srwatson
116243730Srwatsonstatement:
117243730Srwatson	name_statement
118243730Srwatson	|
119243730Srwatson	pidfile_statement
120243730Srwatson	|
121243730Srwatson	timeout_statement
122243730Srwatson	|
123243730Srwatson	sender_statement
124243730Srwatson	|
125243730Srwatson	receiver_statement
126243730Srwatson	;
127243730Srwatson
128243730Srwatsonname_statement:	NAME STR
129243730Srwatson	{
130243730Srwatson		PJDLOG_RASSERT(depth == 0,
131243730Srwatson		    "The name variable can only be specificed in the global section.");
132243730Srwatson
133243730Srwatson		if (lconfig->adc_name[0] != '\0') {
134243730Srwatson			pjdlog_error("The name variable is specified twice.");
135243730Srwatson			free($2);
136243730Srwatson			return (1);
137243730Srwatson		}
138243730Srwatson		if (strlcpy(lconfig->adc_name, $2,
139243730Srwatson		    sizeof(lconfig->adc_name)) >=
140243730Srwatson		    sizeof(lconfig->adc_name)) {
141243730Srwatson			pjdlog_error("The name value is too long.");
142243730Srwatson			free($2);
143243730Srwatson			return (1);
144243730Srwatson		}
145243730Srwatson		free($2);
146243730Srwatson	}
147243730Srwatson	;
148243730Srwatson
149243730Srwatsonpidfile_statement:	PIDFILE STR
150243730Srwatson	{
151243730Srwatson		PJDLOG_RASSERT(depth == 0,
152243730Srwatson		    "The pidfile variable can only be specificed in the global section.");
153243730Srwatson
154243730Srwatson		if (lconfig->adc_pidfile[0] != '\0') {
155243730Srwatson			pjdlog_error("The pidfile variable is specified twice.");
156243730Srwatson			free($2);
157243730Srwatson			return (1);
158243730Srwatson		}
159243730Srwatson		if (strcmp($2, "none") != 0 && $2[0] != '/') {
160243730Srwatson			pjdlog_error("The pidfile variable must be set to absolute pathname or \"none\".");
161243730Srwatson			free($2);
162243730Srwatson			return (1);
163243730Srwatson		}
164243730Srwatson		if (strlcpy(lconfig->adc_pidfile, $2,
165243730Srwatson		    sizeof(lconfig->adc_pidfile)) >=
166243730Srwatson		    sizeof(lconfig->adc_pidfile)) {
167243730Srwatson			pjdlog_error("The pidfile value is too long.");
168243730Srwatson			free($2);
169243730Srwatson			return (1);
170243730Srwatson		}
171243730Srwatson		free($2);
172243730Srwatson	}
173243730Srwatson	;
174243730Srwatson
175243730Srwatsontimeout_statement:	TIMEOUT NUM
176243730Srwatson	{
177243730Srwatson		PJDLOG_ASSERT(depth == 0);
178243730Srwatson
179243730Srwatson		lconfig->adc_timeout = $2;
180243730Srwatson	}
181243730Srwatson	;
182243730Srwatson
183243730Srwatsonsender_statement:	SENDER sender_start sender_entries CB
184243730Srwatson	{
185243730Srwatson		PJDLOG_ASSERT(depth == 0);
186243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_SENDER);
187243730Srwatson
188243730Srwatson		/* Configure defaults. */
189243730Srwatson		if (depth1_checksum == -1)
190243730Srwatson			depth1_checksum = ADIST_CHECKSUM_NONE;
191243730Srwatson		if (depth1_compression == -1)
192243730Srwatson			depth1_compression = ADIST_COMPRESSION_NONE;
193243730Srwatson		if (depth1_directory[0] == '\0') {
194243730Srwatson			(void)strlcpy(depth1_directory, ADIST_DIRECTORY_SENDER,
195243730Srwatson			    sizeof(depth1_directory));
196243730Srwatson		}
197243730Srwatson		/* Empty depth1_source is ok. */
198243730Srwatson		TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
199243730Srwatson			if (curhost->adh_role != ADIST_ROLE_SENDER)
200243730Srwatson				continue;
201243730Srwatson			if (curhost->adh_checksum == -1)
202243730Srwatson				curhost->adh_checksum = depth1_checksum;
203243730Srwatson			if (curhost->adh_compression == -1)
204243730Srwatson				curhost->adh_compression = depth1_compression;
205243730Srwatson			if (curhost->adh_directory[0] == '\0') {
206243730Srwatson				(void)strlcpy(curhost->adh_directory,
207243730Srwatson				    depth1_directory,
208243730Srwatson				    sizeof(curhost->adh_directory));
209243730Srwatson			}
210243730Srwatson			if (curhost->adh_localaddr[0] == '\0') {
211243730Srwatson				(void)strlcpy(curhost->adh_localaddr,
212243730Srwatson				    depth1_source,
213243730Srwatson				    sizeof(curhost->adh_localaddr));
214243730Srwatson			}
215243730Srwatson		}
216243730Srwatson		cursection = SECTION_GLOBAL;
217243730Srwatson	}
218243730Srwatson	;
219243730Srwatson
220243730Srwatsonsender_start:	OB
221243730Srwatson	{
222243730Srwatson		PJDLOG_ASSERT(depth == 1);
223243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_GLOBAL);
224243730Srwatson
225243730Srwatson		cursection = SECTION_SENDER;
226243730Srwatson		depth1_checksum = -1;
227243730Srwatson		depth1_compression = -1;
228243730Srwatson		depth1_source[0] = '\0';
229243730Srwatson		depth1_directory[0] = '\0';
230243730Srwatson
231243730Srwatson#ifndef HAVE_AUDIT_SYSCALLS
232243730Srwatson		pjdlog_error("Sender functionality is not available.");
233243730Srwatson		return (1);
234243730Srwatson#endif
235243730Srwatson	}
236243730Srwatson	;
237243730Srwatson
238243730Srwatsonsender_entries:
239243730Srwatson	|
240243730Srwatson	sender_entries sender_entry
241243730Srwatson	;
242243730Srwatson
243243730Srwatsonsender_entry:
244243730Srwatson	source_statement
245243730Srwatson	|
246243730Srwatson	directory_statement
247243730Srwatson/*
248243730Srwatson	|
249243730Srwatson	checksum_statement
250243730Srwatson	|
251243730Srwatson	compression_statement
252243730Srwatson*/
253243730Srwatson	|
254243730Srwatson	sender_host_statement
255243730Srwatson	;
256243730Srwatson
257243730Srwatsonreceiver_statement:	RECEIVER receiver_start receiver_entries CB
258243730Srwatson	{
259243730Srwatson		PJDLOG_ASSERT(depth == 0);
260243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
261243730Srwatson
262243730Srwatson		/*
263243730Srwatson		 * If not listen addresses were specified,
264243730Srwatson		 * configure default ones.
265243730Srwatson		 */
266243730Srwatson		if (TAILQ_EMPTY(&lconfig->adc_listen)) {
267243730Srwatson			struct adist_listen *lst;
268243730Srwatson
269243730Srwatson			if (family_supported(AF_INET)) {
270243730Srwatson				lst = calloc(1, sizeof(*lst));
271243730Srwatson				if (lst == NULL) {
272243730Srwatson					pjdlog_error("Unable to allocate memory for listen address.");
273243730Srwatson					return (1);
274243730Srwatson				}
275243730Srwatson				(void)strlcpy(lst->adl_addr,
276243730Srwatson				    ADIST_LISTEN_TLS_TCP4,
277243730Srwatson				    sizeof(lst->adl_addr));
278243730Srwatson				TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
279243730Srwatson			} else {
280243730Srwatson				pjdlog_debug(1,
281243730Srwatson				    "No IPv4 support in the kernel, not listening on IPv4 address.");
282243730Srwatson			}
283243730Srwatson			if (family_supported(AF_INET6)) {
284243730Srwatson				lst = calloc(1, sizeof(*lst));
285243730Srwatson				if (lst == NULL) {
286243730Srwatson					pjdlog_error("Unable to allocate memory for listen address.");
287243730Srwatson					return (1);
288243730Srwatson				}
289243730Srwatson				(void)strlcpy(lst->adl_addr,
290243730Srwatson				    ADIST_LISTEN_TLS_TCP6,
291243730Srwatson				    sizeof(lst->adl_addr));
292243730Srwatson				TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
293243730Srwatson			} else {
294243730Srwatson				pjdlog_debug(1,
295243730Srwatson				    "No IPv6 support in the kernel, not listening on IPv6 address.");
296243730Srwatson			}
297243730Srwatson			if (TAILQ_EMPTY(&lconfig->adc_listen)) {
298243730Srwatson				pjdlog_error("No address to listen on.");
299243730Srwatson				return (1);
300243730Srwatson			}
301243730Srwatson		}
302243730Srwatson		/* Configure defaults. */
303243730Srwatson		if (depth1_directory[0] == '\0') {
304243730Srwatson			(void)strlcpy(depth1_directory,
305243730Srwatson			    ADIST_DIRECTORY_RECEIVER,
306243730Srwatson			    sizeof(depth1_directory));
307243730Srwatson		}
308243730Srwatson		TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
309243730Srwatson			if (curhost->adh_role != ADIST_ROLE_RECEIVER)
310243730Srwatson				continue;
311243730Srwatson			if (curhost->adh_directory[0] == '\0') {
312243730Srwatson				if (snprintf(curhost->adh_directory,
313243730Srwatson				    sizeof(curhost->adh_directory), "%s/%s",
314243730Srwatson				    depth1_directory, curhost->adh_name) >=
315243730Srwatson				    (ssize_t)sizeof(curhost->adh_directory)) {
316243730Srwatson					pjdlog_error("Directory value is too long.");
317243730Srwatson					return (1);
318243730Srwatson				}
319243730Srwatson			}
320243730Srwatson		}
321243730Srwatson		cursection = SECTION_GLOBAL;
322243730Srwatson	}
323243730Srwatson	;
324243730Srwatson
325243730Srwatsonreceiver_start:	OB
326243730Srwatson	{
327243730Srwatson		PJDLOG_ASSERT(depth == 1);
328243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_GLOBAL);
329243730Srwatson
330243730Srwatson		cursection = SECTION_RECEIVER;
331243730Srwatson		depth1_directory[0] = '\0';
332243730Srwatson	}
333243730Srwatson	;
334243730Srwatson
335243730Srwatsonreceiver_entries:
336243730Srwatson	|
337243730Srwatson	receiver_entries receiver_entry
338243730Srwatson	;
339243730Srwatson
340243730Srwatsonreceiver_entry:
341243730Srwatson	listen_statement
342243730Srwatson	|
343243730Srwatson	directory_statement
344243730Srwatson	|
345243730Srwatson	certfile_statement
346243730Srwatson	|
347243730Srwatson	keyfile_statement
348243730Srwatson	|
349243730Srwatson	receiver_host_statement
350243730Srwatson	;
351243730Srwatson
352243730Srwatson/*
353243730Srwatsonchecksum_statement:	CHECKSUM checksum_type
354243730Srwatson	{
355243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_SENDER);
356243730Srwatson
357243730Srwatson		switch (depth) {
358243730Srwatson		case 1:
359243730Srwatson			depth1_checksum = $2;
360243730Srwatson			break;
361243730Srwatson		case 2:
362243730Srwatson			PJDLOG_ASSERT(curhost != NULL);
363243730Srwatson			curhost->adh_checksum = $2;
364243730Srwatson			break;
365243730Srwatson		default:
366243730Srwatson			PJDLOG_ABORT("checksum at wrong depth level");
367243730Srwatson		}
368243730Srwatson	}
369243730Srwatson	;
370243730Srwatson
371243730Srwatsonchecksum_type:
372243730Srwatson	NONE		{ $$ = ADIST_CHECKSUM_NONE; }
373243730Srwatson	|
374243730Srwatson	CRC32		{ $$ = ADIST_CHECKSUM_CRC32; }
375243730Srwatson	|
376243730Srwatson	SHA256		{ $$ = ADIST_CHECKSUM_SHA256; }
377243730Srwatson	;
378243730Srwatson
379243730Srwatsoncompression_statement:	COMPRESSION compression_type
380243730Srwatson	{
381243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_SENDER);
382243730Srwatson
383243730Srwatson		switch (depth) {
384243730Srwatson		case 1:
385243730Srwatson			depth1_compression = $2;
386243730Srwatson			break;
387243730Srwatson		case 2:
388243730Srwatson			PJDLOG_ASSERT(curhost != NULL);
389243730Srwatson			curhost->adh_compression = $2;
390243730Srwatson			break;
391243730Srwatson		default:
392243730Srwatson			PJDLOG_ABORT("compression at wrong depth level");
393243730Srwatson		}
394243730Srwatson	}
395243730Srwatson	;
396243730Srwatson
397243730Srwatsoncompression_type:
398243730Srwatson	NONE		{ $$ = ADIST_COMPRESSION_NONE; }
399243730Srwatson	|
400243730Srwatson	LZF		{ $$ = ADIST_COMPRESSION_LZF; }
401243730Srwatson	;
402243730Srwatson*/
403243730Srwatson
404243730Srwatsondirectory_statement:	DIRECTORY STR
405243730Srwatson	{
406243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_SENDER ||
407243730Srwatson		    cursection == SECTION_RECEIVER);
408243730Srwatson
409243730Srwatson		switch (depth) {
410243730Srwatson		case 1:
411243730Srwatson			if (strlcpy(depth1_directory, $2,
412243730Srwatson			    sizeof(depth1_directory)) >=
413243730Srwatson			    sizeof(depth1_directory)) {
414243730Srwatson				pjdlog_error("Directory value is too long.");
415243730Srwatson				free($2);
416243730Srwatson				return (1);
417243730Srwatson			}
418243730Srwatson			if (!adjust_directory(depth1_directory))
419243730Srwatson				return (1);
420243730Srwatson			break;
421243730Srwatson		case 2:
422243730Srwatson			if (cursection == SECTION_SENDER || $2[0] == '/') {
423243730Srwatson				if (strlcpy(curhost->adh_directory, $2,
424243730Srwatson				    sizeof(curhost->adh_directory)) >=
425243730Srwatson				    sizeof(curhost->adh_directory)) {
426243730Srwatson					pjdlog_error("Directory value is too long.");
427243730Srwatson					free($2);
428243730Srwatson					return (1);
429243730Srwatson				}
430243730Srwatson			} else /* if (cursection == SECTION_RECEIVER) */ {
431243730Srwatson				if (depth1_directory[0] == '\0') {
432243730Srwatson					pjdlog_error("Directory path must be absolute.");
433243730Srwatson					free($2);
434243730Srwatson					return (1);
435243730Srwatson				}
436243730Srwatson				if (snprintf(curhost->adh_directory,
437243730Srwatson				    sizeof(curhost->adh_directory), "%s/%s",
438243730Srwatson				    depth1_directory, $2) >=
439243730Srwatson				    (ssize_t)sizeof(curhost->adh_directory)) {
440243730Srwatson					pjdlog_error("Directory value is too long.");
441243730Srwatson					free($2);
442243730Srwatson					return (1);
443243730Srwatson				}
444243730Srwatson			}
445243730Srwatson			break;
446243730Srwatson		default:
447243730Srwatson			PJDLOG_ABORT("directory at wrong depth level");
448243730Srwatson		}
449243730Srwatson		free($2);
450243730Srwatson	}
451243730Srwatson	;
452243730Srwatson
453243730Srwatsonsource_statement:	SOURCE STR
454243730Srwatson	{
455243730Srwatson		PJDLOG_RASSERT(cursection == SECTION_SENDER,
456243730Srwatson		    "The source variable must be in sender section.");
457243730Srwatson
458243730Srwatson		switch (depth) {
459243730Srwatson		case 1:
460243730Srwatson			if (strlcpy(depth1_source, $2,
461243730Srwatson			    sizeof(depth1_source)) >=
462243730Srwatson			    sizeof(depth1_source)) {
463243730Srwatson				pjdlog_error("Source value is too long.");
464243730Srwatson				free($2);
465243730Srwatson				return (1);
466243730Srwatson			}
467243730Srwatson			break;
468243730Srwatson		case 2:
469243730Srwatson			if (strlcpy(curhost->adh_localaddr, $2,
470243730Srwatson			    sizeof(curhost->adh_localaddr)) >=
471243730Srwatson			    sizeof(curhost->adh_localaddr)) {
472243730Srwatson				pjdlog_error("Source value is too long.");
473243730Srwatson				free($2);
474243730Srwatson				return (1);
475243730Srwatson			}
476243730Srwatson			break;
477243730Srwatson		}
478243730Srwatson		free($2);
479243730Srwatson	}
480243730Srwatson	;
481243730Srwatson
482243730Srwatsonfingerprint_statement:	FINGERPRINT STR
483243730Srwatson	{
484243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_SENDER);
485243730Srwatson		PJDLOG_ASSERT(depth == 2);
486243730Srwatson
487243730Srwatson		if (strncasecmp($2, "SHA256=", 7) != 0) {
488243730Srwatson			pjdlog_error("Invalid fingerprint value.");
489243730Srwatson			free($2);
490243730Srwatson			return (1);
491243730Srwatson		}
492243730Srwatson		if (strlcpy(curhost->adh_fingerprint, $2,
493243730Srwatson		    sizeof(curhost->adh_fingerprint)) >=
494243730Srwatson		    sizeof(curhost->adh_fingerprint)) {
495243730Srwatson			pjdlog_error("Fingerprint value is too long.");
496243730Srwatson			free($2);
497243730Srwatson			return (1);
498243730Srwatson		}
499243730Srwatson		free($2);
500243730Srwatson	}
501243730Srwatson	;
502243730Srwatson
503243730Srwatsonpassword_statement:	PASSWORD STR
504243730Srwatson	{
505243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_SENDER ||
506243730Srwatson		    cursection == SECTION_RECEIVER);
507243730Srwatson		PJDLOG_ASSERT(depth == 2);
508243730Srwatson
509243730Srwatson		if (strlcpy(curhost->adh_password, $2,
510243730Srwatson		    sizeof(curhost->adh_password)) >=
511243730Srwatson		    sizeof(curhost->adh_password)) {
512243730Srwatson			pjdlog_error("Password value is too long.");
513243730Srwatson			bzero($2, strlen($2));
514243730Srwatson			free($2);
515243730Srwatson			return (1);
516243730Srwatson		}
517243730Srwatson		bzero($2, strlen($2));
518243730Srwatson		free($2);
519243730Srwatson	}
520243730Srwatson	;
521243730Srwatson
522243730Srwatsoncertfile_statement:	CERTFILE STR
523243730Srwatson	{
524243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
525243730Srwatson		PJDLOG_ASSERT(depth == 1);
526243730Srwatson
527243730Srwatson		if (strlcpy(lconfig->adc_certfile, $2,
528243730Srwatson		    sizeof(lconfig->adc_certfile)) >=
529243730Srwatson		    sizeof(lconfig->adc_certfile)) {
530243730Srwatson			pjdlog_error("Certfile value is too long.");
531243730Srwatson			free($2);
532243730Srwatson			return (1);
533243730Srwatson		}
534243730Srwatson		free($2);
535243730Srwatson	}
536243730Srwatson	;
537243730Srwatson
538243730Srwatsonkeyfile_statement:	KEYFILE STR
539243730Srwatson	{
540243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
541243730Srwatson		PJDLOG_ASSERT(depth == 1);
542243730Srwatson
543243730Srwatson		if (strlcpy(lconfig->adc_keyfile, $2,
544243730Srwatson		    sizeof(lconfig->adc_keyfile)) >=
545243730Srwatson		    sizeof(lconfig->adc_keyfile)) {
546243730Srwatson			pjdlog_error("Keyfile value is too long.");
547243730Srwatson			free($2);
548243730Srwatson			return (1);
549243730Srwatson		}
550243730Srwatson		free($2);
551243730Srwatson	}
552243730Srwatson	;
553243730Srwatson
554243730Srwatsonlisten_statement:	LISTEN STR
555243730Srwatson	{
556243730Srwatson		struct adist_listen *lst;
557243730Srwatson
558243730Srwatson		PJDLOG_ASSERT(depth == 1);
559243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_RECEIVER);
560243730Srwatson
561243730Srwatson		lst = calloc(1, sizeof(*lst));
562243730Srwatson		if (lst == NULL) {
563243730Srwatson			pjdlog_error("Unable to allocate memory for listen address.");
564243730Srwatson			free($2);
565243730Srwatson			return (1);
566243730Srwatson		}
567243730Srwatson		if (strlcpy(lst->adl_addr, $2, sizeof(lst->adl_addr)) >=
568243730Srwatson		    sizeof(lst->adl_addr)) {
569243730Srwatson			pjdlog_error("listen argument is too long.");
570243730Srwatson			free($2);
571243730Srwatson			free(lst);
572243730Srwatson			return (1);
573243730Srwatson		}
574243730Srwatson		TAILQ_INSERT_TAIL(&lconfig->adc_listen, lst, adl_next);
575243730Srwatson		free($2);
576243730Srwatson	}
577243730Srwatson	;
578243730Srwatson
579243730Srwatsonsender_host_statement:	HOST host_start OB sender_host_entries CB
580243730Srwatson	{
581243730Srwatson		/* Put it onto host list. */
582243730Srwatson		TAILQ_INSERT_TAIL(&lconfig->adc_hosts, curhost, adh_next);
583243730Srwatson		curhost = NULL;
584243730Srwatson	}
585243730Srwatson	;
586243730Srwatson
587243730Srwatsonreceiver_host_statement:	HOST host_start OB receiver_host_entries CB
588243730Srwatson	{
589243730Srwatson		/* Put it onto host list. */
590243730Srwatson		TAILQ_INSERT_TAIL(&lconfig->adc_hosts, curhost, adh_next);
591243730Srwatson		curhost = NULL;
592243730Srwatson	}
593243730Srwatson	;
594243730Srwatson
595243730Srwatsonhost_start:	STR
596243730Srwatson	{
597243730Srwatson		/* Check if there is no duplicate entry. */
598243730Srwatson		TAILQ_FOREACH(curhost, &lconfig->adc_hosts, adh_next) {
599243730Srwatson			if (strcmp(curhost->adh_name, $1) != 0)
600243730Srwatson				continue;
601243730Srwatson			if (curhost->adh_role == ADIST_ROLE_SENDER &&
602243730Srwatson			    cursection == SECTION_RECEIVER) {
603243730Srwatson				continue;
604243730Srwatson			}
605243730Srwatson			if (curhost->adh_role == ADIST_ROLE_RECEIVER &&
606243730Srwatson			    cursection == SECTION_SENDER) {
607243730Srwatson				continue;
608243730Srwatson			}
609243730Srwatson			pjdlog_error("%s host %s is configured more than once.",
610243730Srwatson			    curhost->adh_role == ADIST_ROLE_SENDER ?
611243730Srwatson			    "Sender" : "Receiver", curhost->adh_name);
612243730Srwatson			free($1);
613243730Srwatson			return (1);
614243730Srwatson		}
615243730Srwatson
616243730Srwatson		curhost = calloc(1, sizeof(*curhost));
617243730Srwatson		if (curhost == NULL) {
618243730Srwatson			pjdlog_error("Unable to allocate memory for host configuration.");
619243730Srwatson			free($1);
620243730Srwatson			return (1);
621243730Srwatson		}
622243730Srwatson		if (strlcpy(curhost->adh_name, $1, sizeof(curhost->adh_name)) >=
623243730Srwatson		    sizeof(curhost->adh_name)) {
624243730Srwatson			pjdlog_error("Host name is too long.");
625243730Srwatson			free($1);
626243730Srwatson			return (1);
627243730Srwatson		}
628243730Srwatson		free($1);
629243730Srwatson		curhost->adh_role = cursection == SECTION_SENDER ?
630243730Srwatson		    ADIST_ROLE_SENDER : ADIST_ROLE_RECEIVER;
631243730Srwatson		curhost->adh_version = ADIST_VERSION;
632243730Srwatson		curhost->adh_localaddr[0] = '\0';
633243730Srwatson		curhost->adh_remoteaddr[0] = '\0';
634243730Srwatson		curhost->adh_remote = NULL;
635243730Srwatson		curhost->adh_directory[0] = '\0';
636243730Srwatson		curhost->adh_password[0] = '\0';
637243730Srwatson		curhost->adh_fingerprint[0] = '\0';
638243730Srwatson		curhost->adh_worker_pid = 0;
639243730Srwatson		curhost->adh_conn = NULL;
640243730Srwatson	}
641243730Srwatson	;
642243730Srwatson
643243730Srwatsonsender_host_entries:
644243730Srwatson	|
645243730Srwatson	sender_host_entries sender_host_entry
646243730Srwatson	;
647243730Srwatson
648243730Srwatsonsender_host_entry:
649243730Srwatson	source_statement
650243730Srwatson	|
651243730Srwatson	remote_statement
652243730Srwatson	|
653243730Srwatson	directory_statement
654243730Srwatson	|
655243730Srwatson	fingerprint_statement
656243730Srwatson	|
657243730Srwatson	password_statement
658243730Srwatson/*
659243730Srwatson	|
660243730Srwatson	checksum_statement
661243730Srwatson	|
662243730Srwatson	compression_statement
663243730Srwatson*/
664243730Srwatson	;
665243730Srwatson
666243730Srwatsonreceiver_host_entries:
667243730Srwatson	|
668243730Srwatson	receiver_host_entries receiver_host_entry
669243730Srwatson	;
670243730Srwatson
671243730Srwatsonreceiver_host_entry:
672243730Srwatson	remote_statement
673243730Srwatson	|
674243730Srwatson	directory_statement
675243730Srwatson	|
676243730Srwatson	password_statement
677243730Srwatson	;
678243730Srwatson
679243730Srwatsonremote_statement:	REMOTE STR
680243730Srwatson	{
681243730Srwatson		PJDLOG_ASSERT(depth == 2);
682243730Srwatson		PJDLOG_ASSERT(cursection == SECTION_SENDER ||
683243730Srwatson		    cursection == SECTION_RECEIVER);
684243730Srwatson
685243730Srwatson		if (strlcpy(curhost->adh_remoteaddr, $2,
686243730Srwatson		    sizeof(curhost->adh_remoteaddr)) >=
687243730Srwatson		    sizeof(curhost->adh_remoteaddr)) {
688243730Srwatson			pjdlog_error("Remote value is too long.");
689243730Srwatson			free($2);
690243730Srwatson			return (1);
691243730Srwatson		}
692243730Srwatson		free($2);
693243730Srwatson	}
694243730Srwatson	;
695243730Srwatson
696243730Srwatson%%
697243730Srwatson
698243730Srwatsonstatic bool
699243730Srwatsonfamily_supported(int family)
700243730Srwatson{
701243730Srwatson	int sock;
702243730Srwatson
703243730Srwatson	sock = socket(family, SOCK_STREAM, 0);
704243730Srwatson	if (sock == -1 && errno == EPROTONOSUPPORT)
705243730Srwatson		return (false);
706243730Srwatson	if (sock >= 0)
707243730Srwatson		(void)close(sock);
708243730Srwatson	return (true);
709243730Srwatson}
710243730Srwatson
711243730Srwatsonstatic bool
712243730Srwatsonadjust_directory(char *path)
713243730Srwatson{
714243730Srwatson	size_t len;
715243730Srwatson
716243730Srwatson	len = strlen(path);
717243730Srwatson	for (;;) {
718243730Srwatson		if (len == 0) {
719243730Srwatson			pjdlog_error("Directory path is empty.");
720243730Srwatson			return (false);
721243730Srwatson		}
722243730Srwatson		if (path[len - 1] != '/')
723243730Srwatson			break;
724243730Srwatson		len--;
725243730Srwatson		path[len] = '\0';
726243730Srwatson	}
727243730Srwatson	if (path[0] != '/') {
728243730Srwatson		pjdlog_error("Directory path must be absolute.");
729243730Srwatson		return (false);
730243730Srwatson	}
731243730Srwatson	return (true);
732243730Srwatson}
733243730Srwatson
734243730Srwatsonstatic int
735243730Srwatsonmy_name(char *name, size_t size)
736243730Srwatson{
737243730Srwatson	char buf[MAXHOSTNAMELEN];
738243730Srwatson	char *pos;
739243730Srwatson
740243730Srwatson	if (gethostname(buf, sizeof(buf)) < 0) {
741243730Srwatson		pjdlog_errno(LOG_ERR, "gethostname() failed");
742243730Srwatson		return (-1);
743243730Srwatson	}
744243730Srwatson
745243730Srwatson	/* First component of the host name. */
746243730Srwatson	pos = strchr(buf, '.');
747243730Srwatson	if (pos == NULL)
748243730Srwatson		(void)strlcpy(name, buf, size);
749243730Srwatson	else
750243730Srwatson		(void)strlcpy(name, buf, MIN((size_t)(pos - buf + 1), size));
751243730Srwatson
752243730Srwatson	if (name[0] == '\0') {
753243730Srwatson		pjdlog_error("Empty host name.");
754243730Srwatson		return (-1);
755243730Srwatson	}
756243730Srwatson
757243730Srwatson	return (0);
758243730Srwatson}
759243730Srwatson
760243730Srwatsonvoid
761243730Srwatsonyyerror(const char *str)
762243730Srwatson{
763243730Srwatson
764243730Srwatson	pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
765243730Srwatson	    lineno, yytext, str);
766243730Srwatson}
767243730Srwatson
768243730Srwatsonstruct adist_config *
769243730Srwatsonyy_config_parse(const char *config, bool exitonerror)
770243730Srwatson{
771243730Srwatson	int ret;
772243730Srwatson
773243730Srwatson	curhost = NULL;
774243730Srwatson	cursection = SECTION_GLOBAL;
775243730Srwatson	depth = 0;
776243730Srwatson	lineno = 0;
777243730Srwatson
778243730Srwatson	lconfig = calloc(1, sizeof(*lconfig));
779243730Srwatson	if (lconfig == NULL) {
780243730Srwatson		pjdlog_error("Unable to allocate memory for configuration.");
781243730Srwatson		if (exitonerror)
782243730Srwatson			exit(EX_TEMPFAIL);
783243730Srwatson		return (NULL);
784243730Srwatson	}
785243730Srwatson	TAILQ_INIT(&lconfig->adc_hosts);
786243730Srwatson	TAILQ_INIT(&lconfig->adc_listen);
787243730Srwatson	lconfig->adc_name[0] = '\0';
788243730Srwatson	lconfig->adc_timeout = -1;
789243730Srwatson	lconfig->adc_pidfile[0] = '\0';
790243730Srwatson	lconfig->adc_certfile[0] = '\0';
791243730Srwatson	lconfig->adc_keyfile[0] = '\0';
792243730Srwatson
793243730Srwatson	yyin = fopen(config, "r");
794243730Srwatson	if (yyin == NULL) {
795243730Srwatson		pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
796243730Srwatson		    config);
797243730Srwatson		yy_config_free(lconfig);
798243730Srwatson		if (exitonerror)
799243730Srwatson			exit(EX_OSFILE);
800243730Srwatson		return (NULL);
801243730Srwatson	}
802243730Srwatson	yyrestart(yyin);
803243730Srwatson	ret = yyparse();
804243730Srwatson	fclose(yyin);
805243730Srwatson	if (ret != 0) {
806243730Srwatson		yy_config_free(lconfig);
807243730Srwatson		if (exitonerror)
808243730Srwatson			exit(EX_CONFIG);
809243730Srwatson		return (NULL);
810243730Srwatson	}
811243730Srwatson
812243730Srwatson	/*
813243730Srwatson	 * Let's see if everything is set up.
814243730Srwatson	 */
815243730Srwatson	if (lconfig->adc_name[0] == '\0' && my_name(lconfig->adc_name,
816243730Srwatson	    sizeof(lconfig->adc_name)) == -1) {
817243730Srwatson		yy_config_free(lconfig);
818243730Srwatson		if (exitonerror)
819243730Srwatson			exit(EX_CONFIG);
820243730Srwatson		return (NULL);
821243730Srwatson	}
822243730Srwatson	if (lconfig->adc_timeout == -1)
823243730Srwatson		lconfig->adc_timeout = ADIST_TIMEOUT;
824243730Srwatson	if (lconfig->adc_pidfile[0] == '\0') {
825243730Srwatson		(void)strlcpy(lconfig->adc_pidfile, ADIST_PIDFILE,
826243730Srwatson		    sizeof(lconfig->adc_pidfile));
827243730Srwatson	}
828243730Srwatson	if (lconfig->adc_certfile[0] == '\0') {
829243730Srwatson		(void)strlcpy(lconfig->adc_certfile, ADIST_CERTFILE,
830243730Srwatson		    sizeof(lconfig->adc_certfile));
831243730Srwatson	}
832243730Srwatson	if (lconfig->adc_keyfile[0] == '\0') {
833243730Srwatson		(void)strlcpy(lconfig->adc_keyfile, ADIST_KEYFILE,
834243730Srwatson		    sizeof(lconfig->adc_keyfile));
835243730Srwatson	}
836243730Srwatson
837243730Srwatson	return (lconfig);
838243730Srwatson}
839243730Srwatson
840243730Srwatsonvoid
841243730Srwatsonyy_config_free(struct adist_config *config)
842243730Srwatson{
843243730Srwatson	struct adist_host *adhost;
844243730Srwatson	struct adist_listen *lst;
845243730Srwatson
846243730Srwatson	while ((lst = TAILQ_FIRST(&config->adc_listen)) != NULL) {
847243730Srwatson		TAILQ_REMOVE(&config->adc_listen, lst, adl_next);
848243730Srwatson		free(lst);
849243730Srwatson	}
850243730Srwatson	while ((adhost = TAILQ_FIRST(&config->adc_hosts)) != NULL) {
851243730Srwatson		TAILQ_REMOVE(&config->adc_hosts, adhost, adh_next);
852243730Srwatson		bzero(adhost, sizeof(*adhost));
853243730Srwatson		free(adhost);
854243730Srwatson	}
855243730Srwatson	free(config);
856243730Srwatson}
857