1122394Sharti/*
2122394Sharti * Copyright (c) 2001-2003
3122394Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4122394Sharti *	All rights reserved.
5122394Sharti *
6122394Sharti * Author: Harti Brandt <harti@freebsd.org>
7133211Sharti *
8133211Sharti * Redistribution and use in source and binary forms, with or without
9133211Sharti * modification, are permitted provided that the following conditions
10133211Sharti * are met:
11133211Sharti * 1. Redistributions of source code must retain the above copyright
12133211Sharti *    notice, this list of conditions and the following disclaimer.
13122394Sharti * 2. Redistributions in binary form must reproduce the above copyright
14122394Sharti *    notice, this list of conditions and the following disclaimer in the
15122394Sharti *    documentation and/or other materials provided with the distribution.
16133211Sharti *
17133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20133211Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27133211Sharti * SUCH DAMAGE.
28122394Sharti *
29156066Sharti * $Begemot: bsnmp/snmpd/config.c,v 1.25 2006/02/14 09:04:20 brandt_h Exp $
30122394Sharti *
31122394Sharti * Parse configuration file.
32122394Sharti */
33122394Sharti#include <sys/types.h>
34216294Ssyrinx#include <sys/queue.h>
35122394Sharti#include <sys/socket.h>
36122394Sharti#include <sys/un.h>
37122394Sharti#include <stdio.h>
38122394Sharti#include <stdlib.h>
39122394Sharti#include <string.h>
40122394Sharti#include <stdarg.h>
41122394Sharti#include <ctype.h>
42122394Sharti#include <errno.h>
43122394Sharti#include <syslog.h>
44122394Sharti#include <unistd.h>
45122394Sharti#include <limits.h>
46122394Sharti#include <netdb.h>
47122394Sharti#include <setjmp.h>
48122394Sharti#include <inttypes.h>
49122394Sharti
50122394Sharti#include "snmpmod.h"
51122394Sharti#include "snmpd.h"
52122394Sharti#include "tree.h"
53122394Sharti
54122394Sharti/*
55122394Sharti#define DEBUGGING
56122394Sharti*/
57122394Sharti
58122394Sharti/*
59122394Sharti * config_file: EMPTY | config_file line
60122394Sharti *
61122394Sharti * line: oid '=' value
62122394Sharti *     | '%' STRING
63122394Sharti *     | STRING := REST_OF_LINE
64122394Sharti *     | STRING ?= REST_OF_LINE
65122394Sharti *     | . INCLUDE STRING
66122394Sharti *
67122394Sharti * oid: STRING suboid
68122394Sharti *
69122394Sharti * suboid: EMPTY | suboid '.' subid
70122394Sharti *
71122394Sharti * subid: NUM | STRING | '[' STRING ']'
72122394Sharti *
73122394Sharti * value: EMPTY | STRING | NUM
74122394Sharti */
75122394Sharti
76122394Sharti/*
77122394Sharti * Input context for macros and includes
78122394Sharti */
79122394Shartienum input_type {
80122394Sharti	INPUT_FILE	= 1,
81122394Sharti	INPUT_STRING
82122394Sharti};
83122394Shartistruct input {
84122394Sharti	enum input_type	type;
85122394Sharti	union {
86122394Sharti	    struct {
87122394Sharti		FILE	*fp;
88122394Sharti		char	*filename;
89122394Sharti		u_int	lno;
90122394Sharti	    }		file;
91122394Sharti	    struct {
92122394Sharti		char	*macro;
93122394Sharti		char	*str;
94122394Sharti		char	*ptr;
95122394Sharti		size_t	left;
96122394Sharti	    }		str;
97122394Sharti	} u;
98122394Sharti	LIST_ENTRY(input) link;
99122394Sharti};
100122394Shartistatic LIST_HEAD(, input) inputs;
101122394Sharti
102122394Sharti#define input_fp	u.file.fp
103122394Sharti#define input_filename	u.file.filename
104122394Sharti#define input_lno	u.file.lno
105122394Sharti#define input_macro	u.str.macro
106122394Sharti#define input_str	u.str.str
107122394Sharti#define input_ptr	u.str.ptr
108122394Sharti#define input_left	u.str.left
109122394Sharti
110122394Shartistatic int input_push;
111122394Shartistatic int input_buf[2];
112122394Sharti
113122394Sharti/*
114122394Sharti * Configuration data. The configuration file is handled as one single
115122394Sharti * SNMP transaction. So we need to keep the assignment data for the
116122394Sharti * commit or rollback pass. Note, that dependencies and finish functions
117122394Sharti * are NOT allowed here.
118122394Sharti */
119122394Shartistruct assign {
120122394Sharti	struct snmp_value value;
121122394Sharti	struct snmp_scratch scratch;
122122394Sharti	const char *node_name;
123122394Sharti
124122394Sharti	TAILQ_ENTRY(assign) link;
125122394Sharti};
126122394Shartistatic TAILQ_HEAD(assigns, assign) assigns = TAILQ_HEAD_INITIALIZER(assigns);
127122394Sharti
128122394Sharti
129122394Shartistatic struct snmp_context *snmp_ctx;
130122394Sharti
131122394Shartistruct macro {
132122394Sharti	char	*name;
133122394Sharti	char	*value;
134122394Sharti	size_t	length;
135122394Sharti	LIST_ENTRY(macro) link;
136122394Sharti	int	perm;
137122394Sharti};
138205729Santoinestatic LIST_HEAD(, macro) macros = LIST_HEAD_INITIALIZER(macros);
139122394Sharti
140122394Shartienum {
141122394Sharti	TOK_EOF	= 0200,
142122394Sharti	TOK_EOL,
143122394Sharti	TOK_NUM,
144122394Sharti	TOK_STR,
145122394Sharti	TOK_HOST,
146122394Sharti	TOK_ASSIGN,
147122394Sharti	TOK_QASSIGN,
148122394Sharti};
149122394Sharti
150122394Sharti/* lexer values and last token */
151122394Shartistatic uint64_t	numval;
152122394Shartistatic char	strval[_POSIX2_LINE_MAX];
153122394Shartistatic size_t	strvallen;
154122394Shartistatic int	token;
155122394Sharti
156122394Sharti/* error return */
157122394Shartistatic jmp_buf	errjmp[4];
158122394Shartistatic volatile int errstk;
159122394Sharti
160122394Sharti# define ERRPUSH()	(setjmp(errjmp[errstk++]))
161122394Sharti# define ERRPOP()	((void)(errstk--))
162122394Sharti# define ERRNEXT()	(longjmp(errjmp[--errstk], 1))
163122394Sharti# define ERR()		(longjmp(errjmp[--errstk], 1))
164122394Sharti
165122394Sharti/* section context */
166122394Shartistatic int ignore;
167122394Sharti
168122394Sharti/*
169122394Sharti * Report an error and jump to the error label
170122394Sharti */
171122394Shartistatic void report(const char *fmt, ...) __dead2 __printflike(1, 2);
172122394Sharti
173122394Shartistatic void
174122394Shartireport(const char *fmt, ...)
175122394Sharti{
176122394Sharti	va_list ap;
177122394Sharti	const struct input *input;
178122394Sharti
179122394Sharti	va_start(ap, fmt);
180122394Sharti	vsyslog(LOG_ERR, fmt, ap);
181122394Sharti	va_end(ap);
182122394Sharti
183122394Sharti	LIST_FOREACH(input, &inputs, link) {
184122394Sharti		switch (input->type) {
185122394Sharti
186122394Sharti		  case INPUT_FILE:
187122394Sharti			syslog(LOG_ERR, "  in file %s line %u",
188122394Sharti			    input->input_filename, input->input_lno);
189122394Sharti			break;
190122394Sharti
191122394Sharti		  case INPUT_STRING:
192122394Sharti			syslog(LOG_ERR, "  in macro %s pos %td",
193122394Sharti			    input->input_macro,
194122394Sharti			    input->input_ptr - input->input_str);
195122394Sharti			break;
196122394Sharti		}
197122394Sharti	}
198122394Sharti	ERR();
199122394Sharti}
200122394Sharti
201122394Sharti/*
202122394Sharti * Open a file for input
203122394Sharti */
204122394Shartistatic int
205122394Shartiinput_open_file(const char *fname, int sysdir)
206122394Sharti{
207122394Sharti	struct input *input;
208122394Sharti	FILE *fp;
209122394Sharti	char path[PATH_MAX + 1];
210154178Sharti	const char *col;
211122394Sharti	const char *ptr;
212122394Sharti
213122394Sharti	if (sysdir) {
214122394Sharti		ptr = syspath;
215122394Sharti		fp = NULL;
216122394Sharti		while (*ptr != '\0') {
217154178Sharti			if ((col = strchr(ptr, ':')) == NULL) {
218122394Sharti				snprintf(path, sizeof(path), "%s/%s",
219122394Sharti				    ptr, fname);
220154178Sharti				col = ptr + strlen(ptr) - 1;
221154178Sharti			} else if (col == ptr)
222122394Sharti				snprintf(path, sizeof(path), "./%s", fname);
223122394Sharti			else
224122394Sharti				snprintf(path, sizeof(path), "%.*s/%s",
225122394Sharti				    (int)(col - ptr), ptr, fname);
226122394Sharti			if ((fp = fopen(path, "r")) != NULL)
227122394Sharti				break;
228122394Sharti			ptr = col + 1;
229122394Sharti		}
230122394Sharti	} else
231122394Sharti		fp = fopen(fname, "r");
232122394Sharti
233122394Sharti	if (fp == NULL)
234122394Sharti		report("%s: %m", fname);
235122394Sharti
236122394Sharti	if ((input = malloc(sizeof(*input))) == NULL) {
237122394Sharti		fclose(fp);
238122394Sharti		return (-1);
239122394Sharti	}
240122394Sharti	if ((input->input_filename = malloc(strlen(fname) + 1)) == NULL) {
241122394Sharti		fclose(fp);
242122394Sharti		free(input);
243122394Sharti		return (-1);
244122394Sharti	}
245122394Sharti	strcpy(input->input_filename, fname);
246122394Sharti	input->input_fp = fp;
247122394Sharti	input->input_lno = 1;
248122394Sharti	input->type = INPUT_FILE;
249122394Sharti	LIST_INSERT_HEAD(&inputs, input, link);
250122394Sharti	return (0);
251122394Sharti}
252122394Sharti
253122394Sharti/*
254122394Sharti * Make a macro the next input
255122394Sharti */
256122394Shartistatic void
257122394Shartiinput_open_macro(struct macro *m)
258122394Sharti{
259122394Sharti	struct input *input;
260122394Sharti
261122394Sharti	if ((input = malloc(sizeof(*input))) == NULL)
262122394Sharti		report("%m");
263122394Sharti	input->type = INPUT_STRING;
264122394Sharti	input->input_macro = m->name;
265122394Sharti	if ((input->input_str = malloc(m->length)) == NULL) {
266122394Sharti		free(input);
267122394Sharti		report("%m");
268122394Sharti	}
269122394Sharti	memcpy(input->input_str, m->value, m->length);
270122394Sharti	input->input_ptr = input->input_str;
271122394Sharti	input->input_left = m->length;
272122394Sharti	LIST_INSERT_HEAD(&inputs, input, link);
273122394Sharti}
274122394Sharti
275122394Sharti/*
276122394Sharti * Close top input source
277122394Sharti */
278122394Shartistatic void
279122394Shartiinput_close(void)
280122394Sharti{
281122394Sharti	struct input *input;
282122394Sharti
283122394Sharti	if ((input = LIST_FIRST(&inputs)) == NULL)
284122394Sharti		abort();
285122394Sharti	switch (input->type) {
286122394Sharti
287122394Sharti	  case INPUT_FILE:
288122394Sharti		fclose(input->input_fp);
289122394Sharti		free(input->input_filename);
290122394Sharti		break;
291122394Sharti
292122394Sharti	  case INPUT_STRING:
293122394Sharti		free(input->input_str);
294122394Sharti		break;
295122394Sharti	}
296122394Sharti	LIST_REMOVE(input, link);
297122394Sharti	free(input);
298122394Sharti}
299122394Sharti
300122394Sharti/*
301122394Sharti * Close all inputs
302122394Sharti */
303122394Shartistatic void
304122394Shartiinput_close_all(void)
305122394Sharti{
306122394Sharti	while (!LIST_EMPTY(&inputs))
307122394Sharti		input_close();
308122394Sharti}
309122394Sharti
310122394Sharti/*
311122394Sharti * Push back one character
312122394Sharti */
313122394Shartistatic void
314122394Shartiinput_ungetc(int c)
315122394Sharti{
316122394Sharti	if (c == EOF)
317122394Sharti		report("pushing EOF");
318122394Sharti	if (input_push == 2)
319122394Sharti		report("pushing third char");
320122394Sharti	input_buf[input_push++] = c;
321122394Sharti}
322122394Sharti
323122394Sharti
324122394Sharti/*
325122394Sharti * Return next character from the input without preprocessing.
326122394Sharti */
327122394Shartistatic int
328122394Shartiinput_getc_raw(void)
329122394Sharti{
330122394Sharti	int c;
331122394Sharti	struct input *input;
332122394Sharti
333122394Sharti	if (input_push != 0) {
334122394Sharti		c = input_buf[--input_push];
335122394Sharti		goto ok;
336122394Sharti	}
337122394Sharti	while ((input = LIST_FIRST(&inputs)) != NULL) {
338122394Sharti		switch (input->type) {
339122394Sharti
340122394Sharti		  case INPUT_FILE:
341122394Sharti			if ((c = getc(input->input_fp)) == EOF) {
342122394Sharti				if (ferror(input->input_fp))
343122394Sharti					report("read error: %m");
344122394Sharti				input_close();
345122394Sharti				break;
346122394Sharti			}
347122394Sharti			if (c == '\n')
348122394Sharti				input->input_lno++;
349122394Sharti			goto ok;
350122394Sharti
351122394Sharti		  case INPUT_STRING:
352122394Sharti			if (input->input_left-- == 0) {
353122394Sharti				input_close();
354122394Sharti				break;
355122394Sharti			}
356122394Sharti			c = *input->input_ptr++;
357122394Sharti			goto ok;
358122394Sharti		}
359122394Sharti	}
360122394Sharti# ifdef DEBUGGING
361122394Sharti	fprintf(stderr, "EOF");
362122394Sharti# endif
363122394Sharti	return (EOF);
364122394Sharti
365122394Sharti  ok:
366122394Sharti# ifdef DEBUGGING
367122394Sharti	if (!isascii(c) || !isprint(c))
368122394Sharti		fprintf(stderr, "'%#2x'", c);
369122394Sharti	else
370122394Sharti		fprintf(stderr, "'%c'", c);
371122394Sharti# endif
372122394Sharti	return (c);
373122394Sharti}
374122394Sharti
375122394Sharti/*
376122394Sharti * Get character with and \\n -> processing.
377122394Sharti */
378122394Shartistatic int
379122394Shartiinput_getc_plain(void)
380122394Sharti{
381122394Sharti	int c;
382122394Sharti
383122394Sharti  again:
384122394Sharti	if ((c = input_getc_raw()) == '\\') {
385122394Sharti		if ((c = input_getc_raw()) == '\n')
386122394Sharti			goto again;
387122394Sharti		if (c != EOF)
388122394Sharti			input_ungetc(c);
389122394Sharti		return ('\\');
390122394Sharti	}
391122394Sharti	return (c);
392122394Sharti}
393122394Sharti
394122394Sharti/*
395122394Sharti * Get next character with substitution of macros
396122394Sharti */
397122394Shartistatic int
398122394Shartiinput_getc(void)
399122394Sharti{
400122394Sharti	int c;
401122394Sharti	struct macro *m;
402122394Sharti	char	name[_POSIX2_LINE_MAX];
403122394Sharti	size_t	namelen;
404122394Sharti
405122394Sharti  again:
406122394Sharti	if ((c = input_getc_plain()) != '$')
407122394Sharti		return (c);
408122394Sharti
409122394Sharti	if ((c = input_getc()) == EOF)
410122394Sharti		report("unexpected EOF");
411122394Sharti	if (c != '(')
412122394Sharti		report("expecting '(' after '$'");
413122394Sharti
414122394Sharti	namelen = 0;
415122394Sharti	while ((c = input_getc()) != EOF && c != ')') {
416122394Sharti		if (isalpha(c) || c == '_' || (namelen != 0 && isdigit(c)))
417122394Sharti			name[namelen++] = c;
418122394Sharti		else
419122394Sharti			goto badchar;
420122394Sharti	}
421122394Sharti	if (c == EOF)
422122394Sharti		report("unexpected EOF");
423122394Sharti	name[namelen++] = '\0';
424122394Sharti
425122394Sharti	LIST_FOREACH(m, &macros, link)
426122394Sharti		if (strcmp(m->name, name) == 0)
427122394Sharti			break;
428122394Sharti	if (m == NULL)
429122394Sharti		report("undefined macro '%s'", name);
430122394Sharti
431122394Sharti	input_open_macro(m);
432122394Sharti	goto again;
433122394Sharti
434122394Sharti  badchar:
435122394Sharti	if (!isascii(c) || !isprint(c))
436122394Sharti		report("unexpected character %#2x", (u_int)c);
437122394Sharti	else
438122394Sharti		report("bad character '%c'", c);
439122394Sharti}
440122394Sharti
441122394Sharti
442122394Shartistatic void
443122394Shartiinput_getnum(u_int base, u_int flen)
444122394Sharti{
445122394Sharti	int c;
446122394Sharti	u_int cnt;
447122394Sharti
448122394Sharti	cnt = 0;
449122394Sharti	numval = 0;
450122394Sharti	while (flen == 0 || cnt < flen) {
451122394Sharti		if ((c = input_getc()) == EOF) {
452122394Sharti			if (cnt == 0)
453122394Sharti				report("bad number");
454122394Sharti			return;
455122394Sharti		}
456122394Sharti		if (isdigit(c)) {
457122394Sharti			if (base == 8 && (c == '8' || c == '9')) {
458122394Sharti				input_ungetc(c);
459122394Sharti				if (cnt == 0)
460122394Sharti					report("bad number");
461122394Sharti				return;
462122394Sharti			}
463122394Sharti			numval = numval * base + (c - '0');
464122394Sharti		} else if (base == 16 && isxdigit(c)) {
465122394Sharti			if (islower(c))
466122394Sharti				numval = numval * base + (c - 'a' + 10);
467122394Sharti			else
468122394Sharti				numval = numval * base + (c - 'A' + 10);
469122394Sharti		} else {
470122394Sharti			input_ungetc(c);
471122394Sharti			if (cnt == 0)
472122394Sharti				report("bad number");
473122394Sharti			return;
474122394Sharti		}
475122394Sharti		cnt++;
476122394Sharti	}
477122394Sharti}
478122394Sharti
479122394Shartistatic int
480122394Sharti# ifdef DEBUGGING
481122394Sharti_gettoken(void)
482122394Sharti# else
483122394Shartigettoken(void)
484122394Sharti# endif
485122394Sharti{
486122394Sharti	int c;
487122394Sharti	char *end;
488122394Sharti	static const char esc[] = "abfnrtv";
489122394Sharti	static const char chr[] = "\a\b\f\n\r\t\v";
490122394Sharti
491122394Sharti	/*
492122394Sharti	 * Skip any whitespace before the next token
493122394Sharti	 */
494122394Sharti	while ((c = input_getc()) != EOF) {
495122394Sharti		if (!isspace(c) || c == '\n')
496122394Sharti			break;
497122394Sharti	}
498122394Sharti	if (c == EOF)
499122394Sharti		return (token = TOK_EOF);
500122394Sharti	if (!isascii(c))
501122394Sharti		goto badchar;
502122394Sharti
503122394Sharti	/*
504122394Sharti	 * Skip comments
505122394Sharti	 */
506122394Sharti	if (c == '#') {
507122394Sharti		while ((c = input_getc_plain()) != EOF) {
508122394Sharti			if (c == '\n')
509122394Sharti				return (token = TOK_EOL);
510122394Sharti		}
511122394Sharti		goto badeof;
512122394Sharti	}
513122394Sharti
514122394Sharti	/*
515122394Sharti	 * Single character tokens
516122394Sharti	 */
517122394Sharti	if (c == '\n')
518122394Sharti		return (token = TOK_EOL);
519122394Sharti	if (c == '.' || c == '%' || c == '=' || c == '<' || c == '>')
520122394Sharti		return (token = c);
521122394Sharti	if (c == ':') {
522122394Sharti		if ((c = input_getc()) == '=')
523122394Sharti			return (token = TOK_ASSIGN);
524122394Sharti		input_ungetc(c);
525122394Sharti		return (token = ':');
526122394Sharti	}
527122394Sharti	if (c == '?') {
528122394Sharti		if ((c = input_getc()) == '=')
529122394Sharti			return (token = TOK_QASSIGN);
530122394Sharti		input_ungetc(c);
531122394Sharti		goto badchar;
532122394Sharti	}
533122394Sharti
534122394Sharti	/*
535122394Sharti	 * Sort out numbers
536122394Sharti	 */
537122394Sharti	if (isdigit(c)) {
538122394Sharti		if (c == '0') {
539122394Sharti			if ((c = input_getc()) == 'x' || c == 'X') {
540122394Sharti				input_getnum(16, 0);
541122394Sharti			} else if (isdigit(c)) {
542122394Sharti				input_ungetc(c);
543122394Sharti				input_getnum(8, 0);
544122394Sharti			} else {
545122394Sharti				if (c != EOF)
546122394Sharti					input_ungetc(c);
547122394Sharti				numval = 0;
548122394Sharti				c = 1;
549122394Sharti			}
550122394Sharti		} else {
551122394Sharti			input_ungetc(c);
552122394Sharti			input_getnum(10, 0);
553122394Sharti		}
554122394Sharti		return (token = TOK_NUM);
555122394Sharti	}
556122394Sharti
557122394Sharti	/*
558122394Sharti	 * Must be a string then
559122394Sharti	 */
560122394Sharti	strvallen = 0;
561122394Sharti
562122394Sharti# define GETC(C) do {							\
563122394Sharti	if ((c = input_getc()) == EOF)					\
564122394Sharti		goto badeof;						\
565122394Sharti	if (!isascii(c) || (!isprint(c) && c != '\t')) 			\
566122394Sharti		goto badchar;						\
567122394Sharti} while(0)
568122394Sharti
569122394Sharti	if (c == '"') {
570122394Sharti		for(;;) {
571122394Sharti			GETC(c);
572122394Sharti			if (c == '"') {
573122394Sharti				strval[strvallen] = '\0';
574122394Sharti				break;
575122394Sharti			}
576122394Sharti			if (c != '\\') {
577122394Sharti				strval[strvallen++] = c;
578122394Sharti				continue;
579122394Sharti			}
580122394Sharti			GETC(c);
581122394Sharti			if ((end = strchr(esc, c)) != NULL) {
582122394Sharti				strval[strvallen++] = chr[end - esc];
583122394Sharti				continue;
584122394Sharti			}
585122394Sharti			if (c == 'x') {
586122394Sharti				input_getnum(16, 2);
587122394Sharti				c = numval;
588122394Sharti			} else if (c >= '0' && c <= '7') {
589122394Sharti				input_ungetc(c);
590122394Sharti				input_getnum(8, 3);
591122394Sharti				c = numval;
592122394Sharti			}
593122394Sharti			strval[strvallen++] = c;
594122394Sharti		}
595122394Sharti# undef GETC
596122394Sharti
597122394Sharti	} else if (c == '[') {
598122394Sharti		/*
599122394Sharti		 * Skip leading space
600122394Sharti		 */
601122394Sharti		while ((c = input_getc()) != EOF && isspace(c))
602122394Sharti			;
603122394Sharti		if (c == EOF)
604122394Sharti			goto badeof;
605122394Sharti		while (c != ']' && !isspace(c)) {
606122394Sharti			if (!isalnum(c) && c != '.' && c != '-')
607122394Sharti				goto badchar;
608122394Sharti			strval[strvallen++] = c;
609122394Sharti			if ((c = input_getc()) == EOF)
610122394Sharti				goto badeof;
611122394Sharti		}
612122394Sharti		while (c != ']' && isspace(c)) {
613122394Sharti			if ((c = input_getc()) == EOF)
614122394Sharti				goto badeof;
615122394Sharti		}
616122394Sharti		if (c != ']')
617122394Sharti			goto badchar;
618122394Sharti		strval[strvallen] = '\0';
619122394Sharti		return (token = TOK_HOST);
620122394Sharti
621122394Sharti	} else if (!isalpha(c) && c != '_') {
622122394Sharti		goto badchar;
623122394Sharti
624122394Sharti	} else {
625122394Sharti		for (;;) {
626122394Sharti			strval[strvallen++] = c;
627122394Sharti			if ((c = input_getc()) == EOF)
628122394Sharti				goto badeof;
629122394Sharti			if (!isalnum(c) && c != '_' && c != '-') {
630122394Sharti				input_ungetc(c);
631122394Sharti				strval[strvallen] = '\0';
632122394Sharti				break;
633122394Sharti			}
634122394Sharti		}
635122394Sharti	}
636122394Sharti
637122394Sharti	return (token = TOK_STR);
638122394Sharti
639122394Sharti  badeof:
640122394Sharti	report("unexpected EOF");
641122394Sharti
642122394Sharti  badchar:
643122394Sharti	if (!isascii(c) || !isprint(c))
644122394Sharti		report("unexpected character %#2x", (u_int)c);
645122394Sharti	else
646122394Sharti		report("bad character '%c'", c);
647122394Sharti}
648122394Sharti
649122394Sharti# ifdef DEBUGGING
650122394Shartistatic int
651122394Shartigettoken()
652122394Sharti{
653122394Sharti	_gettoken();
654122394Sharti	if (isascii(token) && isprint(token))
655122394Sharti		printf("(%c)", token);
656122394Sharti	else {
657122394Sharti		switch (token) {
658122394Sharti
659122394Sharti		  case TOK_EOF:
660122394Sharti			printf("(EOF)");
661122394Sharti			break;
662122394Sharti		  case TOK_EOL:
663122394Sharti			printf("(EOL)");
664122394Sharti			break;
665122394Sharti		  case TOK_NUM:
666122394Sharti			printf("(NUM %llu)", numval);
667122394Sharti			break;
668122394Sharti		  case TOK_STR:
669122394Sharti			printf("(STR %.*s)", (int)strvallen, strval);
670122394Sharti			break;
671122394Sharti		  case TOK_HOST:
672122394Sharti			printf("(HOST %s)", strval);
673122394Sharti			break;
674122394Sharti		  default:
675122394Sharti			printf("(%#2x)", token);
676122394Sharti			break;
677122394Sharti		}
678122394Sharti	}
679122394Sharti	return (token);
680122394Sharti}
681122394Sharti#endif
682122394Sharti
683122394Sharti
684122394Sharti/*
685122394Sharti * Try to execute the assignment.
686122394Sharti */
687122394Shartistatic void
688122394Shartihandle_assignment(const struct snmp_node *node, struct asn_oid *vindex,
689122394Sharti    const struct snmp_value *value)
690122394Sharti{
691122394Sharti	u_int i;
692122394Sharti	int err;
693122394Sharti	struct assign *tp;
694122394Sharti	char nodename[100];
695122394Sharti
696122394Sharti	if (node->type == SNMP_NODE_LEAF) {
697122394Sharti		/* index must be one single zero or no index at all */
698122394Sharti		if (vindex->len > 1 || (vindex->len == 1 &&
699122394Sharti		    vindex->subs[0] != 0))
700122394Sharti			report("bad index on leaf node");
701122394Sharti		vindex->len = 1;
702122394Sharti		vindex->subs[0] = 0;
703122394Sharti	} else {
704122394Sharti		/* resulting oid must not be too long */
705122394Sharti		if (node->oid.len + vindex->len > ASN_MAXOIDLEN)
706122394Sharti			report("resulting OID too long");
707122394Sharti	}
708122394Sharti
709122394Sharti	/*
710122394Sharti	 * Get the next assignment entry for the transaction.
711122394Sharti	 */
712122394Sharti	if ((tp = malloc(sizeof(*tp))) == NULL)
713122394Sharti		report("%m");
714122394Sharti
715122394Sharti	tp->value = *value;
716122394Sharti	tp->node_name = node->name;
717122394Sharti
718122394Sharti	/*
719122394Sharti	 * Build the OID
720122394Sharti	 */
721122394Sharti	tp->value.var = node->oid;
722122394Sharti	for (i = 0; i < vindex->len; i++)
723122394Sharti		tp->value.var.subs[tp->value.var.len++] = vindex->subs[i];
724122394Sharti
725122394Sharti	/*
726122394Sharti	 * Puzzle together the variables for the call and call the
727122394Sharti	 * set routine. The set routine may make our node pointer
728122394Sharti	 * invalid (if we happend to call the module loader) so
729122394Sharti	 * get a copy of the node name beforehands.
730122394Sharti	 */
731122394Sharti	snprintf(nodename, sizeof(nodename), "%s", node->name);
732122394Sharti	snmp_ctx->scratch = &tp->scratch;
733122394Sharti	snmp_ctx->var_index = 0;
734122394Sharti	err = (*node->op)(snmp_ctx, &tp->value, node->oid.len, node->index,
735122394Sharti	    SNMP_OP_SET);
736122394Sharti	if (err != 0) {
737122394Sharti		free(tp);
738122394Sharti		report("assignment to %s.%s returns %d", nodename,
739122394Sharti		    asn_oid2str(vindex), err);
740122394Sharti	}
741122394Sharti
742122394Sharti	TAILQ_INSERT_TAIL(&assigns, tp, link);
743122394Sharti}
744122394Sharti
745122394Sharti
746122394Sharti/*
747122394Sharti * Parse the section statement
748122394Sharti */
749122394Shartistatic void
750122394Shartiparse_section(const struct lmodule *mod)
751122394Sharti{
752122394Sharti	if (token != TOK_STR)
753122394Sharti		report("expecting section name");
754122394Sharti
755122394Sharti	if (strcmp(strval, "snmpd") == 0) {
756122394Sharti		if (mod != NULL)
757122394Sharti			/* loading a module - ignore common stuff */
758122394Sharti			ignore = 1;
759122394Sharti		else
760122394Sharti			/* global configuration - don't ignore */
761122394Sharti			ignore = 0;
762122394Sharti	} else {
763122394Sharti		if (mod == NULL) {
764122394Sharti			/* global configuration - ignore module stuff */
765122394Sharti			ignore = 1;
766122394Sharti		} else {
767122394Sharti			/* loading module - check if it's our section */
768122394Sharti			ignore = (strcmp(strval, mod->section) != 0);
769122394Sharti		}
770122394Sharti	}
771122394Sharti	gettoken();
772122394Sharti}
773122394Sharti
774122394Sharti/*
775122394Sharti * Convert a hostname to four u_chars
776122394Sharti */
777122394Shartistatic void
778122394Shartigethost(const char *host, u_char *ip)
779122394Sharti{
780122394Sharti	struct addrinfo hints, *res;
781122394Sharti	int error;
782122394Sharti	struct sockaddr_in *sain;
783122394Sharti
784122394Sharti	memset(&hints, 0, sizeof(hints));
785122394Sharti	hints.ai_family = AF_INET;
786122394Sharti	hints.ai_socktype = SOCK_DGRAM;
787122394Sharti	hints.ai_protocol = IPPROTO_UDP;
788122394Sharti	hints.ai_flags = AI_PASSIVE;
789122394Sharti	error = getaddrinfo(host, NULL, &hints, &res);
790122394Sharti	if (error != 0)
791122394Sharti		report("%s: %s", host, gai_strerror(error));
792122394Sharti	if (res == NULL)
793122394Sharti		report("%s: unknown hostname", host);
794122394Sharti
795122394Sharti	sain = (struct sockaddr_in *)(void *)res->ai_addr;
796122394Sharti	sain->sin_addr.s_addr = ntohl(sain->sin_addr.s_addr);
797122394Sharti	ip[0] = sain->sin_addr.s_addr >> 24;
798122394Sharti	ip[1] = sain->sin_addr.s_addr >> 16;
799122394Sharti	ip[2] = sain->sin_addr.s_addr >>  8;
800122394Sharti	ip[3] = sain->sin_addr.s_addr >>  0;
801122394Sharti
802122394Sharti	freeaddrinfo(res);
803122394Sharti}
804122394Sharti
805122394Sharti/*
806122394Sharti * Parse the left hand side of a config line.
807122394Sharti */
808122394Shartistatic const struct snmp_node *
809122394Shartiparse_oid(const char *varname, struct asn_oid *oid)
810122394Sharti{
811122394Sharti	struct snmp_node *node;
812122394Sharti	u_int i;
813122394Sharti	u_char ip[4];
814216294Ssyrinx	struct asn_oid str_oid;
815122394Sharti
816122394Sharti	for (node = tree; node < &tree[tree_size]; node++)
817122394Sharti		if (strcmp(varname, node->name) == 0)
818122394Sharti			break;
819122394Sharti	if (node == &tree[tree_size])
820122394Sharti		node = NULL;
821122394Sharti
822122394Sharti	oid->len = 0;
823122394Sharti	while (token == '.') {
824122394Sharti		if (gettoken() == TOK_NUM) {
825122394Sharti			if (numval > ASN_MAXID)
826150920Sharti				report("subid too large %#"QUADXFMT, numval);
827122394Sharti			if (oid->len == ASN_MAXOIDLEN)
828122394Sharti				report("index too long");
829216294Ssyrinx			if (gettoken() != ':')
830216294Ssyrinx				oid->subs[oid->len++] = numval;
831216294Ssyrinx			else {
832216294Ssyrinx				str_oid.len = 0;
833216294Ssyrinx				str_oid.subs[str_oid.len++] = numval;
834216294Ssyrinx				while (gettoken() == TOK_NUM) {
835216294Ssyrinx					str_oid.subs[str_oid.len++] = numval;
836216294Ssyrinx					if (gettoken() != ':')
837216294Ssyrinx						break;
838216294Ssyrinx				}
839216294Ssyrinx				oid->subs[oid->len++] = str_oid.len;
840216294Ssyrinx				asn_append_oid(oid, &str_oid);
841216294Ssyrinx			}
842122394Sharti
843122394Sharti		} else if (token == TOK_STR) {
844122394Sharti			if (strvallen + oid->len + 1 > ASN_MAXOIDLEN)
845122394Sharti				report("oid too long");
846122394Sharti			oid->subs[oid->len++] = strvallen;
847122394Sharti			for (i = 0; i < strvallen; i++)
848122394Sharti				oid->subs[oid->len++] = strval[i];
849216294Ssyrinx			gettoken();
850122394Sharti
851122394Sharti		} else if (token == TOK_HOST) {
852122394Sharti			gethost(strval, ip);
853122394Sharti			if (oid->len + 4 > ASN_MAXOIDLEN)
854122394Sharti				report("index too long");
855122394Sharti			for (i = 0; i < 4; i++)
856122394Sharti				oid->subs[oid->len++] = ip[i];
857216294Ssyrinx			gettoken();
858122394Sharti		} else
859122394Sharti			report("bad token in index");
860122394Sharti	}
861122394Sharti
862122394Sharti	return (node);
863122394Sharti}
864122394Sharti
865122394Sharti/*
866122394Sharti * Parse the value for an assignment.
867122394Sharti */
868122394Shartistatic void
869122394Shartiparse_syntax_null(struct snmp_value *value __unused)
870122394Sharti{
871122394Sharti	if (token != TOK_EOL)
872122394Sharti		report("bad NULL syntax");
873122394Sharti}
874122394Sharti
875122394Shartistatic void
876122394Shartiparse_syntax_integer(struct snmp_value *value)
877122394Sharti{
878122394Sharti	if (token != TOK_NUM)
879122394Sharti		report("bad INTEGER syntax");
880122394Sharti	if (numval > 0x7fffffff)
881150920Sharti		report("INTEGER too large %"QUADFMT, numval);
882122394Sharti
883122394Sharti	value->v.integer = numval;
884122394Sharti	gettoken();
885122394Sharti}
886122394Sharti
887122394Shartistatic void
888122394Shartiparse_syntax_counter64(struct snmp_value *value)
889122394Sharti{
890122394Sharti	if (token != TOK_NUM)
891122394Sharti		report("bad COUNTER64 syntax");
892122394Sharti
893122394Sharti	value->v.counter64 = numval;
894122394Sharti	gettoken();
895122394Sharti}
896122394Sharti
897122394Shartistatic void
898122394Shartiparse_syntax_octetstring(struct snmp_value *value)
899122394Sharti{
900122394Sharti	u_long alloc;
901122394Sharti	u_char *noct;
902122394Sharti
903122394Sharti	if (token == TOK_STR) {
904122394Sharti		value->v.octetstring.len = strvallen;
905122394Sharti		value->v.octetstring.octets = malloc(strvallen);
906122394Sharti		(void)memcpy(value->v.octetstring.octets, strval, strvallen);
907122394Sharti		gettoken();
908122394Sharti		return;
909122394Sharti	}
910122394Sharti
911122394Sharti	/* XX:XX:XX syntax */
912122394Sharti	value->v.octetstring.octets = NULL;
913122394Sharti	value->v.octetstring.len = 0;
914122394Sharti
915122394Sharti	if (token != TOK_NUM)
916122394Sharti		/* empty string is allowed */
917122394Sharti		return;
918122394Sharti
919122394Sharti	if (ERRPUSH()) {
920122394Sharti		free(value->v.octetstring.octets);
921122394Sharti		ERRNEXT();
922122394Sharti	}
923122394Sharti
924122394Sharti	alloc = 0;
925122394Sharti	for (;;) {
926122394Sharti		if (token != TOK_NUM)
927122394Sharti			report("bad OCTETSTRING syntax");
928122394Sharti		if (numval > 0xff)
929122394Sharti			report("byte value too large");
930122394Sharti		if (alloc == value->v.octetstring.len) {
931122394Sharti			alloc += 100;
932122394Sharti			noct = realloc(value->v.octetstring.octets, alloc);
933122394Sharti			if (noct == NULL)
934122394Sharti				report("%m");
935122394Sharti			value->v.octetstring.octets = noct;
936122394Sharti		}
937122394Sharti		value->v.octetstring.octets[value->v.octetstring.len++]
938122394Sharti		    = numval;
939122394Sharti		if (gettoken() != ':')
940122394Sharti			break;
941122394Sharti		gettoken();
942122394Sharti	}
943122394Sharti	ERRPOP();
944122394Sharti}
945122394Sharti
946122394Shartistatic void
947122394Shartiparse_syntax_oid(struct snmp_value *value)
948122394Sharti{
949122394Sharti	value->v.oid.len = 0;
950122394Sharti
951122394Sharti	if (token != TOK_NUM)
952122394Sharti		return;
953122394Sharti
954122394Sharti	for (;;) {
955122394Sharti		if (token != TOK_NUM)
956122394Sharti			report("bad OID syntax");
957122394Sharti		if (numval > ASN_MAXID)
958122394Sharti			report("subid too large");
959122394Sharti		if (value->v.oid.len == ASN_MAXOIDLEN)
960122394Sharti			report("OID too long");
961122394Sharti		value->v.oid.subs[value->v.oid.len++] = numval;
962122394Sharti		if (gettoken() != '.')
963122394Sharti			break;
964122394Sharti		gettoken();
965122394Sharti	}
966122394Sharti}
967122394Sharti
968122394Shartistatic void
969122394Shartiparse_syntax_ipaddress(struct snmp_value *value)
970122394Sharti{
971122394Sharti	int i;
972122394Sharti	u_char ip[4];
973122394Sharti
974122394Sharti	if (token == TOK_NUM) {
975122394Sharti		/* numerical address */
976122394Sharti		i = 0;
977122394Sharti		for (;;) {
978122394Sharti			if (numval >= 256)
979122394Sharti				report("ip address part too large");
980122394Sharti			value->v.ipaddress[i++] = numval;
981122394Sharti			if (i == 4)
982122394Sharti				break;
983122394Sharti			if (gettoken() != '.')
984122394Sharti				report("expecting '.' in ip address");
985122394Sharti		}
986122394Sharti		gettoken();
987122394Sharti
988122394Sharti	} else if (token == TOK_HOST) {
989122394Sharti		/* host name */
990122394Sharti		gethost(strval, ip);
991122394Sharti		for (i = 0; i < 4; i++)
992122394Sharti			value->v.ipaddress[i] = ip[i];
993122394Sharti		gettoken();
994122394Sharti
995122394Sharti	} else
996122394Sharti		report("bad ip address syntax");
997122394Sharti}
998122394Sharti
999122394Shartistatic void
1000122394Shartiparse_syntax_uint32(struct snmp_value *value)
1001122394Sharti{
1002122394Sharti
1003122394Sharti	if (token != TOK_NUM)
1004122394Sharti		report("bad number syntax");
1005122394Sharti	if (numval > 0xffffffff)
1006122394Sharti		report("number too large");
1007122394Sharti	value->v.uint32 = numval;
1008122394Sharti	gettoken();
1009122394Sharti}
1010122394Sharti
1011122394Sharti/*
1012122394Sharti * Parse an assignement line
1013122394Sharti */
1014122394Shartistatic void
1015122394Shartiparse_assign(const char *varname)
1016122394Sharti{
1017122394Sharti	struct snmp_value value;
1018122394Sharti	struct asn_oid vindex;
1019122394Sharti	const struct snmp_node *node;
1020122394Sharti
1021122394Sharti	node = parse_oid(varname, &vindex);
1022122394Sharti	if (token != '=')
1023216294Ssyrinx		report("'=' expected, got '%c'", token);
1024122394Sharti	gettoken();
1025122394Sharti
1026122394Sharti	if (ignore) {
1027122394Sharti		/* skip rest of line */
1028122394Sharti		while (token != TOK_EOL && token != TOK_EOF)
1029122394Sharti			gettoken();
1030122394Sharti		return;
1031122394Sharti	}
1032122394Sharti	if (node == NULL)
1033122394Sharti		report("unknown variable");
1034122394Sharti
1035122394Sharti	switch (value.syntax = node->syntax) {
1036122394Sharti
1037122394Sharti	  case SNMP_SYNTAX_NULL:
1038122394Sharti		parse_syntax_null(&value);
1039122394Sharti		break;
1040122394Sharti
1041122394Sharti	  case SNMP_SYNTAX_INTEGER:
1042122394Sharti		parse_syntax_integer(&value);
1043122394Sharti		break;
1044122394Sharti
1045122394Sharti	  case SNMP_SYNTAX_COUNTER64:
1046122394Sharti		parse_syntax_counter64(&value);
1047122394Sharti		break;
1048122394Sharti
1049122394Sharti	  case SNMP_SYNTAX_OCTETSTRING:
1050122394Sharti		parse_syntax_octetstring(&value);
1051122394Sharti		break;
1052122394Sharti
1053122394Sharti	  case SNMP_SYNTAX_OID:
1054122394Sharti		parse_syntax_oid(&value);
1055122394Sharti		break;
1056122394Sharti
1057122394Sharti	  case SNMP_SYNTAX_IPADDRESS:
1058122394Sharti		parse_syntax_ipaddress(&value);
1059122394Sharti		break;
1060122394Sharti
1061122394Sharti	  case SNMP_SYNTAX_COUNTER:
1062122394Sharti	  case SNMP_SYNTAX_GAUGE:
1063122394Sharti	  case SNMP_SYNTAX_TIMETICKS:
1064122394Sharti		parse_syntax_uint32(&value);
1065122394Sharti		break;
1066122394Sharti
1067122394Sharti	  case SNMP_SYNTAX_NOSUCHOBJECT:
1068122394Sharti	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1069122394Sharti	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1070122394Sharti		abort();
1071122394Sharti	}
1072122394Sharti
1073122394Sharti	if (ERRPUSH()) {
1074122394Sharti		snmp_value_free(&value);
1075122394Sharti		ERRNEXT();
1076122394Sharti	}
1077122394Sharti
1078122394Sharti	handle_assignment(node, &vindex, &value);
1079122394Sharti
1080122394Sharti	ERRPOP();
1081122394Sharti}
1082122394Sharti
1083122394Sharti/*
1084122394Sharti * Handle macro definition line
1085122394Sharti * We have already seen the := and the input now stands at the character
1086122394Sharti * after the =. Skip whitespace and then call the input routine directly to
1087122394Sharti * eat up characters.
1088122394Sharti */
1089122394Shartistatic void
1090122394Shartiparse_define(const char *varname)
1091122394Sharti{
1092122394Sharti	char *volatile string;
1093122394Sharti	char *new;
1094122394Sharti	volatile size_t alloc, length;
1095122394Sharti	int c;
1096122394Sharti	struct macro *m;
1097122394Sharti	int t = token;
1098122394Sharti
1099122394Sharti	alloc = 100;
1100122394Sharti	length = 0;
1101122394Sharti	if ((string = malloc(alloc)) == NULL)
1102122394Sharti		report("%m");
1103122394Sharti
1104122394Sharti	if (ERRPUSH()) {
1105122394Sharti		free(string);
1106122394Sharti		ERRNEXT();
1107122394Sharti	}
1108122394Sharti
1109122394Sharti	while ((c = input_getc_plain()) != EOF) {
1110122394Sharti		if (c == '\n' || !isspace(c))
1111122394Sharti			break;
1112122394Sharti	}
1113122394Sharti
1114122394Sharti	while (c != EOF && c != '#' && c != '\n') {
1115122394Sharti		if (alloc == length) {
1116122394Sharti			alloc *= 2;
1117122394Sharti			if ((new = realloc(string, alloc)) == NULL)
1118122394Sharti				report("%m");
1119122394Sharti			string = new;
1120122394Sharti		}
1121122394Sharti		string[length++] = c;
1122122394Sharti		c = input_getc_plain();
1123122394Sharti	}
1124122394Sharti	if (c == '#') {
1125122394Sharti		while ((c = input_getc_plain()) != EOF && c != '\n')
1126122394Sharti			;
1127122394Sharti	}
1128122394Sharti	if (c == EOF)
1129122394Sharti		report("EOF in macro definition");
1130122394Sharti
1131122394Sharti	LIST_FOREACH(m, &macros, link)
1132122394Sharti		if (strcmp(m->name, varname) == 0)
1133122394Sharti			break;
1134122394Sharti
1135122394Sharti	if (m == NULL) {
1136122394Sharti		if ((m = malloc(sizeof(*m))) == NULL)
1137122394Sharti			report("%m");
1138122394Sharti		if ((m->name = malloc(strlen(varname) + 1)) == NULL) {
1139122394Sharti			free(m);
1140122394Sharti			report("%m");
1141122394Sharti		}
1142122394Sharti		strcpy(m->name, varname);
1143122394Sharti		m->perm = 0;
1144122394Sharti		LIST_INSERT_HEAD(&macros, m, link);
1145122394Sharti
1146122394Sharti		m->value = string;
1147122394Sharti		m->length = length;
1148122394Sharti	} else {
1149150920Sharti		if (t == TOK_ASSIGN) {
1150122394Sharti			free(m->value);
1151122394Sharti			m->value = string;
1152122394Sharti			m->length = length;
1153122394Sharti		}
1154122394Sharti	}
1155122394Sharti
1156122394Sharti	token = TOK_EOL;
1157122394Sharti
1158122394Sharti	ERRPOP();
1159122394Sharti}
1160122394Sharti
1161122394Sharti/*
1162122394Sharti * Free all macros
1163122394Sharti */
1164122394Shartistatic void
1165122394Shartimacro_free_all(void)
1166122394Sharti{
1167122394Sharti	static struct macro *m, *m1;
1168122394Sharti
1169122394Sharti	m = LIST_FIRST(&macros);
1170122394Sharti	while (m != NULL) {
1171122394Sharti		m1 = LIST_NEXT(m, link);
1172122394Sharti		if (!m->perm) {
1173122394Sharti			free(m->name);
1174122394Sharti			free(m->value);
1175122394Sharti			LIST_REMOVE(m, link);
1176122394Sharti			free(m);
1177122394Sharti		}
1178122394Sharti		m = m1;
1179122394Sharti	}
1180122394Sharti}
1181122394Sharti
1182122394Sharti/*
1183122394Sharti * Parse an include directive and switch to the new file
1184122394Sharti */
1185122394Shartistatic void
1186122394Shartiparse_include(void)
1187122394Sharti{
1188122394Sharti	int sysdir = 0;
1189122394Sharti	char fname[_POSIX2_LINE_MAX];
1190122394Sharti
1191122394Sharti	if (gettoken() == '<') {
1192122394Sharti		sysdir = 1;
1193122394Sharti		if (gettoken() != TOK_STR)
1194122394Sharti			report("expecting filename after in .include");
1195122394Sharti	} else if (token != TOK_STR)
1196122394Sharti		report("expecting filename after in .include");
1197122394Sharti
1198122394Sharti	strcpy(fname, strval);
1199122394Sharti	if (sysdir && gettoken() != '>')
1200122394Sharti		report("expecting '>'");
1201122394Sharti	gettoken();
1202122394Sharti	if (input_open_file(fname, sysdir) == -1)
1203122394Sharti		report("%s: %m", fname);
1204122394Sharti}
1205122394Sharti
1206122394Sharti/*
1207122394Sharti * Parse the configuration file
1208122394Sharti */
1209122394Shartistatic void
1210122394Shartiparse_file(const struct lmodule *mod)
1211122394Sharti{
1212122394Sharti	char varname[_POSIX2_LINE_MAX];
1213122394Sharti
1214122394Sharti	while (gettoken() != TOK_EOF) {
1215122394Sharti		if (token == TOK_EOL)
1216122394Sharti			/* empty line */
1217122394Sharti			continue;
1218122394Sharti		if (token == '%') {
1219122394Sharti			gettoken();
1220122394Sharti			parse_section(mod);
1221122394Sharti		} else if (token == '.') {
1222122394Sharti			if (gettoken() != TOK_STR)
1223122394Sharti				report("keyword expected after '.'");
1224122394Sharti			if (strcmp(strval, "include") == 0)
1225122394Sharti				parse_include();
1226122394Sharti			else
1227122394Sharti				report("unknown keyword '%s'", strval);
1228122394Sharti		} else if (token == TOK_STR) {
1229122394Sharti			strcpy(varname, strval);
1230122394Sharti			if (gettoken() == TOK_ASSIGN || token == TOK_QASSIGN)
1231122394Sharti				parse_define(varname);
1232122394Sharti			else
1233122394Sharti				parse_assign(varname);
1234122394Sharti		}
1235122394Sharti		if (token != TOK_EOL)
1236122394Sharti			report("eol expected");
1237122394Sharti	}
1238122394Sharti}
1239122394Sharti
1240122394Sharti/*
1241122394Sharti * Do rollback on errors
1242122394Sharti */
1243122394Shartistatic void
1244122394Shartido_rollback(void)
1245122394Sharti{
1246122394Sharti	struct assign *tp;
1247122394Sharti	struct snmp_node *node;
1248122394Sharti
1249122394Sharti	while ((tp = TAILQ_LAST(&assigns, assigns)) != NULL) {
1250122394Sharti		TAILQ_REMOVE(&assigns, tp, link);
1251122394Sharti		for (node = tree; node < &tree[tree_size]; node++)
1252122394Sharti			if (node->name == tp->node_name) {
1253122394Sharti				snmp_ctx->scratch = &tp->scratch;
1254122394Sharti				(void)(*node->op)(snmp_ctx, &tp->value,
1255122394Sharti				    node->oid.len, node->index,
1256122394Sharti				    SNMP_OP_ROLLBACK);
1257122394Sharti				break;
1258122394Sharti			}
1259122394Sharti		if (node == &tree[tree_size])
1260122394Sharti			syslog(LOG_ERR, "failed to find node for "
1261122394Sharti			    "rollback");
1262122394Sharti		snmp_value_free(&tp->value);
1263122394Sharti		free(tp);
1264122394Sharti	}
1265122394Sharti}
1266122394Sharti
1267122394Sharti/*
1268122394Sharti * Do commit
1269122394Sharti */
1270122394Shartistatic void
1271122394Shartido_commit(void)
1272122394Sharti{
1273122394Sharti	struct assign *tp;
1274122394Sharti	struct snmp_node *node;
1275122394Sharti
1276122394Sharti	while ((tp = TAILQ_FIRST(&assigns)) != NULL) {
1277122394Sharti		TAILQ_REMOVE(&assigns, tp, link);
1278122394Sharti		for (node = tree; node < &tree[tree_size]; node++)
1279122394Sharti			if (node->name == tp->node_name) {
1280122394Sharti				snmp_ctx->scratch = &tp->scratch;
1281122394Sharti				(void)(*node->op)(snmp_ctx, &tp->value,
1282122394Sharti				    node->oid.len, node->index, SNMP_OP_COMMIT);
1283122394Sharti				break;
1284122394Sharti			}
1285122394Sharti		if (node == &tree[tree_size])
1286122394Sharti			syslog(LOG_ERR, "failed to find node for commit");
1287122394Sharti		snmp_value_free(&tp->value);
1288122394Sharti		free(tp);
1289122394Sharti	}
1290122394Sharti}
1291122394Sharti
1292122394Sharti/*
1293122394Sharti * Read the configuration file. Handle the entire file as one transaction.
1294122394Sharti *
1295122394Sharti * If lodmod is NULL, the sections for 'snmpd' and all loaded modules are
1296122394Sharti * executed. If it is not NULL, only the sections for that module are handled.
1297122394Sharti */
1298122394Shartiint
1299122394Shartiread_config(const char *fname, struct lmodule *lodmod)
1300122394Sharti{
1301122394Sharti	int err;
1302122394Sharti	char objbuf[ASN_OIDSTRLEN];
1303122394Sharti	char idxbuf[ASN_OIDSTRLEN];
1304122394Sharti
1305122394Sharti	ignore = 0;
1306122394Sharti
1307122394Sharti	input_push = 0;
1308133594Sharti
1309133594Sharti	if (ERRPUSH())
1310133594Sharti		return (-1);
1311122394Sharti	if (input_open_file(fname, 0) == -1) {
1312122394Sharti		syslog(LOG_ERR, "%s: %m", fname);
1313122394Sharti		return (-1);
1314122394Sharti	}
1315133594Sharti	ERRPOP();
1316122394Sharti	community = COMM_INITIALIZE;
1317122394Sharti
1318122394Sharti	if ((snmp_ctx = snmp_init_context()) == NULL) {
1319133594Sharti		input_close_all();
1320122394Sharti		syslog(LOG_ERR, "%m");
1321122394Sharti		return (-1);
1322122394Sharti	}
1323122394Sharti
1324122394Sharti	if (ERRPUSH()) {
1325122394Sharti		do_rollback();
1326122394Sharti		input_close_all();
1327122394Sharti		macro_free_all();
1328122394Sharti		free(snmp_ctx);
1329122394Sharti		return (-1);
1330122394Sharti	}
1331122394Sharti	parse_file(lodmod);
1332122394Sharti	ERRPOP();
1333122394Sharti
1334122394Sharti	if ((err = snmp_dep_commit(snmp_ctx)) != SNMP_ERR_NOERROR) {
1335122394Sharti		syslog(LOG_ERR, "init dep failed: %u %s %s", err,
1336122394Sharti		    asn_oid2str_r(&snmp_ctx->dep->obj, objbuf),
1337122394Sharti		    asn_oid2str_r(&snmp_ctx->dep->idx, idxbuf));
1338122394Sharti		snmp_dep_rollback(snmp_ctx);
1339122394Sharti		do_rollback();
1340122394Sharti		input_close_all();
1341122394Sharti		macro_free_all();
1342122394Sharti		free(snmp_ctx);
1343122394Sharti		return (-1);
1344122394Sharti	}
1345122394Sharti
1346122394Sharti	do_commit();
1347128237Sharti	snmp_dep_finish(snmp_ctx);
1348128237Sharti
1349122394Sharti	macro_free_all();
1350122394Sharti
1351122394Sharti	free(snmp_ctx);
1352122394Sharti
1353122394Sharti	return (0);
1354122394Sharti}
1355122394Sharti
1356122394Sharti/*
1357122394Sharti * Define a permanent macro
1358122394Sharti */
1359122394Shartiint
1360122394Shartidefine_macro(const char *name, const char *value)
1361122394Sharti{
1362122394Sharti	struct macro *m;
1363122394Sharti
1364122394Sharti	if ((m = malloc(sizeof(*m))) == NULL)
1365122394Sharti		return (-1);
1366122394Sharti	if ((m->name = malloc(strlen(name) + 1)) == NULL) {
1367122394Sharti		free(m);
1368122394Sharti		return (-1);
1369122394Sharti	}
1370122394Sharti	strcpy(m->name, name);
1371122394Sharti	if ((m->value = malloc(strlen(value) + 1)) == NULL) {
1372122394Sharti		free(m->name);
1373122394Sharti		free(m);
1374122394Sharti		return (-1);
1375122394Sharti	}
1376122394Sharti	strcpy(m->value, value);
1377122394Sharti	m->length = strlen(value);
1378150920Sharti	m->perm = 1;
1379150920Sharti	LIST_INSERT_HEAD(&macros, m, link);
1380122394Sharti	return (0);
1381122394Sharti}
1382