parse.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 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 
14 Permission to use, copy, modify, and distribute this software and its
15 documentation for any purpose and without fee is hereby granted,
16 provided that the above copyright notice appear in all copies and that
17 both that copyright notice and this permission notice appear in
18 supporting documentation, and that the name of CMU not be
19 used in advertising or publicity pertaining to distribution of the
20 software without specific, written prior permission.
21 
22 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
23 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
24 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
25 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
26 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
27 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
28 SOFTWARE.
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  */
96 struct subid {
97  int subid;
98  char *label;
99 };
100 
101 /*
102  * A linked list of nodes.
103  */
104 struct 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 
113 int 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 
160 struct 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 
168 struct 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 
219 static struct tok *buckets[HASHSIZE];
220 
221 static 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)
243 struct node *nbuckets[NHASHSIZE];
244 
245 static void
246 init_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 
264 static void
265 print_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
277 print_subtree(tree, count)
278 struct snmp_mib_tree *tree;
279 int 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 
299 int translation_table[40];
300 
301 static 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  */
349 static void
350 do_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
430 static
431 #endif
432 struct snmp_mib_tree *
433 build_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;
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  */
479 static char last = ' ';
480 
481 static int
482 get_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  */
564 static int
565 getoid(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 
617 static void
618 free_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 
631 static void
632 free_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  */
647 static struct node *
648 parse_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  */
735 static int
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  */
758 static struct node *
759 parse_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
992 static
993 #endif
994 struct node *
995 parse(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 
1083 struct snmp_mib_tree *
1084 read_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) {
1093  int xerrno = errno;
1094  snmplib_debug(1, "init_mib: %s: %s\n", filename, xstrerr(xerrno));
1095  return (NULL);
1096  }
1097  mbuf[0] = '\0';
1098  while ((p = fgets(mbuf, 256, fp)) && strncmp(mbuf, "DUMMY",
1099  strlen("DUMMY")));
1100  if (!p) {
1101  snmplib_debug(0, "Bad MIB version or tag missing, install original!\n");
1102  fclose(fp);
1103  return NULL;
1104  }
1105  if (!strcmp(mbuf, "DUMMY")) {
1106  snmplib_debug(0, "You need to update your MIB!\n");
1107  fclose(fp);
1108  return NULL;
1109  }
1110  nodes = parse(fp);
1111  fclose(fp);
1112  if (!nodes) {
1113  snmplib_debug(0, "Mib table is bad. Exiting\n");
1114  return NULL;
1115  }
1116  tree = build_tree(nodes);
1117  return (tree);
1118 }
1119 
static struct snmp_mib_tree * build_tree(struct node *nodes)
Definition: parse.c:433
#define SNMP_STATUS
Definition: parse.c:142
#define SNMP_OPAQUE
Definition: parse.c:131
#define assert(EX)
Definition: assert.h:17
char parent[64]
Definition: parse.c:108
int token
Definition: parse.c:163
#define ACCESS
Definition: parse.c:136
SQUIDCEXTERN void snmplib_debug(int, const char *,...) PRINTF_FORMAT_ARG2
Definition: snmplib_debug.c:21
#define NUMBER
Definition: parse.c:149
int value
Definition: parse.h:43
int type
Definition: errorpage.cc:79
int len
Definition: parse.c:162
#define RIGHTBRACKET
Definition: parse.c:151
#define NOACCESS
Definition: parse.c:141
#define INDEX
Definition: parse.c:157
int Line
Definition: parse.c:113
static void init_node_hash(struct node *nodes)
Definition: parse.c:246
int i
Definition: membanger.c:49
#define MANDATORY
Definition: parse.c:143
static struct node * parse(FILE *fp)
Definition: parse.c:995
#define OBJID
Definition: parse.c:122
static char last
Definition: parse.c:479
static int parse_asntype(FILE *fp)
Definition: parse.c:736
struct tok * next
Definition: parse.c:165
#define NETADDR
Definition: parse.c:126
#define WRITEONLY
Definition: parse.c:139
static int getoid(register FILE *fp, register struct subid *SubOid, int length)
Definition: parse.c:565
#define TYPE_IPADDR
Definition: parse.h:67
#define NHASHSIZE
Definition: parse.c:241
u_int subid
Definition: parse.c:107
#define xisspace(x)
Definition: xis.h:17
char * p
Definition: membanger.c:43
char mbuf[256]
Definition: membanger.c:41
static void hash_init(void)
Definition: parse.c:222
#define RECOMMENDED
Definition: parse.c:146
static struct node * parse_objecttype(register FILE *fp, char *name)
Definition: parse.c:759
#define HASHSIZE
Definition: parse.c:216
#define READWRITE
Definition: parse.c:138
#define TYPE_TIMETICKS
Definition: parse.h:70
struct snmp_mib_tree * next_peer
Definition: parse.h:52
static void build_translation_table(void)
Definition: parse.c:302
const char * xstrerr(int error)
Definition: xstrerror.cc:83
#define SEQUENCE
Definition: parse.c:133
struct enum_list * enums
Definition: parse.h:57
Definition: parse.c:104
#define COUNTER
Definition: parse.c:128
struct enum_list * enums
Definition: parse.c:110
int subid
Definition: parse.c:97
#define NBUCKET(x)
Definition: parse.c:242
#define TYPE_OTHER
Definition: parse.h:62
static hash_table * hash
Definition: text_backend.cc:41
#define TYPE_INTEGER
Definition: parse.h:65
#define TYPE_OPAQUE
Definition: parse.h:71
FILE * fp
Definition: membanger.c:35
char label[64]
Definition: parse.c:106
static struct node * parse_objectid(FILE *fp, char *name)
Definition: parse.c:648
u_int subid
Definition: parse.h:55
#define EQUALS
Definition: parse.c:148
#define LEFTPAREN
Definition: parse.c:152
char * label
Definition: parse.c:98
struct snmp_mib_tree * read_mib(char *filename)
Definition: parse.c:1084
Definition: parse.c:160
#define COMMA
Definition: parse.c:154
int type
Definition: parse.h:56
#define OF
Definition: parse.c:134
#define RIGHTPAREN
Definition: parse.c:153
char label[64]
Definition: parse.h:54
#define NUL
Definition: parse.c:132
#define BUCKET(x)
Definition: parse.c:217
static void do_subtree(struct snmp_mib_tree *root, struct node **nodes)
Definition: parse.c:350
#define TYPE_NULL
Definition: parse.h:72
#define OCTETSTR
Definition: parse.c:123
#define INTEGER
Definition: parse.c:125
static void print_error(const char *string, const char *token, int type)
Definition: parse.c:265
#define xmalloc
#define LEFTBRACKET
Definition: parse.c:150
#define TYPE_OCTETSTR
Definition: parse.h:64
#define xisdigit(x)
Definition: xis.h:20
static void free_node(struct node *np)
Definition: parse.c:618
#define CONTINUE
Definition: parse.c:116
struct snmp_mib_tree * parent
Definition: parse.h:53
#define DESCRIPTION
Definition: parse.c:156
char * label
Definition: parse.h:44
const char * name
Definition: parse.c:161
struct node * next
Definition: parse.c:105
#define LABEL
Definition: parse.c:118
#define IPADDR
Definition: parse.c:127
#define ENDOFFILE
Definition: parse.c:117
#define TYPE_OBJID
Definition: parse.h:63
int type
Definition: parse.c:109
#define OBSOLETE
Definition: parse.c:145
int hash
Definition: parse.c:164
static void free_node_list(struct node *nl)
Definition: parse.c:632
struct snmp_mib_tree * child_list
Definition: parse.h:51
#define TIMETICKS
Definition: parse.c:130
Definition: parse.c:96
#define xfree
#define TYPE_GAUGE
Definition: parse.h:69
#define READONLY
Definition: parse.c:137
struct enum_list * next
Definition: parse.h:42
#define GAUGE
Definition: parse.c:129
#define QUOTE
Definition: parse.c:158
static int get_token(register FILE *fp, register char *token)
Definition: parse.c:482
#define NULL
Definition: types.h:166
#define SNMP_OPTIONAL
Definition: parse.c:144
#define SYNTAX
Definition: parse.c:120
#define OBJTYPE
Definition: parse.c:135
#define TYPE_COUNTER
Definition: parse.h:68

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors