GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ripd/parse.y Lines: 0 287 0.0 %
Date: 2017-11-07 Branches: 0 219 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: parse.y,v 1.37 2017/01/05 13:53:09 krw Exp $ */
2
3
/*
4
 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
5
 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6
 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
7
 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
8
 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
9
 * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
10
 * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
11
 *
12
 * Permission to use, copy, modify, and distribute this software for any
13
 * purpose with or without fee is hereby granted, provided that the above
14
 * copyright notice and this permission notice appear in all copies.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
17
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
19
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
 */
24
25
%{
26
#include <sys/types.h>
27
#include <sys/socket.h>
28
#include <sys/stat.h>
29
#include <netinet/in.h>
30
#include <arpa/inet.h>
31
#include <ctype.h>
32
#include <err.h>
33
#include <errno.h>
34
#include <unistd.h>
35
#include <ifaddrs.h>
36
#include <limits.h>
37
#include <stdarg.h>
38
#include <stdio.h>
39
#include <string.h>
40
#include <syslog.h>
41
42
#include "ripd.h"
43
#include "rip.h"
44
#include "ripe.h"
45
#include "log.h"
46
47
TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
48
static struct file {
49
	TAILQ_ENTRY(file)	 entry;
50
	FILE			*stream;
51
	char			*name;
52
	int			 lineno;
53
	int			 errors;
54
} *file, *topfile;
55
struct file	*pushfile(const char *, int);
56
int		 popfile(void);
57
int		 yyparse(void);
58
int		 yylex(void);
59
int		 yyerror(const char *, ...)
60
    __attribute__((__format__ (printf, 1, 2)))
61
    __attribute__((__nonnull__ (1)));
62
int		 kw_cmp(const void *, const void *);
63
int		 lookup(char *);
64
int		 lgetc(int);
65
int		 lungetc(int);
66
int		 findeol(void);
67
68
TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
69
struct sym {
70
	TAILQ_ENTRY(sym)	 entry;
71
	int			 used;
72
	int			 persist;
73
	char			*nam;
74
	char			*val;
75
};
76
int		 symset(const char *, const char *, int);
77
char		*symget(const char *);
78
79
static struct {
80
	u_int8_t		 auth_key[MAX_SIMPLE_AUTH_LEN];
81
	struct auth_md_head	 md_list;
82
	enum auth_type		 auth_type;
83
	u_int8_t		 auth_keyid;
84
	u_int8_t		 cost;
85
} *defs, globaldefs, ifacedefs;
86
87
struct iface	*iface = NULL;
88
static struct ripd_conf	*conf;
89
static int		 errors = 0;
90
91
struct iface	*conf_get_if(struct kif *);
92
void		 clear_config(struct ripd_conf *);
93
int		 check_file_secrecy(int, const char *);
94
u_int32_t	 get_rtr_id(void);
95
int		 host(const char *, struct in_addr *, struct in_addr *);
96
97
typedef struct {
98
	union {
99
		int64_t		 number;
100
		char		*string;
101
	} v;
102
	int lineno;
103
} YYSTYPE;
104
105
%}
106
107
%token	SPLIT_HORIZON TRIGGERED_UPDATES FIBUPDATE REDISTRIBUTE RDOMAIN
108
%token	AUTHKEY AUTHTYPE AUTHMD AUTHMDKEYID
109
%token	INTERFACE RTLABEL
110
%token	COST PASSIVE
111
%token	YES NO
112
%token	DEMOTE
113
%token	ERROR
114
%token	<v.string>	STRING
115
%token	<v.number>	NUMBER
116
%type	<v.number>	yesno no
117
%type	<v.string>	string
118
119
%%
120
121
grammar		: /* empty */
122
		| grammar '\n'
123
		| grammar conf_main '\n'
124
		| grammar varset '\n'
125
		| grammar interface '\n'
126
		| grammar error '\n'		{ file->errors++; }
127
		;
128
129
string		: string STRING {
130
			if (asprintf(&$$, "%s %s", $1, $2) == -1) {
131
				free($1);
132
				free($2);
133
				yyerror("string: asprintf");
134
				YYERROR;
135
			}
136
			free($1);
137
			free($2);
138
		}
