GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/sasyncd/conf.y Lines: 0 89 0.0 %
Date: 2017-11-13 Branches: 0 74 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: conf.y,v 1.19 2017/04/09 02:40:24 jsg Exp $	*/
2
3
/*
4
 * Copyright (c) 2005 Håkan Olsson.  All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 *
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
28
/* Definitions */
29
%{
30
#include <sys/types.h>
31
#include <sys/stat.h>
32
#include <sys/socket.h>
33
#include <ctype.h>
34
#include <fcntl.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <unistd.h>
39
#include <pwd.h>
40
41
#include "sasyncd.h"
42
#include "net.h"
43
44
/* Global configuration context.  */
45
struct cfgstate	cfgstate;
46
47
/* Local variables */
48
int	conflen = 0;
49
char	*confbuf, *confptr;
50
51
int	yyparse(void);
52
int	yylex(void);
53
void	yyerror(const char *);
54
unsigned char x2i(unsigned char *);
55
%}
56
57
%union {
58
	char	*string;
59
	int	 val;
60
	struct {
61
		unsigned char	*data;
62
		int	 len;
63
	} hex;
64
}
65
66
%token MODE INTERFACE INTERVAL LISTEN ON PORT PEER SHAREDKEY
67
%token Y_SLAVE Y_MASTER INET INET6 FLUSHMODE STARTUP NEVER SYNC
68
%token GROUP SKIPSLAVE CONTROL
69
%token <string> STRING
70
%token <hex>	HEX
71
%token <val>	VALUE
72
%type  <val>	af port mode flushmode ctlmode
73
74
%%
75
/* Rules */
76
77
settings	: /* empty */
78
		| settings setting
79
		;
80
81
af		: /* empty */		{ $$ = AF_UNSPEC; }
82
		| INET			{ $$ = AF_INET; }
83
		| INET6			{ $$ = AF_INET6; }
84
		;
85
86
port		: /* empty */		{ $$ = SASYNCD_DEFAULT_PORT; }
87
		| PORT VALUE		{ $$ = $2; }
88
		;
89
90
mode		: Y_MASTER		{ $$ = MASTER; }
91
		| Y_SLAVE		{ $$ = SLAVE; }
92
		;
93
94
modes		: SKIPSLAVE
95
		{
96
			cfgstate.flags |= SKIP_LOCAL_SAS;
97
			log_msg(2, "config: not syncing SA to peers");
98
		}
99
		| mode
100
		{
101
			const char *m[] = CARPSTATES;
102
			cfgstate.lockedstate = $1;
103
			log_msg(2, "config: mode set to %s", m[$1]);
104
		}
105
		;
106
107
flushmode	: STARTUP		{ $$ = FM_STARTUP; }
108
		| NEVER			{ $$ = FM_NEVER; }
109
		| SYNC			{ $$ = FM_SYNC; }
110
		;
111
112
key		: STRING
113
		{
114
			if (cfgstate.sharedkey)
115
				free(cfgstate.sharedkey);
116
			cfgstate.sharedkey = $1;
117
			cfgstate.sharedkey_len = strlen($1) * 8;
118
			log_msg(2, "config: shared ascii key");
119
		}
120
		| HEX
121
		{
122
			if (cfgstate.sharedkey)
123
				free(cfgstate.sharedkey);
124
			cfgstate.sharedkey = $1.data;
125
			cfgstate.sharedkey_len = $1.len * 8;
126
			log_msg(2, "config: %d byte shared hex key", $1.len);
127
		}
128
129
ctlmode		: STRING
130
		{
131
			/* Compare strings to avoid keywords for daemons */
132
			if (strcmp("isakmpd", $1) == 0)
133
				$$ = CTL_ISAKMPD;
134
			else if (strcmp("iked", $1) == 0)
135
				$$ = CTL_IKED;
136
			else if (strcmp("all", $1) == 0)
137
				$$ = CTL_MASK;
138
			else if (strcmp("none", $1) == 0)
139
				$$ = CTL_NONE;
140
			else {
141
				log_err("config: invalid control mode");
142
				free($1);
143
				YYERROR;
144
			}
145
			log_msg(2, "config: control mode set to %s", $1);
146
			free($1);
147
		}
148
		;
149
150
setting		: INTERFACE STRING
151
		{
152
			if (cfgstate.carp_ifname)
153
				free(cfgstate.carp_ifname);
154
			cfgstate.carp_ifname = $2;
155
			log_msg(2, "config: interface %s",
156
			    cfgstate.carp_ifname);
157
		}
158
		| GROUP STRING
