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