139
		| STRING
140
		;
141
142
yesno		: YES	{ $$ = 1; }
143
		| NO	{ $$ = 0; }
144
		;
145
146
no		: /* empty */	{ $$ = 0; }
147
		| NO		{ $$ = 1; }
148
149
varset		: STRING '=' string {
150
			char *s = $1;
151
			if (conf->opts & RIPD_OPT_VERBOSE)
152
				printf("%s = \"%s\"\n", $1, $3);
153
			while (*s++) {
154
				if (isspace((unsigned char)*s)) {
155
					yyerror("macro name cannot contain "
156
					    "whitespace");
157
					YYERROR;
158
				}
159
			}
160
			if (symset($1, $3, 0) == -1)
161
				fatal("cannot store variable");
162
			free($1);
163
			free($3);
164
		}
165
		;
166
167
conf_main	: SPLIT_HORIZON STRING {
168
			/* clean flags first */
169
			conf->options &= ~(OPT_SPLIT_HORIZON |
170
			    OPT_SPLIT_POISONED);
171
			if (!strcmp($2, "none"))
172
				/* nothing */ ;
173
			else if (!strcmp($2, "simple"))
174
				conf->options |= OPT_SPLIT_HORIZON;
175
			else if (!strcmp($2, "poisoned"))
176
				conf->options |= OPT_SPLIT_POISONED;
177
			else {
178
				yyerror("unknown split horizon type");
179
				free($2);
180
				YYERROR;
181
			}
182
			free($2);
183
		}
184
		| TRIGGERED_UPDATES yesno {
185
			if ($2 == 1)
186
				conf->options |= OPT_TRIGGERED_UPDATES;
187
			else
188
				conf->options &= ~OPT_TRIGGERED_UPDATES;
189
		}
190
		| RDOMAIN NUMBER {
191
			if ($2 < 0 || $2 > RT_TABLEID_MAX) {
192
				yyerror("invalid rdomain");
193
				YYERROR;
194
			}
195
			conf->rdomain = $2;
196
		}
197
		| FIBUPDATE yesno {
198
			if ($2 == 0)
199
				conf->flags |= RIPD_FLAG_NO_FIB_UPDATE;
200
			else
201
				conf->flags &= ~RIPD_FLAG_NO_FIB_UPDATE;
202
		}
203
		| no REDISTRIBUTE STRING {
204
			struct redistribute	*r;
205
206
			if ((r = calloc(1, sizeof(*r))) == NULL)
207
				fatal(NULL);
208
			if (!strcmp($3, "static"))
209
				r->type = REDIST_STATIC;
210
			else if (!strcmp($3, "connected"))
211
				r->type = REDIST_CONNECTED;
212
			else if (!strcmp($3, "default"))
213
				r->type = REDIST_DEFAULT;
214
			else if (host($3, &r->addr, &r->mask))
215
				r->type = REDIST_ADDR;
216
			else {
217
				yyerror("unknown redistribute type");
218
				free($3);
219
				free(r);
220
				YYERROR;
221
			}
222
223
			if ($1)
224
				r->type |= REDIST_NO;
225
226
			SIMPLEQ_INSERT_TAIL(&conf->redist_list, r,
227
			    entry);
228
229
			conf->redistribute |= REDISTRIBUTE_ON;
230
			free($3);
231
		}
232
		| no REDISTRIBUTE RTLABEL STRING {
233
			struct redistribute	*r;
234
235
			if ((r = calloc(1, sizeof(*r))) == NULL)
236
				fatal(NULL);
237
			r->type = REDIST_LABEL;
238
			r->label = rtlabel_name2id($4);
239
			if ($1)
240
				r->type |= REDIST_NO;
241
			free($4);
242
243
			SIMPLEQ_INSERT_TAIL(&conf->redist_list, r, entry);
244
			conf->redistribute |= REDISTRIBUTE_ON;
245
		}
246
		| defaults
247
		;
