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