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