159
		{
160
			if (cfgstate.carp_ifgroup)
161
				free(cfgstate.carp_ifgroup);
162
			cfgstate.carp_ifgroup = $2;
163
			log_msg(2, "config: group %s",
164
			    cfgstate.carp_ifgroup);
165
		}
166
		| FLUSHMODE flushmode
167
		{
168
			const char *fm[] = { "STARTUP", "NEVER", "SYNC" };
169
			cfgstate.flags |= $2;
170
			log_msg(2, "config: flush mode set to %s", fm[$2]);
171
		}
172
		| PEER STRING
173
		{
174
			struct syncpeer	*peer;
175
			int		 duplicate = 0;
176
177
			for (peer = LIST_FIRST(&cfgstate.peerlist); peer;
178
			     peer = LIST_NEXT(peer, link))
179
				if (strcmp($2, peer->name) == 0) {
180
					duplicate++;
181
					break;
182
				}
183
			if (duplicate)
184
				free($2);
185
			else {
186
				peer = calloc(1, sizeof *peer);
187
				if (!peer) {
188
					log_err("config: calloc(1, %lu) "
189
					    "failed", sizeof *peer);
190
					free($2);
191
					YYERROR;
192
				}
193
				peer->name = $2;
194
			}
195
			LIST_INSERT_HEAD(&cfgstate.peerlist, peer, link);
196
			cfgstate.peercnt++;
197
			log_msg(2, "config: add peer %s", peer->name);
198
		}
199
		| LISTEN ON STRING af port
200
		{
201
			char pstr[20];
202
203
			if (cfgstate.listen_on)
204
				free(cfgstate.listen_on);
205
			cfgstate.listen_on = $3;
206
			cfgstate.listen_family = $4;
207
			cfgstate.listen_port = $5;
208
			if ($5 < 1 || $5 > IPPORT_HILASTAUTO) {
209
				cfgstate.listen_port = SASYNCD_DEFAULT_PORT;
210
				log_msg(0, "config: bad port, listen-port "
211
				    "reset to %u", SASYNCD_DEFAULT_PORT);
212
			}
213
			if ($5 != SASYNCD_DEFAULT_PORT)
214
				snprintf(pstr, sizeof pstr, "port %d",$5);
215
			log_msg(2, "config: listen on %s %s%s",
216
			    cfgstate.listen_on, $4 == AF_INET6 ? "(IPv6) " :
217
			    ($4 == AF_INET ? "(IPv4) " : ""),
218
			    $5 != SASYNCD_DEFAULT_PORT ? pstr : "");
219
		}
220
		| MODE modes
221
		| SHAREDKEY key
222
		{
223
			int bits;
224
225
			bits = cfgstate.sharedkey_len;
226
			if (bits != 128 && bits != 192 && bits != 256) {
227
				log_err("config: bad shared key length %d, "
228
				    "should be 128, 192 or 256 bits\n", bits);
229
				YYERROR;
230
			}
231
			log_msg(2, "config: shared key set");
232
		}
233
		| CONTROL ctlmode
234
		{
235
			cfgstate.flags &= ~CTL_MASK;
236
			cfgstate.flags |= $2;
237
		}
238
		;
