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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors