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