248
249
authmd		: AUTHMD NUMBER STRING {
250
			if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
251
				yyerror("auth-md key-id out of range "
252
				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
253
				free($3);
254
				YYERROR;
255
			}
256
			if (md_list_add(&defs->md_list, $2, $3) == -1) {
257
				yyerror("auth-md key length out of range "
258
				    "(max length %d)", MD5_DIGEST_LENGTH);
259
				free($3);
260
				YYERROR;
261
			}
262
			free($3);
263
		}
264
265
authmdkeyid	: AUTHMDKEYID NUMBER {
266
			if ($2 < MIN_MD_ID || $2 > MAX_MD_ID) {
267
				yyerror("auth-md-keyid out of range "
268
				    "(%d-%d)", MIN_MD_ID, MAX_MD_ID);
269
				YYERROR;
270
			}
271
			defs->auth_keyid = $2;
272
		}
273
274
authtype	: AUTHTYPE STRING {
275
			enum auth_type	type;
276
277
			if (!strcmp($2, "none"))
278
				type = AUTH_NONE;
279
			else if (!strcmp($2, "simple"))
280
				type = AUTH_SIMPLE;
281
			else if (!strcmp($2, "crypt"))
282
				type = AUTH_CRYPT;
283
			else {
284
				yyerror("unknown auth-type");
285
				free($2);
286
				YYERROR;
287
			}
288
			free($2);
289
			defs->auth_type = type;
290
		}
291
		;
292
293
authkey		: AUTHKEY STRING {
294
			if (strlen($2) > MAX_SIMPLE_AUTH_LEN) {
295
				yyerror("auth-key too long (max length %d)",
296
				    MAX_SIMPLE_AUTH_LEN);
297
				free($2);
298
				YYERROR;
299
			}
300
			bzero(defs->auth_key, MAX_SIMPLE_AUTH_LEN);
301
			memcpy(defs->auth_key, $2, strlen($2));
302
			free($2);
303
		}
304
		;
305
306
defaults	: COST NUMBER {
307
			if ($2 < 1 || $2 > INFINITY) {
308
				yyerror("cost out of range (%d-%d)", 1,
309
				    INFINITY);
310
				YYERROR;
311
			}
312
			defs->cost = $2;
313
		}
314
		| authtype
315
		| authkey
316
		| authmdkeyid
317
		| authmd
318
		;
319
320
optnl		: '\n' optnl
321
		|
322
		;
323
324
nl		: '\n' optnl
325
		;
326
327
interface	: INTERFACE STRING {
328
			struct kif *kif;
329
330
			if ((kif = kif_findname($2)) == NULL) {
331
				yyerror("unknown interface %s", $2);
332
				free($2);
333
				YYERROR;
334
			}
335
			free($2);
336
			iface = conf_get_if(kif);
337
			if (iface == NULL)
338
				YYERROR;
339
			LIST_INSERT_HEAD(&conf->iface_list, iface, entry);
340
			memcpy(&ifacedefs, defs, sizeof(ifacedefs));
341
			md_list_copy(&ifacedefs.md_list, &defs->md_list);
342
			defs = &ifacedefs;
343
		} interface_block {
344
			iface->cost = defs->cost;
345
			iface->auth_type = defs->auth_type;
346
			iface->auth_keyid = defs->auth_keyid;
347
			memcpy(iface->auth_key, defs->auth_key,
348
			    sizeof(iface->auth_key));
349
			md_list_copy(&iface->auth_md_list, &defs->md_list);
350
			md_list_clr(&defs->md_list);
351
			defs = &globaldefs;
352
		}
353
		;
354
355
interface_block	: '{' optnl interfaceopts_l '}'
356
		| '{' optnl '}'
357
		;
358
359
interfaceopts_l	: interfaceopts_l interfaceoptsl nl
360
		| interfaceoptsl optnl
361
		;
