]> git.ipfire.org Git - thirdparty/squid.git/blob - snmplib/parse.c
dont exit() in mib.c or parse.c if mib parsing fails
[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 /*
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 #define OBJID 4
117 #define OCTETSTR 5
118 #define INTEGER 6
119 #define NETADDR 7
120 #define IPADDR 8
121 #define COUNTER 9
122 #define GAUGE 10
123 #define TIMETICKS 11
124 #define OPAQUE 12
125 #define NUL 13
126 #define SEQUENCE 14
127 #define OF 15 /* SEQUENCE OF */
128 #define OBJTYPE 16
129 #define ACCESS 17
130 #define READONLY 18
131 #define READWRITE 19
132 #define WRITEONLY 20
133 #define NOACCESS 21
134 #define STATUS 22
135 #define MANDATORY 23
136 #define OPTIONAL 24
137 #define OBSOLETE 25
138 #define RECOMMENDED 26
139 #define PUNCT 27
140 #define EQUALS 28
141 #define NUMBER 29
142 #define LEFTBRACKET 30
143 #define RIGHTBRACKET 31
144 #define LEFTPAREN 32
145 #define RIGHTPAREN 33
146 #define COMMA 34
147 /* For SNMPv2 SMI pseudo-compliance */
148 #define DESCRIPTION 35
149 #define INDEX 36
150 #define QUOTE 37
151
152 struct tok {
153 char *name; /* token name */
154 int len; /* length not counting nul */
155 int token; /* value */
156 int hash; /* hash of name */
157 struct tok *next; /* pointer to next in hash table */
158 };
159
160
161 struct tok tokens[] = {
162 { "obsolete", sizeof ("obsolete")-1, OBSOLETE },
163 { "Opaque", sizeof ("Opaque")-1, OPAQUE },
164 { "recommended", sizeof("recommended")-1, RECOMMENDED },
165 { "optional", sizeof ("optional")-1, OPTIONAL },
166 { "mandatory", sizeof ("mandatory")-1, MANDATORY },
167 { "current", sizeof ("current")-1, MANDATORY },
168 { "not-accessible", sizeof ("not-accessible")-1, NOACCESS },
169 { "write-only", sizeof ("write-only")-1, WRITEONLY },
170 { "read-write", sizeof ("read-write")-1, READWRITE },
171 { "TimeTicks", sizeof ("TimeTicks")-1, TIMETICKS },
172 { "OBJECTIDENTIFIER", sizeof ("OBJECTIDENTIFIER")-1, OBJID },
173 /*
174 * This CONTINUE appends the next word onto OBJECT,
175 * hopefully matching OBJECTIDENTIFIER above.
176 */
177 { "OBJECT", sizeof ("OBJECT")-1, CONTINUE },
178 { "NetworkAddress", sizeof ("NetworkAddress")-1, NETADDR },
179 { "Gauge", sizeof ("Gauge")-1, GAUGE },
180 { "OCTETSTRING", sizeof ("OCTETSTRING")-1, OCTETSTR },
181 { "OCTET", sizeof ("OCTET")-1, -1 },
182 { "OF", sizeof ("OF")-1, OF },
183 { "SEQUENCE", sizeof ("SEQUENCE")-1, SEQUENCE },
184 { "NULL", sizeof ("NULL")-1, NUL },
185 { "IpAddress", sizeof ("IpAddress")-1, IPADDR },
186 { "INTEGER", sizeof ("INTEGER")-1, INTEGER },
187 { "Counter", sizeof ("Counter")-1, COUNTER },
188 { "read-only", sizeof ("read-only")-1, READONLY },
189 { "ACCESS", sizeof ("ACCESS")-1, ACCESS },
190 { "MAX-ACCESS", sizeof ("MAX-ACCESS")-1, ACCESS },
191 { "STATUS", sizeof ("STATUS")-1, STATUS },
192 { "SYNTAX", sizeof ("SYNTAX")-1, SYNTAX },
193 { "OBJECT-TYPE", sizeof ("OBJECT-TYPE")-1, OBJTYPE },
194 { "{", sizeof ("{")-1, LEFTBRACKET },
195 { "}", sizeof ("}")-1, RIGHTBRACKET },
196 { "::=", sizeof ("::=")-1, EQUALS },
197 { "(", sizeof ("(")-1, LEFTPAREN },
198 { ")", sizeof (")")-1, RIGHTPAREN },
199 { ",", sizeof (",")-1, COMMA },
200 { "DESCRIPTION", sizeof ("DESCRIPTION")-1, DESCRIPTION },
201 { "INDEX", sizeof ("INDEX")-1, INDEX },
202 { "\"", sizeof ("\"")-1, QUOTE },
203 { "END", sizeof("END")-1, ENDOFFILE },
204 /* Hacks for easier MIBFILE coercing */
205 { "read-create", sizeof ("read-create")-1, READWRITE },
206 { NULL }
207 };
208
209 #define HASHSIZE 32
210 #define BUCKET(x) (x & 0x01F)
211
212 static struct tok *buckets[HASHSIZE];
213
214 static void
215 hash_init()
216 {
217 register struct tok *tp;
218 register char *cp;
219 register int h;
220 register int b;
221
222 memset((char *)buckets, '\0', sizeof(buckets));
223 for (tp = tokens; tp->name; tp++) {
224 for (h = 0, cp = tp->name; *cp; cp++)
225 h += *cp;
226 tp->hash = h;
227 b = BUCKET(h);
228 if (buckets[b])
229 tp->next = buckets[b]; /* BUG ??? */
230 buckets[b] = tp;
231 }
232 }
233
234 #define NHASHSIZE 128
235 #define NBUCKET(x) (x & 0x7F)
236 struct node *nbuckets[NHASHSIZE];
237
238 static void init_node_hash(nodes)
239 struct node *nodes;
240 {
241 register struct node *np, *nextp;
242 register char *cp;
243 register int hash;
244
245 memset((char *)nbuckets, '\0', sizeof(nbuckets));
246 for(np = nodes; np;){
247 nextp = np->next;
248 hash = 0;
249 for(cp = np->parent; *cp; cp++)
250 hash += *cp;
251 np->next = nbuckets[NBUCKET(hash)];
252 nbuckets[NBUCKET(hash)] = np;
253 np = nextp;
254 }
255 }
256
257
258 static void
259 print_error(string, token, type)
260 char *string;
261 char *token;
262 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 #ifdef 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 build_translation_table(){
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 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(root, nodes)
346 struct snmp_mib_tree *root;
347 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 #ifndef TEST
427 static
428 #endif
429 struct snmp_mib_tree *
430 build_tree(nodes)
431 struct node *nodes;
432 {
433 struct node *np;
434 struct snmp_mib_tree *tp;
435 int bucket, nodes_left = 0;
436
437 /* build root node */
438 tp = (struct snmp_mib_tree *)xmalloc(sizeof(struct snmp_mib_tree));
439 tp->parent = NULL;
440 tp->next_peer = NULL;
441 tp->child_list = NULL;
442 tp->enums = NULL;
443 strcpy(tp->label, "iso");
444 tp->subid = 1;
445 tp->type = 0;
446 build_translation_table();
447 /* grow tree from this root node */
448 init_node_hash(nodes);
449 /* XXX nodes isn't needed in do_subtree() ??? */
450 do_subtree(tp, &nodes);
451 #ifdef TEST
452 print_subtree(tp, 0);
453 #endif /* TEST */
454 /* If any nodes are left, the tree is probably inconsistent */
455 for(bucket = 0; bucket < NHASHSIZE; bucket++){
456 if (nbuckets[bucket]){
457 nodes_left = 1;
458 break;
459 }
460 }
461 if (nodes_left){
462 snmplib_debug(0, "The mib description doesn't seem to be consistent.\n");
463 snmplib_debug(0, "Some nodes couldn't be linked under the \"iso\" tree.\n");
464 snmplib_debug(0, "these nodes are left:\n");
465 for(bucket = 0; bucket < NHASHSIZE; bucket++){
466 for(np = nbuckets[bucket]; np; np = np->next)
467 snmplib_debug(0, "%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
468 np->type);
469 }
470 }
471 return tp;
472 }
473
474
475 /*
476 * Parses a token from the file. The type of the token parsed is returned,
477 * and the text is placed in the string pointed to by token.
478 */
479 static char last = ' ';
480
481 static int
482 get_token(fp, token)
483 register FILE *fp;
484 register char *token;
485 {
486 register int ch;
487 register char *cp = token;
488 register int hash = 0;
489 register struct tok *tp;
490
491 *cp = 0;
492 ch = last;
493 /* skip all white space */
494 while(isspace(ch) && ch != -1){
495 ch = getc(fp);
496 if (ch == '\n')
497 Line++;
498 }
499 if (ch == -1)
500 return ENDOFFILE;
501
502 /*
503 * Accumulate characters until end of token is found. Then attempt to match this
504 * token as a reserved word. If a match is found, return the type. Else it is
505 * a label.
506 */
507 do {
508 if (ch == '\n')
509 Line++;
510 if (isspace(ch) || ch == '(' || ch == ')' ||
511 ch == '{' || ch == '}' || ch == ',' ||
512 ch == '"' ) {
513 if (!isspace(ch) && *token == 0){
514 hash += ch;
515 *cp++ = ch;
516 last = ' ';
517 } else {
518 last = ch;
519 }
520 *cp = '\0';
521
522 for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
523 if ((tp->hash == hash) && (strcmp(tp->name, token) == 0))
524 break;
525 }
526 if (tp){
527 if (tp->token == CONTINUE)
528 continue;
529 return (tp->token);
530 }
531
532 if (token[0] == '-' && token[1] == '-'){
533 /* strip comment */
534 while ((ch = getc(fp)) != -1)
535 if (ch == '\n'){
536 Line++;
537 break;
538 }
539 if (ch == -1)
540 return ENDOFFILE;
541 last = ch;
542 return get_token(fp, token);
543 }
544 for(cp = token; *cp; cp++)
545 if (!isdigit(*cp))
546 return LABEL;
547 return NUMBER;
548 } else {
549 hash += ch;
550 *cp++ = ch;
551 if (ch == '\n')
552 Line++;
553 }
554
555 } while ((ch = getc(fp)) != -1);
556 return ENDOFFILE;
557 }
558
559 /*
560 * Takes a list of the form:
561 * { iso org(3) dod(6) 1 }
562 * and creates several nodes, one for each parent-child pair.
563 * Returns NULL on error.
564 */
565 static int
566 getoid(fp, SubOid, length)
567 register FILE *fp;
568 register struct subid *SubOid; /* an array of subids */
569 int length; /* the length of the array */
570 {
571 register int count;
572 int type;
573 char token[128];
574 register char *cp;
575
576 if ((type = get_token(fp, token)) != LEFTBRACKET){
577 print_error("Expected \"{\"", token, type);
578 return 0;
579 }
580 type = get_token(fp, token);
581 for(count = 0; count < length; count++, SubOid++){
582 SubOid->label = 0;
583 SubOid->subid = -1;
584 if (type == RIGHTBRACKET){
585 return count;
586 } else if (type != LABEL && type != NUMBER){
587 print_error("Not valid for object identifier", token, type);
588 return 0;
589 }
590 if (type == LABEL){
591 /* this entry has a label */
592 cp = (char *)xmalloc((unsigned)strlen(token) + 1);
593 strcpy(cp, token);
594 SubOid->label = cp;
595 type = get_token(fp, token);
596 if (type == LEFTPAREN){
597 type = get_token(fp, token);
598 if (type == NUMBER){
599 SubOid->subid = atoi(token);
600 if ((type = get_token(fp, token)) != RIGHTPAREN){
601 print_error("Unexpected a closing parenthesis", token, type);
602 return 0;
603 }
604 } else {
605 print_error("Expected a number", token, type);
606 return 0;
607 }
608 } else {
609 continue;
610 }
611 } else {
612 /* this entry has just an integer sub-identifier */
613 SubOid->subid = atoi(token);
614 }
615 type = get_token(fp, token);
616 }
617 return count;
618
619
620 }
621
622 static void
623 free_node(np)
624 struct node *np;
625 {
626 struct enum_list *ep, *tep;
627
628 ep = np->enums;
629 while(ep){
630 tep = ep;
631 ep = ep->next;
632 xfree((char *)tep);
633 }
634 xfree((char *)np);
635 }
636
637 /*
638 * Parse an entry of the form:
639 * label OBJECT IDENTIFIER ::= { parent 2 }
640 * The "label OBJECT IDENTIFIER" portion has already been parsed.
641 * Returns 0 on error.
642 */
643 static struct node *
644 parse_objectid(fp, name)
645 FILE *fp;
646 char *name;
647 {
648 int type;
649 char token[64];
650 register int count;
651 register struct subid *op, *nop;
652 int length;
653 struct subid SubOid[32];
654 struct node *np, *root, *oldnp = NULL;
655
656 type = get_token(fp, token);
657 if (type != EQUALS){
658 print_error("Bad format", token, type);
659 return 0;
660 }
661 if ((length = getoid(fp, SubOid, 32)) != 0){
662 np = root = (struct node *)xmalloc(sizeof(struct node));
663 memset((char *)np, '\0', sizeof(struct node));
664 /*
665 * For each parent-child subid pair in the subid array,
666 * create a node and link it into the node list.
667 */
668 for(count = 0, op = SubOid, nop=SubOid+1; count < (length - 2); count++,
669 op++, nop++){
670 /* every node must have parent's name and child's name or number */
671 if (op->label && (nop->label || (nop->subid != -1))){
672 strcpy(np->parent, op->label);
673 if (nop->label)
674 strcpy(np->label, nop->label);
675 if (nop->subid != -1)
676 np->subid = nop->subid;
677 np->type = 0;
678 np->enums = 0;
679 /* set up next entry */
680 np->next = (struct node *)xmalloc(sizeof(*np->next));
681 memset((char *)np->next, '\0', sizeof(struct node));
682 oldnp = np;
683 np = np->next;
684 }
685 }
686 np->next = (struct node *)NULL;
687 /*
688 * The above loop took care of all but the last pair. This pair is taken
689 * care of here. The name for this node is taken from the label for this
690 * entry.
691 * np still points to an unused entry.
692 */
693 if (count == (length - 2)){
694 if (op->label){
695 strcpy(np->parent, op->label);
696 strcpy(np->label, name);
697 if (nop->subid != -1)
698 np->subid = nop->subid;
699 else
700 print_error("Warning: This entry is pretty silly", np->label, type);
701 } else {
702 free_node(np);
703 if (oldnp)
704 oldnp->next = NULL;
705 else
706 return NULL;
707 }
708 } else {
709 print_error("Missing end of oid", (char *)NULL, type);
710 free_node(np); /* the last node allocated wasn't used */
711 if (oldnp)
712 oldnp->next = NULL;
713 return NULL;
714 }
715 /* free the oid array */
716 for(count = 0, op = SubOid; count < length; count++, op++){
717 if (op->label)
718 xfree(op->label);
719 op->label = 0;
720 }
721 return root;
722 } else {
723 print_error("Bad object identifier", (char *)NULL, type);
724 return 0;
725 }
726 }
727
728 /*
729 * Parses an asn type. This structure is ignored by this parser.
730 * Returns NULL on error.
731 */
732 static int
733 parse_asntype(fp)
734 FILE *fp;
735 {
736 int type;
737 char token[64];
738
739 type = get_token(fp, token);
740 if (type != SEQUENCE){
741 print_error("Not a sequence", token, type); /* should we handle this */
742 return ENDOFFILE;
743 }
744 while((type = get_token(fp, token)) != ENDOFFILE){
745 if (type == RIGHTBRACKET)
746 return type;
747 }
748 print_error("Expected \"}\"", token, type);
749 return ENDOFFILE;
750 }
751
752 /*
753 * Parses an OBJECT TYPE macro.
754 * Returns 0 on error.
755 */
756 static struct node *
757 parse_objecttype(fp, name)
758 register FILE *fp;
759 char *name;
760 {
761 register int type;
762 char token[64];
763 int count, length;
764 struct subid SubOid[32];
765 char syntax[64];
766 int nexttype;
767 char nexttoken[64];
768 register struct node *np=NULL;
769 register struct enum_list *ep=NULL;
770
771 type = get_token(fp, token);
772 if (type != SYNTAX){
773 print_error("Bad format for OBJECT TYPE", token, type);
774 return 0;
775 }
776 np = (struct node *)xmalloc(sizeof(struct node));
777 np->next = 0;
778 np->enums = 0;
779 type = get_token(fp, token);
780 nexttype = get_token(fp, nexttoken);
781 np->type = type;
782 switch(type){
783 case SEQUENCE:
784 strcpy(syntax, token);
785 if (nexttype == OF){
786 strcat(syntax, " ");
787 strcat(syntax, nexttoken);
788 nexttype = get_token(fp, nexttoken);
789 strcat(syntax, " ");
790 strcat(syntax, nexttoken);
791 nexttype = get_token(fp, nexttoken);
792 }
793 break;
794 case INTEGER:
795 strcpy(syntax, token);
796 if (nexttype == LEFTBRACKET) {
797 /* if there is an enumeration list, parse it */
798 while((type = get_token(fp, token)) != ENDOFFILE){
799 if (type == RIGHTBRACKET)
800 break;
801 if (type == LABEL){
802 /* this is an enumerated label */
803 if (np->enums == 0){
804 ep = np->enums = (struct enum_list *)
805 xmalloc(sizeof(struct enum_list));
806 } else {
807 ep->next = (struct enum_list *)
808 xmalloc(sizeof(struct enum_list));
809 ep = ep->next;
810 }
811 ep->next = 0;
812 /* a reasonable approximation for the length */
813 ep->label = (char *)xmalloc((unsigned)strlen(token) + 1);
814 strcpy(ep->label, token);
815 type = get_token(fp, token);
816 if (type != LEFTPAREN){
817 print_error("Expected \"(\"", token, type);
818 free_node(np);
819 return 0;
820 }
821 type = get_token(fp, token);
822 if (type != NUMBER){
823 print_error("Expected integer", token, type);
824 free_node(np);
825 return 0;
826 }
827 ep->value = atoi(token);
828 type = get_token(fp, token);
829 if (type != RIGHTPAREN){
830 print_error("Expected \")\"", token, type);
831 free_node(np);
832 return 0;
833 }
834 }
835 }
836 if (type == ENDOFFILE){
837 print_error("Expected \"}\"", token, type);
838 free_node(np);
839 return 0;
840 }
841 nexttype = get_token(fp, nexttoken);
842 } else if (nexttype == LEFTPAREN){
843 /* ignore the "constrained integer" for now */
844 nexttype = get_token(fp, nexttoken);
845 nexttype = get_token(fp, nexttoken);
846 nexttype = get_token(fp, nexttoken);
847 }
848 break;
849 case OBJID:
850 case OCTETSTR:
851 case NETADDR:
852 case IPADDR:
853 case COUNTER:
854 case GAUGE:
855 case TIMETICKS:
856 case OPAQUE:
857 case NUL:
858 case LABEL:
859 strcpy(syntax, token);
860 break;
861 default:
862 print_error("Bad syntax", token, type);
863 free_node(np);
864 return 0;
865 }
866 if (nexttype != ACCESS){
867 print_error("Should be ACCESS", nexttoken, nexttype);
868 free_node(np);
869 return 0;
870 }
871 type = get_token(fp, token);
872 if (type != READONLY && type != READWRITE && type != WRITEONLY
873 && type != NOACCESS){
874 print_error("Bad access type", nexttoken, nexttype);
875 free_node(np);
876 return 0;
877 }
878 type = get_token(fp, token);
879 if (type != STATUS){
880 print_error("Should be STATUS", token, nexttype);
881 free_node(np);
882 return 0;
883 }
884 type = get_token(fp, token);
885 if (type != MANDATORY && type != OPTIONAL && type != OBSOLETE && type != RECOMMENDED){
886 print_error("Bad status", token, type);
887 free_node(np);
888 return 0;
889 }
890 /* Fetch next token. Either:
891 *
892 * -> EQUALS (Old MIB format)
893 * -> DESCRIPTION, INDEX (New MIB format)
894 */
895 type = get_token(fp, token);
896 if ((type != DESCRIPTION) && (type != INDEX) && (type != EQUALS)) {
897 print_error("Should be DESCRIPTION, INDEX, or EQUALS", token, nexttype);
898 free_node(np);
899 return 0;
900 }
901
902 if (type == DESCRIPTION) {
903
904 type = get_token(fp, token);
905 if (type != QUOTE) {
906 print_error("Should be Description open quote", token, nexttype);
907 free_node(np);
908 return 0;
909 }
910
911 /* Fetch description string */
912 {
913 int ReadChar;
914
915 ReadChar = last;
916 /* skip everything until closing quote */
917 while((ReadChar != '"') && (ReadChar != -1)) {
918 ReadChar = getc(fp);
919 if (ReadChar == '\n')
920 Line++;
921 }
922 last = ' ';
923 }
924 /* ASSERT: Done with description. */
925 type = get_token(fp, token);
926 }
927
928 if ((type != INDEX) && (type != EQUALS)) {
929 print_error("Should be INDEX, or EQUALS", token, nexttype);
930 free_node(np);
931 return 0;
932 }
933
934 if (type == INDEX) {
935
936 /* Scarf INDEX */
937
938 type = get_token(fp, token);
939 if (type != LEFTBRACKET){
940 print_error("Should be INDEX left brace", token, type);
941 free_node(np);
942 return 0;
943 }
944
945 /* Fetch description string */
946 {
947 int ReadChar;
948
949 ReadChar = last;
950 /* skip everything until closing quote */
951 while((ReadChar != '}') && (ReadChar != -1)) {
952 ReadChar = getc(fp);
953 if (ReadChar == '\n')
954 Line++;
955 }
956 last = ' ';
957 }
958 /* ASSERT: Done with INDEX. */
959 type = get_token(fp, token);
960 }
961
962 if (type != EQUALS){
963 print_error("Bad format", token, type);
964 free_node(np);
965 return 0;
966 }
967 length = getoid(fp, SubOid, 32);
968 if (length > 1 && length <= 32){
969 /* just take the last pair in the oid list */
970 if (SubOid[length - 2].label)
971 strncpy(np->parent, SubOid[length - 2].label, 64);
972 strcpy(np->label, name);
973 if (SubOid[length - 1].subid != -1)
974 np->subid = SubOid[length - 1].subid;
975 else
976 print_error("Warning: This entry is pretty silly", np->label, type);
977 } else {
978 print_error("No end to oid", (char *)NULL, type);
979 free_node(np);
980 np = 0;
981 }
982 /* free oid array */
983 for(count = 0; count < length; count++){
984 if (SubOid[count].label)
985 xfree(SubOid[count].label);
986 SubOid[count].label = 0;
987 }
988 return np;
989 }
990
991
992 /*
993 * Parses a mib file and returns a linked list of nodes found in the file.
994 * Returns NULL on error.
995 */
996 #ifndef TEST
997 static
998 #endif
999 struct node *
1000 parse(fp)
1001 FILE *fp;
1002 {
1003 char token[64];
1004 char name[64];
1005 int type = 1;
1006 struct node *np=NULL, *root = NULL;
1007
1008 hash_init();
1009
1010 while(type != ENDOFFILE){
1011 type = get_token(fp, token);
1012 if (type != LABEL){
1013 if (type == ENDOFFILE){
1014 return root;
1015 }
1016 print_error(token, "is a reserved word", type);
1017 return NULL;
1018 }
1019 strncpy(name, token, 64);
1020 type = get_token(fp, token);
1021 if (type == OBJTYPE){
1022 if (root == NULL){
1023 /* first link in chain */
1024 np = root = parse_objecttype(fp, name);
1025 if (np == NULL){
1026 print_error("Bad parse of object type", (char *)NULL, type);
1027 return NULL;
1028 }
1029 } else {
1030 np->next = parse_objecttype(fp, name);
1031 if (np->next == NULL){
1032 print_error("Bad parse of objecttype", (char *)NULL, type);
1033 return NULL;
1034 }
1035 }
1036 /* now find end of chain */
1037 while(np->next)
1038 np = np->next;
1039 } else if (type == OBJID){
1040 if (root == NULL){
1041 /* first link in chain */
1042 np = root = parse_objectid(fp, name);
1043 if (np == NULL){
1044 print_error("Bad parse of object id", (char *)NULL, type);
1045 return NULL;
1046 }
1047 } else {
1048 np->next = parse_objectid(fp, name);
1049 if (np->next == NULL){
1050 print_error("Bad parse of object type", (char *)NULL, type);
1051 return NULL;
1052 }
1053 }
1054 /* now find end of chain */
1055 while(np->next)
1056 np = np->next;
1057 } else if (type == EQUALS){
1058 type = parse_asntype(fp);
1059 } else if (type == ENDOFFILE){
1060 break;
1061 } else {
1062 print_error("Bad operator", (char *)NULL, type);
1063 return NULL;
1064 }
1065 }
1066 #ifdef TEST
1067 {
1068 struct enum_list *ep;
1069
1070 for(np = root; np; np = np->next){
1071 printf("%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
1072 np->type);
1073 if (np->enums){
1074 printf("Enums: \n");
1075 for(ep = np->enums; ep; ep = ep->next){
1076 printf("%s(%d)\n", ep->label, ep->value);
1077 }
1078 }
1079 }
1080 }
1081 #endif /* TEST */
1082 return root;
1083 }
1084
1085 struct snmp_mib_tree *
1086 read_mib(filename)
1087 char *filename;
1088 {
1089 FILE *fp;
1090 struct node *nodes;
1091 struct snmp_mib_tree *tree;
1092 char mbuf[256];
1093 char *p;
1094
1095 fp = fopen(filename, "r");
1096 if (fp == NULL) {
1097 snmplib_debug(0, "failed to open MIB file: '%s'\n", filename);
1098 return(NULL);
1099 }
1100
1101 mbuf[0]='\0';
1102 while ( (p=fgets(mbuf, 256, fp)) && strncmp(&mbuf[4], CURRENT_MIB_VERSION,
1103 strlen(CURRENT_MIB_VERSION)));
1104 if (!p) {
1105 snmplib_debug(0, "Bad MIB version or tag missing, install original!\n");
1106 return NULL;
1107 }
1108
1109 if (!strcmp(mbuf, CURRENT_MIB_VERSION)) {
1110 snmplib_debug(0, "You need to update your MIB!\n");
1111 return NULL;
1112 }
1113 nodes = parse(fp);
1114 if (!nodes){
1115 snmplib_debug(0, "Mib table is bad. Exiting\n");
1116 return NULL;
1117 }
1118 tree = build_tree(nodes);
1119 fclose(fp);
1120 return(tree);
1121 }
1122
1123