]>
Commit | Line | Data |
---|---|---|
85269fdf | 1 | /*********************************************************** |
2 | Copyright 1989 by Carnegie Mellon University | |
627f6d02 | 3 | |
4 | All Rights Reserved | |
5 | ||
26ac0430 AJ |
6 | Permission to use, copy, modify, and distribute this software and its |
7 | documentation for any purpose and without fee is hereby granted, | |
627f6d02 | 8 | provided that the above copyright notice appear in all copies and that |
26ac0430 | 9 | both that copyright notice and this permission notice appear in |
627f6d02 | 10 | supporting documentation, and that the name of CMU not be |
11 | used in advertising or publicity pertaining to distribution of the | |
26ac0430 | 12 | software without specific, written prior permission. |
627f6d02 | 13 | |
14 | CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
15 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
16 | CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
17 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
18 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
19 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
20 | SOFTWARE. | |
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 | */ | |
92 | struct subid { | |
93 | int subid; | |
94 | char *label; | |
95 | }; | |
96 | ||
85269fdf | 97 | /* |
98 | * A linked list of nodes. | |
99 | */ | |
100 | struct 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 | |
109 | int 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 | |
156 | struct 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 | 165 | struct 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 | 216 | static struct tok *buckets[HASHSIZE]; |
627f6d02 | 217 | |
218 | static void | |
5c52f59a | 219 | hash_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) | |
240 | struct node *nbuckets[NHASHSIZE]; | |
241 | ||
80047df2 | 242 | static void |
5c52f59a | 243 | init_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 | |
262 | static void | |
5c52f59a | 263 | print_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 | 275 | print_subtree(tree, count) |
26ac0430 AJ |
276 | struct snmp_mib_tree *tree; |
277 | int 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 | 297 | int translation_table[40]; |
627f6d02 | 298 | |
80047df2 | 299 | static void |
5c52f59a | 300 | build_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 | */ | |
347 | static void | |
5c52f59a | 348 | do_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 |
428 | static | |
429 | #endif | |
430 | struct snmp_mib_tree * | |
e1381638 | 431 | build_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 | */ | |
478 | static char last = ' '; | |
479 | ||
480 | static int | |
5c52f59a | 481 | get_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 | */ |
563 | static int | |
5c52f59a | 564 | getoid(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 | ||
617 | static void | |
5c52f59a | 618 | free_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 | */ | |
637 | static struct node * | |
e1381638 | 638 | parse_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 | 723 | static int |
5c52f59a | 724 | parse_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 | 746 | static struct node * |
e1381638 | 747 | parse_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 |
978 | static | |
979 | #endif | |
980 | struct node * | |
e1381638 | 981 | parse(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 | 1064 | struct snmp_mib_tree * |
e1381638 | 1065 | read_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 | } |