362
363
interfaceoptsl	: PASSIVE		{ iface->passive = 1; }
364
		| DEMOTE STRING		{
365
			if (strlcpy(iface->demote_group, $2,
366
			    sizeof(iface->demote_group)) >=
367
			    sizeof(iface->demote_group)) {
368
				yyerror("demote group name \"%s\" too long",
369
				    $2);
370
				free($2);
371
				YYERROR;
372
			}
373
			free($2);
374
			if (carp_demote_init(iface->demote_group,
375
			    conf->opts & RIPD_OPT_FORCE_DEMOTE) == -1) {
376
				yyerror("error initializing group \"%s\"",
377
				    iface->demote_group);
378
				YYERROR;
379
			}
380
		}
381
		| defaults
382
		;
383
%%
384
385
struct keywords {
386
	const char	*k_name;
387
	int		 k_val;
388
};
389
390
int
391
yyerror(const char *fmt, ...)
392
{
393
	va_list		 ap;
394
	char		*msg;
395
396
	file->errors++;
397
	va_start(ap, fmt);
398
	if (vasprintf(&msg, fmt, ap) == -1)
399
		fatalx("yyerror vasprintf");
400
	va_end(ap);
401
	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
402
	free(msg);
403
	return (0);
404
}
405
406
int
407
kw_cmp(const void *k, const void *e)
408
{
409
	return (strcmp(k, ((const struct keywords *)e)->k_name));
410
}
411
412
int
413
lookup(char *s)
414
{
415
	/* this has to be sorted always */
416
	static const struct keywords keywords[] = {
417
	    {"auth-key",		AUTHKEY},
418
	    {"auth-md",			AUTHMD},
419
	    {"auth-md-keyid",		AUTHMDKEYID},
420
	    {"auth-type",		AUTHTYPE},
421
	    {"cost",			COST},
422
	    {"demote",			DEMOTE},
423
	    {"fib-update",		FIBUPDATE},
424
	    {"interface",		INTERFACE},
425
	    {"no",			NO},
426
	    {"passive",			PASSIVE},
427
	    {"rdomain",			RDOMAIN},
428
	    {"redistribute",		REDISTRIBUTE},
429
	    {"rtlabel",			RTLABEL},
430
	    {"split-horizon",		SPLIT_HORIZON},
431
	    {"triggered-updates",	TRIGGERED_UPDATES},
432
	    {"yes",			YES}
433
	};
434
	const struct keywords	*p;
435
436
	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
437
	    sizeof(keywords[0]), kw_cmp);
438
439
	if (p)
440
		return (p->k_val);
441
	else
442
		return (STRING);
