parse.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /***********************************************************
10  Copyright 1989 by Carnegie Mellon University
11 
12  All Rights Reserved
13 
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)
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 
277 
278 static void
280 {
281  int count;
282 
283  for (count = 0; count < 40; count++) {
284  switch (count) {
285  case OBJID:
286  translation_table[count] = TYPE_OBJID;
287  break;
288  case OCTETSTR:
290  break;
291  case INTEGER:
293  break;
294  case NETADDR:
296  break;
297  case IPADDR:
299  break;
300  case COUNTER:
302  break;
303  case GAUGE:
304  translation_table[count] = TYPE_GAUGE;
305  break;
306  case TIMETICKS:
308  break;
309  case SNMP_OPAQUE:
311  break;
312  case NUL:
313  translation_table[count] = TYPE_NULL;
314  break;
315  default:
316  translation_table[count] = TYPE_OTHER;
317  break;
318  }
319  }
320 }
321 
322 /*
323  * Find all the children of root in the list of nodes. Link them into the
324  * tree and out of the nodes list.
325  */
326 static void
327 do_subtree(struct snmp_mib_tree *root, struct node **nodes)
328 {
329  register struct snmp_mib_tree *tp;
330  struct snmp_mib_tree *peer = NULL;
331  register struct node *np = NULL, **headp = NULL;
332  struct node *oldnp = NULL, *child_list = NULL, *childp = NULL;
333  char *cp;
334  int hash;
335 
336  tp = root;
337  hash = 0;
338  for (cp = tp->label; *cp; cp++)
339  hash += *cp;
340  headp = &nbuckets[NBUCKET(hash)];
341  /*
342  * Search each of the nodes for one whose parent is root, and
343  * move each into a separate list.
344  */
345  for (np = *headp; np; np = np->next) {
346  if ((*tp->label != *np->parent) || strcmp(tp->label, np->parent)) {
347  if ((*tp->label == *np->label) && !strcmp(tp->label, np->label)) {
348  /* if there is another node with the same label, assume that
349  * any children after this point in the list belong to the other node.
350  * This adds some scoping to the table and allows vendors to
351  * reuse names such as "ip".
352  */
353  break;
354  }
355  oldnp = np;
356  } else {
357  if (child_list == NULL) {
358  child_list = childp = np; /* first entry in child list */
359  } else {
360  childp->next = np;
361  childp = np;
362  }
363  /* take this node out of the node list */
364  if (oldnp == NULL) {
365  *headp = np->next; /* fix root of node list */
366  } else {
367  oldnp->next = np->next; /* link around this node */
368  }
369  }
370  }
371  if (childp)
372  childp->next = 0; /* re-terminate list */
373  /*
374  * Take each element in the child list and place it into the tree.
375  */
376  for (np = child_list; np; np = np->next) {
377  tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree));
378  tp->parent = root;
379  tp->next_peer = NULL;
380  tp->child_list = NULL;
381  strcpy(tp->label, np->label);
382  tp->subid = np->subid;
383  tp->type = translation_table[np->type];
384  tp->enums = np->enums;
385  np->enums = NULL; /* so we don't free them later */
386  if (root->child_list == NULL) {
387  root->child_list = tp;
388  } else if (peer) {
389  peer->next_peer = tp;
390  }
391  peer = tp;
392  /* if (tp->type == TYPE_OTHER) */
393  do_subtree(tp, nodes); /* recurse on this child if it isn't an end node */
394  }
395  /* free all nodes that were copied into tree */
396  oldnp = NULL;
397  for (np = child_list; np; np = np->next) {
398  if (oldnp)
399  xfree(oldnp);
400  oldnp = np;
401  }
402  if (oldnp)
403  xfree(oldnp);
404 }
405 
406 static
407 struct snmp_mib_tree *
408 build_tree(struct node *nodes) {
409  struct node *np;
410  struct snmp_mib_tree *tp;
411  int bucket, nodes_left = 0;
412 
413  /* build root node */
414  tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree));
415  tp->parent = NULL;
416  tp->next_peer = NULL;
417  tp->child_list = NULL;
418  tp->enums = NULL;
419  strcpy(tp->label, "iso");
420  tp->subid = 1;
421  tp->type = 0;
423  /* grow tree from this root node */
424  init_node_hash(nodes);
425  /* XXX nodes isn't needed in do_subtree() ??? */
426  do_subtree(tp, &nodes);
427  /* If any nodes are left, the tree is probably inconsistent */
428  for (bucket = 0; bucket < NHASHSIZE; bucket++) {
429  if (nbuckets[bucket]) {
430  nodes_left = 1;
431  break;
432  }
433  }
434  if (nodes_left) {
435  snmplib_debug(0, "The mib description doesn't seem to be consistent.\n");
436  snmplib_debug(0, "Some nodes couldn't be linked under the \"iso\" tree.\n");
437  snmplib_debug(0, "these nodes are left:\n");
438  for (bucket = 0; bucket < NHASHSIZE; bucket++) {
439  for (np = nbuckets[bucket]; np; np = np->next)
440  snmplib_debug(5, "%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
441  np->type);
442  }
443  }
444  return tp;
445 }
446 
447 /*
448  * Parses a token from the file. The type of the token parsed is returned,
449  * and the text is placed in the string pointed to by token.
450  */
451 static char last = ' ';
452 
453 static int
454 get_token(register FILE *fp, register char *token)
455 {
456  register int ch;
457  register char *cp = token;
458  register int hash = 0;
459  register struct tok *tp;
460 
461  *cp = 0;
462  ch = (unsigned char)last;
463  /* skip all white space */
464  while (xisspace(ch) && ch != -1) {
465  ch = getc(fp);
466  if (ch == '\n')
467  Line++;
468  }
469  if (ch == -1)
470  return ENDOFFILE;
471 
472  /*
473  * Accumulate characters until end of token is found. Then attempt to match this
474  * token as a reserved word. If a match is found, return the type. Else it is
475  * a label.
476  */
477  do {
478  if (ch == '\n')
479  Line++;
480  if (xisspace(ch) || ch == '(' || ch == ')' ||
481  ch == '{' || ch == '}' || ch == ',' ||
482  ch == '"') {
483  if (!xisspace(ch) && *token == 0) {
484  hash += ch;
485  *cp++ = ch;
486  last = ' ';
487  } else {
488  last = ch;
489  }
490  *cp = '\0';
491 
492  for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
493  if ((tp->hash == hash) && (strcmp(tp->name, token) == 0))
494  break;
495  }
496  if (tp) {
497  if (tp->token == CONTINUE)
498  continue;
499  return (tp->token);
500  }
501  if (token[0] == '-' && token[1] == '-') {
502  /* strip comment */
503  while ((ch = getc(fp)) != -1)
504  if (ch == '\n') {
505  Line++;
506  break;
507  }
508  if (ch == -1)
509  return ENDOFFILE;
510  last = ch;
511  return get_token(fp, token);
512  }
513  for (cp = token; *cp; cp++)
514  if (!xisdigit(*cp))
515  return LABEL;
516  return NUMBER;
517  } else {
518  hash += ch;
519  *cp++ = ch;
520  if (ch == '\n')
521  Line++;
522  }
523 
524  } while ((ch = getc(fp)) != -1);
525  return ENDOFFILE;
526 }
527 
528 /*
529  * Takes a list of the form:
530  * { iso org(3) dod(6) 1 }
531  * and creates several nodes, one for each parent-child pair.
532  * Returns NULL on error.
533  * register struct subid *SubOid; an array of subids
534  * int length; the length of the array
535  */
536 static int
537 getoid(register FILE *fp, register struct subid *SubOid, int length)
538 {
539  register int count;
540  int type;
541  char token[128];
542  register char *cp;
543 
544  if ((type = get_token(fp, token)) != LEFTBRACKET) {
545  print_error("Expected \"{\"", token, type);
546  return 0;
547  }
548  type = get_token(fp, token);
549  for (count = 0; count < length; count++, SubOid++) {
550  SubOid->label = 0;
551  SubOid->subid = -1;
552  if (type == RIGHTBRACKET) {
553  return count;
554  } else if (type != LABEL && type != NUMBER) {
555  print_error("Not valid for object identifier", token, type);
556  return 0;
557  }
558  if (type == LABEL) {
559  /* this entry has a label */
560  cp = (char *) xmalloc((unsigned) strlen(token) + 1);
561  strcpy(cp, token);
562  SubOid->label = cp;
563  type = get_token(fp, token);
564  if (type == LEFTPAREN) {
565  type = get_token(fp, token);
566  if (type == NUMBER) {
567  SubOid->subid = atoi(token);
568  if ((type = get_token(fp, token)) != RIGHTPAREN) {
569  print_error("Unexpected a closing parenthesis", token, type);
570  return 0;
571  }
572  } else {
573  print_error("Expected a number", token, type);
574  return 0;
575  }
576  } else {
577  continue;
578  }
579  } else {
580  /* this entry has just an integer sub-identifier */
581  SubOid->subid = atoi(token);
582  }
583  type = get_token(fp, token);
584  }
585  return count;
586 
587 }
588 
589 static void
590 free_node(struct node *np)
591 {
592  struct enum_list *ep, *tep;
593 
594  ep = np->enums;
595  while (ep) {
596  tep = ep;
597  ep = ep->next;
598  xfree((char *) tep);
599  }
600  xfree((char *) np);
601 }
602 
603 static void
604 free_node_list(struct node *nl)
605 {
606  while (nl) {
607  struct node *t = nl->next;
608  free_node(nl);
609  nl = t;
610  }
611 }
612 
613 /*
614  * Parse an entry of the form:
615  * label OBJECT IDENTIFIER ::= { parent 2 }
616  * The "label OBJECT IDENTIFIER" portion has already been parsed.
617  * Returns 0 on error.
618  */
619 static struct node *
620 parse_objectid(FILE *fp, char *name) {
621  int type;
622  char token[64];
623  register int count;
624  register struct subid *op, *nop;
625  int length;
626  struct subid SubOid[32];
627  struct node *np, *root, *oldnp = NULL;
628 
629  type = get_token(fp, token);
630  if (type != EQUALS) {
631  print_error("Bad format", token, type);
632  return 0;
633  }
634  if ((length = getoid(fp, SubOid, 32)) != 0) {
635  np = root = (struct node *) xmalloc(sizeof(struct node));
636  memset((char *) np, '\0', sizeof(struct node));
637  /*
638  * For each parent-child subid pair in the subid array,
639  * create a node and link it into the node list.
640  */
641  for (count = 0, op = SubOid, nop = SubOid + 1; count < (length - 2); count++,
642  op++, nop++) {
643  /* every node must have parent's name and child's name or number */
644  if (op->label && (nop->label || (nop->subid != -1))) {
645  strncpy(np->parent, op->label, sizeof(np->parent) - 1);
646  if (nop->label)
647  strncpy(np->label, nop->label, sizeof(np->label) - 1);
648  if (nop->subid != -1)
649  np->subid = nop->subid;
650  np->type = 0;
651  np->enums = 0;
652  /* set up next entry */
653  np->next = (struct node *) xmalloc(sizeof(*np->next));
654  memset((char *) np->next, '\0', sizeof(struct node));
655  oldnp = np;
656  np = np->next;
657  }
658  }
659  np->next = (struct node *) NULL;
660  /*
661  * The above loop took care of all but the last pair. This pair is taken
662  * care of here. The name for this node is taken from the label for this
663  * entry.
664  * np still points to an unused entry.
665  */
666  if (count == (length - 2)) {
667  if (op->label) {
668  strncpy(np->parent, op->label, sizeof(np->parent)-1);
669  strncpy(np->label, name, sizeof(np->label)-1);
670  if (nop->subid != -1)
671  np->subid = nop->subid;
672  else
673  print_error("Warning: This entry is pretty silly", np->label, type);
674  } else {
675  free_node(np);
676  if (oldnp)
677  oldnp->next = NULL;
678  else {
679  free_node_list(root); // we need to clear the newly allocated list
680  return NULL;
681  }
682  }
683  } else {
684  print_error("Missing end of oid", (char *) NULL, type);
685  free_node_list(root); // we need to clear the newly allocated list
686  if (oldnp)
687  oldnp->next = NULL;
688  return NULL;
689  }
690  /* free the oid array */
691  for (count = 0, op = SubOid; count < length; count++, op++) {
692  if (op->label)
693  xfree(op->label);
694  op->label = 0;
695  }
696  return root;
697  } else {
698  print_error("Bad object identifier", (char *) NULL, type);
699  return 0;
700  }
701 }
702 
703 /*
704  * Parses an asn type. This structure is ignored by this parser.
705  * Returns NULL on error.
706  */
707 static int
708 parse_asntype(FILE *fp)
709 {
710  int type;
711  char token[64];
712 
713  type = get_token(fp, token);
714  if (type != SEQUENCE) {
715  print_error("Not a sequence", token, type); /* should we handle this */
716  return ENDOFFILE;
717  }
718  while ((type = get_token(fp, token)) != ENDOFFILE) {
719  if (type == RIGHTBRACKET)
720  return type;
721  }
722  print_error("Expected \"}\"", token, type);
723  return ENDOFFILE;
724 }
725 
726 /*
727  * Parses an OBJECT TYPE macro.
728  * Returns 0 on error.
729  */
730 static struct node *
731 parse_objecttype(register FILE *fp, char *name) {
732  register int type;
733  char token[64];
734  int count, length;
735  struct subid SubOid[32];
736  char syntax[64];
737  int nexttype;
738  char nexttoken[64];
739  register struct node *np = NULL;
740  register struct enum_list *ep = NULL;
741 
742  type = get_token(fp, token);
743  if (type != SYNTAX) {
744  print_error("Bad format for OBJECT TYPE", token, type);
745  return 0;
746  }
747  np = (struct node *) xmalloc(sizeof(struct node));
748  np->next = 0;
749  np->enums = 0;
750  type = get_token(fp, token);
751  nexttype = get_token(fp, nexttoken);
752  np->type = type;
753  switch (type) {
754  case SEQUENCE:
755  strcpy(syntax, token);
756  if (nexttype == OF) {
757  strcat(syntax, " ");
758  strcat(syntax, nexttoken);
759  nexttype = get_token(fp, nexttoken);
760  strcat(syntax, " ");
761  strcat(syntax, nexttoken);
762  nexttype = get_token(fp, nexttoken);
763  }
764  break;
765  case INTEGER:
766  strcpy(syntax, token);
767  if (nexttype == LEFTBRACKET) {
768  /* if there is an enumeration list, parse it */
769  while ((type = get_token(fp, token)) != ENDOFFILE) {
770  if (type == RIGHTBRACKET)
771  break;
772  if (type == LABEL) {
773  /* this is an enumerated label */
774  if (np->enums == 0) {
775  ep = np->enums = (struct enum_list *)
776  xmalloc(sizeof(struct enum_list));
777  } else {
778  ep->next = (struct enum_list *)
779  xmalloc(sizeof(struct enum_list));
780  ep = ep->next;
781  }
782  ep->next = 0;
783  /* a reasonable approximation for the length */
784  ep->label = (char *) xmalloc((unsigned) strlen(token) + 1);
785  strcpy(ep->label, token);
786  type = get_token(fp, token);
787  if (type != LEFTPAREN) {
788  print_error("Expected \"(\"", token, type);
789  free_node(np);
790  return 0;
791  }
792  type = get_token(fp, token);
793  if (type != NUMBER) {
794  print_error("Expected integer", token, type);
795  free_node(np);
796  return 0;
797  }
798  ep->value = atoi(token);
799  type = get_token(fp, token);
800  if (type != RIGHTPAREN) {
801  print_error("Expected \")\"", token, type);
802  free_node(np);
803  return 0;
804  }
805  }
806  }
807  if (type == ENDOFFILE) {
808  print_error("Expected \"}\"", token, type);
809  free_node(np);
810  return 0;
811  }
812  nexttype = get_token(fp, nexttoken);
813  } else if (nexttype == LEFTPAREN) {
814  /* ignore the "constrained integer" for now */
815  nexttype = get_token(fp, nexttoken);
816  nexttype = get_token(fp, nexttoken);
817  nexttype = get_token(fp, nexttoken);
818  }
819  break;
820  case OBJID:
821  case OCTETSTR:
822  case NETADDR:
823  case IPADDR:
824  case COUNTER:
825  case GAUGE:
826  case TIMETICKS:
827  case SNMP_OPAQUE:
828  case NUL:
829  case LABEL:
830  strcpy(syntax, token);
831  break;
832  default:
833  print_error("Bad syntax", token, type);
834  free_node(np);
835  return 0;
836  }
837  if (nexttype != ACCESS) {
838  print_error("Should be ACCESS", nexttoken, nexttype);
839  free_node(np);
840  return 0;
841  }
842  type = get_token(fp, token);
843  if (type != READONLY && type != READWRITE && type != WRITEONLY
844  && type != NOACCESS) {
845  print_error("Bad access type", nexttoken, nexttype);
846  free_node(np);
847  return 0;
848  }
849  type = get_token(fp, token);
850  if (type != SNMP_STATUS) {
851  print_error("Should be STATUS", token, nexttype);
852  free_node(np);
853  return 0;
854  }
855  type = get_token(fp, token);
856  if (type != MANDATORY && type != SNMP_OPTIONAL && type != OBSOLETE && type != RECOMMENDED) {
857  print_error("Bad status", token, type);
858  free_node(np);
859  return 0;
860  }
861  /* Fetch next token. Either:
862  *
863  * -> EQUALS (Old MIB format)
864  * -> DESCRIPTION, INDEX (New MIB format)
865  */
866  type = get_token(fp, token);
867  if ((type != DESCRIPTION) && (type != INDEX) && (type != EQUALS)) {
868  print_error("Should be DESCRIPTION, INDEX, or EQUALS", token, nexttype);
869  free_node(np);
870  return 0;
871  }
872  if (type == DESCRIPTION) {
873 
874  type = get_token(fp, token);
875  if (type != QUOTE) {
876  print_error("Should be Description open quote", token, nexttype);
877  free_node(np);
878  return 0;
879  }
880  /* Fetch description string */
881  {
882  int ReadChar;
883 
884  ReadChar = last;
885  /* skip everything until closing quote */
886  while ((ReadChar != '"') && (ReadChar != -1)) {
887  ReadChar = getc(fp);
888  if (ReadChar == '\n')
889  Line++;
890  }
891  last = ' ';
892  }
893  /* ASSERT: Done with description. */
894  type = get_token(fp, token);
895  }
896  if ((type != INDEX) && (type != EQUALS)) {
897  print_error("Should be INDEX, or EQUALS", token, nexttype);
898  free_node(np);
899  return 0;
900  }
901  if (type == INDEX) {
902 
903  /* Scarf INDEX */
904 
905  type = get_token(fp, token);
906  if (type != LEFTBRACKET) {
907  print_error("Should be INDEX left brace", token, type);
908  free_node(np);
909  return 0;
910  }
911  /* Fetch description string */
912  {
913  int ReadChar;
914 
915  ReadChar = last;
916  /* skip everything until closing quote */
917  while ((ReadChar != '}') && (ReadChar != -1)) {
918  ReadChar = getc(fp);
919  if (ReadChar == '\n')
920  Line++;
921  }
922  last = ' ';
923  }
924  /* ASSERT: Done with INDEX. */
925  type = get_token(fp, token);
926  }
927  if (type != EQUALS) {
928  print_error("Bad format", token, type);
929  free_node(np);
930  return 0;
931  }
932  length = getoid(fp, SubOid, 32);
933  if (length > 1 && length <= 32) {
934  /* just take the last pair in the oid list */
935  if (SubOid[length - 2].label) {
936  strncpy(np->parent, SubOid[length - 2].label, 64);
937  np->parent[63] = '\0';
938  }
939  strncpy(np->label, name, sizeof(np->label));
940  np->label[sizeof(np->label) - 1] = '\0';
941  if (SubOid[length - 1].subid != -1)
942  np->subid = SubOid[length - 1].subid;
943  else
944  print_error("Warning: This entry is pretty silly", np->label, type);
945  } else {
946  print_error("No end to oid", (char *) NULL, type);
947  free_node(np);
948  np = 0;
949  }
950  /* free oid array */
951  for (count = 0; count < length; count++) {
952  if (SubOid[count].label)
953  xfree(SubOid[count].label);
954  SubOid[count].label = 0;
955  }
956  return np;
957 }
958 
959 /*
960  * Parses a mib file and returns a linked list of nodes found in the file.
961  * Returns NULL on error.
962  */
963 static
964 struct node *
965 parse(FILE *fp) {
966  char token[64];
967  char name[64];
968  int type = 1;
969  struct node *np = NULL, *root = NULL;
970 
971  hash_init();
972 
973  while (type != ENDOFFILE) {
974  type = get_token(fp, token);
975  if (type != LABEL) {
976  if (type == ENDOFFILE) {
977  return root;
978  }
979  print_error(token, "is a reserved word", type);
980  free_node_list(root);
981  return NULL;
982  }
983  strncpy(name, token, 64);
984  name[63] = '\0';
985  type = get_token(fp, token);
986  if (type == OBJTYPE) {
987  if (root == NULL) {
988  /* first link in chain */
989  np = root = parse_objecttype(fp, name);
990  if (np == NULL) {
991  print_error("Bad parse of object type", (char *) NULL, type);
992  return NULL;
993  }
994  } else {
995  np->next = parse_objecttype(fp, name);
996  if (np->next == NULL) {
997  print_error("Bad parse of objecttype", (char *) NULL, type);
998  free_node_list(root);
999  return NULL;
1000  }
1001  }
1002  /* now find end of chain */
1003  while (np->next)
1004  np = np->next;
1005  } else if (type == OBJID) {
1006  if (root == NULL) {
1007  /* first link in chain */
1008  np = root = parse_objectid(fp, name);
1009  if (np == NULL) {
1010  print_error("Bad parse of object id", (char *) NULL, type);
1011  return NULL;
1012  }
1013  } else {
1014  np->next = parse_objectid(fp, name);
1015  if (np->next == NULL) {
1016  print_error("Bad parse of object type", (char *) NULL, type);
1017  free_node_list(root);
1018  return NULL;
1019  }
1020  }
1021  /* now find end of chain */
1022  while (np->next)
1023  np = np->next;
1024  } else if (type == EQUALS) {
1025  type = parse_asntype(fp);
1026  } else if (type == ENDOFFILE) {
1027  break;
1028  } else {
1029  print_error("Bad operator", (char *) NULL, type);
1030  free_node_list(root);
1031  return NULL;
1032  }
1033  }
1034  return root;
1035 }
1036 
1037 struct snmp_mib_tree *
1038 read_mib(char *filename) {
1039  FILE *fp;
1040  struct node *nodes;
1041  struct snmp_mib_tree *tree;
1042  char mbuf[256];
1043  char *p;
1044 
1045  fp = fopen(filename, "r");
1046  if (!fp) {
1047  int xerrno = errno;
1048  snmplib_debug(1, "init_mib: %s: %s\n", filename, xstrerr(xerrno));
1049  return (NULL);
1050  }
1051  mbuf[0] = '\0';
1052  while ((p = fgets(mbuf, 256, fp)) && strncmp(mbuf, "DUMMY",
1053  strlen("DUMMY")));
1054  if (!p) {
1055  snmplib_debug(0, "Bad MIB version or tag missing, install original!\n");
1056  fclose(fp);
1057  return NULL;
1058  }
1059  if (!strcmp(mbuf, "DUMMY")) {
1060  snmplib_debug(0, "You need to update your MIB!\n");
1061  fclose(fp);
1062  return NULL;
1063  }
1064  nodes = parse(fp);
1065  fclose(fp);
1066  if (!nodes) {
1067  snmplib_debug(0, "Mib table is bad. Exiting\n");
1068  return NULL;
1069  }
1070  tree = build_tree(nodes);
1071  return (tree);
1072 }
1073 
#define LEFTPAREN
Definition: parse.c:152
struct snmp_mib_tree * read_mib(char *filename)
Definition: parse.c:1038
const char * xstrerr(int error)
Definition: xstrerror.cc:83
Definition: parse.c:104
#define EQUALS
Definition: parse.c:148
#define NUL
Definition: parse.c:132
#define xmalloc
#define INDEX
Definition: parse.c:157
#define NBUCKET(x)
Definition: parse.c:242
int Line
Definition: parse.c:113
#define TYPE_OCTETSTR
Definition: parse.h:64
struct node * next
Definition: parse.c:105
#define WRITEONLY
Definition: parse.c:139
static struct node * parse_objectid(FILE *fp, char *name)
Definition: parse.c:620
#define TYPE_INTEGER
Definition: parse.h:65
#define LABEL
Definition: parse.c:118
char * label
Definition: parse.h:64
#define SNMP_OPAQUE
Definition: parse.c:131
#define GAUGE
Definition: parse.c:129
int hash
Definition: parse.c:164
#define OBJTYPE
Definition: parse.c:135
struct tok * next
Definition: parse.c:165
struct snmp_mib_tree * child_list
Definition: parse.h:51
static char last
Definition: parse.c:451
static struct node * parse(FILE *fp)
Definition: parse.c:965
#define TIMETICKS
Definition: parse.c:130
#define OBSOLETE
Definition: parse.c:145
#define COMMA
Definition: parse.c:154
static struct snmp_mib_tree * build_tree(struct node *nodes)
Definition: parse.c:408
const char * name
Definition: parse.c:161
#define TYPE_TIMETICKS
Definition: parse.h:70
struct tok tokens[]
Definition: parse.c:168
struct enum_list * enums
Definition: parse.h:57
#define NULL
Definition: types.h:145
static void free_node(struct node *np)
Definition: parse.c:590
#define TYPE_GAUGE
Definition: parse.h:69
static struct tok * buckets[HASHSIZE]
Definition: parse.c:219
#define ACCESS
Definition: parse.c:136
static void hash_init(void)
Definition: parse.c:222
char label[64]
Definition: parse.c:106
struct enum_list * next
Definition: parse.h:62
static void do_subtree(struct snmp_mib_tree *root, struct node **nodes)
Definition: parse.c:327
int subid
Definition: parse.c:117
static void init_node_hash(struct node *nodes)
Definition: parse.c:246
#define LEFTBRACKET
Definition: parse.c:150
char * label
Definition: parse.c:118
#define TYPE_OTHER
Definition: parse.h:62
#define NUMBER
Definition: parse.c:149
#define INTEGER
Definition: parse.c:125
struct snmp_mib_tree * parent
Definition: parse.h:53
struct enum_list * enums
Definition: parse.c:110
#define SYNTAX
Definition: parse.c:120
#define assert(EX)
Definition: assert.h:17
#define ENDOFFILE
Definition: parse.c:117
static int getoid(register FILE *fp, register struct subid *SubOid, int length)
Definition: parse.c:537
static int parse_asntype(FILE *fp)
Definition: parse.c:708
#define RIGHTBRACKET
Definition: parse.c:151
#define xisdigit(x)
Definition: xis.h:18
#define OCTETSTR
Definition: parse.c:123
u_int subid
Definition: parse.h:55
static void build_translation_table(void)
Definition: parse.c:279
#define TYPE_NULL
Definition: parse.h:72
static hash_table * hash
Definition: text_backend.cc:41
static void print_error(const char *string, const char *token, int type)
Definition: parse.c:265
#define xfree
int translation_table[40]
Definition: parse.c:276
#define TYPE_OBJID
Definition: parse.h:63
int value
Definition: parse.h:63
static int get_token(register FILE *fp, register char *token)
Definition: parse.c:454
#define DESCRIPTION
Definition: parse.c:156
#define NOACCESS
Definition: parse.c:141
char label[64]
Definition: parse.h:54
#define TYPE_COUNTER
Definition: parse.h:68
Definition: parse.c:160
Definition: parse.c:96
#define QUOTE
Definition: parse.c:158
#define OBJID
Definition: parse.c:122
#define IPADDR
Definition: parse.c:127
#define TYPE_OPAQUE
Definition: parse.h:71
static struct node * parse_objecttype(register FILE *fp, char *name)
Definition: parse.c:731
int len
Definition: parse.c:162
int type
Definition: parse.c:109
#define CONTINUE
Definition: parse.c:116
#define SNMP_OPTIONAL
Definition: parse.c:144
char parent[64]
Definition: parse.c:108
#define TYPE_IPADDR
Definition: parse.h:67
#define RECOMMENDED
Definition: parse.c:146
#define COUNTER
Definition: parse.c:128
int type
Definition: parse.h:56
#define NETADDR
Definition: parse.c:126
#define READONLY
Definition: parse.c:137
int token
Definition: parse.c:163
#define MANDATORY
Definition: parse.c:143
#define HASHSIZE
Definition: parse.c:216
#define xisspace(x)
Definition: xis.h:15
SQUIDCEXTERN void snmplib_debug(int, const char *,...) PRINTF_FORMAT_ARG2
Definition: snmplib_debug.c:21
u_int subid
Definition: parse.c:107
static void free_node_list(struct node *nl)
Definition: parse.c:604
#define RIGHTPAREN
Definition: parse.c:153
#define OF
Definition: parse.c:134
struct node * nbuckets[NHASHSIZE]
Definition: parse.c:243
struct snmp_mib_tree * next_peer
Definition: parse.h:52
#define BUCKET(x)
Definition: parse.c:217
#define SNMP_STATUS
Definition: parse.c:142
#define READWRITE
Definition: parse.c:138
#define NHASHSIZE
Definition: parse.c:241
#define SEQUENCE
Definition: parse.c:133

 

Introduction

Documentation

Support

Miscellaneous