239
240
%%
241
/* Program */
242
243
struct keyword {
244
	char *name;
245
	int   value;
246
};
247
248
static int
249
match_cmp(const void *a, const void *b)
250
{
251
	return strcmp(a, ((const struct keyword *)b)->name);
252
}
253
254
static int
255
match(char *token)
256
{
257
	/* Sorted */
258
	static const struct keyword keywords[] = {
259
		{ "control", CONTROL },
260
		{ "flushmode", FLUSHMODE },
261
		{ "group", GROUP },
262
		{ "inet", INET },
263
		{ "inet6", INET6 },
264
		{ "interface", INTERFACE },
265
		{ "listen", LISTEN },
266
		{ "master", Y_MASTER },
267
		{ "mode", MODE },
268
		{ "never", NEVER },
269
		{ "on", ON },
270
		{ "peer", PEER },
271
		{ "port", PORT },
272
		{ "sharedkey", SHAREDKEY },
273
		{ "skipslave", SKIPSLAVE },
274
		{ "slave", Y_SLAVE },
275
		{ "startup", STARTUP },
276
		{ "sync", SYNC },
277
	};
278
	const struct keyword *k;
279
280
	k = bsearch(token, keywords, sizeof keywords / sizeof keywords[0],
281
	    sizeof keywords[0], match_cmp);
282
283
	return k ? k->value : STRING;
284
}
285
286
int
287
yylex(void)
288
{
289
	char *p;
290
	int v, i, len;
291
292
	/* Locate next token */
293
	if (!confptr)
294
		confptr = confbuf;
295
	else {
296
		for (p = confptr; p < confbuf + conflen && *p; p++)
297
			;
298
		if (p == confbuf + conflen)
299
			return 0;
300
		p++;
301
		if (!*p)
302
			return 0;
303
		confptr = p;
304
	}
305
306
	/* Hex token? */
307
	p = confptr;
308
	if (!strncmp(p, "0x", 2)) {
309
		for (p = confptr + 2; *p; p++)
310
			if (!isxdigit(*p))
311
				goto is_string;
312
		p = confptr + 2;
313
		len = strlen(p) / 2;
314
		if ((yylval.hex.data = calloc(len, sizeof(unsigned char)))
315
		    == NULL) {
316
			log_err("yylex: calloc()");
317
			exit(1);
318
		}
319
		for (i = 0; i < len; i++)
320
			yylval.hex.data[i] = x2i(p + 2 * i);
321
		yylval.hex.len = len;
322
		return HEX;
323
	}
324
325
	/* Numerical token? */
326
	if (isdigit(*confptr)) {
327
		for (p = confptr; *p; p++)
328
			if (*p == '.') /* IP address, or bad input */
329
				goto is_string;
330
		v = (int)strtol(confptr, (char **)NULL, 10);
331
		yylval.val = v;
332
		return VALUE;
333
	}
334
335
  is_string:
336
	v = match(confptr);
337
	if (v == STRING) {
338
		yylval.string = strdup(confptr);
339
		if (!yylval.string) {
340
			log_err("yylex: strdup()");
341
			exit(1);
342
		}
343
	}
344
	return v;
345
}
346
347
int
348
conf_parse_file(char *cfgfile)
349
{
350
	struct stat	st;
351
	int		fd, r;
352
	char		*buf, *s, *d;
353
	struct passwd	*pw;
354
355
	if (stat(cfgfile, &st) != 0)
356
		goto bad;
357
358
	pw = getpwnam(SASYNCD_USER);
359
	if (pw == NULL) {
360
		log_err("getpwnam(%s) failed", SASYNCD_USER);
361
		return 1;
362
	}
363
364
	/* Valid file? */
365
	if ((st.st_uid && st.st_uid != pw->pw_uid) ||
366
	    ((st.st_mode & S_IFMT) != S_IFREG) ||
367
	    ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0)) {
368
		log_msg(0, "configuration file has bad owner, type or mode");
369
		goto bad;
370
	}
371
372
	fd = open(cfgfile, O_RDONLY, 0);
373
	if (fd < 0)
374
		goto bad;
375
376
	conflen = st.st_size;
377
	buf = malloc(conflen + 1);
378
	if (!buf) {
379
		log_err("malloc(%d) failed", conflen + 1);
380
		close(fd);
381
		return 1;
382
	}
383
384
	if (read(fd, buf, conflen) != conflen) {
385
		log_err("read() failed");
386
		free(buf);
387
		close(fd);
388
		return 1;
389
	}
390
	close(fd);
391
392
	/* Prepare the buffer somewhat in the way of strsep() */
393
	buf[conflen] = (char)0;
394
	for (s = buf, d = s; s < buf + conflen && *s; s++) {
395
		if (isspace(*s) && isspace(*(s+1)))
396
			continue;
397
		if (*s == '#') {
398
			while (*s != '\n' && s < buf + conflen)
399
				s++;
400
			continue;
401
		}
402
		if (d == buf && isspace(*s))
403
			continue;
404
		*d++ = *s;
405
	}
406
	*d = (char)0;
407
	for (s = buf; s <= d; s++)
408
		if (isspace(*s))
409
			*s = (char)0;
410
411
	confbuf = buf;
412
	confptr = NULL;
413
	r = yyparse();
414
	free(buf);
415
416
	if (!cfgstate.carp_ifgroup)
417
		cfgstate.carp_ifgroup = strdup("carp");
418
419
	return r;
420
421
  bad:
422
	log_msg(0, "failed to open \"%s\"", cfgfile);
423
	return 1;
424
}
425
426
unsigned char
427
x2i(unsigned char *s)
428
{
429
        char    ss[3];
430
431
        ss[0] = s[0];
432
        ss[1] = s[1];
433
        ss[2] = 0;
434
435
        return ((unsigned char)strtoul(ss, NULL, 16));
436
}
437
438
void
439
yyerror(const char *s)
440
{
441
	fprintf(stderr, "config: %s\n", s);
442
}