source: squid-ssl/trunk/fuentes/lib/snmplib/parse.c @ 5495

Last change on this file since 5495 was 5495, checked in by Juanma, 2 years ago

Initial release

File size: 32.7 KB
Line 
1/*
2 * Copyright (C) 1996-2015 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
222hash_init(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)
243struct node *nbuckets[NHASHSIZE];
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
276#if TEST
277print_subtree(tree, count)
278struct snmp_mib_tree *tree;
279int count;
280{
281    struct snmp_mib_tree *tp;
282    int i;
283
284    for (i = 0; i < count; i++)
285        printf("  ");
286    printf("Children of %s:\n", tree->label);
287    count++;
288    for (tp = tree->child_list; tp; tp = tp->next_peer) {
289        for (i = 0; i < count; i++)
290            printf("  ");
291        printf("%s\n", tp->label);
292    }
293    for (tp = tree->child_list; tp; tp = tp->next_peer) {
294        print_subtree(tp, count);
295    }
296}
297#endif /* TEST */
298
299int translation_table[40];
300
301static void
302build_translation_table(void)
303{
304    int count;
305
306    for (count = 0; count < 40; count++) {
307        switch (count) {
308        case OBJID:
309            translation_table[count] = TYPE_OBJID;
310            break;
311        case OCTETSTR:
312            translation_table[count] = TYPE_OCTETSTR;
313            break;
314        case INTEGER:
315            translation_table[count] = TYPE_INTEGER;
316            break;
317        case NETADDR:
318            translation_table[count] = TYPE_IPADDR;
319            break;
320        case IPADDR:
321            translation_table[count] = TYPE_IPADDR;
322            break;
323        case COUNTER:
324            translation_table[count] = TYPE_COUNTER;
325            break;
326        case GAUGE:
327            translation_table[count] = TYPE_GAUGE;
328            break;
329        case TIMETICKS:
330            translation_table[count] = TYPE_TIMETICKS;
331            break;
332        case SNMP_OPAQUE:
333            translation_table[count] = TYPE_OPAQUE;
334            break;
335        case NUL:
336            translation_table[count] = TYPE_NULL;
337            break;
338        default:
339            translation_table[count] = TYPE_OTHER;
340            break;
341        }
342    }
343}
344
345/*
346 * Find all the children of root in the list of nodes.  Link them into the
347 * tree and out of the nodes list.
348 */
349static void
350do_subtree(struct snmp_mib_tree *root, struct node **nodes)
351{
352    register struct snmp_mib_tree *tp;
353    struct snmp_mib_tree *peer = NULL;
354    register struct node *np = NULL, **headp = NULL;
355    struct node *oldnp = NULL, *child_list = NULL, *childp = NULL;
356    char *cp;
357    int hash;
358
359    tp = root;
360    hash = 0;
361    for (cp = tp->label; *cp; cp++)
362        hash += *cp;
363    headp = &nbuckets[NBUCKET(hash)];
364    /*
365     * Search each of the nodes for one whose parent is root, and
366     * move each into a separate list.
367     */
368    for (np = *headp; np; np = np->next) {
369        if ((*tp->label != *np->parent) || strcmp(tp->label, np->parent)) {
370            if ((*tp->label == *np->label) && !strcmp(tp->label, np->label)) {
371                /* if there is another node with the same label, assume that
372                 * any children after this point in the list belong to the other node.
373                 * This adds some scoping to the table and allows vendors to
374                 * reuse names such as "ip".
375                 */
376                break;
377            }
378            oldnp = np;
379        } else {
380            if (child_list == NULL) {
381                child_list = childp = np;   /* first entry in child list */
382            } else {
383                childp->next = np;
384                childp = np;
385            }
386            /* take this node out of the node list */
387            if (oldnp == NULL) {
388                *headp = np->next;  /* fix root of node list */
389            } else {
390                oldnp->next = np->next;     /* link around this node */
391            }
392        }
393    }
394    if (childp)
395        childp->next = 0;   /* re-terminate list */
396    /*
397     * Take each element in the child list and place it into the tree.
398     */
399    for (np = child_list; np; np = np->next) {
400        tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree));
401        tp->parent = root;
402        tp->next_peer = NULL;
403        tp->child_list = NULL;
404        strcpy(tp->label, np->label);
405        tp->subid = np->subid;
406        tp->type = translation_table[np->type];
407        tp->enums = np->enums;
408        np->enums = NULL;   /* so we don't free them later */
409        if (root->child_list == NULL) {
410            root->child_list = tp;
411        } else if (peer) {
412            peer->next_peer = tp;
413        }
414        peer = tp;
415        /*      if (tp->type == TYPE_OTHER) */
416        do_subtree(tp, nodes);  /* recurse on this child if it isn't an end node */
417    }
418    /* free all nodes that were copied into tree */
419    oldnp = NULL;
420    for (np = child_list; np; np = np->next) {
421        if (oldnp)
422            xfree(oldnp);
423        oldnp = np;
424    }
425    if (oldnp)
426        xfree(oldnp);
427}
428
429#if !TEST
430static
431#endif
432struct snmp_mib_tree *
433build_tree(struct node *nodes) {
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#if 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 * 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 */
479static char last = ' ';
480
481static int
482get_token(register FILE *fp, register char *token)
483{
484    register int ch;
485    register char *cp = token;
486    register int hash = 0;
487    register struct tok *tp;
488
489    *cp = 0;
490    ch = (unsigned char)last;
491    /* skip all white space */
492    while (xisspace(ch) && ch != -1) {
493        ch = getc(fp);
494        if (ch == '\n')
495            Line++;
496    }
497    if (ch == -1)
498        return ENDOFFILE;
499
500    /*
501     * Accumulate characters until end of token is found.  Then attempt to match this
502     * token as a reserved word.  If a match is found, return the type.  Else it is
503     * a label.
504     */
505    do {
506        if (ch == '\n')
507            Line++;
508        if (xisspace(ch) || ch == '(' || ch == ')' ||
509                ch == '{' || ch == '}' || ch == ',' ||
510                ch == '"') {
511            if (!xisspace(ch) && *token == 0) {
512                hash += ch;
513                *cp++ = ch;
514                last = ' ';
515            } else {
516                last = ch;
517            }
518            *cp = '\0';
519
520            for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
521                if ((tp->hash == hash) && (strcmp(tp->name, token) == 0))
522                    break;
523            }
524            if (tp) {
525                if (tp->token == CONTINUE)
526                    continue;
527                return (tp->token);
528            }
529            if (token[0] == '-' && token[1] == '-') {
530                /* strip comment */
531                while ((ch = getc(fp)) != -1)
532                    if (ch == '\n') {
533                        Line++;
534                        break;
535                    }
536                if (ch == -1)
537                    return ENDOFFILE;
538                last = ch;
539                return get_token(fp, token);
540            }
541            for (cp = token; *cp; cp++)
542                if (!xisdigit(*cp))
543                    return LABEL;
544            return NUMBER;
545        } else {
546            hash += ch;
547            *cp++ = ch;
548            if (ch == '\n')
549                Line++;
550        }
551
552    } while ((ch = getc(fp)) != -1);
553    return ENDOFFILE;
554}
555
556/*
557 * Takes a list of the form:
558 * { iso org(3) dod(6) 1 }
559 * and creates several nodes, one for each parent-child pair.
560 * Returns NULL on error.
561 *   register struct subid *SubOid; an array of subids
562 *   int length;            the length of the array
563 */
564static int
565getoid(register FILE *fp, register struct subid *SubOid, int length)
566{
567    register int count;
568    int type;
569    char token[128];
570    register char *cp;
571
572    if ((type = get_token(fp, token)) != LEFTBRACKET) {
573        print_error("Expected \"{\"", token, type);
574        return 0;
575    }
576    type = get_token(fp, token);
577    for (count = 0; count < length; count++, SubOid++) {
578        SubOid->label = 0;
579        SubOid->subid = -1;
580        if (type == RIGHTBRACKET) {
581            return count;
582        } else if (type != LABEL && type != NUMBER) {
583            print_error("Not valid for object identifier", token, type);
584            return 0;
585        }
586        if (type == LABEL) {
587            /* this entry has a label */
588            cp = (char *) xmalloc((unsigned) strlen(token) + 1);
589            strcpy(cp, token);
590            SubOid->label = cp;
591            type = get_token(fp, token);
592            if (type == LEFTPAREN) {
593                type = get_token(fp, token);
594                if (type == NUMBER) {
595                    SubOid->subid = atoi(token);
596                    if ((type = get_token(fp, token)) != RIGHTPAREN) {
597                        print_error("Unexpected a closing parenthesis", token, type);
598                        return 0;
599                    }
600                } else {
601                    print_error("Expected a number", token, type);
602                    return 0;
603                }
604            } else {
605                continue;
606            }
607        } else {
608            /* this entry  has just an integer sub-identifier */
609            SubOid->subid = atoi(token);
610        }
611        type = get_token(fp, token);
612    }
613    return count;
614
615}
616
617static void
618free_node(struct node *np)
619{
620    struct enum_list *ep, *tep;
621
622    ep = np->enums;
623    while (ep) {
624        tep = ep;
625        ep = ep->next;
626        xfree((char *) tep);
627    }
628    xfree((char *) np);
629}
630
631static void
632free_node_list(struct node *nl)
633{
634    while (nl) {
635        struct node *t = nl->next;
636        free_node(nl);
637        nl = t;
638    }
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 */
647static struct node *
648parse_objectid(FILE *fp, char *name) {
649    int type;
650    char token[64];
651    register int count;
652    register struct subid *op, *nop;
653    int length;
654    struct subid SubOid[32];
655    struct node *np, *root, *oldnp = NULL;
656
657    type = get_token(fp, token);
658    if (type != EQUALS) {
659        print_error("Bad format", token, type);
660        return 0;
661    }
662    if ((length = getoid(fp, SubOid, 32)) != 0) {
663        np = root = (struct node *) xmalloc(sizeof(struct node));
664        memset((char *) np, '\0', sizeof(struct node));
665        /*
666         * For each parent-child subid pair in the subid array,
667         * create a node and link it into the node list.
668         */
669        for (count = 0, op = SubOid, nop = SubOid + 1; count < (length - 2); count++,
670                op++, nop++) {
671            /* every node must have parent's name and child's name or number */
672            if (op->label && (nop->label || (nop->subid != -1))) {
673                strncpy(np->parent, op->label, sizeof(np->parent) - 1);
674                if (nop->label)
675                    strncpy(np->label, nop->label, sizeof(np->label) - 1);
676                if (nop->subid != -1)
677                    np->subid = nop->subid;
678                np->type = 0;
679                np->enums = 0;
680                /* set up next entry */
681                np->next = (struct node *) xmalloc(sizeof(*np->next));
682                memset((char *) np->next, '\0', sizeof(struct node));
683                oldnp = np;
684                np = np->next;
685            }
686        }
687        np->next = (struct node *) NULL;
688        /*
689         * The above loop took care of all but the last pair.  This pair is taken
690         * care of here.  The name for this node is taken from the label for this
691         * entry.
692         * np still points to an unused entry.
693         */
694        if (count == (length - 2)) {
695            if (op->label) {
696                strncpy(np->parent, op->label, sizeof(np->parent)-1);
697                strncpy(np->label, name, sizeof(np->label)-1);
698                if (nop->subid != -1)
699                    np->subid = nop->subid;
700                else
701                    print_error("Warning: This entry is pretty silly", np->label, type);
702            } else {
703                free_node(np);
704                if (oldnp)
705                    oldnp->next = NULL;
706                else {
707                    free_node_list(root); // we need to clear the newly allocated list
708                    return NULL;
709                }
710            }
711        } else {
712            print_error("Missing end of oid", (char *) NULL, type);
713            free_node_list(root); // we need to clear the newly allocated list
714            if (oldnp)
715                oldnp->next = NULL;
716            return NULL;
717        }
718        /* free the oid array */
719        for (count = 0, op = SubOid; count < length; count++, op++) {
720            if (op->label)
721                xfree(op->label);
722            op->label = 0;
723        }
724        return root;
725    } else {
726        print_error("Bad object identifier", (char *) NULL, type);
727        return 0;
728    }
729}
730
731/*
732 * Parses an asn type.  This structure is ignored by this parser.
733 * Returns NULL on error.
734 */
735static int
736parse_asntype(FILE *fp)
737{
738    int type;
739    char token[64];
740
741    type = get_token(fp, token);
742    if (type != SEQUENCE) {
743        print_error("Not a sequence", token, type); /* should we handle this */
744        return ENDOFFILE;
745    }
746    while ((type = get_token(fp, token)) != ENDOFFILE) {
747        if (type == RIGHTBRACKET)
748            return type;
749    }
750    print_error("Expected \"}\"", token, type);
751    return ENDOFFILE;
752}
753
754/*
755 * Parses an OBJECT TYPE macro.
756 * Returns 0 on error.
757 */
758static struct node *
759parse_objecttype(register FILE *fp, char *name) {
760    register int type;
761    char token[64];
762    int count, length;
763    struct subid SubOid[32];
764    char syntax[64];
765    int nexttype;
766    char nexttoken[64];
767    register struct node *np = NULL;
768    register struct enum_list *ep = NULL;
769
770    type = get_token(fp, token);
771    if (type != SYNTAX) {
772        print_error("Bad format for OBJECT TYPE", token, type);
773        return 0;
774    }
775    np = (struct node *) xmalloc(sizeof(struct node));
776    np->next = 0;
777    np->enums = 0;
778    type = get_token(fp, token);
779    nexttype = get_token(fp, nexttoken);
780    np->type = type;
781    switch (type) {
782    case SEQUENCE:
783        strcpy(syntax, token);
784        if (nexttype == OF) {
785            strcat(syntax, " ");
786            strcat(syntax, nexttoken);
787            nexttype = get_token(fp, nexttoken);
788            strcat(syntax, " ");
789            strcat(syntax, nexttoken);
790            nexttype = get_token(fp, nexttoken);
791        }
792        break;
793    case INTEGER:
794        strcpy(syntax, token);
795        if (nexttype == LEFTBRACKET) {
796            /* if there is an enumeration list, parse it */
797            while ((type = get_token(fp, token)) != ENDOFFILE) {
798                if (type == RIGHTBRACKET)
799                    break;
800                if (type == LABEL) {
801                    /* this is an enumerated label */
802                    if (np->enums == 0) {
803                        ep = np->enums = (struct enum_list *)
804                                         xmalloc(sizeof(struct enum_list));
805                    } else {
806                        ep->next = (struct enum_list *)
807                                   xmalloc(sizeof(struct enum_list));
808                        ep = ep->next;
809                    }
810                    ep->next = 0;
811                    /* a reasonable approximation for the length */
812                    ep->label = (char *) xmalloc((unsigned) strlen(token) + 1);
813                    strcpy(ep->label, token);
814                    type = get_token(fp, token);
815                    if (type != LEFTPAREN) {
816                        print_error("Expected \"(\"", token, type);
817                        free_node(np);
818                        return 0;
819                    }
820                    type = get_token(fp, token);
821                    if (type != NUMBER) {
822                        print_error("Expected integer", token, type);
823                        free_node(np);
824                        return 0;
825                    }
826                    ep->value = atoi(token);
827                    type = get_token(fp, token);
828                    if (type != RIGHTPAREN) {
829                        print_error("Expected \")\"", token, type);
830                        free_node(np);
831                        return 0;
832                    }
833                }
834            }
835            if (type == ENDOFFILE) {
836                print_error("Expected \"}\"", token, type);
837                free_node(np);
838                return 0;
839            }
840            nexttype = get_token(fp, nexttoken);
841        } else if (nexttype == LEFTPAREN) {
842            /* ignore the "constrained integer" for now */
843            nexttype = get_token(fp, nexttoken);
844            nexttype = get_token(fp, nexttoken);
845            nexttype = get_token(fp, nexttoken);
846        }
847        break;
848    case OBJID:
849    case OCTETSTR:
850    case NETADDR:
851    case IPADDR:
852    case COUNTER:
853    case GAUGE:
854    case TIMETICKS:
855    case SNMP_OPAQUE:
856    case NUL:
857    case LABEL:
858        strcpy(syntax, token);
859        break;
860    default:
861        print_error("Bad syntax", token, type);
862        free_node(np);
863        return 0;
864    }
865    if (nexttype != ACCESS) {
866        print_error("Should be ACCESS", nexttoken, nexttype);
867        free_node(np);
868        return 0;
869    }
870    type = get_token(fp, token);
871    if (type != READONLY && type != READWRITE && type != WRITEONLY
872            && type != NOACCESS) {
873        print_error("Bad access type", nexttoken, nexttype);
874        free_node(np);
875        return 0;
876    }
877    type = get_token(fp, token);
878    if (type != SNMP_STATUS) {
879        print_error("Should be STATUS", token, nexttype);
880        free_node(np);
881        return 0;
882    }
883    type = get_token(fp, token);
884    if (type != MANDATORY && type != SNMP_OPTIONAL && type != OBSOLETE && type != RECOMMENDED) {
885        print_error("Bad status", token, type);
886        free_node(np);
887        return 0;
888    }
889    /* Fetch next token.  Either:
890     *
891     * -> EQUALS (Old MIB format)
892     * -> DESCRIPTION, INDEX (New MIB format)
893     */
894    type = get_token(fp, token);
895    if ((type != DESCRIPTION) && (type != INDEX) && (type != EQUALS)) {
896        print_error("Should be DESCRIPTION, INDEX, or EQUALS", token, nexttype);
897        free_node(np);
898        return 0;
899    }
900    if (type == DESCRIPTION) {
901
902        type = get_token(fp, token);
903        if (type != QUOTE) {
904            print_error("Should be Description open quote", token, nexttype);
905            free_node(np);
906            return 0;
907        }
908        /* Fetch description string */
909        {
910            int ReadChar;
911
912            ReadChar = last;
913            /* skip everything until closing quote */
914            while ((ReadChar != '"') && (ReadChar != -1)) {
915                ReadChar = getc(fp);
916                if (ReadChar == '\n')
917                    Line++;
918            }
919            last = ' ';
920        }
921        /* ASSERT:  Done with description. */
922        type = get_token(fp, token);
923    }
924    if ((type != INDEX) && (type != EQUALS)) {
925        print_error("Should be INDEX, or EQUALS", token, nexttype);
926        free_node(np);
927        return 0;
928    }
929    if (type == INDEX) {
930
931        /* Scarf INDEX */
932
933        type = get_token(fp, token);
934        if (type != LEFTBRACKET) {
935            print_error("Should be INDEX left brace", token, type);
936            free_node(np);
937            return 0;
938        }
939        /* Fetch description string */
940        {
941            int ReadChar;
942
943            ReadChar = last;
944            /* skip everything until closing quote */
945            while ((ReadChar != '}') && (ReadChar != -1)) {
946                ReadChar = getc(fp);
947                if (ReadChar == '\n')
948                    Line++;
949            }
950            last = ' ';
951        }
952        /* ASSERT:  Done with INDEX. */
953        type = get_token(fp, token);
954    }
955    if (type != EQUALS) {
956        print_error("Bad format", token, type);
957        free_node(np);
958        return 0;
959    }
960    length = getoid(fp, SubOid, 32);
961    if (length > 1 && length <= 32) {
962        /* just take the last pair in the oid list */
963        if (SubOid[length - 2].label) {
964            strncpy(np->parent, SubOid[length - 2].label, 64);
965            np->parent[63] = '\0';
966        }
967        strncpy(np->label, name, sizeof(np->label));
968        np->label[sizeof(np->label) - 1] = '\0';
969        if (SubOid[length - 1].subid != -1)
970            np->subid = SubOid[length - 1].subid;
971        else
972            print_error("Warning: This entry is pretty silly", np->label, type);
973    } else {
974        print_error("No end to oid", (char *) NULL, type);
975        free_node(np);
976        np = 0;
977    }
978    /* free oid array */
979    for (count = 0; count < length; count++) {
980        if (SubOid[count].label)
981            xfree(SubOid[count].label);
982        SubOid[count].label = 0;
983    }
984    return np;
985}
986
987/*
988 * Parses a mib file and returns a linked list of nodes found in the file.
989 * Returns NULL on error.
990 */
991#if !TEST
992static
993#endif
994struct node *
995parse(FILE *fp) {
996    char token[64];
997    char name[64];
998    int type = 1;
999    struct node *np = NULL, *root = NULL;
1000
1001    hash_init();
1002
1003    while (type != ENDOFFILE) {
1004        type = get_token(fp, token);
1005        if (type != LABEL) {
1006            if (type == ENDOFFILE) {
1007                return root;
1008            }
1009            print_error(token, "is a reserved word", type);
1010            free_node_list(root);
1011            return NULL;
1012        }
1013        strncpy(name, token, 64);
1014        name[63] = '\0';
1015        type = get_token(fp, token);
1016        if (type == OBJTYPE) {
1017            if (root == NULL) {
1018                /* first link in chain */
1019                np = root = parse_objecttype(fp, name);
1020                if (np == NULL) {
1021                    print_error("Bad parse of object type", (char *) NULL, type);
1022                    return NULL;
1023                }
1024            } else {
1025                np->next = parse_objecttype(fp, name);
1026                if (np->next == NULL) {
1027                    print_error("Bad parse of objecttype", (char *) NULL, type);
1028                    free_node_list(root);
1029                    return NULL;
1030                }
1031            }
1032            /* now find end of chain */
1033            while (np->next)
1034                np = np->next;
1035        } else if (type == OBJID) {
1036            if (root == NULL) {
1037                /* first link in chain */
1038                np = root = parse_objectid(fp, name);
1039                if (np == NULL) {
1040                    print_error("Bad parse of object id", (char *) NULL, type);
1041                    return NULL;
1042                }
1043            } else {
1044                np->next = parse_objectid(fp, name);
1045                if (np->next == NULL) {
1046                    print_error("Bad parse of object type", (char *) NULL, type);
1047                    free_node_list(root);
1048                    return NULL;
1049                }
1050            }
1051            /* now find end of chain */
1052            while (np->next)
1053                np = np->next;
1054        } else if (type == EQUALS) {
1055            type = parse_asntype(fp);
1056        } else if (type == ENDOFFILE) {
1057            break;
1058        } else {
1059            print_error("Bad operator", (char *) NULL, type);
1060            free_node_list(root);
1061            return NULL;
1062        }
1063    }
1064#if TEST
1065    {
1066        struct enum_list *ep;
1067
1068        for (np = root; np; np = np->next) {
1069            printf("%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
1070                   np->type);
1071            if (np->enums) {
1072                printf("Enums: \n");
1073                for (ep = np->enums; ep; ep = ep->next) {
1074                    printf("%s(%d)\n", ep->label, ep->value);
1075                }
1076            }
1077        }
1078    }
1079#endif /* TEST */
1080    return root;
1081}
1082
1083struct snmp_mib_tree *
1084read_mib(char *filename) {
1085    FILE *fp;
1086    struct node *nodes;
1087    struct snmp_mib_tree *tree;
1088    char mbuf[256];
1089    char *p;
1090
1091    fp = fopen(filename, "r");
1092    if (fp == NULL) {
1093        snmplib_debug(1, "init_mib: %s: %s\n", filename, xstrerror());
1094        return (NULL);
1095    }
1096    mbuf[0] = '\0';
1097    while ((p = fgets(mbuf, 256, fp)) && strncmp(mbuf, "DUMMY",
1098            strlen("DUMMY")));
1099    if (!p) {
1100        snmplib_debug(0, "Bad MIB version or tag missing, install original!\n");
1101        fclose(fp);
1102        return NULL;
1103    }
1104    if (!strcmp(mbuf, "DUMMY")) {
1105        snmplib_debug(0, "You need to update your MIB!\n");
1106        fclose(fp);
1107        return NULL;
1108    }
1109    nodes = parse(fp);
1110    fclose(fp);
1111    if (!nodes) {
1112        snmplib_debug(0, "Mib table is bad.  Exiting\n");
1113        return NULL;
1114    }
1115    tree = build_tree(nodes);
1116    return (tree);
1117}
1118
Note: See TracBrowser for help on using the repository browser.