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