443
}
444
445
#define MAXPUSHBACK	128
446
447
u_char	*parsebuf;
448
int	 parseindex;
449
u_char	 pushback_buffer[MAXPUSHBACK];
450
int	 pushback_index = 0;
451
452
int
453
lgetc(int quotec)
454
{
455
	int		c, next;
456
457
	if (parsebuf) {
458
		/* Read character from the parsebuffer instead of input. */
459
		if (parseindex >= 0) {
460
			c = parsebuf[parseindex++];
461
			if (c != '\0')
462
				return (c);
463
			parsebuf = NULL;
464
		} else
465
			parseindex++;
466
	}
467
468
	if (pushback_index)
469
		return (pushback_buffer[--pushback_index]);
470
471
	if (quotec) {
472
		if ((c = getc(file->stream)) == EOF) {
473
			yyerror("reached end of file while parsing "
474
			    "quoted string");
475
			if (file == topfile || popfile() == EOF)
476
				return (EOF);
477
			return (quotec);
478
		}
479
		return (c);
480
	}
481
482
	while ((c = getc(file->stream)) == '\\') {
483
		next = getc(file->stream);
484
		if (next != '\n') {
485
			c = next;
486
			break;
487
		}
488
		yylval.lineno = file->lineno;
489
		file->lineno++;
490
	}
491
492
	while (c == EOF) {
493
		if (file == topfile || popfile() == EOF)
494
			return (EOF);
495
		c = getc(file->stream);
496
	}
497
	return (c);
498
}
499
500
int
501
lungetc(int c)
502
{
503
	if (c == EOF)
504
		return (EOF);
505
	if (parsebuf) {
506
		parseindex--;
507
		if (parseindex >= 0)
508
			return (c);
509
	}
510
	if (pushback_index < MAXPUSHBACK-1)
511
		return (pushback_buffer[pushback_index++] = c);
512
	else
513
		return (EOF);
514
}
515
516
int
517
findeol(void)
518
{
519
	int	c;
520
521
	parsebuf = NULL;
522
523
	/* skip to either EOF or the first real EOL */
524
	while (1) {
525
		if (pushback_index)
526
			c = pushback_buffer[--pushback_index];
527
		else
528
			c = lgetc(0);
529
		if (c == '\n') {
530
			file->lineno++;
531
			break;
532
		}
533
		if (c == EOF)
534
			break;
535
	}
536
	return (ERROR);
537
}
538
539
int
540
yylex(void)
541
{
542
	u_char	 buf[8096];
543
	u_char	*p, *val;
544
	int	 quotec, next, c;
545
	int	 token;
546
547
top:
548
	p = buf;
549
	while ((c = lgetc(0)) == ' ' || c == '\t')
550
		; /* nothing */
551
552
	yylval.lineno = file->lineno;
553
	if (c == '#')
554
		while ((c = lgetc(0)) != '\n' && c != EOF)
555
			; /* nothing */
556
	if (c == '$' && parsebuf == NULL) {
557
		while (1) {
558
			if ((c = lgetc(0)) == EOF)
559
				return (0);
560
561
			if (p + 1 >= buf + sizeof(buf) - 1) {
562
				yyerror("string too long");
563
				return (findeol());
564
			}
565
			if (isalnum(c) || c == '_') {
566
				*p++ = c;
567
				continue;
568
			}
569
			*p = '\0';
570
			lungetc(c);
571
			break;
572
		}
573
		val = symget(buf);
574
		if (val == NULL) {
575
			yyerror("macro '%s' not defined", buf);
576
			return (findeol());
577
		}
578
		parsebuf = val;
579
		parseindex = 0;
580
		goto top;
581
	}
582
583
	switch (c) {
584
	case '\'':
585
	case '"':
586
		quotec = c;
587
		while (1) {
588
			if ((c = lgetc(quotec)) == EOF)
589
				return (0);
590
			if (c == '\n') {
591
				file->lineno++;
592
				continue;
593
			} else if (c == '\\') {
594
				if ((next = lgetc(quotec)) == EOF)
595
					return (0);
596
				if (next == quotec || c == ' ' || c == '\t')
597
					c = next;
598
				else if (next == '\n') {
599
					file->lineno++;
600
					continue;
601
				} else
602
					lungetc(next);
603
			} else if (c == quotec) {
604
				*p = '\0';
605
				break;
606
			} else if (c == '\0') {
607
				yyerror("syntax error");
608
				return (findeol());
609
			}
610
			if (p + 1 >= buf + sizeof(buf) - 1) {
611
				yyerror("string too long");
612
				return (findeol());
613
			}
614
			*p++ = c;
615
		}
616
		yylval.v.string = strdup(buf);
617
		if (yylval.v.string == NULL)
618
			err(1, "yylex: strdup");
619
		return (STRING);
620
	}
621
622
#define allowed_to_end_number(x) \
623
	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
624
625
	if (c == '-' || isdigit(c)) {
626
		do {
627
			*p++ = c;
628
			if ((unsigned)(p-buf) >= sizeof(buf)) {
629
				yyerror("string too long");
630
				return (findeol());
631
			}
632
		} while ((c = lgetc(0)) != EOF && isdigit(c));
633
		lungetc(c);
634
		if (p == buf + 1 && buf[0] == '-')
635
			goto nodigits;
636
		if (c == EOF || allowed_to_end_number(c)) {
637
			const char *errstr = NULL;
638
639
			*p = '\0';
640
			yylval.v.number = strtonum(buf, LLONG_MIN,
641
			    LLONG_MAX, &errstr);
642
			if (errstr) {
643
				yyerror("\"%s\" invalid number: %s",
644
				    buf, errstr);
645
				return (findeol());
646
			}
647
			return (NUMBER);
648
		} else {
649
nodigits:
650
			while (p > buf + 1)
651
				lungetc(*--p);
652
			c = *--p;
653
			if (c == '-')
654
				return (c);
655
		}
656
	}
657
658
#define allowed_in_string(x) \
659
	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
660
	x != '{' && x != '}' && \
661
	x != '!' && x != '=' && x != '#' && \
662
	x != ','))
