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