parse.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:27k
源码类别:

代理服务器

开发平台:

Unix_Linux

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