1 /*-
2  * Copyright (c) 2006 The FreeBSD Project
3  * All rights reserved.
4  *
5  * Author: Shteryana Shopova <syrinx@FreeBSD.org>
6  *
7  * Redistribution of this software and documentation and use in source and
8  * binary forms, with or without modification, are permitted provided that
9  * the following conditions are met:
10  *
11  * 1. Redistributions of source code or documentation must retain the above
12  *    copyright notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 /*
33  * Read file containing table description - reuse magic from gensnmptree.c.
34  * Hopefully one day most of the code here will be part of libbsnmp and
35  * this duplication won't be necessary.
36  *
37  * Syntax is:
38  * ---------
39  * file := top | top file
40  *
41  * top := tree | typedef | include
42  *
43  * tree := head elements ')'
44  *
45  * entry := head ':' index STRING elements ')'
46  *
47  * leaf := head type STRING ACCESS ')'
48  *
49  * column := head type ACCESS ')'
50  *
51  * type := BASETYPE | BASETYPE '|' subtype | enum | bits
52  *
53  * subtype := STRING
54  *
55  * enum := ENUM '(' value ')'
56  *
57  * bits := BITS '(' value ')'
58  *
59  * value := INT STRING | INT STRING value
60  *
61  * head := '(' INT STRING
62  *
63  * elements := EMPTY | elements element
64  *
65  * element := tree | leaf | column
66  *
67  * index := type | index type
68  *
69  * typedef := 'typedef' STRING type
70  *
71  * include := 'include' filespec
72  *
73  * filespec := '"' STRING '"' | '<' STRING '>'
74  */
75 
76 #include <sys/param.h>
77 #include <sys/queue.h>
78 #include <sys/uio.h>
79 
80 #include <ctype.h>
81 #include <err.h>
82 #include <errno.h>
83 #include <fcntl.h>
84 #include <paths.h>
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <syslog.h>
89 #include <unistd.h>
90 
91 #include <bsnmp/asn1.h>
92 #include <bsnmp/snmp.h>
93 #include <bsnmp/snmpagent.h>	/* SNMP_INDEXES_MAX */
94 #include "bsnmptc.h"
95 #include "bsnmptools.h"
96 
97 enum snmp_tbl_entry {
98 	ENTRY_NONE = 0,
99 	ENTRY_INDEX,
100 	ENTRY_DATA
101 };
102 
103 enum {
104 	FL_GET	= 0x01,
105 	FL_SET	= 0x02,
106 };
107 
108 /************************************************************
109  *
110  * Allocate memory and panic just in the case...
111  */
112 static void *
113 xalloc(size_t size)
114 {
115 	void *ptr;
116 
117 	if ((ptr = malloc(size)) == NULL)
118 		err(1, "allocing %zu bytes", size);
119 
120 	return (ptr);
121 }
122 
123 static char *
124 savestr(const char *s)
125 {
126 	if (s == NULL)
127 		return (NULL);
128 
129 	return (strcpy(xalloc(strlen(s) + 1), s));
130 }
131 
132 /************************************************************
133  *
134  * Input stack
135  */
136 struct input {
137 	FILE		*fp;
138 	uint32_t	lno;
139 	char		*fname;
140 	char		*path;
141 	LIST_ENTRY(input) link;
142 };
143 
144 static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
145 static struct input *input = NULL;
146 static int32_t pbchar = -1;
147 
148 #define	MAX_PATHS	100
149 
150 static const char *paths[MAX_PATHS + 1] = {
151 	"/usr/share/snmp/defs",
152 	_PATH_LOCALBASE "/share/snmp/defs",
153 	NULL
154 };
155 
156 static void
157 input_new(FILE *fp, const char *path, const char *fname)
158 {
159 	struct input *ip;
160 
161 	ip = xalloc(sizeof(*ip));
162 	ip->fp = fp;
163 	ip->lno = 1;
164 	ip->fname = savestr(fname);
165 	ip->path = savestr(path);
166 	LIST_INSERT_HEAD(&inputs, ip, link);
167 
168 	input = ip;
169 }
170 
171 static void
172 input_close(void)
173 {
174 	if (input == NULL)
175 		return;
176 
177 	fclose(input->fp);
178 	free(input->fname);
179 	free(input->path);
180 	LIST_REMOVE(input, link);
181 	free(input);
182 
183 	input = LIST_FIRST(&inputs);
184 }
185 
186 static FILE *
187 tryopen(const char *path, const char *fname)
188 {
189 	char *fn;
190 	FILE *fp;
191 
192 	if (path == NULL)
193 		fn = savestr(fname);
194 	else {
195 		fn = xalloc(strlen(path) + strlen(fname) + 2);
196 		sprintf(fn, "%s/%s", path, fname);
197 	}
198 	fp = fopen(fn, "r");
199 	free(fn);
200 	return (fp);
201 }
202 
203 static int32_t
204 input_fopen(const char *fname)
205 {
206 	FILE *fp;
207 	u_int p;
208 
209 	if (fname[0] == '/' || fname[0] == '.' || fname[0] == '~') {
210 		if ((fp = tryopen(NULL, fname)) != NULL) {
211 			input_new(fp, NULL, fname);
212 			return (0);
213 		}
214 
215 	} else {
216 
217 		for (p = 0; paths[p] != NULL; p++)
218 			if ((fp = tryopen(paths[p], fname)) != NULL) {
219 				input_new(fp, paths[p], fname);
220 				return (0);
221 			}
222 	}
223 
224 	warnx("cannot open '%s'", fname);
225 	return (-1);
226 }
227 
228 static int32_t
229 tgetc(void)
230 {
231 	int c;
232 
233 	if (pbchar != -1) {
234 		c = pbchar;
235 		pbchar = -1;
236 		return (c);
237 	}
238 
239 	for (;;) {
240 		if (input == NULL)
241 			return (EOF);
242 
243 		if ((c = getc(input->fp)) != EOF)
244 			return (c);
245 
246 		input_close();
247 	}
248 }
249 
250 static int32_t
251 tungetc(int c)
252 {
253 
254 	if (pbchar != -1)
255 		return (-1);
256 
257 	pbchar = c;
258 	return (1);
259 }
260 
261 /************************************************************
262  *
263  * Parsing input
264  */
265 enum tok {
266 	TOK_EOF = 0200,	/* end-of-file seen */
267 	TOK_NUM,	/* number */
268 	TOK_STR,	/* string */
269 	TOK_ACCESS,	/* access operator */
270 	TOK_TYPE,	/* type operator */
271 	TOK_ENUM,	/* enum token (kind of a type) */
272 	TOK_TYPEDEF,	/* typedef directive */
273 	TOK_DEFTYPE,	/* defined type */
274 	TOK_INCLUDE,	/* include directive */
275 	TOK_FILENAME,	/* filename ("foo.bar" or <foo.bar>) */
276 	TOK_BITS,	/* bits token (kind of a type) */
277 	TOK_ERR		/* unexpected char - exit */
278 };
279 
280 static const struct {
281 	const char	*str;
282 	enum tok	tok;
283 	uint32_t	val;
284 } keywords[] = {
285 	{ "GET", TOK_ACCESS, FL_GET },
286 	{ "SET", TOK_ACCESS, FL_SET },
287 	{ "NULL", TOK_TYPE, SNMP_SYNTAX_NULL },
288 	{ "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER },
289 	{ "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER },
290 	{ "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE },
291 	{ "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING },
292 	{ "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS },
293 	{ "OID", TOK_TYPE, SNMP_SYNTAX_OID },
294 	{ "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS },
295 	{ "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER },
296 	{ "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE },
297 	{ "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 },
298 	{ "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER },
299 	{ "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING },
300 	{ "typedef", TOK_TYPEDEF, 0 },
301 	{ "include", TOK_INCLUDE, 0 },
302 	{ NULL, 0, 0 }
303 };
304 
305 static struct {
306 	/* Current OID type, regarding table membership. */
307 	enum snmp_tbl_entry	tbl_type;
308 	/* A pointer to a structure in table list to add to its members. */
309 	struct snmp_index_entry	*table_idx;
310 } table_data;
311 
312 static struct asn_oid current_oid;
313 static char nexttok[MAXSTR];
314 static u_long val;		/* integer values */
315 static int32_t	all_cond;	/* all conditions are true */
316 static int32_t saved_token = -1;
317 
318 /* Prepare the global data before parsing a new file. */
319 static void
320 snmp_import_init(struct asn_oid *append)
321 {
322 	memset(&table_data, 0, sizeof(table_data));
323 	memset(&current_oid, 0, sizeof(struct asn_oid));
324 	memset(nexttok, 0, MAXSTR);
325 
326 	if (append != NULL)
327 		asn_append_oid(&current_oid, append);
328 
329 	all_cond = 0;
330 	val = 0;
331 	saved_token = -1;
332 }
333 
334 static int32_t
335 gettoken(struct snmp_toolinfo *snmptoolctx)
336 {
337 	int c;
338 	struct enum_type *t;
339 
340 	if (saved_token != -1) {
341 		c = saved_token;
342 		saved_token = -1;
343 		return (c);
344 	}
345 
346   again:
347 	/*
348 	 * Skip any whitespace before the next token.
349 	 */
350 	while ((c = tgetc()) != EOF) {
351 		if (c == '\n')
352 			input->lno++;
353 		if (!isspace(c))
354 			break;
355 	}
356 	if (c == EOF)
357 		return (TOK_EOF);
358 
359 	if (!isascii(c)) {
360 		warnx("unexpected character %#2x", (u_int) c);
361 		return (TOK_ERR);
362 	}
363 
364 	/*
365 	 * Skip comments.
366 	 */
367 	if (c == '#') {
368 		while ((c = tgetc()) != EOF) {
369 			if (c == '\n') {
370 				input->lno++;
371 				goto again;
372 			}
373 		}
374 		warnx("unexpected EOF in comment");
375 		return (TOK_ERR);
376 	}
377 
378 	/*
379 	 * Single character tokens.
380 	 */
381 	if (strchr("():|", c) != NULL)
382 		return (c);
383 
384 	if (c == '"' || c == '<') {
385 		int32_t end = c;
386 		size_t n = 0;
387 
388 		val = 1;
389 		if (c == '<') {
390 			val = 0;
391 			end = '>';
392 		}
393 
394 		while ((c = tgetc()) != EOF) {
395 			if (c == end)
396 				break;
397 			if (n == sizeof(nexttok) - 1) {
398 				nexttok[n++] = '\0';
399 				warnx("filename too long '%s...'", nexttok);
400 				return (TOK_ERR);
401 			}
402 			nexttok[n++] = c;
403 		}
404 		nexttok[n++] = '\0';
405 		return (TOK_FILENAME);
406 	}
407 
408 	/*
409 	 * Sort out numbers.
410 	 */
411 	if (isdigit(c)) {
412 		size_t n = 0;
413 		nexttok[n++] = c;
414 		while ((c = tgetc()) != EOF) {
415 			if (!isdigit(c)) {
416 				if (tungetc(c) < 0)
417 					return (TOK_ERR);
418 				break;
419 			}
420 			if (n == sizeof(nexttok) - 1) {
421 				nexttok[n++] = '\0';
422 				warnx("number too long '%s...'", nexttok);
423 				return (TOK_ERR);
424 			}
425 			nexttok[n++] = c;
426 		}
427 		nexttok[n++] = '\0';
428 		sscanf(nexttok, "%lu", &val);
429 		return (TOK_NUM);
430 	}
431 
432 	/*
433 	 * So that has to be a string.
434 	 */
435 	if (isalpha(c) || c == '_' || c == '-') {
436 		size_t n = 0;
437 		nexttok[n++] = c;
438 		while ((c = tgetc()) != EOF) {
439 			if (!isalnum(c) && c != '_' && c != '-') {
440 				if (tungetc (c) < 0)
441 					return (TOK_ERR);
442 				break;
443 			}
444 			if (n == sizeof(nexttok) - 1) {
445 				nexttok[n++] = '\0';
446 				warnx("string too long '%s...'", nexttok);
447 				return (TOK_ERR);
448 			}
449 			nexttok[n++] = c;
450 		}
451 		nexttok[n++] = '\0';
452 
453 		/*
454 		 * Keywords.
455 		 */
456 		for (c = 0; keywords[c].str != NULL; c++)
457 			if (strcmp(keywords[c].str, nexttok) == 0) {
458 				val = keywords[c].val;
459 				return (keywords[c].tok);
460 			}
461 
462 		if ((t = snmp_enumtc_lookup(snmptoolctx, nexttok)) != NULL) {
463 			val = t->syntax;
464 			return (TOK_DEFTYPE);
465 		}
466 
467 		return (TOK_STR);
468 	}
469 
470 	if (isprint(c))
471 		warnx("%u: unexpected character '%c'", input->lno, c);
472 	else
473 		warnx("%u: unexpected character 0x%02x", input->lno, (u_int) c);
474 
475 	return (TOK_ERR);
476 }
477 
478 /*
479  * Update table information.
480  */
481 static struct snmp_index_entry *
482 snmp_import_update_table(enum snmp_tbl_entry te, struct snmp_index_entry *tbl)
483 {
484 	switch (te) {
485 		case ENTRY_NONE:
486 			if (table_data.tbl_type == ENTRY_NONE)
487 				return (NULL);
488 			if (table_data.tbl_type == ENTRY_INDEX)
489 				table_data.table_idx = NULL;
490 			table_data.tbl_type--;
491 			return (NULL);
492 
493 		case ENTRY_INDEX:
494 			if (tbl == NULL)
495 				warnx("No table_index to add!!!");
496 			table_data.table_idx = tbl;
497 			table_data.tbl_type = ENTRY_INDEX;
498 			return (tbl);
499 
500 		case ENTRY_DATA:
501 			if (table_data.tbl_type == ENTRY_INDEX) {
502 				table_data.tbl_type = ENTRY_DATA;
503 				return (table_data.table_idx);
504 			}
505 			return (NULL);
506 
507 		default:
508 			/* NOTREACHED */
509 			warnx("Unknown table entry type!!!");
510 			break;
511 	}
512 
513 	return (NULL);
514 }
515 
516 static int32_t
517 parse_enum(struct snmp_toolinfo *snmptoolctx, int32_t *tok,
518     struct enum_pairs *enums)
519 {
520 	while ((*tok = gettoken(snmptoolctx)) == TOK_STR) {
521 		if (enum_pair_insert(enums, val, nexttok) < 0)
522 			return (-1);
523 		if ((*tok = gettoken(snmptoolctx)) != TOK_NUM)
524 			break;
525 	}
526 
527 	if (*tok != ')') {
528 		warnx("')' at end of enums");
529 		return (-1);
530 	}
531 
532 	return (1);
533 }
534 
535 static int32_t
536 parse_subtype(struct snmp_toolinfo *snmptoolctx, int32_t *tok,
537     enum snmp_tc *tc)
538 {
539 	if ((*tok = gettoken(snmptoolctx)) != TOK_STR) {
540 		warnx("subtype expected after '|'");
541 		return (-1);
542 	}
543 
544 	*tc = snmp_get_tc(nexttok);
545 	*tok = gettoken(snmptoolctx);
546 
547 	return (1);
548 }
549 
550 static int32_t
551 parse_type(struct snmp_toolinfo *snmptoolctx, int32_t *tok,
552     enum snmp_tc *tc, struct enum_pairs **snmp_enum)
553 {
554 	int32_t syntax, mem;
555 
556 	syntax = val;
557 	*tc = 0;
558 
559 	if (*tok == TOK_ENUM || *tok == TOK_BITS) {
560 		if (*snmp_enum == NULL) {
561 			if ((*snmp_enum = enum_pairs_init()) == NULL)
562 				return (-1);
563 			mem = 1;
564 			*tc = SNMP_TC_OWN;
565 		} else
566 			mem = 0;
567 
568 		if (gettoken(snmptoolctx) != '(') {
569 			warnx("'(' expected after ENUM/BITS");
570 			return (-1);
571 		}
572 
573 		if ((*tok = gettoken(snmptoolctx)) != TOK_NUM) {
574 			warnx("need value for ENUM//BITS");
575 			if (mem == 1) {
576 				free(*snmp_enum);
577 				*snmp_enum = NULL;
578 			}
579 			return (-1);
580 		}
581 
582 		if (parse_enum(snmptoolctx, tok, *snmp_enum) < 0) {
583 			enum_pairs_free(*snmp_enum);
584 			*snmp_enum = NULL;
585 			return (-1);
586 		}
587 
588 		*tok = gettoken(snmptoolctx);
589 
590 	} else if (*tok == TOK_DEFTYPE) {
591 		struct enum_type *t;
592 
593 		*tc = 0;
594 		t = snmp_enumtc_lookup(snmptoolctx, nexttok);
595 		if (t != NULL)
596 			*snmp_enum = t->snmp_enum;
597 
598 		*tok = gettoken(snmptoolctx);
599 
600 	} else {
601 		if ((*tok = gettoken(snmptoolctx)) == '|') {
602 			if (parse_subtype(snmptoolctx, tok, tc) < 0)
603 				return (-1);
604 		}
605 	}
606 
607 	return (syntax);
608 }
609 
610 static int32_t
611 snmp_import_head(struct snmp_toolinfo *snmptoolctx)
612 {
613 	enum tok tok;
614 
615 	if ((tok = gettoken(snmptoolctx)) == '(')
616 		tok = gettoken(snmptoolctx);
617 
618 	if (tok != TOK_NUM  || val > ASN_MAXID ) {
619 		warnx("Suboid expected - line %d", input->lno);
620 		return (-1);
621 	}
622 
623 	if (gettoken(snmptoolctx) != TOK_STR) {
624 		warnx("Node name expected at line %d", input->lno);
625 		return (-1);
626 	}
627 
628 	return (1);
629 }
630 
631 static int32_t
632 snmp_import_table(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *obj)
633 {
634 	int32_t i, tok;
635 	enum snmp_tc tc;
636 	struct snmp_index_entry *entry;
637 
638 	if ((entry = calloc(1, sizeof(struct snmp_index_entry))) == NULL) {
639 		syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
640 		return (-1);
641 	}
642 
643 	STAILQ_INIT(&(entry->index_list));
644 
645 	for (i = 0, tok = gettoken(snmptoolctx); i < SNMP_INDEXES_MAX; i++) {
646 		int32_t syntax;
647 		struct enum_pairs *enums = NULL;
648 
649 		if (tok != TOK_TYPE && tok != TOK_DEFTYPE && tok != TOK_ENUM &&
650 		    tok != TOK_BITS)
651 			break;
652 
653 		if ((syntax = parse_type(snmptoolctx, &tok, &tc, &enums)) < 0) {
654 			enum_pairs_free(enums);
655 			snmp_index_listfree(&(entry->index_list));
656 			free(entry);
657 			return (-1);
658 		}
659 
660 		if (snmp_syntax_insert(&(entry->index_list), enums, syntax,
661 		    tc) < 0) {
662 			snmp_index_listfree(&(entry->index_list));
663 			enum_pairs_free(enums);
664 			free(entry);
665 			return (-1);
666 		}
667 	}
668 
669 	if (i == 0 || i > SNMP_INDEXES_MAX) {
670 		warnx("Bad number of indexes at line %d", input->lno);
671 		snmp_index_listfree(&(entry->index_list));
672 		free(entry);
673 		return (-1);
674 	}
675 
676 	if (tok != TOK_STR) {
677 		warnx("String expected after indexes at line %d", input->lno);
678 		snmp_index_listfree(&(entry->index_list));
679 		free(entry);
680 		return (-1);
681 	}
682 
683 	entry->string = obj->string;
684 	entry->strlen = obj->strlen;
685 	asn_append_oid(&(entry->var), &(obj->var));
686 
687 	if ((i = snmp_table_insert(snmptoolctx, entry)) < 0) {
688 		snmp_index_listfree(&(entry->index_list));
689 		free(entry);
690 		return (-1);
691 	} else if (i == 0) {
692 		/* Same entry already present in lists. */
693 		free(entry->string);
694 		free(entry);
695 		return (0);
696 	}
697 
698 	(void) snmp_import_update_table(ENTRY_INDEX, entry);
699 
700 	return (1);
701 }
702 
703 /*
704  * Read everything after the syntax type that is certainly a leaf OID info.
705  */
706 static int32_t
707 snmp_import_leaf(struct snmp_toolinfo *snmptoolctx, int32_t *tok,
708     struct snmp_oid2str *oid2str)
709 {
710 	int32_t i, syntax;
711 
712 	if ((syntax = parse_type(snmptoolctx, tok, &(oid2str->tc), &(oid2str->snmp_enum)))
713 	    < 0)
714 		return(-1);
715 
716 	oid2str->syntax = syntax;
717 	/*
718 	 * That is the name of the function, corresponding to the entry.
719 	 * It is used by bsnmpd, but is not interesting for us.
720 	 */
721 	if (*tok == TOK_STR)
722 		*tok = gettoken(snmptoolctx);
723 
724 	for (i = 0; i < SNMP_ACCESS_GETSET && *tok == TOK_ACCESS; i++) {
725 		oid2str->access |=  (uint32_t) val;
726 		*tok = gettoken(snmptoolctx);
727 	}
728 
729 	if (*tok != ')') {
730 		warnx("')' expected at end of line %d", input->lno);
731 		return (-1);
732 	}
733 
734 	oid2str->table_idx = snmp_import_update_table(ENTRY_DATA,  NULL);
735 
736 	if ((i = snmp_leaf_insert(snmptoolctx, oid2str)) < 0) {
737 		warnx("Error adding leaf %s to list", oid2str->string);
738 		return (-1);
739 	}
740 
741 	/*
742 	 * Same entry is already present in the mapping lists and
743 	 * the new one was not inserted.
744 	 */
745 	if (i == 0)  {
746 		free(oid2str->string);
747 		free(oid2str);
748 	}
749 
750 	(void) snmp_import_update_table(ENTRY_NONE, NULL);
751 
752 	return (1);
753 }
754 
755 static int32_t
756 snmp_import_object(struct snmp_toolinfo *snmptoolctx)
757 {
758 	char *string;
759 	int i;
760 	int32_t tok;
761 	struct snmp_oid2str *oid2str;
762 
763 	if (snmp_import_head(snmptoolctx) < 0)
764 		return (-1);
765 
766 	if ((oid2str = calloc(1, sizeof(struct snmp_oid2str))) == NULL) {
767 		syslog(LOG_ERR, "calloc() failed: %s", strerror(errno));
768 		return (-1);
769 	}
770 
771 	if ((string = strdup(nexttok)) == NULL) {
772 		syslog(LOG_ERR, "strdup() failed: %s", strerror(errno));
773 		free(oid2str);
774 		return (-1);
775 	}
776 
777 	oid2str->string = string;
778 	oid2str->strlen = strlen(nexttok);
779 
780 	asn_append_oid(&(oid2str->var), &(current_oid));
781 	if (snmp_suboid_append(&(oid2str->var), (asn_subid_t) val) < 0)
782 		goto error;
783 
784 	/*
785 	 * Prepared the entry - now figure out where to insert it.
786 	 * After the object we have following options:
787 	 * 1) new line, blank, ) - then it is an enum oid -> snmp_enumlist;
788 	 * 2) new line , ( - nonleaf oid -> snmp_nodelist;
789 	 * 2) ':' - table entry - a variable length SYNTAX_TYPE (one or more)
790 	 *     may follow and second string must end line -> snmp_tablelist;
791 	 * 3) OID , string  ) - this is a trap entry or a leaf -> snmp_oidlist;
792 	 * 4) SYNTAX_TYPE, string (not always), get/set modifier - always last
793 	 *     and )- this is definitely a leaf.
794 	 */
795 
796 	switch (tok = gettoken(snmptoolctx)) {
797 	    case  ')':
798 		if ((i = snmp_enum_insert(snmptoolctx, oid2str)) < 0)
799 			goto error;
800 		if (i == 0) {
801 			free(oid2str->string);
802 			free(oid2str);
803 		}
804 		return (1);
805 
806 	    case '(':
807 		if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
808 			goto error;
809 
810 		/*
811 		 * Ignore the error for nodes since the .def files currently
812 		 * contain different strings for 1.3.6.1.2.1 - mibII. Only make
813 		 * sure the memory is freed and don't complain.
814 		 */
815 		if ((i = snmp_node_insert(snmptoolctx, oid2str)) <= 0) {
816 			free(string);
817 			free(oid2str);
818 		}
819 		return (snmp_import_object(snmptoolctx));
820 
821 	    case ':':
822 		if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
823 			goto error;
824 		if (snmp_import_table(snmptoolctx, oid2str) < 0)
825 			goto error;
826 		/*
827 		 * A different table entry type was malloced and the data is
828 		 * contained there.
829 		 */
830 		free(oid2str);
831 		return (1);
832 
833 	    case TOK_TYPE:
834 		/* FALLTHROUGH */
835 	    case TOK_DEFTYPE:
836 		/* FALLTHROUGH */
837 	    case TOK_ENUM:
838 	    	/* FALLTHROUGH */
839 	    case TOK_BITS:
840 		if (snmp_import_leaf(snmptoolctx, &tok, oid2str) < 0)
841 				goto error;
842 		return (1);
843 
844 	    default:
845 		warnx("Unexpected token at line %d - %s", input->lno,
846 		    input->fname);
847 		break;
848 	}
849 
850 error:
851 	snmp_mapping_entryfree(oid2str);
852 
853 	return (-1);
854 }
855 
856 static int32_t
857 snmp_import_tree(struct snmp_toolinfo *snmptoolctx, int32_t *tok)
858 {
859 	while (*tok != TOK_EOF) {
860 		switch (*tok) {
861 		    case TOK_ERR:
862 			return (-1);
863 		    case '(':
864 			if (snmp_import_object(snmptoolctx) < 0)
865 			    return (-1);
866 			break;
867 		    case ')':
868 			if (snmp_suboid_pop(&current_oid) < 0)
869 			    return (-1);
870 			(void) snmp_import_update_table(ENTRY_NONE, NULL);
871 			break;
872 		    default:
873 			/* Anything else here would be illegal. */
874 			return (-1);
875 		}
876 		*tok = gettoken(snmptoolctx);
877 	}
878 
879 	return (0);
880 }
881 
882 static int32_t
883 snmp_import_top(struct snmp_toolinfo *snmptoolctx, int32_t *tok)
884 {
885 	enum snmp_tc tc;
886 	struct enum_type *t;
887 
888 	if (*tok == '(')
889 		return (snmp_import_tree(snmptoolctx, tok));
890 
891 	if (*tok == TOK_TYPEDEF) {
892 		if ((*tok = gettoken(snmptoolctx)) != TOK_STR) {
893 			warnx("type name expected after typedef - %s",
894 			    input->fname);
895 			return (-1);
896 		}
897 
898 		t = snmp_enumtc_init(nexttok);
899 
900 		*tok = gettoken(snmptoolctx);
901 		t->is_enum = (*tok == TOK_ENUM);
902 		t->is_bits = (*tok == TOK_BITS);
903 		t->syntax = parse_type(snmptoolctx, tok, &tc, &(t->snmp_enum));
904 		snmp_enumtc_insert(snmptoolctx, t);
905 
906 		return (1);
907 	}
908 
909 	if (*tok == TOK_INCLUDE) {
910 		int i;
911 
912 		*tok = gettoken(snmptoolctx);
913 		if (*tok != TOK_FILENAME) {
914 			warnx("filename expected in include directive - %s",
915 			    nexttok);
916 			return (-1);
917 		}
918 
919 		if (( i = add_filename(snmptoolctx, nexttok, NULL, 1)) == 0) {
920 			*tok = gettoken(snmptoolctx);
921 			return (1);
922 		}
923 
924 		if (i == -1)
925 			return (-1);
926 
927 		input_fopen(nexttok);
928 		*tok = gettoken(snmptoolctx);
929 		return (1);
930 	}
931 
932 	warnx("'(' or 'typedef' expected - %s", nexttok);
933 	return (-1);
934 }
935 
936 static int32_t
937 snmp_import(struct snmp_toolinfo *snmptoolctx)
938 {
939 	int i;
940 	int32_t tok;
941 
942 	tok = gettoken(snmptoolctx);
943 
944 	do
945 		i = snmp_import_top(snmptoolctx, &tok);
946 	while (i > 0);
947 
948 	return (i);
949 }
950 
951 /*
952  * Read a .def file and import oid<->string mapping.
953  * Mappings are inserted into a global structure containing list for each OID
954  * syntax type.
955  */
956 int32_t
957 snmp_import_file(struct snmp_toolinfo *snmptoolctx, struct fname *file)
958 {
959 	int idx;
960 
961 	snmp_import_init(&(file->cut));
962 	input_fopen(file->name);
963 	if ((idx = snmp_import(snmptoolctx)) < 0)
964 		warnx("Failed to read mappings from file %s", file->name);
965 
966 	input_close();
967 
968 	return (idx);
969 }
970