]> git.ipfire.org Git - thirdparty/squid.git/blob - snmplib/parse.c
Merge from trunk
[thirdparty/squid.git] / snmplib / parse.c
1 /***********************************************************
2 Copyright 1989 by Carnegie Mellon University
3
4 All Rights Reserved
5
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of CMU not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
13
14 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21 ******************************************************************/
22
23 /*
24 * parse.c
25 */
26 #include "squid.h"
27
28 #include <stdio.h>
29
30 #if HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #if HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
36 #if HAVE_SYS_TYPES_H
37 #include <sys/types.h>
38 #endif
39 #if HAVE_CTYPE_H
40 #include <ctype.h>
41 #endif
42 #if HAVE_GNUMALLOC_H
43 #include <gnumalloc.h>
44 #elif HAVE_MALLOC_H
45 #include <malloc.h>
46 #endif
47 #if HAVE_MEMORY_H
48 #include <memory.h>
49 #endif
50 #if HAVE_STRING_H
51 #include <string.h>
52 #endif
53 #if HAVE_STRINGS_H
54 #include <strings.h>
55 #endif
56 #if HAVE_BSTRING_H
57 #include <bstring.h>
58 #endif
59 #if HAVE_SYS_SOCKET_H
60 #include <sys/socket.h>
61 #endif
62 #if HAVE_NETINET_IN_H
63 #include <netinet/in.h>
64 #endif
65 #if HAVE_ARPA_INET_H
66 #include <arpa/inet.h>
67 #endif
68 #if HAVE_SYS_TIME_H
69 #include <sys/time.h>
70 #endif
71 #if HAVE_NETDB_H
72 #include <netdb.h>
73 #endif
74 #if HAVE_ASSERT_H
75 #include <assert.h>
76 #endif
77 #if HAVE_ERRNO_H
78 #include <errno.h>
79 #endif
80
81 #include "asn1.h"
82 #include "snmp_vars.h"
83 #include "parse.h"
84 #include "snmp_debug.h"
85
86 #include "util.h"
87
88 #include "cache_snmp.h"
89 /*
90 * This is one element of an object identifier with either an integer subidentifier,
91 * or a textual string label, or both.
92 * The subid is -1 if not present, and label is NULL if not present.
93 */
94 struct subid {
95 int subid;
96 char *label;
97 };
98
99 /*
100 * A linked list of nodes.
101 */
102 struct node {
103 struct node *next;
104 char label[64]; /* This node's (unique) textual name */
105 u_int subid; /* This node's integer subidentifier */
106 char parent[64]; /* The parent's textual name */
107 int type; /* The type of object this represents */
108 struct enum_list *enums; /* (optional) list of enumerated integers (otherwise NULL) */
109 };
110
111 int Line = 1;
112
113 /* types of tokens */
114 #define CONTINUE -1
115 #define ENDOFFILE 0
116 #define LABEL 1
117 #define SUBTREE 2
118 #define SYNTAX 3
119 #undef OBJID
120 #define OBJID 4
121 #define OCTETSTR 5
122 #undef INTEGER
123 #define INTEGER 6
124 #define NETADDR 7
125 #define IPADDR 8
126 #define COUNTER 9
127 #define GAUGE 10
128 #define TIMETICKS 11
129 #define SNMP_OPAQUE 12
130 #define NUL 13
131 #define SEQUENCE 14
132 #define OF 15 /* SEQUENCE OF */
133 #define OBJTYPE 16
134 #define ACCESS 17
135 #define READONLY 18
136 #define READWRITE 19
137 #define WRITEONLY 20
138 #undef NOACCESS
139 #define NOACCESS 21
140 #define SNMP_STATUS 22
141 #define MANDATORY 23
142 #define SNMP_OPTIONAL 24
143 #define OBSOLETE 25
144 #define RECOMMENDED 26
145 #define PUNCT 27
146 #define EQUALS 28
147 #define NUMBER 29
148 #define LEFTBRACKET 30
149 #define RIGHTBRACKET 31
150 #define LEFTPAREN 32
151 #define RIGHTPAREN 33
152 #define COMMA 34
153 /* For SNMPv2 SMI pseudo-compliance */
154 #define DESCRIPTION 35
155 #define INDEX 36
156 #define QUOTE 37
157
158 struct tok {
159 const char *name; /* token name */
160 int len; /* length not counting nul */
161 int token; /* value */
162 int hash; /* hash of name */
163 struct tok *next; /* pointer to next in hash table */
164 };
165
166
167 struct tok tokens[] = {
168 {"obsolete", sizeof("obsolete") - 1, OBSOLETE},
169 {"Opaque", sizeof("Opaque") - 1, SNMP_OPAQUE},
170 {"recommended", sizeof("recommended") - 1, RECOMMENDED},
171 {"optional", sizeof("optional") - 1, SNMP_OPTIONAL},
172 {"mandatory", sizeof("mandatory") - 1, MANDATORY},
173 {"current", sizeof("current") - 1, MANDATORY},
174 {"not-accessible", sizeof("not-accessible") - 1, NOACCESS},
175 {"write-only", sizeof("write-only") - 1, WRITEONLY},
176 {"read-write", sizeof("read-write") - 1, READWRITE},
177 {"TimeTicks", sizeof("TimeTicks") - 1, TIMETICKS},
178 {"OBJECTIDENTIFIER", sizeof("OBJECTIDENTIFIER") - 1, OBJID},
179 /*
180 * This CONTINUE appends the next word onto OBJECT,
181 * hopefully matching OBJECTIDENTIFIER above.
182 */
183 {"OBJECT", sizeof("OBJECT") - 1, CONTINUE},
184 {"NetworkAddress", sizeof("NetworkAddress") - 1, NETADDR},
185 {"Gauge", sizeof("Gauge") - 1, GAUGE},
186 {"OCTETSTRING", sizeof("OCTETSTRING") - 1, OCTETSTR},
187 {"OCTET", sizeof("OCTET") - 1, -1},
188 {"OF", sizeof("OF") - 1, OF},
189 {"SEQUENCE", sizeof("SEQUENCE") - 1, SEQUENCE},
190 {"NULL", sizeof("NULL") - 1, NUL},
191 {"IpAddress", sizeof("IpAddress") - 1, IPADDR},
192 {"INTEGER", sizeof("INTEGER") - 1, INTEGER},
193 {"Counter", sizeof("Counter") - 1, COUNTER},
194 {"read-only", sizeof("read-only") - 1, READONLY},
195 {"ACCESS", sizeof("ACCESS") - 1, ACCESS},
196 {"MAX-ACCESS", sizeof("MAX-ACCESS") - 1, ACCESS},
197 {"STATUS", sizeof("STATUS") - 1, SNMP_STATUS},
198 {"SYNTAX", sizeof("SYNTAX") - 1, SYNTAX},
199 {"OBJECT-TYPE", sizeof("OBJECT-TYPE") - 1, OBJTYPE},
200 {"{", sizeof("{") - 1, LEFTBRACKET},
201 {"}", sizeof("}") - 1, RIGHTBRACKET},
202 {"::=", sizeof("::=") - 1, EQUALS},
203 {"(", sizeof("(") - 1, LEFTPAREN},
204 {")", sizeof(")") - 1, RIGHTPAREN},
205 {",", sizeof(",") - 1, COMMA},
206 {"DESCRIPTION", sizeof("DESCRIPTION") - 1, DESCRIPTION},
207 {"INDEX", sizeof("INDEX") - 1, INDEX},
208 {"\"", sizeof("\"") - 1, QUOTE},
209 {"END", sizeof("END") - 1, ENDOFFILE},
210 /* Hacks for easier MIBFILE coercing */
211 {"read-create", sizeof("read-create") - 1, READWRITE},
212 {NULL}
213 };
214
215 #define HASHSIZE 32
216 #define BUCKET(x) (x & 0x01F)
217
218 static struct tok *buckets[HASHSIZE];
219
220 static void
221 hash_init(void)
222 {
223 register struct tok *tp;
224 register const char *cp;
225 register int h;
226 register int b;
227
228 memset((char *) buckets, '\0', sizeof(buckets));
229 for (tp = tokens; tp->name; tp++) {
230 for (h = 0, cp = tp->name; *cp; cp++)
231 h += *cp;
232 tp->hash = h;
233 b = BUCKET(h);
234 if (buckets[b])
235 tp->next = buckets[b]; /* BUG ??? */
236 buckets[b] = tp;
237 }
238 }
239
240 #define NHASHSIZE 128
241 #define NBUCKET(x) (x & 0x7F)
242 struct node *nbuckets[NHASHSIZE];
243
244 static void
245 init_node_hash(struct node *nodes)
246 {
247 register struct node *np, *nextp;
248 register char *cp;
249 register int hash;
250
251 memset((char *) nbuckets, '\0', sizeof(nbuckets));
252 for (np = nodes; np;) {
253 nextp = np->next;
254 hash = 0;
255 for (cp = np->parent; *cp; cp++)
256 hash += *cp;
257 np->next = nbuckets[NBUCKET(hash)];
258 nbuckets[NBUCKET(hash)] = np;
259 np = nextp;
260 }
261 }
262
263
264 static void
265 print_error(const char *string, const char *token, int type)
266 {
267 assert(string != NULL);
268 if (type == ENDOFFILE)
269 snmplib_debug(0, "%s(EOF): On or around line %d\n", string, Line);
270 else if (token)
271 snmplib_debug(0, "%s(%s): On or around line %d\n", string, token, Line);
272 else
273 snmplib_debug(0, "%s: On or around line %d\n", string, Line);
274 }
275
276 #if TEST
277 print_subtree(tree, count)
278 struct snmp_mib_tree *tree;
279 int count;
280 {
281 struct snmp_mib_tree *tp;
282 int i;
283
284 for (i = 0; i < count; i++)
285 printf(" ");
286 printf("Children of %s:\n", tree->label);
287 count++;
288 for (tp = tree->child_list; tp; tp = tp->next_peer) {
289 for (i = 0; i < count; i++)
290 printf(" ");
291 printf("%s\n", tp->label);
292 }
293 for (tp = tree->child_list; tp; tp = tp->next_peer) {
294 print_subtree(tp, count);
295 }
296 }
297 #endif /* TEST */
298
299 int translation_table[40];
300
301 static void
302 build_translation_table(void)
303 {
304 int count;
305
306 for (count = 0; count < 40; count++) {
307 switch (count) {
308 case OBJID:
309 translation_table[count] = TYPE_OBJID;
310 break;
311 case OCTETSTR:
312 translation_table[count] = TYPE_OCTETSTR;
313 break;
314 case INTEGER:
315 translation_table[count] = TYPE_INTEGER;
316 break;
317 case NETADDR:
318 translation_table[count] = TYPE_IPADDR;
319 break;
320 case IPADDR:
321 translation_table[count] = TYPE_IPADDR;
322 break;
323 case COUNTER:
324 translation_table[count] = TYPE_COUNTER;
325 break;
326 case GAUGE:
327 translation_table[count] = TYPE_GAUGE;
328 break;
329 case TIMETICKS:
330 translation_table[count] = TYPE_TIMETICKS;
331 break;
332 case SNMP_OPAQUE:
333 translation_table[count] = TYPE_OPAQUE;
334 break;
335 case NUL:
336 translation_table[count] = TYPE_NULL;
337 break;
338 default:
339 translation_table[count] = TYPE_OTHER;
340 break;
341 }
342 }
343 }
344
345 /*
346 * Find all the children of root in the list of nodes. Link them into the
347 * tree and out of the nodes list.
348 */
349 static void
350 do_subtree(struct snmp_mib_tree *root, struct node **nodes)
351 {
352 register struct snmp_mib_tree *tp;
353 struct snmp_mib_tree *peer = NULL;
354 register struct node *np = NULL, **headp = NULL;
355 struct node *oldnp = NULL, *child_list = NULL, *childp = NULL;
356 char *cp;
357 int hash;
358
359 tp = root;
360 hash = 0;
361 for (cp = tp->label; *cp; cp++)
362 hash += *cp;
363 headp = &nbuckets[NBUCKET(hash)];
364 /*
365 * Search each of the nodes for one whose parent is root, and
366 * move each into a separate list.
367 */
368 for (np = *headp; np; np = np->next) {
369 if ((*tp->label != *np->parent) || strcmp(tp->label, np->parent)) {
370 if ((*tp->label == *np->label) && !strcmp(tp->label, np->label)) {
371 /* if there is another node with the same label, assume that
372 * any children after this point in the list belong to the other node.
373 * This adds some scoping to the table and allows vendors to
374 * reuse names such as "ip".
375 */
376 break;
377 }
378 oldnp = np;
379 } else {
380 if (child_list == NULL) {
381 child_list = childp = np; /* first entry in child list */
382 } else {
383 childp->next = np;
384 childp = np;
385 }
386 /* take this node out of the node list */
387 if (oldnp == NULL) {
388 *headp = np->next; /* fix root of node list */
389 } else {
390 oldnp->next = np->next; /* link around this node */
391 }
392 }
393 }
394 if (childp)
395 childp->next = 0; /* re-terminate list */
396 /*
397 * Take each element in the child list and place it into the tree.
398 */
399 for (np = child_list; np; np = np->next) {
400 tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree));
401 tp->parent = root;
402 tp->next_peer = NULL;
403 tp->child_list = NULL;
404 strcpy(tp->label, np->label);
405 tp->subid = np->subid;
406 tp->type = translation_table[np->type];
407 tp->enums = np->enums;
408 np->enums = NULL; /* so we don't free them later */
409 if (root->child_list == NULL) {
410 root->child_list = tp;
411 } else {
412 peer->next_peer = tp;
413 }
414 peer = tp;
415 /* if (tp->type == TYPE_OTHER) */
416 do_subtree(tp, nodes); /* recurse on this child if it isn't an end node */
417 }
418 /* free all nodes that were copied into tree */
419 oldnp = NULL;
420 for (np = child_list; np; np = np->next) {
421 if (oldnp)
422 xfree(oldnp);
423 oldnp = np;
424 }
425 if (oldnp)
426 xfree(oldnp);
427 }
428
429 #if !TEST
430 static
431 #endif
432 struct snmp_mib_tree *
433 build_tree(struct node *nodes) {
434 struct node *np;
435 struct snmp_mib_tree *tp;
436 int bucket, nodes_left = 0;
437
438 /* build root node */
439 tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree));
440 tp->parent = NULL;
441 tp->next_peer = NULL;
442 tp->child_list = NULL;
443 tp->enums = NULL;
444 strcpy(tp->label, "iso");
445 tp->subid = 1;
446 tp->type = 0;
447 build_translation_table();
448 /* grow tree from this root node */
449 init_node_hash(nodes);
450 /* XXX nodes isn't needed in do_subtree() ??? */
451 do_subtree(tp, &nodes);
452 #if TEST
453 print_subtree(tp, 0);
454 #endif /* TEST */
455 /* If any nodes are left, the tree is probably inconsistent */
456 for (bucket = 0; bucket < NHASHSIZE; bucket++) {
457 if (nbuckets[bucket]) {
458 nodes_left = 1;
459 break;
460 }
461 }
462 if (nodes_left) {
463 snmplib_debug(0, "The mib description doesn't seem to be consistent.\n");
464 snmplib_debug(0, "Some nodes couldn't be linked under the \"iso\" tree.\n");
465 snmplib_debug(0, "these nodes are left:\n");
466 for (bucket = 0; bucket < NHASHSIZE; bucket++) {
467 for (np = nbuckets[bucket]; np; np = np->next)
468 snmplib_debug(5, "%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
469 np->type);
470 }
471 }
472 return tp;
473 }
474
475
476 /*
477 * Parses a token from the file. The type of the token parsed is returned,
478 * and the text is placed in the string pointed to by token.
479 */
480 static char last = ' ';
481
482 static int
483 get_token(register FILE *fp, register char *token)
484 {
485 register int ch;
486 register char *cp = token;
487 register int hash = 0;
488 register struct tok *tp;
489
490 *cp = 0;
491 ch = (unsigned char)last;
492 /* skip all white space */
493 while (xisspace(ch) && ch != -1) {
494 ch = getc(fp);
495 if (ch == '\n')
496 Line++;
497 }
498 if (ch == -1)
499 return ENDOFFILE;
500
501 /*
502 * Accumulate characters until end of token is found. Then attempt to match this
503 * token as a reserved word. If a match is found, return the type. Else it is
504 * a label.
505 */
506 do {
507 if (ch == '\n')
508 Line++;
509 if (xisspace(ch) || ch == '(' || ch == ')' ||
510 ch == '{' || ch == '}' || ch == ',' ||
511 ch == '"') {
512 if (!xisspace(ch) && *token == 0) {
513 hash += ch;
514 *cp++ = ch;
515 last = ' ';
516 } else {
517 last = ch;
518 }
519 *cp = '\0';
520
521 for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
522 if ((tp->hash == hash) && (strcmp(tp->name, token) == 0))
523 break;
524 }
525 if (tp) {
526 if (tp->token == CONTINUE)
527 continue;
528 return (tp->token);
529 }
530 if (token[0] == '-' && token[1] == '-') {
531 /* strip comment */
532 while ((ch = getc(fp)) != -1)
533 if (ch == '\n') {
534 Line++;
535 break;
536 }
537 if (ch == -1)
538 return ENDOFFILE;
539 last = ch;
540 return get_token(fp, token);
541 }
542 for (cp = token; *cp; cp++)
543 if (!xisdigit(*cp))
544 return LABEL;
545 return NUMBER;
546 } else {
547 hash += ch;
548 *cp++ = ch;
549 if (ch == '\n')
550 Line++;
551 }
552
553 } while ((ch = getc(fp)) != -1);
554 return ENDOFFILE;
555 }
556
557 /*
558 * Takes a list of the form:
559 * { iso org(3) dod(6) 1 }
560 * and creates several nodes, one for each parent-child pair.
561 * Returns NULL on error.
562 * register struct subid *SubOid; an array of subids
563 * int length; the length of the array
564 */
565 static int
566 getoid(register FILE *fp, register struct subid *SubOid, int length)
567 {
568 register int count;
569 int type;
570 char token[128];
571 register char *cp;
572
573 if ((type = get_token(fp, token)) != LEFTBRACKET) {
574 print_error("Expected \"{\"", token, type);
575 return 0;
576 }
577 type = get_token(fp, token);
578 for (count = 0; count < length; count++, SubOid++) {
579 SubOid->label = 0;
580 SubOid->subid = -1;
581 if (type == RIGHTBRACKET) {
582 return count;
583 } else if (type != LABEL && type != NUMBER) {
584 print_error("Not valid for object identifier", token, type);
585 return 0;
586 }
587 if (type == LABEL) {
588 /* this entry has a label */
589 cp = (char *) xmalloc((unsigned) strlen(token) + 1);
590 strcpy(cp, token);
591 SubOid->label = cp;
592 type = get_token(fp, token);
593 if (type == LEFTPAREN) {
594 type = get_token(fp, token);
595 if (type == NUMBER) {
596 SubOid->subid = atoi(token);
597 if ((type = get_token(fp, token)) != RIGHTPAREN) {
598 print_error("Unexpected a closing parenthesis", token, type);
599 return 0;
600 }
601 } else {
602 print_error("Expected a number", token, type);
603 return 0;
604 }
605 } else {
606 continue;
607 }
608 } else {
609 /* this entry has just an integer sub-identifier */
610 SubOid->subid = atoi(token);
611 }
612 type = get_token(fp, token);
613 }
614 return count;
615
616
617 }
618
619 static void
620 free_node(struct node *np)
621 {
622 struct enum_list *ep, *tep;
623
624 ep = np->enums;
625 while (ep) {
626 tep = ep;
627 ep = ep->next;
628 xfree((char *) tep);
629 }
630 xfree((char *) np);
631 }
632
633 /*
634 * Parse an entry of the form:
635 * label OBJECT IDENTIFIER ::= { parent 2 }
636 * The "label OBJECT IDENTIFIER" portion has already been parsed.
637 * Returns 0 on error.
638 */
639 static struct node *
640 parse_objectid(FILE *fp, char *name) {
641 int type;
642 char token[64];
643 register int count;
644 register struct subid *op, *nop;
645 int length;
646 struct subid SubOid[32];
647 struct node *np, *root, *oldnp = NULL;
648
649 type = get_token(fp, token);
650 if (type != EQUALS) {
651 print_error("Bad format", token, type);
652 return 0;
653 }
654 if ((length = getoid(fp, SubOid, 32)) != 0) {
655 np = root = (struct node *) xmalloc(sizeof(struct node));
656 memset((char *) np, '\0', sizeof(struct node));
657 /*
658 * For each parent-child subid pair in the subid array,
659 * create a node and link it into the node list.
660 */
661 for (count = 0, op = SubOid, nop = SubOid + 1; count < (length - 2); count++,
662 op++, nop++) {
663 /* every node must have parent's name and child's name or number */
664 if (op->label && (nop->label || (nop->subid != -1))) {
665 strcpy(np->parent, op->label);
666 if (nop->label)
667 strcpy(np->label, nop->label);
668 if (nop->subid != -1)
669 np->subid = nop->subid;
670 np->type = 0;
671 np->enums = 0;
672 /* set up next entry */
673 np->next = (struct node *) xmalloc(sizeof(*np->next));
674 memset((char *) np->next, '\0', sizeof(struct node));
675 oldnp = np;
676 np = np->next;
677 }
678 }
679 np->next = (struct node *) NULL;
680 /*
681 * The above loop took care of all but the last pair. This pair is taken
682 * care of here. The name for this node is taken from the label for this
683 * entry.
684 * np still points to an unused entry.
685 */
686 if (count == (length - 2)) {
687 if (op->label) {
688 strcpy(np->parent, op->label);
689 strcpy(np->label, name);
690 if (nop->subid != -1)
691 np->subid = nop->subid;
692 else
693 print_error("Warning: This entry is pretty silly", np->label, type);
694 } else {
695 free_node(np);
696 if (oldnp)
697 oldnp->next = NULL;
698 else
699 return NULL;
700 }
701 } else {
702 print_error("Missing end of oid", (char *) NULL, type);
703 free_node(np); /* the last node allocated wasn't used */
704 if (oldnp)
705 oldnp->next = NULL;
706 return NULL;
707 }
708 /* free the oid array */
709 for (count = 0, op = SubOid; count < length; count++, op++) {
710 if (op->label)
711 xfree(op->label);
712 op->label = 0;
713 }
714 return root;
715 } else {
716 print_error("Bad object identifier", (char *) NULL, type);
717 return 0;
718 }
719 }
720
721 /*
722 * Parses an asn type. This structure is ignored by this parser.
723 * Returns NULL on error.
724 */
725 static int
726 parse_asntype(FILE *fp)
727 {
728 int type;
729 char token[64];
730
731 type = get_token(fp, token);
732 if (type != SEQUENCE) {
733 print_error("Not a sequence", token, type); /* should we handle this */
734 return ENDOFFILE;
735 }
736 while ((type = get_token(fp, token)) != ENDOFFILE) {
737 if (type == RIGHTBRACKET)
738 return type;
739 }
740 print_error("Expected \"}\"", token, type);
741 return ENDOFFILE;
742 }
743
744 /*
745 * Parses an OBJECT TYPE macro.
746 * Returns 0 on error.
747 */
748 static struct node *
749 parse_objecttype(register FILE *fp, char *name) {
750 register int type;
751 char token[64];
752 int count, length;
753 struct subid SubOid[32];
754 char syntax[64];
755 int nexttype;
756 char nexttoken[64];
757 register struct node *np = NULL;
758 register struct enum_list *ep = NULL;
759
760 type = get_token(fp, token);
761 if (type != SYNTAX) {
762 print_error("Bad format for OBJECT TYPE", token, type);
763 return 0;
764 }
765 np = (struct node *) xmalloc(sizeof(struct node));
766 np->next = 0;
767 np->enums = 0;
768 type = get_token(fp, token);
769 nexttype = get_token(fp, nexttoken);
770 np->type = type;
771 switch (type) {
772 case SEQUENCE:
773 strcpy(syntax, token);
774 if (nexttype == OF) {
775 strcat(syntax, " ");
776 strcat(syntax, nexttoken);
777 nexttype = get_token(fp, nexttoken);
778 strcat(syntax, " ");
779 strcat(syntax, nexttoken);
780 nexttype = get_token(fp, nexttoken);
781 }
782 break;
783 case INTEGER:
784 strcpy(syntax, token);
785 if (nexttype == LEFTBRACKET) {
786 /* if there is an enumeration list, parse it */
787 while ((type = get_token(fp, token)) != ENDOFFILE) {
788 if (type == RIGHTBRACKET)
789 break;
790 if (type == LABEL) {
791 /* this is an enumerated label */
792 if (np->enums == 0) {
793 ep = np->enums = (struct enum_list *)
794 xmalloc(sizeof(struct enum_list));
795 } else {
796 ep->next = (struct enum_list *)
797 xmalloc(sizeof(struct enum_list));
798 ep = ep->next;
799 }
800 ep->next = 0;
801 /* a reasonable approximation for the length */
802 ep->label = (char *) xmalloc((unsigned) strlen(token) + 1);
803 strcpy(ep->label, token);
804 type = get_token(fp, token);
805 if (type != LEFTPAREN) {
806 print_error("Expected \"(\"", token, type);
807 free_node(np);
808 return 0;
809 }
810 type = get_token(fp, token);
811 if (type != NUMBER) {
812 print_error("Expected integer", token, type);
813 free_node(np);
814 return 0;
815 }
816 ep->value = atoi(token);
817 type = get_token(fp, token);
818 if (type != RIGHTPAREN) {
819 print_error("Expected \")\"", token, type);
820 free_node(np);
821 return 0;
822 }
823 }
824 }
825 if (type == ENDOFFILE) {
826 print_error("Expected \"}\"", token, type);
827 free_node(np);
828 return 0;
829 }
830 nexttype = get_token(fp, nexttoken);
831 } else if (nexttype == LEFTPAREN) {
832 /* ignore the "constrained integer" for now */
833 nexttype = get_token(fp, nexttoken);
834 nexttype = get_token(fp, nexttoken);
835 nexttype = get_token(fp, nexttoken);
836 }
837 break;
838 case OBJID:
839 case OCTETSTR:
840 case NETADDR:
841 case IPADDR:
842 case COUNTER:
843 case GAUGE:
844 case TIMETICKS:
845 case SNMP_OPAQUE:
846 case NUL:
847 case LABEL:
848 strcpy(syntax, token);
849 break;
850 default:
851 print_error("Bad syntax", token, type);
852 free_node(np);
853 return 0;
854 }
855 if (nexttype != ACCESS) {
856 print_error("Should be ACCESS", nexttoken, nexttype);
857 free_node(np);
858 return 0;
859 }
860 type = get_token(fp, token);
861 if (type != READONLY && type != READWRITE && type != WRITEONLY
862 && type != NOACCESS) {
863 print_error("Bad access type", nexttoken, nexttype);
864 free_node(np);
865 return 0;
866 }
867 type = get_token(fp, token);
868 if (type != SNMP_STATUS) {
869 print_error("Should be STATUS", token, nexttype);
870 free_node(np);
871 return 0;
872 }
873 type = get_token(fp, token);
874 if (type != MANDATORY && type != SNMP_OPTIONAL && type != OBSOLETE && type != RECOMMENDED) {
875 print_error("Bad status", token, type);
876 free_node(np);
877 return 0;
878 }
879 /* Fetch next token. Either:
880 *
881 * -> EQUALS (Old MIB format)
882 * -> DESCRIPTION, INDEX (New MIB format)
883 */
884 type = get_token(fp, token);
885 if ((type != DESCRIPTION) && (type != INDEX) && (type != EQUALS)) {
886 print_error("Should be DESCRIPTION, INDEX, or EQUALS", token, nexttype);
887 free_node(np);
888 return 0;
889 }
890 if (type == DESCRIPTION) {
891
892 type = get_token(fp, token);
893 if (type != QUOTE) {
894 print_error("Should be Description open quote", token, nexttype);
895 free_node(np);
896 return 0;
897 }
898 /* Fetch description string */
899 {
900 int ReadChar;
901
902 ReadChar = last;
903 /* skip everything until closing quote */
904 while ((ReadChar != '"') && (ReadChar != -1)) {
905 ReadChar = getc(fp);
906 if (ReadChar == '\n')
907 Line++;
908 }
909 last = ' ';
910 }
911 /* ASSERT: Done with description. */
912 type = get_token(fp, token);
913 }
914 if ((type != INDEX) && (type != EQUALS)) {
915 print_error("Should be INDEX, or EQUALS", token, nexttype);
916 free_node(np);
917 return 0;
918 }
919 if (type == INDEX) {
920
921 /* Scarf INDEX */
922
923 type = get_token(fp, token);
924 if (type != LEFTBRACKET) {
925 print_error("Should be INDEX left brace", token, type);
926 free_node(np);
927 return 0;
928 }
929 /* Fetch description string */
930 {
931 int ReadChar;
932
933 ReadChar = last;
934 /* skip everything until closing quote */
935 while ((ReadChar != '}') && (ReadChar != -1)) {
936 ReadChar = getc(fp);
937 if (ReadChar == '\n')
938 Line++;
939 }
940 last = ' ';
941 }
942 /* ASSERT: Done with INDEX. */
943 type = get_token(fp, token);
944 }
945 if (type != EQUALS) {
946 print_error("Bad format", token, type);
947 free_node(np);
948 return 0;
949 }
950 length = getoid(fp, SubOid, 32);
951 if (length > 1 && length <= 32) {
952 /* just take the last pair in the oid list */
953 if (SubOid[length - 2].label)
954 strncpy(np->parent, SubOid[length - 2].label, 64);
955 strcpy(np->label, name);
956 if (SubOid[length - 1].subid != -1)
957 np->subid = SubOid[length - 1].subid;
958 else
959 print_error("Warning: This entry is pretty silly", np->label, type);
960 } else {
961 print_error("No end to oid", (char *) NULL, type);
962 free_node(np);
963 np = 0;
964 }
965 /* free oid array */
966 for (count = 0; count < length; count++) {
967 if (SubOid[count].label)
968 xfree(SubOid[count].label);
969 SubOid[count].label = 0;
970 }
971 return np;
972 }
973
974
975 /*
976 * Parses a mib file and returns a linked list of nodes found in the file.
977 * Returns NULL on error.
978 */
979 #if !TEST
980 static
981 #endif
982 struct node *
983 parse(FILE *fp) {
984 char token[64];
985 char name[64];
986 int type = 1;
987 struct node *np = NULL, *root = NULL;
988
989 hash_init();
990
991 while (type != ENDOFFILE) {
992 type = get_token(fp, token);
993 if (type != LABEL) {
994 if (type == ENDOFFILE) {
995 return root;
996 }
997 print_error(token, "is a reserved word", type);
998 return NULL;
999 }
1000 strncpy(name, token, 64);
1001 type = get_token(fp, token);
1002 if (type == OBJTYPE) {
1003 if (root == NULL) {
1004 /* first link in chain */
1005 np = root = parse_objecttype(fp, name);
1006 if (np == NULL) {
1007 print_error("Bad parse of object type", (char *) NULL, type);
1008 return NULL;
1009 }
1010 } else {
1011 np->next = parse_objecttype(fp, name);
1012 if (np->next == NULL) {
1013 print_error("Bad parse of objecttype", (char *) NULL, type);
1014 return NULL;
1015 }
1016 }
1017 /* now find end of chain */
1018 while (np->next)
1019 np = np->next;
1020 } else if (type == OBJID) {
1021 if (root == NULL) {
1022 /* first link in chain */
1023 np = root = parse_objectid(fp, name);
1024 if (np == NULL) {
1025 print_error("Bad parse of object id", (char *) NULL, type);
1026 return NULL;
1027 }
1028 } else {
1029 np->next = parse_objectid(fp, name);
1030 if (np->next == NULL) {
1031 print_error("Bad parse of object type", (char *) NULL, type);
1032 return NULL;
1033 }
1034 }
1035 /* now find end of chain */
1036 while (np->next)
1037 np = np->next;
1038 } else if (type == EQUALS) {
1039 type = parse_asntype(fp);
1040 } else if (type == ENDOFFILE) {
1041 break;
1042 } else {
1043 print_error("Bad operator", (char *) NULL, type);
1044 return NULL;
1045 }
1046 }
1047 #if TEST
1048 {
1049 struct enum_list *ep;
1050
1051 for (np = root; np; np = np->next) {
1052 printf("%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
1053 np->type);
1054 if (np->enums) {
1055 printf("Enums: \n");
1056 for (ep = np->enums; ep; ep = ep->next) {
1057 printf("%s(%d)\n", ep->label, ep->value);
1058 }
1059 }
1060 }
1061 }
1062 #endif /* TEST */
1063 return root;
1064 }
1065
1066 struct snmp_mib_tree *
1067 read_mib(char *filename) {
1068 FILE *fp;
1069 struct node *nodes;
1070 struct snmp_mib_tree *tree;
1071 char mbuf[256];
1072 char *p;
1073
1074 fp = fopen(filename, "r");
1075 if (fp == NULL) {
1076 snmplib_debug(1, "init_mib: %s: %s\n", filename, xstrerror());
1077 return (NULL);
1078 }
1079 mbuf[0] = '\0';
1080 while ((p = fgets(mbuf, 256, fp)) && strncmp(mbuf, "DUMMY",
1081 strlen("DUMMY")));
1082 if (!p) {
1083 snmplib_debug(0, "Bad MIB version or tag missing, install original!\n");
1084 return NULL;
1085 }
1086 if (!strcmp(mbuf, "DUMMY")) {
1087 snmplib_debug(0, "You need to update your MIB!\n");
1088 return NULL;
1089 }
1090 nodes = parse(fp);
1091 if (!nodes) {
1092 snmplib_debug(0, "Mib table is bad. Exiting\n");
1093 return NULL;
1094 }
1095 tree = build_tree(nodes);
1096 fclose(fp);
1097 return (tree);
1098 }