663
664
	if (isalnum(c) || c == ':' || c == '_') {
665
		do {
666
			*p++ = c;
667
			if ((unsigned)(p-buf) >= sizeof(buf)) {
668
				yyerror("string too long");
669
				return (findeol());
670
			}
671
		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
672
		lungetc(c);
673
		*p = '\0';
674
		if ((token = lookup(buf)) == STRING)
675
			if ((yylval.v.string = strdup(buf)) == NULL)
676
				err(1, "yylex: strdup");
677
		return (token);
678
	}
679
	if (c == '\n') {
680
		yylval.lineno = file->lineno;
681
		file->lineno++;
682
	}
683
	if (c == EOF)
684
		return (0);
685
	return (c);
686
}
687
688
int
689
check_file_secrecy(int fd, const char *fname)
690
{
691
	struct stat	st;
692
693
	if (fstat(fd, &st)) {
694
		log_warn("cannot stat %s", fname);
695
		return (-1);
696
	}
697
	if (st.st_uid != 0 && st.st_uid != getuid()) {
698
		log_warnx("%s: owner not root or current user", fname);
699
		return (-1);
700
	}
701
	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
702
		log_warnx("%s: group writable or world read/writable", fname);
703
		return (-1);
704
	}
705
	return (0);
706
}
707
708
struct file *
709
pushfile(const char *name, int secret)
710
{
711
	struct file	*nfile;
712
713
	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
714
		log_warn("malloc");
715
		return (NULL);
716
	}
717
	if ((nfile->name = strdup(name)) == NULL) {
718
		log_warn("malloc");
719
		free(nfile);
720
		return (NULL);
721
	}
722
	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
723
		log_warn("%s", nfile->name);
724
		free(nfile->name);
725
		free(nfile);
726
		return (NULL);
727
	} else if (secret &&
728
	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
729
		fclose(nfile->stream);
730
		free(nfile->name);
731
		free(nfile);
732
		return (NULL);
733
	}
734
	nfile->lineno = 1;
735
	TAILQ_INSERT_TAIL(&files, nfile, entry);
736
	return (nfile);
737
}
738
739
int
740
popfile(void)
741
{
742
	struct file	*prev;
743
744
	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
745
		prev->errors += file->errors;
746
747
	TAILQ_REMOVE(&files, file, entry);
748
	fclose(file->stream);
749
	free(file->name);
750
	free(file);
751
	file = prev;
752
	return (file ? 0 : EOF);
753
}
754
755
struct ripd_conf *
756
parse_config(char *filename, int opts)
757
{
758
	struct sym	*sym, *next;
759
760
	if ((conf = calloc(1, sizeof(struct ripd_conf))) == NULL)
761
		fatal("parse_config");
762
763
	bzero(&globaldefs, sizeof(globaldefs));
764
	defs = &globaldefs;
765
	TAILQ_INIT(&defs->md_list);
766
	defs->cost = DEFAULT_COST;
767
	defs->auth_type = AUTH_NONE;
768
	conf->opts = opts;
769
	conf->options = OPT_SPLIT_POISONED;
770
	SIMPLEQ_INIT(&conf->redist_list);
771
772
	if ((file = pushfile(filename, !(conf->opts & RIPD_OPT_NOACTION))) == NULL) {
773
		free(conf);
774
		return (NULL);
775
	}
776
	topfile = file;
777
778
	yyparse();
779
	errors = file->errors;
780
	popfile();
781
782
	/* Free macros and check which have not been used. */
783
	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
784
		if ((conf->opts & RIPD_OPT_VERBOSE2) && !sym->used)
785
			fprintf(stderr, "warning: macro '%s' not "
786
			    "used\n", sym->nam);
787
		if (!sym->persist) {
788
			free(sym->nam);
789
			free(sym->val);
790
			TAILQ_REMOVE(&symhead, sym, entry);
791
			free(sym);
792
		}
793
	}
