]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/snmplib/parse.c
Source Format Enforcement (#763)
[thirdparty/squid.git] / lib / snmplib / parse.c
CommitLineData
c04fda28 1/*
f70aedc4 2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
c04fda28
AJ
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
85269fdf 9/***********************************************************
f53969cc 10 Copyright 1989 by Carnegie Mellon University
627f6d02 11
12 All Rights Reserved
13
26ac0430
AJ
14Permission to use, copy, modify, and distribute this software and its
15documentation for any purpose and without fee is hereby granted,
627f6d02 16provided that the above copyright notice appear in all copies and that
26ac0430 17both that copyright notice and this permission notice appear in
627f6d02 18supporting documentation, and that the name of CMU not be
19used in advertising or publicity pertaining to distribution of the
26ac0430 20software without specific, written prior permission.
627f6d02 21
22CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
23ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
24CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
25ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
26WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
27ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
28SOFTWARE.
29******************************************************************/
9aa84e04 30
f7f3304a 31#include "squid.h"
3d41e53a
FC
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"
9aa84e04 39
85269fdf 40#if HAVE_UNISTD_H
41#include <unistd.h>
9aa84e04 42#endif
85269fdf 43#if HAVE_STDLIB_H
44#include <stdlib.h>
9aa84e04 45#endif
46#if HAVE_SYS_TYPES_H
627f6d02 47#include <sys/types.h>
9aa84e04 48#endif
85269fdf 49#if HAVE_CTYPE_H
50#include <ctype.h>
627f6d02 51#endif
9aa84e04 52#if HAVE_GNUMALLOC_H
53#include <gnumalloc.h>
482aa790 54#elif HAVE_MALLOC_H
627f6d02 55#include <malloc.h>
9aa84e04 56#endif
85269fdf 57#if HAVE_MEMORY_H
58#include <memory.h>
59#endif
32d002cb 60#if HAVE_STRING_H
85269fdf 61#include <string.h>
62#endif
32d002cb 63#if HAVE_STRINGS_H
85269fdf 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
636cbcb8 84#if HAVE_ASSERT_H
85#include <assert.h>
86#endif
25f98340
AJ
87#if HAVE_ERRNO_H
88#include <errno.h>
89#endif
85269fdf 90
627f6d02 91/*
85269fdf 92 * This is one element of an object identifier with either an integer subidentifier,
93 * or a textual string label, or both.
627f6d02 94 * The subid is -1 if not present, and label is NULL if not present.
95 */
96struct subid {
97 int subid;
98 char *label;
99};
100
85269fdf 101/*
102 * A linked list of nodes.
103 */
104struct node {
105 struct node *next;
f53969cc
SM
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) */
85269fdf 111};
627f6d02 112
113int Line = 1;
114
85269fdf 115/* types of tokens */
f53969cc 116#define CONTINUE -1
627f6d02 117#define ENDOFFILE 0
f53969cc
SM
118#define LABEL 1
119#define SUBTREE 2
120#define SYNTAX 3
9fe245c5 121#undef OBJID
f53969cc 122#define OBJID 4
85269fdf 123#define OCTETSTR 5
9fe245c5 124#undef INTEGER
f53969cc
SM
125#define INTEGER 6
126#define NETADDR 7
127#define IPADDR 8
128#define COUNTER 9
129#define GAUGE 10
85269fdf 130#define TIMETICKS 11
f53969cc
SM
131#define SNMP_OPAQUE 12
132#define NUL 13
627f6d02 133#define SEQUENCE 14
f53969cc
SM
134#define OF 15 /* SEQUENCE OF */
135#define OBJTYPE 16
136#define ACCESS 17
627f6d02 137#define READONLY 18
138#define READWRITE 19
f53969cc 139#define WRITEONLY 20
9fe245c5 140#undef NOACCESS
627f6d02 141#define NOACCESS 21
137a13ea 142#define SNMP_STATUS 22
627f6d02 143#define MANDATORY 23
29f69185 144#define SNMP_OPTIONAL 24
627f6d02 145#define OBSOLETE 25
85269fdf 146#define RECOMMENDED 26
f53969cc
SM
147#define PUNCT 27
148#define EQUALS 28
149#define NUMBER 29
627f6d02 150#define LEFTBRACKET 30
151#define RIGHTBRACKET 31
f53969cc 152#define LEFTPAREN 32
627f6d02 153#define RIGHTPAREN 33
f53969cc 154#define COMMA 34
85269fdf 155/* For SNMPv2 SMI pseudo-compliance */
627f6d02 156#define DESCRIPTION 35
85269fdf 157#define INDEX 36
158#define QUOTE 37
627f6d02 159
160struct tok {
f53969cc
SM
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 */
627f6d02 166};
167
26ac0430 168struct tok tokens[] = {
43d4303e 169 {"obsolete", sizeof("obsolete") - 1, OBSOLETE},
29f69185 170 {"Opaque", sizeof("Opaque") - 1, SNMP_OPAQUE},
43d4303e 171 {"recommended", sizeof("recommended") - 1, RECOMMENDED},
29f69185 172 {"optional", sizeof("optional") - 1, SNMP_OPTIONAL},
43d4303e 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},
26ac0430
AJ
180 /*
181 * This CONTINUE appends the next word onto OBJECT,
182 * hopefully matching OBJECTIDENTIFIER above.
183 */
43d4303e 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},
137a13ea 198 {"STATUS", sizeof("STATUS") - 1, SNMP_STATUS},
43d4303e 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},
26ac0430 211 /* Hacks for easier MIBFILE coercing */
43d4303e 212 {"read-create", sizeof("read-create") - 1, READWRITE},
213 {NULL}
627f6d02 214};
215
f53969cc
SM
216#define HASHSIZE 32
217#define BUCKET(x) (x & 0x01F)
627f6d02 218
43d4303e 219static struct tok *buckets[HASHSIZE];
627f6d02 220
221static void
5c52f59a 222hash_init(void)
627f6d02 223{
43d4303e 224 register struct tok *tp;
5c52f59a 225 register const char *cp;
43d4303e 226 register int h;
227 register int b;
228
229 memset((char *) buckets, '\0', sizeof(buckets));
230 for (tp = tokens; tp->name; tp++) {
26ac0430
AJ
231 for (h = 0, cp = tp->name; *cp; cp++)
232 h += *cp;
233 tp->hash = h;
234 b = BUCKET(h);
235 if (buckets[b])
f53969cc 236 tp->next = buckets[b]; /* BUG ??? */
26ac0430 237 buckets[b] = tp;
43d4303e 238 }
627f6d02 239}
240
241#define NHASHSIZE 128
242#define NBUCKET(x) (x & 0x7F)
243struct node *nbuckets[NHASHSIZE];
244
80047df2 245static void
5c52f59a 246init_node_hash(struct node *nodes)
627f6d02 247{
43d4303e 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;) {
26ac0430
AJ
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;
43d4303e 261 }
627f6d02 262}
263
627f6d02 264static void
5c52f59a 265print_error(const char *string, const char *token, int type)
627f6d02 266{
636cbcb8 267 assert(string != NULL);
636cbcb8 268 if (type == ENDOFFILE)
26ac0430 269 snmplib_debug(0, "%s(EOF): On or around line %d\n", string, Line);
627f6d02 270 else if (token)
26ac0430 271 snmplib_debug(0, "%s(%s): On or around line %d\n", string, token, Line);
627f6d02 272 else
26ac0430 273 snmplib_debug(0, "%s: On or around line %d\n", string, Line);
627f6d02 274}
275
32d002cb 276#if TEST
85269fdf 277print_subtree(tree, count)
26ac0430
AJ
278struct snmp_mib_tree *tree;
279int count;
627f6d02 280{
85269fdf 281 struct snmp_mib_tree *tp;
627f6d02 282 int i;
283
43d4303e 284 for (i = 0; i < count; i++)
26ac0430 285 printf(" ");
627f6d02 286 printf("Children of %s:\n", tree->label);
287 count++;
43d4303e 288 for (tp = tree->child_list; tp; tp = tp->next_peer) {
26ac0430
AJ
289 for (i = 0; i < count; i++)
290 printf(" ");
291 printf("%s\n", tp->label);
627f6d02 292 }
43d4303e 293 for (tp = tree->child_list; tp; tp = tp->next_peer) {
26ac0430 294 print_subtree(tp, count);
627f6d02 295 }
296}
297#endif /* TEST */
298
85269fdf 299int translation_table[40];
627f6d02 300
80047df2 301static void
5c52f59a 302build_translation_table(void)
43d4303e 303{
627f6d02 304 int count;
305
43d4303e 306 for (count = 0; count < 40; count++) {
26ac0430
AJ
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 }
627f6d02 342 }
627f6d02 343}
344
345/*
346 * Find all the children of root in the list of nodes. Link them into the
347 * tree and out of the nodes list.
348 */
349static void
5c52f59a 350do_subtree(struct snmp_mib_tree *root, struct node **nodes)
627f6d02 351{
85269fdf 352 register struct snmp_mib_tree *tp;
353 struct snmp_mib_tree *peer = NULL;
43d4303e 354 register struct node *np = NULL, **headp = NULL;
627f6d02 355 struct node *oldnp = NULL, *child_list = NULL, *childp = NULL;
356 char *cp;
357 int hash;
43d4303e 358
627f6d02 359 tp = root;
360 hash = 0;
43d4303e 361 for (cp = tp->label; *cp; cp++)
26ac0430 362 hash += *cp;
627f6d02 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 */
43d4303e 368 for (np = *headp; np; np = np->next) {
26ac0430
AJ
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) {
f53969cc 381 child_list = childp = np; /* first entry in child list */
26ac0430
AJ
382 } else {
383 childp->next = np;
384 childp = np;
385 }
386 /* take this node out of the node list */
387 if (oldnp == NULL) {
f53969cc 388 *headp = np->next; /* fix root of node list */
26ac0430 389 } else {
f53969cc 390 oldnp->next = np->next; /* link around this node */
26ac0430
AJ
391 }
392 }
627f6d02 393 }
394 if (childp)
f53969cc 395 childp->next = 0; /* re-terminate list */
627f6d02 396 /*
397 * Take each element in the child list and place it into the tree.
398 */
43d4303e 399 for (np = child_list; np; np = np->next) {
26ac0430
AJ
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;
f53969cc 408 np->enums = NULL; /* so we don't free them later */
26ac0430
AJ
409 if (root->child_list == NULL) {
410 root->child_list = tp;
2082bd1c 411 } else if (peer) {
26ac0430
AJ
412 peer->next_peer = tp;
413 }
414 peer = tp;
415 /* if (tp->type == TYPE_OTHER) */
f53969cc 416 do_subtree(tp, nodes); /* recurse on this child if it isn't an end node */
627f6d02 417 }
418 /* free all nodes that were copied into tree */
419 oldnp = NULL;
43d4303e 420 for (np = child_list; np; np = np->next) {
26ac0430
AJ
421 if (oldnp)
422 xfree(oldnp);
423 oldnp = np;
627f6d02 424 }
425 if (oldnp)
26ac0430 426 xfree(oldnp);
627f6d02 427}
428
32d002cb 429#if !TEST
85269fdf 430static
431#endif
432struct snmp_mib_tree *
e1381638 433build_tree(struct node *nodes) {
85269fdf 434 struct node *np;
435 struct snmp_mib_tree *tp;
436 int bucket, nodes_left = 0;
43d4303e 437
85269fdf 438 /* build root node */
43d4303e 439 tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree));
85269fdf 440 tp->parent = NULL;
441 tp->next_peer = NULL;
442 tp->child_list = NULL;
443 tp->enums = NULL;
444 strcpy(tp->label, "iso");
445 tp->subid = 1;
446 tp->type = 0;
447 build_translation_table();
448 /* grow tree from this root node */
449 init_node_hash(nodes);
450 /* XXX nodes isn't needed in do_subtree() ??? */
451 do_subtree(tp, &nodes);
32d002cb 452#if TEST
85269fdf 453 print_subtree(tp, 0);
454#endif /* TEST */
455 /* If any nodes are left, the tree is probably inconsistent */
43d4303e 456 for (bucket = 0; bucket < NHASHSIZE; bucket++) {
26ac0430
AJ
457 if (nbuckets[bucket]) {
458 nodes_left = 1;
459 break;
460 }
85269fdf 461 }
43d4303e 462 if (nodes_left) {
26ac0430
AJ
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 }
85269fdf 471 }
472 return tp;
473}
474
85269fdf 475/*
476 * Parses a token from the file. The type of the token parsed is returned,
477 * and the text is placed in the string pointed to by token.
478 */
479static char last = ' ';
480
481static int
5c52f59a 482get_token(register FILE *fp, register char *token)
85269fdf 483{
484 register int ch;
485 register char *cp = token;
486 register int hash = 0;
487 register struct tok *tp;
488
489 *cp = 0;
ec451a0f 490 ch = (unsigned char)last;
85269fdf 491 /* skip all white space */
ec451a0f 492 while (xisspace(ch) && ch != -1) {
26ac0430
AJ
493 ch = getc(fp);
494 if (ch == '\n')
495 Line++;
85269fdf 496 }
497 if (ch == -1)
26ac0430 498 return ENDOFFILE;
85269fdf 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 {
26ac0430
AJ
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 }
43d4303e 551
85269fdf 552 } while ((ch = getc(fp)) != -1);
553 return ENDOFFILE;
554}
627f6d02 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.
f53969cc
SM
561 * register struct subid *SubOid; an array of subids
562 * int length; the length of the array
627f6d02 563 */
564static int
5c52f59a 565getoid(register FILE *fp, register struct subid *SubOid, int length)
627f6d02 566{
85269fdf 567 register int count;
627f6d02 568 int type;
85269fdf 569 char token[128];
570 register char *cp;
627f6d02 571
43d4303e 572 if ((type = get_token(fp, token)) != LEFTBRACKET) {
26ac0430
AJ
573 print_error("Expected \"{\"", token, type);
574 return 0;
627f6d02 575 }
576 type = get_token(fp, token);
43d4303e 577 for (count = 0; count < length; count++, SubOid++) {
26ac0430
AJ
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);
627f6d02 612 }
613 return count;
614
627f6d02 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
2082bd1c
TH
631static void
632free_node_list(struct node *nl)
633{
634 while (nl) {
635 struct node *t = nl->next;
636 free_node(nl);
637 nl = t;
638 }
639}
640
627f6d02 641/*
642 * Parse an entry of the form:
643 * label OBJECT IDENTIFIER ::= { parent 2 }
644 * The "label OBJECT IDENTIFIER" portion has already been parsed.
645 * Returns 0 on error.
646 */
647static struct node *
e1381638 648parse_objectid(FILE *fp, char *name) {
627f6d02 649 int type;
85269fdf 650 char token[64];
651 register int count;
652 register struct subid *op, *nop;
627f6d02 653 int length;
85269fdf 654 struct subid SubOid[32];
627f6d02 655 struct node *np, *root, *oldnp = NULL;
656
657 type = get_token(fp, token);
43d4303e 658 if (type != EQUALS) {
26ac0430
AJ
659 print_error("Bad format", token, type);
660 return 0;
627f6d02 661 }
43d4303e 662 if ((length = getoid(fp, SubOid, 32)) != 0) {
26ac0430
AJ
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))) {
2082bd1c 673 strncpy(np->parent, op->label, sizeof(np->parent) - 1);
26ac0430 674 if (nop->label)
2082bd1c 675 strncpy(np->label, nop->label, sizeof(np->label) - 1);
26ac0430
AJ
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) {
268421d1
AJ
696 strncpy(np->parent, op->label, sizeof(np->parent)-1);
697 strncpy(np->label, name, sizeof(np->label)-1);
26ac0430
AJ
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;
2082bd1c
TH
706 else {
707 free_node_list(root); // we need to clear the newly allocated list
26ac0430 708 return NULL;
2082bd1c 709 }
26ac0430
AJ
710 }
711 } else {
712 print_error("Missing end of oid", (char *) NULL, type);
2082bd1c 713 free_node_list(root); // we need to clear the newly allocated list
26ac0430
AJ
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;
627f6d02 725 } else {
26ac0430
AJ
726 print_error("Bad object identifier", (char *) NULL, type);
727 return 0;
627f6d02 728 }
729}
730
85269fdf 731/*
732 * Parses an asn type. This structure is ignored by this parser.
733 * Returns NULL on error.
734 */
627f6d02 735static int
5c52f59a 736parse_asntype(FILE *fp)
627f6d02 737{
85269fdf 738 int type;
739 char token[64];
627f6d02 740
85269fdf 741 type = get_token(fp, token);
43d4303e 742 if (type != SEQUENCE) {
f53969cc 743 print_error("Not a sequence", token, type); /* should we handle this */
26ac0430 744 return ENDOFFILE;
627f6d02 745 }
43d4303e 746 while ((type = get_token(fp, token)) != ENDOFFILE) {
26ac0430
AJ
747 if (type == RIGHTBRACKET)
748 return type;
85269fdf 749 }
750 print_error("Expected \"}\"", token, type);
751 return ENDOFFILE;
627f6d02 752}
753
754/*
85269fdf 755 * Parses an OBJECT TYPE macro.
756 * Returns 0 on error.
627f6d02 757 */
85269fdf 758static struct node *
e1381638 759parse_objecttype(register FILE *fp, char *name) {
85269fdf 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];
43d4303e 767 register struct node *np = NULL;
768 register struct enum_list *ep = NULL;
da2d50d1 769
627f6d02 770 type = get_token(fp, token);
43d4303e 771 if (type != SYNTAX) {
26ac0430
AJ
772 print_error("Bad format for OBJECT TYPE", token, type);
773 return 0;
627f6d02 774 }
43d4303e 775 np = (struct node *) xmalloc(sizeof(struct node));
627f6d02 776 np->next = 0;
777 np->enums = 0;
627f6d02 778 type = get_token(fp, token);
627f6d02 779 nexttype = get_token(fp, nexttoken);
85269fdf 780 np->type = type;
43d4303e 781 switch (type) {
782 case SEQUENCE:
26ac0430
AJ
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;
43d4303e 793 case INTEGER:
26ac0430
AJ
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;
43d4303e 848 case OBJID:
849 case OCTETSTR:
850 case NETADDR:
851 case IPADDR:
852 case COUNTER:
853 case GAUGE:
854 case TIMETICKS:
29f69185 855 case SNMP_OPAQUE:
43d4303e 856 case NUL:
857 case LABEL:
26ac0430
AJ
858 strcpy(syntax, token);
859 break;
43d4303e 860 default:
26ac0430
AJ
861 print_error("Bad syntax", token, type);
862 free_node(np);
863 return 0;
627f6d02 864 }
43d4303e 865 if (nexttype != ACCESS) {
26ac0430
AJ
866 print_error("Should be ACCESS", nexttoken, nexttype);
867 free_node(np);
868 return 0;
627f6d02 869 }
870 type = get_token(fp, token);
871 if (type != READONLY && type != READWRITE && type != WRITEONLY
26ac0430
AJ
872 && type != NOACCESS) {
873 print_error("Bad access type", nexttoken, nexttype);
874 free_node(np);
875 return 0;
627f6d02 876 }
877 type = get_token(fp, token);
137a13ea 878 if (type != SNMP_STATUS) {
26ac0430
AJ
879 print_error("Should be STATUS", token, nexttype);
880 free_node(np);
881 return 0;
627f6d02 882 }
883 type = get_token(fp, token);
29f69185 884 if (type != MANDATORY && type != SNMP_OPTIONAL && type != OBSOLETE && type != RECOMMENDED) {
26ac0430
AJ
885 print_error("Bad status", token, type);
886 free_node(np);
887 return 0;
627f6d02 888 }
85269fdf 889 /* Fetch next token. Either:
890 *
891 * -> EQUALS (Old MIB format)
892 * -> DESCRIPTION, INDEX (New MIB format)
627f6d02 893 */
894 type = get_token(fp, token);
85269fdf 895 if ((type != DESCRIPTION) && (type != INDEX) && (type != EQUALS)) {
26ac0430
AJ
896 print_error("Should be DESCRIPTION, INDEX, or EQUALS", token, nexttype);
897 free_node(np);
898 return 0;
43d4303e 899 }
900 if (type == DESCRIPTION) {
627f6d02 901
26ac0430
AJ
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);
627f6d02 923 }
85269fdf 924 if ((type != INDEX) && (type != EQUALS)) {
26ac0430
AJ
925 print_error("Should be INDEX, or EQUALS", token, nexttype);
926 free_node(np);
927 return 0;
43d4303e 928 }
929 if (type == INDEX) {
627f6d02 930
26ac0430
AJ
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);
627f6d02 954 }
43d4303e 955 if (type != EQUALS) {
26ac0430
AJ
956 print_error("Bad format", token, type);
957 free_node(np);
958 return 0;
627f6d02 959 }
85269fdf 960 length = getoid(fp, SubOid, 32);
43d4303e 961 if (length > 1 && length <= 32) {
26ac0430 962 /* just take the last pair in the oid list */
2082bd1c 963 if (SubOid[length - 2].label) {
26ac0430 964 strncpy(np->parent, SubOid[length - 2].label, 64);
2082bd1c
TH
965 np->parent[63] = '\0';
966 }
967 strncpy(np->label, name, sizeof(np->label));
968 np->label[sizeof(np->label) - 1] = '\0';
26ac0430
AJ
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);
627f6d02 973 } else {
26ac0430
AJ
974 print_error("No end to oid", (char *) NULL, type);
975 free_node(np);
976 np = 0;
627f6d02 977 }
978 /* free oid array */
43d4303e 979 for (count = 0; count < length; count++) {
26ac0430
AJ
980 if (SubOid[count].label)
981 xfree(SubOid[count].label);
982 SubOid[count].label = 0;
627f6d02 983 }
984 return np;
985}
986
627f6d02 987/*
988 * Parses a mib file and returns a linked list of nodes found in the file.
989 * Returns NULL on error.
990 */
32d002cb 991#if !TEST
85269fdf 992static
993#endif
994struct node *
e1381638 995parse(FILE *fp) {
85269fdf 996 char token[64];
997 char name[64];
43d4303e 998 int type = 1;
999 struct node *np = NULL, *root = NULL;
627f6d02 1000
1001 hash_init();
627f6d02 1002
43d4303e 1003 while (type != ENDOFFILE) {
26ac0430
AJ
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);
2082bd1c 1010 free_node_list(root);
26ac0430
AJ
1011 return NULL;
1012 }
1013 strncpy(name, token, 64);
85494816 1014 name[63] = '\0';
26ac0430
AJ
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);
2082bd1c 1028 free_node_list(root);
26ac0430
AJ
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);
2082bd1c 1047 free_node_list(root);
26ac0430
AJ
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);
2082bd1c 1060 free_node_list(root);
26ac0430
AJ
1061 return NULL;
1062 }
627f6d02 1063 }
32d002cb 1064#if TEST
43d4303e 1065 {
26ac0430
AJ
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 }
627f6d02 1078 }
627f6d02 1079#endif /* TEST */
1080 return root;
1081}
1082
85269fdf 1083struct snmp_mib_tree *
e1381638 1084read_mib(char *filename) {
627f6d02 1085 FILE *fp;
1086 struct node *nodes;
85269fdf 1087 struct snmp_mib_tree *tree;
f658b0cc 1088 char mbuf[256];
1089 char *p;
627f6d02 1090
1091 fp = fopen(filename, "r");
b69e9ffa
AJ
1092 if (!fp) {
1093 int xerrno = errno;
1094 snmplib_debug(1, "init_mib: %s: %s\n", filename, xstrerr(xerrno));
26ac0430 1095 return (NULL);
1f0e06c4 1096 }
43d4303e 1097 mbuf[0] = '\0';
019d3d4d 1098 while ((p = fgets(mbuf, 256, fp)) && strncmp(mbuf, "DUMMY",
26ac0430 1099 strlen("DUMMY")));
f658b0cc 1100 if (!p) {
26ac0430 1101 snmplib_debug(0, "Bad MIB version or tag missing, install original!\n");
2082bd1c 1102 fclose(fp);
26ac0430 1103 return NULL;
f658b0cc 1104 }
019d3d4d 1105 if (!strcmp(mbuf, "DUMMY")) {
26ac0430 1106 snmplib_debug(0, "You need to update your MIB!\n");
2082bd1c 1107 fclose(fp);
26ac0430 1108 return NULL;
f658b0cc 1109 }
627f6d02 1110 nodes = parse(fp);
2082bd1c 1111 fclose(fp);
43d4303e 1112 if (!nodes) {
26ac0430
AJ
1113 snmplib_debug(0, "Mib table is bad. Exiting\n");
1114 return NULL;
627f6d02 1115 }
1116 tree = build_tree(nodes);
43d4303e 1117 return (tree);
627f6d02 1118}
f53969cc 1119