794
795
	/* free global config defaults */
796
	md_list_clr(&globaldefs.md_list);
797
798
	if (errors) {
799
		clear_config(conf);
800
		return (NULL);
801
	}
802
803
	return (conf);
804
}
805
806
int
807
symset(const char *nam, const char *val, int persist)
808
{
809
	struct sym	*sym;
810
811
	TAILQ_FOREACH(sym, &symhead, entry) {
812
		if (strcmp(nam, sym->nam) == 0)
813
			break;
814
	}
815
816
	if (sym != NULL) {
817
		if (sym->persist == 1)
818
			return (0);
819
		else {
820
			free(sym->nam);
821
			free(sym->val);
822
			TAILQ_REMOVE(&symhead, sym, entry);
823
			free(sym);
824
		}
825
	}
826
	if ((sym = calloc(1, sizeof(*sym))) == NULL)
827
		return (-1);
828
829
	sym->nam = strdup(nam);
830
	if (sym->nam == NULL) {
831
		free(sym);
832
		return (-1);
833
	}
834
	sym->val = strdup(val);
835
	if (sym->val == NULL) {
836
		free(sym->nam);
837
		free(sym);
838
		return (-1);
839
	}
840
	sym->used = 0;
841
	sym->persist = persist;
842
	TAILQ_INSERT_TAIL(&symhead, sym, entry);
843
	return (0);
844
}
845
846
int
847
cmdline_symset(char *s)
848
{
849
	char	*sym, *val;
850
	int	ret;
851
	size_t	len;
852
853
	if ((val = strrchr(s, '=')) == NULL)
854
		return (-1);
855
856
	len = strlen(s) - strlen(val) + 1;
857
	if ((sym = malloc(len)) == NULL)
858
		errx(1, "cmdline_symset: malloc");
859
860
	strlcpy(sym, s, len);
861
862
	ret = symset(sym, val + 1, 1);
863
	free(sym);
864
865
	return (ret);
866
}
867
868
char *
869
symget(const char *nam)
870
{
871
	struct sym	*sym;
872
873
	TAILQ_FOREACH(sym, &symhead, entry) {
874
		if (strcmp(nam, sym->nam) == 0) {
875
			sym->used = 1;
876
			return (sym->val);
877
		}
878
	}
879
	return (NULL);
880
}
881
882
struct iface *
883
conf_get_if(struct kif *kif)
884
{
885
	struct iface	*i;
886
887
	LIST_FOREACH(i, &conf->iface_list, entry)
888
		if (i->ifindex == kif->ifindex) {
889
			yyerror("interface %s already configured",
890
			    kif->ifname);
891
			return (NULL);
892
		}
893
894
	i = if_new(kif);
895
	i->auth_keyid = 1;
896
	i->passive = 0;
897
898
	return (i);
899
}
900
901
void
902
clear_config(struct ripd_conf *xconf)
903
{
904
	struct iface	*i;
905
906
	while ((i = LIST_FIRST(&conf->iface_list)) != NULL) {
907
		LIST_REMOVE(i, entry);
908
		if_del(i);
909
	}
910
911
	free(xconf);
912
}
913
914
int
915
host(const char *s, struct in_addr *addr, struct in_addr *mask)
916
{
917
	struct in_addr		 ina;
918
	int			 bits = 32;
919
920
	bzero(&ina, sizeof(struct in_addr));
921
	if (strrchr(s, '/') != NULL) {
922
		if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
923
			return (0);
924
	} else {
925
		if (inet_pton(AF_INET, s, &ina) != 1)
926
			return (0);
927
	}
928
929
	addr->s_addr = ina.s_addr;
930
	mask->s_addr = prefixlen2mask(bits);
931
932
	return (1);
933
}