1 /*
2 * parse.c
3 *
4 */
5 /* Portions of this file are subject to the following copyrights. See
6 * the Net-SNMP's COPYING file for more details and other copyrights
7 * that may apply:
8 */
9 /******************************************************************
10 Copyright 1989, 1991, 1992 by Carnegie Mellon University
11
12 All Rights Reserved
13
14 Permission to use, copy, modify, and distribute this software and its
15 documentation for any purpose and without fee is hereby granted,
16 provided that the above copyright notice appear in all copies and that
17 both that copyright notice and this permission notice appear in
18 supporting documentation, and that the name of CMU not be
19 used in advertising or publicity pertaining to distribution of the
20 software without specific, written prior permission.
21
22 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
23 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
24 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
25 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
26 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
27 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
28 SOFTWARE.
29 ******************************************************************/
30 /*
31 * Copyright � 2003 Sun Microsystems, Inc. All rights reserved.
32 * Use is subject to license terms specified in the COPYING file
33 * distributed with the Net-SNMP package.
34 */
35 #include <net-snmp/net-snmp-config.h>
36 #include <net-snmp/net-snmp-features.h>
37
38 #ifndef NETSNMP_DISABLE_MIB_LOADING
39
40 #if HAVE_LIMITS_H
41 #include <limits.h>
42 #endif
43 #include <stdio.h>
44 #if HAVE_STDLIB_H
45 #include <stdlib.h>
46 #endif
47 #if HAVE_STRING_H
48 #include <string.h>
49 #else
50 #include <strings.h>
51 #endif
52 #include <ctype.h>
53 #include <sys/types.h>
54 #if HAVE_SYS_STAT_H
55 #include <sys/stat.h>
56 #endif
57
58 /*
59 * Wow. This is ugly. -- Wes
60 */
61 #if HAVE_DIRENT_H
62 # include <dirent.h>
63 # define NAMLEN(dirent) strlen((dirent)->d_name)
64 #else
65 # define dirent direct
66 # define NAMLEN(dirent) (dirent)->d_namlen
67 # if HAVE_SYS_NDIR_H
68 # include <sys/ndir.h>
69 # endif
70 # if HAVE_SYS_DIR_H
71 # include <sys/dir.h>
72 # endif
73 # if HAVE_NDIR_H
74 # include <ndir.h>
75 # endif
76 #endif
77 #if TIME_WITH_SYS_TIME
78 # include <sys/time.h>
79 # include <time.h>
80 #else
81 # if HAVE_SYS_TIME_H
82 # include <sys/time.h>
83 # else
84 # include <time.h>
85 # endif
86 #endif
87 #if HAVE_NETINET_IN_H
88 #include <netinet/in.h>
89 #endif
90 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
91 #include <regex.h>
92 #endif
93 #if HAVE_UNISTD_H
94 #include <unistd.h>
95 #endif
96
97 #include <errno.h>
98
99 #include <net-snmp/types.h>
100 #include <net-snmp/output_api.h>
101 #include <net-snmp/config_api.h>
102 #include <net-snmp/utilities.h>
103
104 #include <net-snmp/library/parse.h>
105 #include <net-snmp/library/mib.h>
106 #include <net-snmp/library/snmp_api.h>
107 #include <net-snmp/library/tools.h>
108
109 netsnmp_feature_child_of(find_module, mib_api);
110 netsnmp_feature_child_of(get_tc_description, mib_api);
111
112 /*
113 * A linked list of nodes.
114 */
115 struct node {
116 struct node *next;
117 char *label; /* This node's (unique) textual name */
118 u_long subid; /* This node's integer subidentifier */
119 int modid; /* The module containing this node */
120 char *parent; /* The parent's textual name */
121 int tc_index; /* index into tclist (-1 if NA) */
122 int type; /* The type of object this represents */
123 int access;
124 int status;
125 struct enum_list *enums; /* (optional) list of enumerated integers */
126 struct range_list *ranges;
127 struct index_list *indexes;
128 char *augments;
129 struct varbind_list *varbinds;
130 char *hint;
131 char *units;
132 char *description; /* description (a quoted string) */
133 char *reference; /* references (a quoted string) */
134 char *defaultValue;
135 char *filename;
136 int lineno;
137 };
138
139 /*
140 * This is one element of an object identifier with either an integer
141 * subidentifier, or a textual string label, or both.
142 * The subid is -1 if not present, and label is NULL if not present.
143 */
144 struct subid_s {
145 int subid;
146 int modid;
147 char *label;
148 };
149
150 #define TC_INCR 100
151 struct tc { /* textual conventions */
152 int type;
153 int modid;
154 char *descriptor;
155 char *hint;
156 struct enum_list *enums;
157 struct range_list *ranges;
158 char *description;
159 } *tclist;
160 int tc_alloc;
161
162 int mibLine = 0;
163 const char *File = "(none)";
164 static int anonymous = 0;
165
166 struct objgroup {
167 char *name;
168 int line;
169 struct objgroup *next;
170 } *objgroups = NULL, *objects = NULL, *notifs = NULL;
171
172 #define SYNTAX_MASK 0x80
173 /*
174 * types of tokens
175 * Tokens wiht the SYNTAX_MASK bit set are syntax tokens
176 */
177 #define CONTINUE -1
178 #define ENDOFFILE 0
179 #define LABEL 1
180 #define SUBTREE 2
181 #define SYNTAX 3
182 #define OBJID (4 | SYNTAX_MASK)
183 #define OCTETSTR (5 | SYNTAX_MASK)
184 #define INTEGER (6 | SYNTAX_MASK)
185 #define NETADDR (7 | SYNTAX_MASK)
186 #define IPADDR (8 | SYNTAX_MASK)
187 #define COUNTER (9 | SYNTAX_MASK)
188 #define GAUGE (10 | SYNTAX_MASK)
189 #define TIMETICKS (11 | SYNTAX_MASK)
190 #define KW_OPAQUE (12 | SYNTAX_MASK)
191 #define NUL (13 | SYNTAX_MASK)
192 #define SEQUENCE 14
193 #define OF 15 /* SEQUENCE OF */
194 #define OBJTYPE 16
195 #define ACCESS 17
196 #define READONLY 18
197 #define READWRITE 19
198 #define WRITEONLY 20
199 #ifdef NOACCESS
200 #undef NOACCESS /* agent 'NOACCESS' token */
201 #endif
202 #define NOACCESS 21
203 #define STATUS 22
204 #define MANDATORY 23
205 #define KW_OPTIONAL 24
206 #define OBSOLETE 25
207 /*
208 * #define RECOMMENDED 26
209 */
210 #define PUNCT 27
211 #define EQUALS 28
212 #define NUMBER 29
213 #define LEFTBRACKET 30
214 #define RIGHTBRACKET 31
215 #define LEFTPAREN 32
216 #define RIGHTPAREN 33
217 #define COMMA 34
218 #define DESCRIPTION 35
219 #define QUOTESTRING 36
220 #define INDEX 37
221 #define DEFVAL 38
222 #define DEPRECATED 39
223 #define SIZE 40
224 #define BITSTRING (41 | SYNTAX_MASK)
225 #define NSAPADDRESS (42 | SYNTAX_MASK)
226 #define COUNTER64 (43 | SYNTAX_MASK)
227 #define OBJGROUP 44
228 #define NOTIFTYPE 45
229 #define AUGMENTS 46
230 #define COMPLIANCE 47
231 #define READCREATE 48
232 #define UNITS 49
233 #define REFERENCE 50
234 #define NUM_ENTRIES 51
235 #define MODULEIDENTITY 52
236 #define LASTUPDATED 53
237 #define ORGANIZATION 54
238 #define CONTACTINFO 55
239 #define UINTEGER32 (56 | SYNTAX_MASK)
240 #define CURRENT 57
241 #define DEFINITIONS 58
242 #define END 59
243 #define SEMI 60
244 #define TRAPTYPE 61
245 #define ENTERPRISE 62
246 /*
247 * #define DISPLAYSTR (63 | SYNTAX_MASK)
248 */
249 #define BEGIN 64
250 #define IMPORTS 65
251 #define EXPORTS 66
252 #define ACCNOTIFY 67
253 #define BAR 68
254 #define RANGE 69
255 #define CONVENTION 70
256 #define DISPLAYHINT 71
257 #define FROM 72
258 #define AGENTCAP 73
259 #define MACRO 74
260 #define IMPLIED 75
261 #define SUPPORTS 76
262 #define INCLUDES 77
263 #define VARIATION 78
264 #define REVISION 79
265 #define NOTIMPL 80
266 #define OBJECTS 81
267 #define NOTIFICATIONS 82
268 #define MODULE 83
269 #define MINACCESS 84
270 #define PRODREL 85
271 #define WRSYNTAX 86
272 #define CREATEREQ 87
273 #define NOTIFGROUP 88
274 #define MANDATORYGROUPS 89
275 #define GROUP 90
276 #define OBJECT 91
277 #define IDENTIFIER 92
278 #define CHOICE 93
279 #define LEFTSQBRACK 95
280 #define RIGHTSQBRACK 96
281 #define IMPLICIT 97
282 #define APPSYNTAX (98 | SYNTAX_MASK)
283 #define OBJSYNTAX (99 | SYNTAX_MASK)
284 #define SIMPLESYNTAX (100 | SYNTAX_MASK)
285 #define OBJNAME (101 | SYNTAX_MASK)
286 #define NOTIFNAME (102 | SYNTAX_MASK)
287 #define VARIABLES 103
288 #define UNSIGNED32 (104 | SYNTAX_MASK)
289 #define INTEGER32 (105 | SYNTAX_MASK)
290 #define OBJIDENTITY 106
291 /*
292 * Beware of reaching SYNTAX_MASK (0x80)
293 */
294
295 struct tok {
296 const char *name; /* token name */
297 int len; /* length not counting nul */
298 int token; /* value */
299 int hash; /* hash of name */
300 struct tok *next; /* pointer to next in hash table */
301 };
302
303
304 static struct tok tokens[] = {
305 {"obsolete", sizeof("obsolete") - 1, OBSOLETE}
306 ,
307 {"Opaque", sizeof("Opaque") - 1, KW_OPAQUE}
308 ,
309 {"optional", sizeof("optional") - 1, KW_OPTIONAL}
310 ,
311 {"LAST-UPDATED", sizeof("LAST-UPDATED") - 1, LASTUPDATED}
312 ,
313 {"ORGANIZATION", sizeof("ORGANIZATION") - 1, ORGANIZATION}
314 ,
315 {"CONTACT-INFO", sizeof("CONTACT-INFO") - 1, CONTACTINFO}
316 ,
317 {"MODULE-IDENTITY", sizeof("MODULE-IDENTITY") - 1, MODULEIDENTITY}
318 ,
319 {"MODULE-COMPLIANCE", sizeof("MODULE-COMPLIANCE") - 1, COMPLIANCE}
320 ,
321 {"DEFINITIONS", sizeof("DEFINITIONS") - 1, DEFINITIONS}
322 ,
323 {"END", sizeof("END") - 1, END}
324 ,
325 {"AUGMENTS", sizeof("AUGMENTS") - 1, AUGMENTS}
326 ,
327 {"not-accessible", sizeof("not-accessible") - 1, NOACCESS}
328 ,
329 {"write-only", sizeof("write-only") - 1, WRITEONLY}
330 ,
331 {"NsapAddress", sizeof("NsapAddress") - 1, NSAPADDRESS}
332 ,
333 {"UNITS", sizeof("Units") - 1, UNITS}
334 ,
335 {"REFERENCE", sizeof("REFERENCE") - 1, REFERENCE}
336 ,
337 {"NUM-ENTRIES", sizeof("NUM-ENTRIES") - 1, NUM_ENTRIES}
338 ,
339 {"BITSTRING", sizeof("BITSTRING") - 1, BITSTRING}
340 ,
341 {"BIT", sizeof("BIT") - 1, CONTINUE}
342 ,
343 {"BITS", sizeof("BITS") - 1, BITSTRING}
344 ,
345 {"Counter64", sizeof("Counter64") - 1, COUNTER64}
346 ,
347 {"TimeTicks", sizeof("TimeTicks") - 1, TIMETICKS}
348 ,
349 {"NOTIFICATION-TYPE", sizeof("NOTIFICATION-TYPE") - 1, NOTIFTYPE}
350 ,
351 {"OBJECT-GROUP", sizeof("OBJECT-GROUP") - 1, OBJGROUP}
352 ,
353 {"OBJECT-IDENTITY", sizeof("OBJECT-IDENTITY") - 1, OBJIDENTITY}
354 ,
355 {"IDENTIFIER", sizeof("IDENTIFIER") - 1, IDENTIFIER}
356 ,
357 {"OBJECT", sizeof("OBJECT") - 1, OBJECT}
358 ,
359 {"NetworkAddress", sizeof("NetworkAddress") - 1, NETADDR}
360 ,
361 {"Gauge", sizeof("Gauge") - 1, GAUGE}
362 ,
363 {"Gauge32", sizeof("Gauge32") - 1, GAUGE}
364 ,
365 {"Unsigned32", sizeof("Unsigned32") - 1, UNSIGNED32}
366 ,
367 {"read-write", sizeof("read-write") - 1, READWRITE}
368 ,
369 {"read-create", sizeof("read-create") - 1, READCREATE}
370 ,
371 {"OCTETSTRING", sizeof("OCTETSTRING") - 1, OCTETSTR}
372 ,
373 {"OCTET", sizeof("OCTET") - 1, CONTINUE}
374 ,
375 {"OF", sizeof("OF") - 1, OF}
376 ,
377 {"SEQUENCE", sizeof("SEQUENCE") - 1, SEQUENCE}
378 ,
379 {"NULL", sizeof("NULL") - 1, NUL}
380 ,
381 {"IpAddress", sizeof("IpAddress") - 1, IPADDR}
382 ,
383 {"UInteger32", sizeof("UInteger32") - 1, UINTEGER32}
384 ,
385 {"INTEGER", sizeof("INTEGER") - 1, INTEGER}
386 ,
387 {"Integer32", sizeof("Integer32") - 1, INTEGER32}
388 ,
389 {"Counter", sizeof("Counter") - 1, COUNTER}
390 ,
391 {"Counter32", sizeof("Counter32") - 1, COUNTER}
392 ,
393 {"read-only", sizeof("read-only") - 1, READONLY}
394 ,
395 {"DESCRIPTION", sizeof("DESCRIPTION") - 1, DESCRIPTION}
396 ,
397 {"INDEX", sizeof("INDEX") - 1, INDEX}
398 ,
399 {"DEFVAL", sizeof("DEFVAL") - 1, DEFVAL}
400 ,
401 {"deprecated", sizeof("deprecated") - 1, DEPRECATED}
402 ,
403 {"SIZE", sizeof("SIZE") - 1, SIZE}
404 ,
405 {"MAX-ACCESS", sizeof("MAX-ACCESS") - 1, ACCESS}
406 ,
407 {"ACCESS", sizeof("ACCESS") - 1, ACCESS}
408 ,
409 {"mandatory", sizeof("mandatory") - 1, MANDATORY}
410 ,
411 {"current", sizeof("current") - 1, CURRENT}
412 ,
413 {"STATUS", sizeof("STATUS") - 1, STATUS}
414 ,
415 {"SYNTAX", sizeof("SYNTAX") - 1, SYNTAX}
416 ,
417 {"OBJECT-TYPE", sizeof("OBJECT-TYPE") - 1, OBJTYPE}
418 ,
419 {"TRAP-TYPE", sizeof("TRAP-TYPE") - 1, TRAPTYPE}
420 ,
421 {"ENTERPRISE", sizeof("ENTERPRISE") - 1, ENTERPRISE}
422 ,
423 {"BEGIN", sizeof("BEGIN") - 1, BEGIN}
424 ,
425 {"IMPORTS", sizeof("IMPORTS") - 1, IMPORTS}
426 ,
427 {"EXPORTS", sizeof("EXPORTS") - 1, EXPORTS}
428 ,
429 {"accessible-for-notify", sizeof("accessible-for-notify") - 1,
430 ACCNOTIFY}
431 ,
432 {"TEXTUAL-CONVENTION", sizeof("TEXTUAL-CONVENTION") - 1, CONVENTION}
433 ,
434 {"NOTIFICATION-GROUP", sizeof("NOTIFICATION-GROUP") - 1, NOTIFGROUP}
435 ,
436 {"DISPLAY-HINT", sizeof("DISPLAY-HINT") - 1, DISPLAYHINT}
437 ,
438 {"FROM", sizeof("FROM") - 1, FROM}
439 ,
440 {"AGENT-CAPABILITIES", sizeof("AGENT-CAPABILITIES") - 1, AGENTCAP}
441 ,
442 {"MACRO", sizeof("MACRO") - 1, MACRO}
443 ,
444 {"IMPLIED", sizeof("IMPLIED") - 1, IMPLIED}
445 ,
446 {"SUPPORTS", sizeof("SUPPORTS") - 1, SUPPORTS}
447 ,
448 {"INCLUDES", sizeof("INCLUDES") - 1, INCLUDES}
449 ,
450 {"VARIATION", sizeof("VARIATION") - 1, VARIATION}
451 ,
452 {"REVISION", sizeof("REVISION") - 1, REVISION}
453 ,
454 {"not-implemented", sizeof("not-implemented") - 1, NOTIMPL}
455 ,
456 {"OBJECTS", sizeof("OBJECTS") - 1, OBJECTS}
457 ,
458 {"NOTIFICATIONS", sizeof("NOTIFICATIONS") - 1, NOTIFICATIONS}
459 ,
460 {"MODULE", sizeof("MODULE") - 1, MODULE}
461 ,
462 {"MIN-ACCESS", sizeof("MIN-ACCESS") - 1, MINACCESS}
463 ,
464 {"PRODUCT-RELEASE", sizeof("PRODUCT-RELEASE") - 1, PRODREL}
465 ,
466 {"WRITE-SYNTAX", sizeof("WRITE-SYNTAX") - 1, WRSYNTAX}
467 ,
468 {"CREATION-REQUIRES", sizeof("CREATION-REQUIRES") - 1, CREATEREQ}
469 ,
470 {"MANDATORY-GROUPS", sizeof("MANDATORY-GROUPS") - 1, MANDATORYGROUPS}
471 ,
472 {"GROUP", sizeof("GROUP") - 1, GROUP}
473 ,
474 {"CHOICE", sizeof("CHOICE") - 1, CHOICE}
475 ,
476 {"IMPLICIT", sizeof("IMPLICIT") - 1, IMPLICIT}
477 ,
478 {"ObjectSyntax", sizeof("ObjectSyntax") - 1, OBJSYNTAX}
479 ,
480 {"SimpleSyntax", sizeof("SimpleSyntax") - 1, SIMPLESYNTAX}
481 ,
482 {"ApplicationSyntax", sizeof("ApplicationSyntax") - 1, APPSYNTAX}
483 ,
484 {"ObjectName", sizeof("ObjectName") - 1, OBJNAME}
485 ,
486 {"NotificationName", sizeof("NotificationName") - 1, NOTIFNAME}
487 ,
488 {"VARIABLES", sizeof("VARIABLES") - 1, VARIABLES}
489 ,
490 {NULL}
491 };
492
493 static struct module_compatability *module_map_head;
494 static struct module_compatability module_map[] = {
495 {"RFC1065-SMI", "RFC1155-SMI", NULL, 0},
496 {"RFC1066-MIB", "RFC1156-MIB", NULL, 0},
497 /*
498 * 'mib' -> 'mib-2'
499 */
500 {"RFC1156-MIB", "RFC1158-MIB", NULL, 0},
501 /*
502 * 'snmpEnableAuthTraps' -> 'snmpEnableAuthenTraps'
503 */
504 {"RFC1158-MIB", "RFC1213-MIB", NULL, 0},
505 /*
506 * 'nullOID' -> 'zeroDotZero'
507 */
508 {"RFC1155-SMI", "SNMPv2-SMI", NULL, 0},
509 {"RFC1213-MIB", "SNMPv2-SMI", "mib-2", 0},
510 {"RFC1213-MIB", "SNMPv2-MIB", "sys", 3},
511 {"RFC1213-MIB", "IF-MIB", "if", 2},
512 {"RFC1213-MIB", "IP-MIB", "ip", 2},
513 {"RFC1213-MIB", "IP-MIB", "icmp", 4},
514 {"RFC1213-MIB", "TCP-MIB", "tcp", 3},
515 {"RFC1213-MIB", "UDP-MIB", "udp", 3},
516 {"RFC1213-MIB", "SNMPv2-SMI", "transmission", 0},
517 {"RFC1213-MIB", "SNMPv2-MIB", "snmp", 4},
518 {"RFC1231-MIB", "TOKENRING-MIB", NULL, 0},
519 {"RFC1271-MIB", "RMON-MIB", NULL, 0},
520 {"RFC1286-MIB", "SOURCE-ROUTING-MIB", "dot1dSr", 7},
521 {"RFC1286-MIB", "BRIDGE-MIB", NULL, 0},
522 {"RFC1315-MIB", "FRAME-RELAY-DTE-MIB", NULL, 0},
523 {"RFC1316-MIB", "CHARACTER-MIB", NULL, 0},
524 {"RFC1406-MIB", "DS1-MIB", NULL, 0},
525 {"RFC-1213", "RFC1213-MIB", NULL, 0},
526 };
527
528 #define MODULE_NOT_FOUND 0
529 #define MODULE_LOADED_OK 1
530 #define MODULE_ALREADY_LOADED 2
531 /*
532 * #define MODULE_LOAD_FAILED 3
533 */
534 #define MODULE_LOAD_FAILED MODULE_NOT_FOUND
535 #define MODULE_SYNTAX_ERROR 4
536
537 int gMibError = 0,gLoop = 0;
538 static char *gpMibErrorString;
539 char gMibNames[STRINGMAX];
540
541 #define HASHSIZE 32
542 #define BUCKET(x) (x & (HASHSIZE-1))
543
544 #define NHASHSIZE 128
545 #define NBUCKET(x) (x & (NHASHSIZE-1))
546
547 static struct tok *buckets[HASHSIZE];
548
549 static struct node *nbuckets[NHASHSIZE];
550 static struct tree *tbuckets[NHASHSIZE];
551 static struct module *module_head = NULL;
552
553 static struct node *orphan_nodes = NULL;
554 NETSNMP_IMPORT struct tree *tree_head;
555 struct tree *tree_head = NULL;
556
557 #define NUMBER_OF_ROOT_NODES 3
558 static struct module_import root_imports[NUMBER_OF_ROOT_NODES];
559
560 static int current_module = 0;
561 static int max_module = 0;
562 static int first_err_module = 1;
563 static char *last_err_module = NULL; /* no repeats on "Cannot find module..." */
564
565 static void tree_from_node(struct tree *tp, struct node *np);
566 static void do_subtree(struct tree *, struct node **);
567 static void do_linkup(struct module *, struct node *);
568 static void dump_module_list(void);
569 static int get_token(FILE *, char *, int);
570 static int parseQuoteString(FILE *, char *, int);
571 static int tossObjectIdentifier(FILE *);
572 static int name_hash(const char *);
573 static void init_node_hash(struct node *);
574 static void print_error(const char *, const char *, int);
575 static void free_tree(struct tree *);
576 static void free_partial_tree(struct tree *, int);
577 static void free_node(struct node *);
578 static void build_translation_table(void);
579 static void init_tree_roots(void);
580 static void merge_anon_children(struct tree *, struct tree *);
581 static void unlink_tbucket(struct tree *);
582 static void unlink_tree(struct tree *);
583 static int getoid(FILE *, struct subid_s *, int);
584 static struct node *parse_objectid(FILE *, char *);
585 static int get_tc(const char *, int, int *, struct enum_list **,
586 struct range_list **, char **);
587 static int get_tc_index(const char *, int);
588 static struct enum_list *parse_enumlist(FILE *, struct enum_list **);
589 static struct range_list *parse_ranges(FILE * fp, struct range_list **);
590 static struct node *parse_asntype(FILE *, char *, int *, char *);
591 static struct node *parse_objecttype(FILE *, char *);
592 static struct node *parse_objectgroup(FILE *, char *, int,
593 struct objgroup **);
594 static struct node *parse_notificationDefinition(FILE *, char *);
595 static struct node *parse_trapDefinition(FILE *, char *);
596 static struct node *parse_compliance(FILE *, char *);
597 static struct node *parse_capabilities(FILE *, char *);
598 static struct node *parse_moduleIdentity(FILE *, char *);
599 static struct node *parse_macro(FILE *, char *);
600 static void parse_imports(FILE *);
601 static struct node *parse(FILE *, struct node *);
602
603 static int read_module_internal(const char *);
604 static int read_module_replacements(const char *);
605 static int read_import_replacements(const char *,
606 struct module_import *);
607
608 static struct node *merge_parse_objectid(struct node *, FILE *, char *);
609 static struct index_list *getIndexes(FILE * fp, struct index_list **);
610 static struct varbind_list *getVarbinds(FILE * fp, struct varbind_list **);
611 static void free_indexes(struct index_list **);
612 static void free_varbinds(struct varbind_list **);
613 static void free_ranges(struct range_list **);
614 static void free_enums(struct enum_list **);
615 static struct range_list *copy_ranges(struct range_list *);
616 static struct enum_list *copy_enums(struct enum_list *);
617
618 static u_int compute_match(const char *search_base, const char *key);
619
620 void
snmp_mib_toggle_options_usage(const char * lead,FILE * outf)621 snmp_mib_toggle_options_usage(const char *lead, FILE * outf)
622 {
623 fprintf(outf, "%su: %sallow the use of underlines in MIB symbols\n",
624 lead, ((netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
625 NETSNMP_DS_LIB_MIB_PARSE_LABEL)) ?
626 "dis" : ""));
627 fprintf(outf, "%sc: %sallow the use of \"--\" to terminate comments\n",
628 lead, ((netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
629 NETSNMP_DS_LIB_MIB_COMMENT_TERM)) ?
630 "" : "dis"));
631
632 fprintf(outf, "%sd: %ssave the DESCRIPTIONs of the MIB objects\n",
633 lead, ((netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
634 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) ?
635 "do not " : ""));
636
637 fprintf(outf, "%se: disable errors when MIB symbols conflict\n", lead);
638
639 fprintf(outf, "%sw: enable warnings when MIB symbols conflict\n", lead);
640
641 fprintf(outf, "%sW: enable detailed warnings when MIB symbols conflict\n",
642 lead);
643
644 fprintf(outf, "%sR: replace MIB symbols from latest module\n", lead);
645 }
646
647 char *
snmp_mib_toggle_options(char * options)648 snmp_mib_toggle_options(char *options)
649 {
650 if (options) {
651 while (*options) {
652 switch (*options) {
653 case 'u':
654 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_PARSE_LABEL,
655 !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
656 NETSNMP_DS_LIB_MIB_PARSE_LABEL));
657 break;
658
659 case 'c':
660 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID,
661 NETSNMP_DS_LIB_MIB_COMMENT_TERM);
662 break;
663
664 case 'e':
665 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID,
666 NETSNMP_DS_LIB_MIB_ERRORS);
667 break;
668
669 case 'w':
670 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
671 NETSNMP_DS_LIB_MIB_WARNINGS, 1);
672 break;
673
674 case 'W':
675 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
676 NETSNMP_DS_LIB_MIB_WARNINGS, 2);
677 break;
678
679 case 'd':
680 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID,
681 NETSNMP_DS_LIB_SAVE_MIB_DESCRS);
682 break;
683
684 case 'R':
685 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID,
686 NETSNMP_DS_LIB_MIB_REPLACE);
687 break;
688
689 default:
690 /*
691 * return at the unknown option
692 */
693 return options;
694 }
695 options++;
696 }
697 }
698 return NULL;
699 }
700
701 static int
name_hash(const char * name)702 name_hash(const char *name)
703 {
704 int hash = 0;
705 const char *cp;
706
707 if (!name)
708 return 0;
709 for (cp = name; *cp; cp++)
710 hash += tolower((unsigned char)(*cp));
711 return (hash);
712 }
713
714 void
netsnmp_init_mib_internals(void)715 netsnmp_init_mib_internals(void)
716 {
717 register struct tok *tp;
718 register int b, i;
719 int max_modc;
720
721 if (tree_head)
722 return;
723
724 /*
725 * Set up hash list of pre-defined tokens
726 */
727 memset(buckets, 0, sizeof(buckets));
728 for (tp = tokens; tp->name; tp++) {
729 tp->hash = name_hash(tp->name);
730 b = BUCKET(tp->hash);
731 if (buckets[b])
732 tp->next = buckets[b]; /* BUG ??? */
733 buckets[b] = tp;
734 }
735
736 /*
737 * Initialise other internal structures
738 */
739
740 max_modc = sizeof(module_map) / sizeof(module_map[0]) - 1;
741 for (i = 0; i < max_modc; ++i)
742 module_map[i].next = &(module_map[i + 1]);
743 module_map[max_modc].next = NULL;
744 module_map_head = module_map;
745
746 memset(nbuckets, 0, sizeof(nbuckets));
747 memset(tbuckets, 0, sizeof(tbuckets));
748 tc_alloc = TC_INCR;
749 tclist = calloc(tc_alloc, sizeof(struct tc));
750 build_translation_table();
751 init_tree_roots(); /* Set up initial roots */
752 /*
753 * Relies on 'add_mibdir' having set up the modules
754 */
755 }
756
757 #ifndef NETSNMP_NO_LEGACY_DEFINITIONS
758 void
init_mib_internals(void)759 init_mib_internals(void)
760 {
761 netsnmp_init_mib_internals();
762 }
763 #endif
764
765 static void
init_node_hash(struct node * nodes)766 init_node_hash(struct node *nodes)
767 {
768 struct node *np, *nextp;
769 int hash;
770
771 memset(nbuckets, 0, sizeof(nbuckets));
772 for (np = nodes; np;) {
773 nextp = np->next;
774 hash = NBUCKET(name_hash(np->parent));
775 np->next = nbuckets[hash];
776 nbuckets[hash] = np;
777 np = nextp;
778 }
779 }
780
781 static int erroneousMibs = 0;
782
783 netsnmp_feature_child_of(parse_get_error_count, netsnmp_unused);
784 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_GET_ERROR_COUNT
785 int
get_mib_parse_error_count(void)786 get_mib_parse_error_count(void)
787 {
788 return erroneousMibs;
789 }
790 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_GET_ERROR_COUNT */
791
792
793 static void
print_error(const char * str,const char * token,int type)794 print_error(const char *str, const char *token, int type)
795 {
796 erroneousMibs++;
797 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
798 NETSNMP_DS_LIB_MIB_ERRORS))
799 return;
800 DEBUGMSGTL(("parse-mibs", "\n"));
801 if (type == ENDOFFILE)
802 snmp_log(LOG_ERR, "%s (EOF): At line %d in %s\n", str, mibLine,
803 File);
804 else if (token && *token)
805 snmp_log(LOG_ERR, "%s (%s): At line %d in %s\n", str, token,
806 mibLine, File);
807 else
808 snmp_log(LOG_ERR, "%s: At line %d in %s\n", str, mibLine, File);
809 }
810
811 static void
print_module_not_found(const char * cp)812 print_module_not_found(const char *cp)
813 {
814 if (first_err_module) {
815 snmp_log(LOG_ERR, "MIB search path: %s\n",
816 netsnmp_get_mib_directory());
817 first_err_module = 0;
818 }
819 if (!last_err_module || strcmp(cp, last_err_module))
820 print_error("Cannot find module", cp, CONTINUE);
821 if (last_err_module)
822 free(last_err_module);
823 last_err_module = strdup(cp);
824 }
825
826 static struct node *
alloc_node(int modid)827 alloc_node(int modid)
828 {
829 struct node *np;
830 np = (struct node *) calloc(1, sizeof(struct node));
831 if (np) {
832 np->tc_index = -1;
833 np->modid = modid;
834 np->filename = strdup(File);
835 np->lineno = mibLine;
836 }
837 return np;
838 }
839
840 static void
unlink_tbucket(struct tree * tp)841 unlink_tbucket(struct tree *tp)
842 {
843 int hash = NBUCKET(name_hash(tp->label));
844 struct tree *otp = NULL, *ntp = tbuckets[hash];
845
846 while (ntp && ntp != tp) {
847 otp = ntp;
848 ntp = ntp->next;
849 }
850 if (!ntp)
851 snmp_log(LOG_EMERG, "Can't find %s in tbuckets\n", tp->label);
852 else if (otp)
853 otp->next = ntp->next;
854 else
855 tbuckets[hash] = tp->next;
856 }
857
858 static void
unlink_tree(struct tree * tp)859 unlink_tree(struct tree *tp)
860 {
861 struct tree *otp = NULL, *ntp = tp->parent;
862
863 if (!ntp) { /* this tree has no parent */
864 DEBUGMSGTL(("unlink_tree", "Tree node %s has no parent\n",
865 tp->label));
866 } else {
867 ntp = ntp->child_list;
868
869 while (ntp && ntp != tp) {
870 otp = ntp;
871 ntp = ntp->next_peer;
872 }
873 if (!ntp)
874 snmp_log(LOG_EMERG, "Can't find %s in %s's children\n",
875 tp->label, tp->parent->label);
876 else if (otp)
877 otp->next_peer = ntp->next_peer;
878 else
879 tp->parent->child_list = tp->next_peer;
880 }
881
882 if (tree_head == tp)
883 tree_head = tp->next_peer;
884 }
885
886 static void
free_partial_tree(struct tree * tp,int keep_label)887 free_partial_tree(struct tree *tp, int keep_label)
888 {
889 if (!tp)
890 return;
891
892 /*
893 * remove the data from this tree node
894 */
895 free_enums(&tp->enums);
896 free_ranges(&tp->ranges);
897 free_indexes(&tp->indexes);
898 free_varbinds(&tp->varbinds);
899 if (!keep_label)
900 SNMP_FREE(tp->label);
901 SNMP_FREE(tp->hint);
902 SNMP_FREE(tp->units);
903 SNMP_FREE(tp->description);
904 SNMP_FREE(tp->reference);
905 SNMP_FREE(tp->augments);
906 SNMP_FREE(tp->defaultValue);
907 }
908
909 /*
910 * free a tree node. Note: the node must already have been unlinked
911 * from the tree when calling this routine
912 */
913 static void
free_tree(struct tree * Tree)914 free_tree(struct tree *Tree)
915 {
916 if (!Tree)
917 return;
918
919 unlink_tbucket(Tree);
920 free_partial_tree(Tree, FALSE);
921 if (Tree->module_list != &Tree->modid)
922 free(Tree->module_list);
923 free(Tree);
924 }
925
926 static void
free_node(struct node * np)927 free_node(struct node *np)
928 {
929 if (!np)
930 return;
931
932 free_enums(&np->enums);
933 free_ranges(&np->ranges);
934 free_indexes(&np->indexes);
935 free_varbinds(&np->varbinds);
936 if (np->label)
937 free(np->label);
938 if (np->hint)
939 free(np->hint);
940 if (np->units)
941 free(np->units);
942 if (np->description)
943 free(np->description);
944 if (np->reference)
945 free(np->reference);
946 if (np->defaultValue)
947 free(np->defaultValue);
948 if (np->parent)
949 free(np->parent);
950 if (np->augments)
951 free(np->augments);
952 if (np->filename)
953 free(np->filename);
954 free((char *) np);
955 }
956
957 static void
print_range_value(FILE * fp,int type,struct range_list * rp)958 print_range_value(FILE * fp, int type, struct range_list * rp)
959 {
960 switch (type) {
961 case TYPE_INTEGER:
962 case TYPE_INTEGER32:
963 if (rp->low == rp->high)
964 fprintf(fp, "%d", rp->low);
965 else
966 fprintf(fp, "%d..%d", rp->low, rp->high);
967 break;
968 case TYPE_UNSIGNED32:
969 case TYPE_OCTETSTR:
970 case TYPE_GAUGE:
971 case TYPE_UINTEGER:
972 if (rp->low == rp->high)
973 fprintf(fp, "%u", (unsigned)rp->low);
974 else
975 fprintf(fp, "%u..%u", (unsigned)rp->low, (unsigned)rp->high);
976 break;
977 default:
978 /* No other range types allowed */
979 break;
980 }
981 }
982
983 #ifdef TEST
984 static void
print_nodes(FILE * fp,struct node * root)985 print_nodes(FILE * fp, struct node *root)
986 {
987 struct enum_list *ep;
988 struct index_list *ip;
989 struct varbind_list *vp;
990 struct node *np;
991
992 for (np = root; np; np = np->next) {
993 fprintf(fp, "%s ::= { %s %ld } (%d)\n", np->label, np->parent,
994 np->subid, np->type);
995 if (np->tc_index >= 0)
996 fprintf(fp, " TC = %s\n", tclist[np->tc_index].descriptor);
997 if (np->enums) {
998 fprintf(fp, " Enums: \n");
999 for (ep = np->enums; ep; ep = ep->next) {
1000 fprintf(fp, " %s(%d)\n", ep->label, ep->value);
1001 }
1002 }
1003 if (np->ranges) {
1004 struct range_list *rp;
1005 fprintf(fp, " Ranges: ");
1006 for (rp = np->ranges; rp; rp = rp->next) {
1007 fprintf(fp, "\n ");
1008 print_range_value(fp, np->type, rp);
1009 }
1010 fprintf(fp, "\n");
1011 }
1012 if (np->indexes) {
1013 fprintf(fp, " Indexes: \n");
1014 for (ip = np->indexes; ip; ip = ip->next) {
1015 fprintf(fp, " %s\n", ip->ilabel);
1016 }
1017 }
1018 if (np->augments)
1019 fprintf(fp, " Augments: %s\n", np->augments);
1020 if (np->varbinds) {
1021 fprintf(fp, " Varbinds: \n");
1022 for (vp = np->varbinds; vp; vp = vp->next) {
1023 fprintf(fp, " %s\n", vp->vblabel);
1024 }
1025 }
1026 if (np->hint)
1027 fprintf(fp, " Hint: %s\n", np->hint);
1028 if (np->units)
1029 fprintf(fp, " Units: %s\n", np->units);
1030 if (np->defaultValue)
1031 fprintf(fp, " DefaultValue: %s\n", np->defaultValue);
1032 }
1033 }
1034 #endif
1035
1036 void
print_subtree(FILE * f,struct tree * tree,int count)1037 print_subtree(FILE * f, struct tree *tree, int count)
1038 {
1039 struct tree *tp;
1040 int i;
1041 char modbuf[256];
1042
1043 for (i = 0; i < count; i++)
1044 fprintf(f, " ");
1045 fprintf(f, "Children of %s(%ld):\n", tree->label, tree->subid);
1046 count++;
1047 for (tp = tree->child_list; tp; tp = tp->next_peer) {
1048 for (i = 0; i < count; i++)
1049 fprintf(f, " ");
1050 fprintf(f, "%s:%s(%ld) type=%d",
1051 module_name(tp->module_list[0], modbuf),
1052 tp->label, tp->subid, tp->type);
1053 if (tp->tc_index != -1)
1054 fprintf(f, " tc=%d", tp->tc_index);
1055 if (tp->hint)
1056 fprintf(f, " hint=%s", tp->hint);
1057 if (tp->units)
1058 fprintf(f, " units=%s", tp->units);
1059 if (tp->number_modules > 1) {
1060 fprintf(f, " modules:");
1061 for (i = 1; i < tp->number_modules; i++)
1062 fprintf(f, " %s", module_name(tp->module_list[i], modbuf));
1063 }
1064 fprintf(f, "\n");
1065 }
1066 for (tp = tree->child_list; tp; tp = tp->next_peer) {
1067 if (tp->child_list)
1068 print_subtree(f, tp, count);
1069 }
1070 }
1071
1072 void
print_ascii_dump_tree(FILE * f,struct tree * tree,int count)1073 print_ascii_dump_tree(FILE * f, struct tree *tree, int count)
1074 {
1075 struct tree *tp;
1076
1077 count++;
1078 for (tp = tree->child_list; tp; tp = tp->next_peer) {
1079 fprintf(f, "%s OBJECT IDENTIFIER ::= { %s %ld }\n", tp->label,
1080 tree->label, tp->subid);
1081 }
1082 for (tp = tree->child_list; tp; tp = tp->next_peer) {
1083 if (tp->child_list)
1084 print_ascii_dump_tree(f, tp, count);
1085 }
1086 }
1087
1088 static int translation_table[256];
1089
1090 static void
build_translation_table(void)1091 build_translation_table(void)
1092 {
1093 int count;
1094
1095 for (count = 0; count < 256; count++) {
1096 switch (count) {
1097 case OBJID:
1098 translation_table[count] = TYPE_OBJID;
1099 break;
1100 case OCTETSTR:
1101 translation_table[count] = TYPE_OCTETSTR;
1102 break;
1103 case INTEGER:
1104 translation_table[count] = TYPE_INTEGER;
1105 break;
1106 case NETADDR:
1107 translation_table[count] = TYPE_NETADDR;
1108 break;
1109 case IPADDR:
1110 translation_table[count] = TYPE_IPADDR;
1111 break;
1112 case COUNTER:
1113 translation_table[count] = TYPE_COUNTER;
1114 break;
1115 case GAUGE:
1116 translation_table[count] = TYPE_GAUGE;
1117 break;
1118 case TIMETICKS:
1119 translation_table[count] = TYPE_TIMETICKS;
1120 break;
1121 case KW_OPAQUE:
1122 translation_table[count] = TYPE_OPAQUE;
1123 break;
1124 case NUL:
1125 translation_table[count] = TYPE_NULL;
1126 break;
1127 case COUNTER64:
1128 translation_table[count] = TYPE_COUNTER64;
1129 break;
1130 case BITSTRING:
1131 translation_table[count] = TYPE_BITSTRING;
1132 break;
1133 case NSAPADDRESS:
1134 translation_table[count] = TYPE_NSAPADDRESS;
1135 break;
1136 case INTEGER32:
1137 translation_table[count] = TYPE_INTEGER32;
1138 break;
1139 case UINTEGER32:
1140 translation_table[count] = TYPE_UINTEGER;
1141 break;
1142 case UNSIGNED32:
1143 translation_table[count] = TYPE_UNSIGNED32;
1144 break;
1145 case TRAPTYPE:
1146 translation_table[count] = TYPE_TRAPTYPE;
1147 break;
1148 case NOTIFTYPE:
1149 translation_table[count] = TYPE_NOTIFTYPE;
1150 break;
1151 case NOTIFGROUP:
1152 translation_table[count] = TYPE_NOTIFGROUP;
1153 break;
1154 case OBJGROUP:
1155 translation_table[count] = TYPE_OBJGROUP;
1156 break;
1157 case MODULEIDENTITY:
1158 translation_table[count] = TYPE_MODID;
1159 break;
1160 case OBJIDENTITY:
1161 translation_table[count] = TYPE_OBJIDENTITY;
1162 break;
1163 case AGENTCAP:
1164 translation_table[count] = TYPE_AGENTCAP;
1165 break;
1166 case COMPLIANCE:
1167 translation_table[count] = TYPE_MODCOMP;
1168 break;
1169 default:
1170 translation_table[count] = TYPE_OTHER;
1171 break;
1172 }
1173 }
1174 }
1175
1176 static void
init_tree_roots(void)1177 init_tree_roots(void)
1178 {
1179 struct tree *tp, *lasttp;
1180 int base_modid;
1181 int hash;
1182
1183 base_modid = which_module("SNMPv2-SMI");
1184 if (base_modid == -1)
1185 base_modid = which_module("RFC1155-SMI");
1186 if (base_modid == -1)
1187 base_modid = which_module("RFC1213-MIB");
1188
1189 /*
1190 * build root node
1191 */
1192 tp = (struct tree *) calloc(1, sizeof(struct tree));
1193 if (tp == NULL)
1194 return;
1195 tp->label = strdup("joint-iso-ccitt");
1196 tp->modid = base_modid;
1197 tp->number_modules = 1;
1198 tp->module_list = &(tp->modid);
1199 tp->subid = 2;
1200 tp->tc_index = -1;
1201 set_function(tp); /* from mib.c */
1202 hash = NBUCKET(name_hash(tp->label));
1203 tp->next = tbuckets[hash];
1204 tbuckets[hash] = tp;
1205 lasttp = tp;
1206 root_imports[0].label = strdup(tp->label);
1207 root_imports[0].modid = base_modid;
1208
1209 /*
1210 * build root node
1211 */
1212 tp = (struct tree *) calloc(1, sizeof(struct tree));
1213 if (tp == NULL)
1214 return;
1215 tp->next_peer = lasttp;
1216 tp->label = strdup("ccitt");
1217 tp->modid = base_modid;
1218 tp->number_modules = 1;
1219 tp->module_list = &(tp->modid);
1220 tp->subid = 0;
1221 tp->tc_index = -1;
1222 set_function(tp); /* from mib.c */
1223 hash = NBUCKET(name_hash(tp->label));
1224 tp->next = tbuckets[hash];
1225 tbuckets[hash] = tp;
1226 lasttp = tp;
1227 root_imports[1].label = strdup(tp->label);
1228 root_imports[1].modid = base_modid;
1229
1230 /*
1231 * build root node
1232 */
1233 tp = (struct tree *) calloc(1, sizeof(struct tree));
1234 if (tp == NULL)
1235 return;
1236 tp->next_peer = lasttp;
1237 tp->label = strdup("iso");
1238 tp->modid = base_modid;
1239 tp->number_modules = 1;
1240 tp->module_list = &(tp->modid);
1241 tp->subid = 1;
1242 tp->tc_index = -1;
1243 set_function(tp); /* from mib.c */
1244 hash = NBUCKET(name_hash(tp->label));
1245 tp->next = tbuckets[hash];
1246 tbuckets[hash] = tp;
1247 lasttp = tp;
1248 root_imports[2].label = strdup(tp->label);
1249 root_imports[2].modid = base_modid;
1250
1251 tree_head = tp;
1252 }
1253
1254 #ifdef STRICT_MIB_PARSEING
1255 #define label_compare strcasecmp
1256 #else
1257 #define label_compare strcmp
1258 #endif
1259
1260
1261 struct tree *
find_tree_node(const char * name,int modid)1262 find_tree_node(const char *name, int modid)
1263 {
1264 struct tree *tp, *headtp;
1265 int count, *int_p;
1266
1267 if (!name || !*name)
1268 return (NULL);
1269
1270 headtp = tbuckets[NBUCKET(name_hash(name))];
1271 for (tp = headtp; tp; tp = tp->next) {
1272 if (tp->label && !label_compare(tp->label, name)) {
1273
1274 if (modid == -1) /* Any module */
1275 return (tp);
1276
1277 for (int_p = tp->module_list, count = 0;
1278 count < tp->number_modules; ++count, ++int_p)
1279 if (*int_p == modid)
1280 return (tp);
1281 }
1282 }
1283
1284 return (NULL);
1285 }
1286
1287 /*
1288 * computes a value which represents how close name1 is to name2.
1289 * * high scores mean a worse match.
1290 * * (yes, the algorithm sucks!)
1291 */
1292 #define MAX_BAD 0xffffff
1293
1294 static u_int
compute_match(const char * search_base,const char * key)1295 compute_match(const char *search_base, const char *key)
1296 {
1297 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
1298 int rc;
1299 regex_t parsetree;
1300 regmatch_t pmatch;
1301 rc = regcomp(&parsetree, key, REG_ICASE | REG_EXTENDED);
1302 if (rc == 0)
1303 rc = regexec(&parsetree, search_base, 1, &pmatch, 0);
1304 regfree(&parsetree);
1305 if (rc == 0) {
1306 /*
1307 * found
1308 */
1309 return pmatch.rm_so;
1310 }
1311 #else /* use our own wildcard matcher */
1312 /*
1313 * first find the longest matching substring (ick)
1314 */
1315 char *first = NULL, *result = NULL, *entry;
1316 const char *position;
1317 char *newkey = strdup(key);
1318 char *st;
1319
1320
1321 entry = strtok_r(newkey, "*", &st);
1322 position = search_base;
1323 while (entry) {
1324 result = strcasestr(position, entry);
1325
1326 if (result == NULL) {
1327 free(newkey);
1328 return MAX_BAD;
1329 }
1330
1331 if (first == NULL)
1332 first = result;
1333
1334 position = result + strlen(entry);
1335 entry = strtok_r(NULL, "*", &st);
1336 }
1337 free(newkey);
1338 if (result)
1339 return (first - search_base);
1340 #endif
1341
1342 /*
1343 * not found
1344 */
1345 return MAX_BAD;
1346 }
1347
1348 /*
1349 * Find the tree node that best matches the pattern string.
1350 * Use the "reported" flag such that only one match
1351 * is attempted for every node.
1352 *
1353 * Warning! This function may recurse.
1354 *
1355 * Caller _must_ invoke clear_tree_flags before first call
1356 * to this function. This function may be called multiple times
1357 * to ensure that the entire tree is traversed.
1358 */
1359
1360 struct tree *
find_best_tree_node(const char * pattrn,struct tree * tree_top,u_int * match)1361 find_best_tree_node(const char *pattrn, struct tree *tree_top,
1362 u_int * match)
1363 {
1364 struct tree *tp, *best_so_far = NULL, *retptr;
1365 u_int old_match = MAX_BAD, new_match = MAX_BAD;
1366
1367 if (!pattrn || !*pattrn)
1368 return (NULL);
1369
1370 if (!tree_top)
1371 tree_top = get_tree_head();
1372
1373 for (tp = tree_top; tp; tp = tp->next_peer) {
1374 if (!tp->reported && tp->label)
1375 new_match = compute_match(tp->label, pattrn);
1376 tp->reported = 1;
1377
1378 if (new_match < old_match) {
1379 best_so_far = tp;
1380 old_match = new_match;
1381 }
1382 if (new_match == 0)
1383 break; /* this is the best result we can get */
1384 if (tp->child_list) {
1385 retptr =
1386 find_best_tree_node(pattrn, tp->child_list, &new_match);
1387 if (new_match < old_match) {
1388 best_so_far = retptr;
1389 old_match = new_match;
1390 }
1391 if (new_match == 0)
1392 break; /* this is the best result we can get */
1393 }
1394 }
1395 if (match)
1396 *match = old_match;
1397 return (best_so_far);
1398 }
1399
1400
1401 static void
merge_anon_children(struct tree * tp1,struct tree * tp2)1402 merge_anon_children(struct tree *tp1, struct tree *tp2)
1403 /*
1404 * NB: tp1 is the 'anonymous' node
1405 */
1406 {
1407 struct tree *child1, *child2, *previous;
1408
1409 for (child1 = tp1->child_list; child1;) {
1410
1411 for (child2 = tp2->child_list, previous = NULL;
1412 child2; previous = child2, child2 = child2->next_peer) {
1413
1414 if (child1->subid == child2->subid) {
1415 /*
1416 * Found 'matching' children,
1417 * so merge them
1418 */
1419 if (!strncmp(child1->label, ANON, ANON_LEN)) {
1420 merge_anon_children(child1, child2);
1421
1422 child1->child_list = NULL;
1423 previous = child1; /* Finished with 'child1' */
1424 child1 = child1->next_peer;
1425 free_tree(previous);
1426 goto next;
1427 }
1428
1429 else if (!strncmp(child2->label, ANON, ANON_LEN)) {
1430 merge_anon_children(child2, child1);
1431
1432 if (previous)
1433 previous->next_peer = child2->next_peer;
1434 else
1435 tp2->child_list = child2->next_peer;
1436 free_tree(child2);
1437
1438 previous = child1; /* Move 'child1' to 'tp2' */
1439 child1 = child1->next_peer;
1440 previous->next_peer = tp2->child_list;
1441 tp2->child_list = previous;
1442 for (previous = tp2->child_list;
1443 previous; previous = previous->next_peer)
1444 previous->parent = tp2;
1445 goto next;
1446 } else if (!label_compare(child1->label, child2->label)) {
1447 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
1448 NETSNMP_DS_LIB_MIB_WARNINGS)) {
1449 snmp_log(LOG_WARNING,
1450 "Warning: %s.%ld is both %s and %s (%s)\n",
1451 tp2->label, child1->subid, child1->label,
1452 child2->label, File);
1453 }
1454 continue;
1455 } else {
1456 /*
1457 * Two copies of the same node.
1458 * 'child2' adopts the children of 'child1'
1459 */
1460
1461 if (child2->child_list) {
1462 for (previous = child2->child_list; previous->next_peer; previous = previous->next_peer); /* Find the end of the list */
1463 previous->next_peer = child1->child_list;
1464 } else
1465 child2->child_list = child1->child_list;
1466 for (previous = child1->child_list;
1467 previous; previous = previous->next_peer)
1468 previous->parent = child2;
1469 child1->child_list = NULL;
1470
1471 previous = child1; /* Finished with 'child1' */
1472 child1 = child1->next_peer;
1473 free_tree(previous);
1474 goto next;
1475 }
1476 }
1477 }
1478 /*
1479 * If no match, move 'child1' to 'tp2' child_list
1480 */
1481 if (child1) {
1482 previous = child1;
1483 child1 = child1->next_peer;
1484 previous->parent = tp2;
1485 previous->next_peer = tp2->child_list;
1486 tp2->child_list = previous;
1487 }
1488 next:;
1489 }
1490 }
1491
1492
1493 /*
1494 * Find all the children of root in the list of nodes. Link them into the
1495 * tree and out of the nodes list.
1496 */
1497 static void
do_subtree(struct tree * root,struct node ** nodes)1498 do_subtree(struct tree *root, struct node **nodes)
1499 {
1500 struct tree *tp, *anon_tp = NULL;
1501 struct tree *xroot = root;
1502 struct node *np, **headp;
1503 struct node *oldnp = NULL, *child_list = NULL, *childp = NULL;
1504 int hash;
1505 int *int_p;
1506
1507 while (xroot->next_peer && xroot->next_peer->subid == root->subid) {
1508 #if 0
1509 printf("xroot: %s.%s => %s\n", xroot->parent->label, xroot->label,
1510 xroot->next_peer->label);
1511 #endif
1512 xroot = xroot->next_peer;
1513 }
1514
1515 tp = root;
1516 headp = &nbuckets[NBUCKET(name_hash(tp->label))];
1517 /*
1518 * Search each of the nodes for one whose parent is root, and
1519 * move each into a separate list.
1520 */
1521 for (np = *headp; np; np = np->next) {
1522 if (!label_compare(tp->label, np->parent)) {
1523 /*
1524 * take this node out of the node list
1525 */
1526 if (oldnp == NULL) {
1527 *headp = np->next; /* fix root of node list */
1528 } else {
1529 oldnp->next = np->next; /* link around this node */
1530 }
1531 if (child_list)
1532 childp->next = np;
1533 else
1534 child_list = np;
1535 childp = np;
1536 } else {
1537 oldnp = np;
1538 }
1539
1540 }
1541 if (childp)
1542 childp->next = NULL;
1543 /*
1544 * Take each element in the child list and place it into the tree.
1545 */
1546 for (np = child_list; np; np = np->next) {
1547 struct tree *otp = NULL;
1548 struct tree *xxroot = xroot;
1549 anon_tp = NULL;
1550 tp = xroot->child_list;
1551
1552 if (np->subid == -1) {
1553 /*
1554 * name ::= { parent }
1555 */
1556 np->subid = xroot->subid;
1557 tp = xroot;
1558 xxroot = xroot->parent;
1559 }
1560
1561 while (tp) {
1562 if (tp->subid == np->subid)
1563 break;
1564 else {
1565 otp = tp;
1566 tp = tp->next_peer;
1567 }
1568 }
1569 if (tp) {
1570 if (!label_compare(tp->label, np->label)) {
1571 /*
1572 * Update list of modules
1573 */
1574 int_p = malloc((tp->number_modules + 1) * sizeof(int));
1575 if (int_p == NULL)
1576 return;
1577 memcpy(int_p, tp->module_list,
1578 tp->number_modules * sizeof(int));
1579 int_p[tp->number_modules] = np->modid;
1580 if (tp->module_list != &tp->modid)
1581 free(tp->module_list);
1582 ++tp->number_modules;
1583 tp->module_list = int_p;
1584
1585 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1586 NETSNMP_DS_LIB_MIB_REPLACE)) {
1587 /*
1588 * Replace from node
1589 */
1590 tree_from_node(tp, np);
1591 }
1592 /*
1593 * Handle children
1594 */
1595 do_subtree(tp, nodes);
1596 continue;
1597 }
1598 if (!strncmp(np->label, ANON, ANON_LEN) ||
1599 !strncmp(tp->label, ANON, ANON_LEN)) {
1600 anon_tp = tp; /* Need to merge these two trees later */
1601 } else if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
1602 NETSNMP_DS_LIB_MIB_WARNINGS)) {
1603 snmp_log(LOG_WARNING,
1604 "Warning: %s.%ld is both %s and %s (%s)\n",
1605 root->label, np->subid, tp->label, np->label,
1606 File);
1607 }
1608 }
1609
1610 tp = (struct tree *) calloc(1, sizeof(struct tree));
1611 if (tp == NULL)
1612 return;
1613 tp->parent = xxroot;
1614 tp->modid = np->modid;
1615 tp->number_modules = 1;
1616 tp->module_list = &(tp->modid);
1617 tree_from_node(tp, np);
1618 tp->next_peer = otp ? otp->next_peer : xxroot->child_list;
1619 if (otp)
1620 otp->next_peer = tp;
1621 else
1622 xxroot->child_list = tp;
1623 hash = NBUCKET(name_hash(tp->label));
1624 tp->next = tbuckets[hash];
1625 tbuckets[hash] = tp;
1626 do_subtree(tp, nodes);
1627
1628 if (anon_tp) {
1629 if (!strncmp(tp->label, ANON, ANON_LEN)) {
1630 /*
1631 * The new node is anonymous,
1632 * so merge it with the existing one.
1633 */
1634 merge_anon_children(tp, anon_tp);
1635
1636 /*
1637 * unlink and destroy tp
1638 */
1639 unlink_tree(tp);
1640 free_tree(tp);
1641 } else if (!strncmp(anon_tp->label, ANON, ANON_LEN)) {
1642 struct tree *ntp;
1643 /*
1644 * The old node was anonymous,
1645 * so merge it with the existing one,
1646 * and fill in the full information.
1647 */
1648 merge_anon_children(anon_tp, tp);
1649
1650 /*
1651 * unlink anon_tp from the hash
1652 */
1653 unlink_tbucket(anon_tp);
1654
1655 /*
1656 * get rid of old contents of anon_tp
1657 */
1658 free_partial_tree(anon_tp, FALSE);
1659
1660 /*
1661 * put in the current information
1662 */
1663 anon_tp->label = tp->label;
1664 anon_tp->child_list = tp->child_list;
1665 anon_tp->modid = tp->modid;
1666 anon_tp->tc_index = tp->tc_index;
1667 anon_tp->type = tp->type;
1668 anon_tp->enums = tp->enums;
1669 anon_tp->indexes = tp->indexes;
1670 anon_tp->augments = tp->augments;
1671 anon_tp->varbinds = tp->varbinds;
1672 anon_tp->ranges = tp->ranges;
1673 anon_tp->hint = tp->hint;
1674 anon_tp->units = tp->units;
1675 anon_tp->description = tp->description;
1676 anon_tp->reference = tp->reference;
1677 anon_tp->defaultValue = tp->defaultValue;
1678 anon_tp->parent = tp->parent;
1679
1680 set_function(anon_tp);
1681
1682 /*
1683 * update parent pointer in moved children
1684 */
1685 ntp = anon_tp->child_list;
1686 while (ntp) {
1687 ntp->parent = anon_tp;
1688 ntp = ntp->next_peer;
1689 }
1690
1691 /*
1692 * hash in anon_tp in its new place
1693 */
1694 hash = NBUCKET(name_hash(anon_tp->label));
1695 anon_tp->next = tbuckets[hash];
1696 tbuckets[hash] = anon_tp;
1697
1698 /*
1699 * unlink and destroy tp
1700 */
1701 unlink_tbucket(tp);
1702 unlink_tree(tp);
1703 free(tp);
1704 } else {
1705 /*
1706 * Uh? One of these two should have been anonymous!
1707 */
1708 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
1709 NETSNMP_DS_LIB_MIB_WARNINGS)) {
1710 snmp_log(LOG_WARNING,
1711 "Warning: expected anonymous node (either %s or %s) in %s\n",
1712 tp->label, anon_tp->label, File);
1713 }
1714 }
1715 anon_tp = NULL;
1716 }
1717 }
1718 /*
1719 * free all nodes that were copied into tree
1720 */
1721 oldnp = NULL;
1722 for (np = child_list; np; np = np->next) {
1723 if (oldnp)
1724 free_node(oldnp);
1725 oldnp = np;
1726 }
1727 if (oldnp)
1728 free_node(oldnp);
1729 }
1730
1731 static void
do_linkup(struct module * mp,struct node * np)1732 do_linkup(struct module *mp, struct node *np)
1733 {
1734 struct module_import *mip;
1735 struct node *onp, *oldp, *newp;
1736 struct tree *tp;
1737 int i, more;
1738 /*
1739 * All modules implicitly import
1740 * the roots of the tree
1741 */
1742 if (snmp_get_do_debugging() > 1)
1743 dump_module_list();
1744 DEBUGMSGTL(("parse-mibs", "Processing IMPORTS for module %d %s\n",
1745 mp->modid, mp->name));
1746 if (mp->no_imports == 0) {
1747 mp->no_imports = NUMBER_OF_ROOT_NODES;
1748 mp->imports = root_imports;
1749 }
1750
1751 /*
1752 * Build the tree
1753 */
1754 init_node_hash(np);
1755 for (i = 0, mip = mp->imports; i < mp->no_imports; ++i, ++mip) {
1756 char modbuf[256];
1757 DEBUGMSGTL(("parse-mibs", " Processing import: %s\n",
1758 mip->label));
1759 if (get_tc_index(mip->label, mip->modid) != -1)
1760 continue;
1761 tp = find_tree_node(mip->label, mip->modid);
1762 if (!tp) {
1763 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_ERRORS))
1764 snmp_log(LOG_WARNING,
1765 "Did not find '%s' in module %s (%s)\n",
1766 mip->label, module_name(mip->modid, modbuf),
1767 File);
1768 continue;
1769 }
1770 do_subtree(tp, &np);
1771 }
1772
1773 /*
1774 * If any nodes left over,
1775 * check that they're not the result of a "fully qualified"
1776 * name, and then add them to the list of orphans
1777 */
1778
1779 if (!np)
1780 return;
1781 for (tp = tree_head; tp; tp = tp->next_peer)
1782 do_subtree(tp, &np);
1783 if (!np)
1784 return;
1785
1786 /*
1787 * quietly move all internal references to the orphan list
1788 */
1789 oldp = orphan_nodes;
1790 do {
1791 for (i = 0; i < NHASHSIZE; i++)
1792 for (onp = nbuckets[i]; onp; onp = onp->next) {
1793 struct node *op = NULL;
1794 int hash = NBUCKET(name_hash(onp->label));
1795 np = nbuckets[hash];
1796 while (np) {
1797 if (label_compare(onp->label, np->parent)) {
1798 op = np;
1799 np = np->next;
1800 } else {
1801 if (op)
1802 op->next = np->next;
1803 else
1804 nbuckets[hash] = np->next;
1805 DEBUGMSGTL(("parse-mibs", "Moving %s to orphanage", np->label));
1806 np->next = orphan_nodes;
1807 orphan_nodes = np;
1808 op = NULL;
1809 np = nbuckets[hash];
1810 }
1811 }
1812 }
1813 newp = orphan_nodes;
1814 more = 0;
1815 for (onp = orphan_nodes; onp != oldp; onp = onp->next) {
1816 struct node *op = NULL;
1817 int hash = NBUCKET(name_hash(onp->label));
1818 np = nbuckets[hash];
1819 while (np) {
1820 if (label_compare(onp->label, np->parent)) {
1821 op = np;
1822 np = np->next;
1823 } else {
1824 if (op)
1825 op->next = np->next;
1826 else
1827 nbuckets[hash] = np->next;
1828 np->next = orphan_nodes;
1829 orphan_nodes = np;
1830 op = NULL;
1831 np = nbuckets[hash];
1832 more = 1;
1833 }
1834 }
1835 }
1836 oldp = newp;
1837 } while (more);
1838
1839 /*
1840 * complain about left over nodes
1841 */
1842 for (np = orphan_nodes; np && np->next; np = np->next); /* find the end of the orphan list */
1843 for (i = 0; i < NHASHSIZE; i++)
1844 if (nbuckets[i]) {
1845 if (orphan_nodes)
1846 onp = np->next = nbuckets[i];
1847 else
1848 onp = orphan_nodes = nbuckets[i];
1849 nbuckets[i] = NULL;
1850 while (onp) {
1851 snmp_log(LOG_WARNING,
1852 "Unlinked OID in %s: %s ::= { %s %ld }\n",
1853 (mp->name ? mp->name : "<no module>"),
1854 (onp->label ? onp->label : "<no label>"),
1855 (onp->parent ? onp->parent : "<no parent>"),
1856 onp->subid);
1857 snmp_log(LOG_WARNING,
1858 "Undefined identifier: %s near line %d of %s\n",
1859 (onp->parent ? onp->parent : "<no parent>"),
1860 onp->lineno, onp->filename);
1861 np = onp;
1862 onp = onp->next;
1863 }
1864 }
1865 return;
1866 }
1867
1868
1869 /*
1870 * Takes a list of the form:
1871 * { iso org(3) dod(6) 1 }
1872 * and creates several nodes, one for each parent-child pair.
1873 * Returns 0 on error.
1874 */
1875 static int
getoid(FILE * fp,struct subid_s * id,int length)1876 getoid(FILE * fp, struct subid_s *id, /* an array of subids */
1877 int length)
1878 { /* the length of the array */
1879 register int count;
1880 int type;
1881 char token[MAXTOKEN];
1882
1883 if ((type = get_token(fp, token, MAXTOKEN)) != LEFTBRACKET) {
1884 print_error("Expected \"{\"", token, type);
1885 return 0;
1886 }
1887 type = get_token(fp, token, MAXTOKEN);
1888 for (count = 0; count < length; count++, id++) {
1889 id->label = NULL;
1890 id->modid = current_module;
1891 id->subid = -1;
1892 if (type == RIGHTBRACKET)
1893 return count;
1894 if (type == LABEL) {
1895 /*
1896 * this entry has a label
1897 */
1898 id->label = strdup(token);
1899 type = get_token(fp, token, MAXTOKEN);
1900 if (type == LEFTPAREN) {
1901 type = get_token(fp, token, MAXTOKEN);
1902 if (type == NUMBER) {
1903 id->subid = strtoul(token, NULL, 10);
1904 if ((type =
1905 get_token(fp, token, MAXTOKEN)) != RIGHTPAREN) {
1906 print_error("Expected a closing parenthesis",
1907 token, type);
1908 return 0;
1909 }
1910 } else {
1911 print_error("Expected a number", token, type);
1912 return 0;
1913 }
1914 } else {
1915 continue;
1916 }
1917 } else if (type == NUMBER) {
1918 /*
1919 * this entry has just an integer sub-identifier
1920 */
1921 id->subid = strtoul(token, NULL, 10);
1922 } else {
1923 print_error("Expected label or number", token, type);
1924 return 0;
1925 }
1926 type = get_token(fp, token, MAXTOKEN);
1927 }
1928 print_error("Too long OID", token, type);
1929 return 0;
1930 }
1931
1932 /*
1933 * Parse a sequence of object subidentifiers for the given name.
1934 * The "label OBJECT IDENTIFIER ::=" portion has already been parsed.
1935 *
1936 * The majority of cases take this form :
1937 * label OBJECT IDENTIFIER ::= { parent 2 }
1938 * where a parent label and a child subidentifier number are specified.
1939 *
1940 * Variations on the theme include cases where a number appears with
1941 * the parent, or intermediate subidentifiers are specified by label,
1942 * by number, or both.
1943 *
1944 * Here are some representative samples :
1945 * internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 }
1946 * mgmt OBJECT IDENTIFIER ::= { internet 2 }
1947 * rptrInfoHealth OBJECT IDENTIFIER ::= { snmpDot3RptrMgt 0 4 }
1948 *
1949 * Here is a very rare form :
1950 * iso OBJECT IDENTIFIER ::= { 1 }
1951 *
1952 * Returns NULL on error. When this happens, memory may be leaked.
1953 */
1954 static struct node *
parse_objectid(FILE * fp,char * name)1955 parse_objectid(FILE * fp, char *name)
1956 {
1957 register int count;
1958 register struct subid_s *op, *nop;
1959 int length;
1960 struct subid_s loid[32];
1961 struct node *np, *root = NULL, *oldnp = NULL;
1962 struct tree *tp;
1963
1964 if ((length = getoid(fp, loid, 32)) == 0) {
1965 print_error("Bad object identifier", NULL, CONTINUE);
1966 return NULL;
1967 }
1968
1969 /*
1970 * Handle numeric-only object identifiers,
1971 * by labelling the first sub-identifier
1972 */
1973 op = loid;
1974 if (!op->label) {
1975 if (length == 1) {
1976 print_error("Attempt to define a root oid", name, OBJECT);
1977 return NULL;
1978 }
1979 for (tp = tree_head; tp; tp = tp->next_peer)
1980 if ((int) tp->subid == op->subid) {
1981 op->label = strdup(tp->label);
1982 break;
1983 }
1984 }
1985
1986 /*
1987 * Handle "label OBJECT-IDENTIFIER ::= { subid }"
1988 */
1989 if (length == 1) {
1990 op = loid;
1991 np = alloc_node(op->modid);
1992 if (np == NULL)
1993 return (NULL);
1994 np->subid = op->subid;
1995 np->label = strdup(name);
1996 np->parent = op->label;
1997 return np;
1998 }
1999
2000 /*
2001 * For each parent-child subid pair in the subid array,
2002 * create a node and link it into the node list.
2003 */
2004 for (count = 0, op = loid, nop = loid + 1; count < (length - 1);
2005 count++, op++, nop++) {
2006 /*
2007 * every node must have parent's name and child's name or number
2008 */
2009 /*
2010 * XX the next statement is always true -- does it matter ??
2011 */
2012 if (op->label && (nop->label || (nop->subid != -1))) {
2013 np = alloc_node(nop->modid);
2014 if (np == NULL)
2015 goto err;
2016 if (root == NULL)
2017 root = np;
2018
2019 np->parent = strdup(op->label);
2020 if (count == (length - 2)) {
2021 /*
2022 * The name for this node is the label for this entry
2023 */
2024 np->label = strdup(name);
2025 if (np->label == NULL)
2026 goto err;
2027 } else {
2028 if (!nop->label) {
2029 nop->label = (char *) malloc(20 + ANON_LEN);
2030 if (nop->label == NULL)
2031 goto err;
2032 sprintf(nop->label, "%s%d", ANON, anonymous++);
2033 }
2034 np->label = strdup(nop->label);
2035 }
2036 if (nop->subid != -1)
2037 np->subid = nop->subid;
2038 else
2039 print_error("Warning: This entry is pretty silly",
2040 np->label, CONTINUE);
2041
2042 /*
2043 * set up next entry
2044 */
2045 if (oldnp)
2046 oldnp->next = np;
2047 oldnp = np;
2048 } /* end if(op->label... */
2049 }
2050
2051 out:
2052 /*
2053 * free the loid array
2054 */
2055 for (count = 0, op = loid; count < length; count++, op++) {
2056 if (op->label)
2057 free(op->label);
2058 }
2059
2060 return root;
2061
2062 err:
2063 for (; root; root = np) {
2064 np = root->next;
2065 free_node(root);
2066 }
2067 goto out;
2068 }
2069
2070 static int
get_tc(const char * descriptor,int modid,int * tc_index,struct enum_list ** ep,struct range_list ** rp,char ** hint)2071 get_tc(const char *descriptor,
2072 int modid,
2073 int *tc_index,
2074 struct enum_list **ep, struct range_list **rp, char **hint)
2075 {
2076 int i;
2077 struct tc *tcp;
2078
2079 i = get_tc_index(descriptor, modid);
2080 if (tc_index)
2081 *tc_index = i;
2082 if (i != -1) {
2083 tcp = &tclist[i];
2084 if (ep) {
2085 free_enums(ep);
2086 *ep = copy_enums(tcp->enums);
2087 }
2088 if (rp) {
2089 free_ranges(rp);
2090 *rp = copy_ranges(tcp->ranges);
2091 }
2092 if (hint) {
2093 if (*hint)
2094 free(*hint);
2095 *hint = (tcp->hint ? strdup(tcp->hint) : NULL);
2096 }
2097 return tcp->type;
2098 }
2099 return LABEL;
2100 }
2101
2102 /*
2103 * return index into tclist of given TC descriptor
2104 * return -1 if not found
2105 */
2106 static int
get_tc_index(const char * descriptor,int modid)2107 get_tc_index(const char *descriptor, int modid)
2108 {
2109 int i;
2110 struct tc *tcp;
2111 struct module *mp;
2112 struct module_import *mip;
2113
2114 /*
2115 * Check that the descriptor isn't imported
2116 * by searching the import list
2117 */
2118
2119 for (mp = module_head; mp; mp = mp->next)
2120 if (mp->modid == modid)
2121 break;
2122 if (mp)
2123 for (i = 0, mip = mp->imports; i < mp->no_imports; ++i, ++mip) {
2124 if (!label_compare(mip->label, descriptor)) {
2125 /*
2126 * Found it - so amend the module ID
2127 */
2128 modid = mip->modid;
2129 break;
2130 }
2131 }
2132
2133
2134 for (i = 0, tcp = tclist; i < tc_alloc; i++, tcp++) {
2135 if (tcp->type == 0)
2136 break;
2137 if (!label_compare(descriptor, tcp->descriptor) &&
2138 ((modid == tcp->modid) || (modid == -1))) {
2139 return i;
2140 }
2141 }
2142 return -1;
2143 }
2144
2145 /*
2146 * translate integer tc_index to string identifier from tclist
2147 * *
2148 * * Returns pointer to string in table (should not be modified) or NULL
2149 */
2150 const char *
get_tc_descriptor(int tc_index)2151 get_tc_descriptor(int tc_index)
2152 {
2153 if (tc_index < 0 || tc_index >= tc_alloc)
2154 return NULL;
2155 return tclist[tc_index].descriptor;
2156 }
2157
2158 #ifndef NETSNMP_FEATURE_REMOVE_GET_TC_DESCRIPTION
2159 /* used in the perl module */
2160 const char *
get_tc_description(int tc_index)2161 get_tc_description(int tc_index)
2162 {
2163 if (tc_index < 0 || tc_index >= tc_alloc)
2164 return NULL;
2165 return tclist[tc_index].description;
2166 }
2167 #endif /* NETSNMP_FEATURE_REMOVE_GET_TC_DESCRIPTION */
2168
2169
2170 /*
2171 * Parses an enumeration list of the form:
2172 * { label(value) label(value) ... }
2173 * The initial { has already been parsed.
2174 * Returns NULL on error.
2175 */
2176
2177 static struct enum_list *
parse_enumlist(FILE * fp,struct enum_list ** retp)2178 parse_enumlist(FILE * fp, struct enum_list **retp)
2179 {
2180 register int type;
2181 char token[MAXTOKEN];
2182 struct enum_list *ep = NULL, **epp = &ep;
2183
2184 free_enums(retp);
2185
2186 while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE) {
2187 if (type == RIGHTBRACKET)
2188 break;
2189 /* some enums use "deprecated" to indicate a no longer value label */
2190 /* (EG: IP-MIB's IpAddressStatusTC) */
2191 if (type == LABEL || type == DEPRECATED) {
2192 /*
2193 * this is an enumerated label
2194 */
2195 *epp =
2196 (struct enum_list *) calloc(1, sizeof(struct enum_list));
2197 if (*epp == NULL)
2198 return (NULL);
2199 /*
2200 * a reasonable approximation for the length
2201 */
2202 (*epp)->label = strdup(token);
2203 type = get_token(fp, token, MAXTOKEN);
2204 if (type != LEFTPAREN) {
2205 print_error("Expected \"(\"", token, type);
2206 return NULL;
2207 }
2208 type = get_token(fp, token, MAXTOKEN);
2209 if (type != NUMBER) {
2210 print_error("Expected integer", token, type);
2211 return NULL;
2212 }
2213 (*epp)->value = strtol(token, NULL, 10);
2214 type = get_token(fp, token, MAXTOKEN);
2215 if (type != RIGHTPAREN) {
2216 print_error("Expected \")\"", token, type);
2217 return NULL;
2218 }
2219 epp = &(*epp)->next;
2220 }
2221 }
2222 if (type == ENDOFFILE) {
2223 print_error("Expected \"}\"", token, type);
2224 return NULL;
2225 }
2226 *retp = ep;
2227 return ep;
2228 }
2229
2230 static struct range_list *
parse_ranges(FILE * fp,struct range_list ** retp)2231 parse_ranges(FILE * fp, struct range_list **retp)
2232 {
2233 int low, high;
2234 char nexttoken[MAXTOKEN];
2235 int nexttype;
2236 struct range_list *rp = NULL, **rpp = &rp;
2237 int size = 0, taken = 1;
2238
2239 free_ranges(retp);
2240
2241 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2242 if (nexttype == SIZE) {
2243 size = 1;
2244 taken = 0;
2245 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2246 if (nexttype != LEFTPAREN)
2247 print_error("Expected \"(\" after SIZE", nexttoken, nexttype);
2248 }
2249
2250 do {
2251 if (!taken)
2252 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2253 else
2254 taken = 0;
2255 high = low = strtoul(nexttoken, NULL, 10);
2256 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2257 if (nexttype == RANGE) {
2258 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2259 errno = 0;
2260 high = strtoul(nexttoken, NULL, 10);
2261 if ( errno == ERANGE ) {
2262 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
2263 NETSNMP_DS_LIB_MIB_WARNINGS))
2264 snmp_log(LOG_WARNING,
2265 "Warning: Upper bound not handled correctly (%s != %d): At line %d in %s\n",
2266 nexttoken, high, mibLine, File);
2267 }
2268 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2269 }
2270 *rpp = (struct range_list *) calloc(1, sizeof(struct range_list));
2271 if (*rpp == NULL)
2272 break;
2273 (*rpp)->low = low;
2274 (*rpp)->high = high;
2275 rpp = &(*rpp)->next;
2276
2277 } while (nexttype == BAR);
2278 if (size) {
2279 if (nexttype != RIGHTPAREN)
2280 print_error("Expected \")\" after SIZE", nexttoken, nexttype);
2281 nexttype = get_token(fp, nexttoken, nexttype);
2282 }
2283 if (nexttype != RIGHTPAREN)
2284 print_error("Expected \")\"", nexttoken, nexttype);
2285
2286 *retp = rp;
2287 return rp;
2288 }
2289
2290 /*
2291 * Parses an asn type. Structures are ignored by this parser.
2292 * Returns NULL on error.
2293 */
2294 static struct node *
parse_asntype(FILE * fp,char * name,int * ntype,char * ntoken)2295 parse_asntype(FILE * fp, char *name, int *ntype, char *ntoken)
2296 {
2297 int type, i;
2298 char token[MAXTOKEN];
2299 char quoted_string_buffer[MAXQUOTESTR];
2300 char *hint = NULL;
2301 char *descr = NULL;
2302 struct tc *tcp;
2303 int level;
2304
2305 type = get_token(fp, token, MAXTOKEN);
2306 if (type == SEQUENCE || type == CHOICE) {
2307 level = 0;
2308 while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE) {
2309 if (type == LEFTBRACKET) {
2310 level++;
2311 } else if (type == RIGHTBRACKET && --level == 0) {
2312 *ntype = get_token(fp, ntoken, MAXTOKEN);
2313 return NULL;
2314 }
2315 }
2316 print_error("Expected \"}\"", token, type);
2317 return NULL;
2318 } else if (type == LEFTBRACKET) {
2319 struct node *np;
2320 int ch_next = '{';
2321 ungetc(ch_next, fp);
2322 np = parse_objectid(fp, name);
2323 if (np != NULL) {
2324 *ntype = get_token(fp, ntoken, MAXTOKEN);
2325 return np;
2326 }
2327 return NULL;
2328 } else if (type == LEFTSQBRACK) {
2329 int size = 0;
2330 do {
2331 type = get_token(fp, token, MAXTOKEN);
2332 } while (type != ENDOFFILE && type != RIGHTSQBRACK);
2333 if (type != RIGHTSQBRACK) {
2334 print_error("Expected \"]\"", token, type);
2335 return NULL;
2336 }
2337 type = get_token(fp, token, MAXTOKEN);
2338 if (type == IMPLICIT)
2339 type = get_token(fp, token, MAXTOKEN);
2340 *ntype = get_token(fp, ntoken, MAXTOKEN);
2341 if (*ntype == LEFTPAREN) {
2342 switch (type) {
2343 case OCTETSTR:
2344 *ntype = get_token(fp, ntoken, MAXTOKEN);
2345 if (*ntype != SIZE) {
2346 print_error("Expected SIZE", ntoken, *ntype);
2347 return NULL;
2348 }
2349 size = 1;
2350 *ntype = get_token(fp, ntoken, MAXTOKEN);
2351 if (*ntype != LEFTPAREN) {
2352 print_error("Expected \"(\" after SIZE", ntoken,
2353 *ntype);
2354 return NULL;
2355 }
2356 /* FALL THROUGH */
2357 case INTEGER:
2358 *ntype = get_token(fp, ntoken, MAXTOKEN);
2359 do {
2360 if (*ntype != NUMBER)
2361 print_error("Expected NUMBER", ntoken, *ntype);
2362 *ntype = get_token(fp, ntoken, MAXTOKEN);
2363 if (*ntype == RANGE) {
2364 *ntype = get_token(fp, ntoken, MAXTOKEN);
2365 if (*ntype != NUMBER)
2366 print_error("Expected NUMBER", ntoken, *ntype);
2367 *ntype = get_token(fp, ntoken, MAXTOKEN);
2368 }
2369 } while (*ntype == BAR);
2370 if (*ntype != RIGHTPAREN) {
2371 print_error("Expected \")\"", ntoken, *ntype);
2372 return NULL;
2373 }
2374 *ntype = get_token(fp, ntoken, MAXTOKEN);
2375 if (size) {
2376 if (*ntype != RIGHTPAREN) {
2377 print_error("Expected \")\" to terminate SIZE",
2378 ntoken, *ntype);
2379 return NULL;
2380 }
2381 *ntype = get_token(fp, ntoken, MAXTOKEN);
2382 }
2383 }
2384 }
2385 return NULL;
2386 } else {
2387 if (type == CONVENTION) {
2388 while (type != SYNTAX && type != ENDOFFILE) {
2389 if (type == DISPLAYHINT) {
2390 type = get_token(fp, token, MAXTOKEN);
2391 if (type != QUOTESTRING) {
2392 print_error("DISPLAY-HINT must be string", token,
2393 type);
2394 } else {
2395 free(hint);
2396 hint = strdup(token);
2397 }
2398 } else if (type == DESCRIPTION &&
2399 netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
2400 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
2401 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2402 if (type != QUOTESTRING) {
2403 print_error("DESCRIPTION must be string", token,
2404 type);
2405 } else {
2406 free(descr);
2407 descr = strdup(quoted_string_buffer);
2408 }
2409 } else
2410 type =
2411 get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2412 }
2413 type = get_token(fp, token, MAXTOKEN);
2414 if (type == OBJECT) {
2415 type = get_token(fp, token, MAXTOKEN);
2416 if (type != IDENTIFIER) {
2417 print_error("Expected IDENTIFIER", token, type);
2418 goto err;
2419 }
2420 type = OBJID;
2421 }
2422 } else if (type == OBJECT) {
2423 type = get_token(fp, token, MAXTOKEN);
2424 if (type != IDENTIFIER) {
2425 print_error("Expected IDENTIFIER", token, type);
2426 goto err;
2427 }
2428 type = OBJID;
2429 }
2430
2431 if (type == LABEL) {
2432 type = get_tc(token, current_module, NULL, NULL, NULL, NULL);
2433 }
2434
2435 /*
2436 * textual convention
2437 */
2438 for (i = 0; i < tc_alloc; i++) {
2439 if (tclist[i].type == 0)
2440 break;
2441 }
2442
2443 if (i == tc_alloc) {
2444 tclist = realloc(tclist, (tc_alloc + TC_INCR)*sizeof(struct tc));
2445 memset(tclist+tc_alloc, 0, TC_INCR*sizeof(struct tc));
2446 tc_alloc += TC_INCR;
2447 }
2448 if (!(type & SYNTAX_MASK)) {
2449 print_error("Textual convention doesn't map to real type",
2450 token, type);
2451 goto err;
2452 }
2453 tcp = &tclist[i];
2454 tcp->modid = current_module;
2455 tcp->descriptor = strdup(name);
2456 tcp->hint = hint;
2457 tcp->description = descr;
2458 tcp->type = type;
2459 *ntype = get_token(fp, ntoken, MAXTOKEN);
2460 if (*ntype == LEFTPAREN) {
2461 tcp->ranges = parse_ranges(fp, &tcp->ranges);
2462 *ntype = get_token(fp, ntoken, MAXTOKEN);
2463 } else if (*ntype == LEFTBRACKET) {
2464 /*
2465 * if there is an enumeration list, parse it
2466 */
2467 tcp->enums = parse_enumlist(fp, &tcp->enums);
2468 *ntype = get_token(fp, ntoken, MAXTOKEN);
2469 }
2470 return NULL;
2471 }
2472
2473 err:
2474 SNMP_FREE(descr);
2475 SNMP_FREE(hint);
2476 return NULL;
2477 }
2478
2479
2480 /*
2481 * Parses an OBJECT TYPE macro.
2482 * Returns 0 on error.
2483 */
2484 static struct node *
parse_objecttype(FILE * fp,char * name)2485 parse_objecttype(FILE * fp, char *name)
2486 {
2487 register int type;
2488 char token[MAXTOKEN];
2489 char nexttoken[MAXTOKEN];
2490 char quoted_string_buffer[MAXQUOTESTR];
2491 int nexttype, tctype;
2492 register struct node *np;
2493
2494 type = get_token(fp, token, MAXTOKEN);
2495 if (type != SYNTAX) {
2496 print_error("Bad format for OBJECT-TYPE", token, type);
2497 return NULL;
2498 }
2499 np = alloc_node(current_module);
2500 if (np == NULL)
2501 return (NULL);
2502 type = get_token(fp, token, MAXTOKEN);
2503 if (type == OBJECT) {
2504 type = get_token(fp, token, MAXTOKEN);
2505 if (type != IDENTIFIER) {
2506 print_error("Expected IDENTIFIER", token, type);
2507 free_node(np);
2508 return NULL;
2509 }
2510 type = OBJID;
2511 }
2512 if (type == LABEL) {
2513 int tmp_index;
2514 tctype = get_tc(token, current_module, &tmp_index,
2515 &np->enums, &np->ranges, &np->hint);
2516 if (tctype == LABEL &&
2517 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
2518 NETSNMP_DS_LIB_MIB_WARNINGS) > 1) {
2519 print_error("Warning: No known translation for type", token,
2520 type);
2521 }
2522 type = tctype;
2523 np->tc_index = tmp_index; /* store TC for later reference */
2524 }
2525 np->type = type;
2526 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2527 switch (type) {
2528 case SEQUENCE:
2529 if (nexttype == OF) {
2530 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2531 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2532
2533 }
2534 break;
2535 case INTEGER:
2536 case INTEGER32:
2537 case UINTEGER32:
2538 case UNSIGNED32:
2539 case COUNTER:
2540 case GAUGE:
2541 case BITSTRING:
2542 case LABEL:
2543 if (nexttype == LEFTBRACKET) {
2544 /*
2545 * if there is an enumeration list, parse it
2546 */
2547 np->enums = parse_enumlist(fp, &np->enums);
2548 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2549 } else if (nexttype == LEFTPAREN) {
2550 /*
2551 * if there is a range list, parse it
2552 */
2553 np->ranges = parse_ranges(fp, &np->ranges);
2554 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2555 }
2556 break;
2557 case OCTETSTR:
2558 case KW_OPAQUE:
2559 /*
2560 * parse any SIZE specification
2561 */
2562 if (nexttype == LEFTPAREN) {
2563 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2564 if (nexttype == SIZE) {
2565 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2566 if (nexttype == LEFTPAREN) {
2567 np->ranges = parse_ranges(fp, &np->ranges);
2568 nexttype = get_token(fp, nexttoken, MAXTOKEN); /* ) */
2569 if (nexttype == RIGHTPAREN) {
2570 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2571 break;
2572 }
2573 }
2574 }
2575 print_error("Bad SIZE syntax", token, type);
2576 free_node(np);
2577 return NULL;
2578 }
2579 break;
2580 case OBJID:
2581 case NETADDR:
2582 case IPADDR:
2583 case TIMETICKS:
2584 case NUL:
2585 case NSAPADDRESS:
2586 case COUNTER64:
2587 break;
2588 default:
2589 print_error("Bad syntax", token, type);
2590 free_node(np);
2591 return NULL;
2592 }
2593 if (nexttype == UNITS) {
2594 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2595 if (type != QUOTESTRING) {
2596 print_error("Bad UNITS", quoted_string_buffer, type);
2597 free_node(np);
2598 return NULL;
2599 }
2600 np->units = strdup(quoted_string_buffer);
2601 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2602 }
2603 if (nexttype != ACCESS) {
2604 print_error("Should be ACCESS", nexttoken, nexttype);
2605 free_node(np);
2606 return NULL;
2607 }
2608 type = get_token(fp, token, MAXTOKEN);
2609 if (type != READONLY && type != READWRITE && type != WRITEONLY
2610 && type != NOACCESS && type != READCREATE && type != ACCNOTIFY) {
2611 print_error("Bad ACCESS type", token, type);
2612 free_node(np);
2613 return NULL;
2614 }
2615 np->access = type;
2616 type = get_token(fp, token, MAXTOKEN);
2617 if (type != STATUS) {
2618 print_error("Should be STATUS", token, type);
2619 free_node(np);
2620 return NULL;
2621 }
2622 type = get_token(fp, token, MAXTOKEN);
2623 if (type != MANDATORY && type != CURRENT && type != KW_OPTIONAL &&
2624 type != OBSOLETE && type != DEPRECATED) {
2625 print_error("Bad STATUS", token, type);
2626 free_node(np);
2627 return NULL;
2628 }
2629 np->status = type;
2630 /*
2631 * Optional parts of the OBJECT-TYPE macro
2632 */
2633 type = get_token(fp, token, MAXTOKEN);
2634 while (type != EQUALS && type != ENDOFFILE) {
2635 switch (type) {
2636 case DESCRIPTION:
2637 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2638
2639 if (type != QUOTESTRING) {
2640 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
2641 free_node(np);
2642 return NULL;
2643 }
2644 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
2645 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
2646 np->description = strdup(quoted_string_buffer);
2647 }
2648 break;
2649
2650 case REFERENCE:
2651 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2652 if (type != QUOTESTRING) {
2653 print_error("Bad REFERENCE", quoted_string_buffer, type);
2654 free_node(np);
2655 return NULL;
2656 }
2657 np->reference = strdup(quoted_string_buffer);
2658 break;
2659 case INDEX:
2660 if (np->augments) {
2661 print_error("Cannot have both INDEX and AUGMENTS", token,
2662 type);
2663 free_node(np);
2664 return NULL;
2665 }
2666 np->indexes = getIndexes(fp, &np->indexes);
2667 if (np->indexes == NULL) {
2668 print_error("Bad INDEX list", token, type);
2669 free_node(np);
2670 return NULL;
2671 }
2672 break;
2673 case AUGMENTS:
2674 if (np->indexes) {
2675 print_error("Cannot have both INDEX and AUGMENTS", token,
2676 type);
2677 free_node(np);
2678 return NULL;
2679 }
2680 np->indexes = getIndexes(fp, &np->indexes);
2681 if (np->indexes == NULL) {
2682 print_error("Bad AUGMENTS list", token, type);
2683 free_node(np);
2684 return NULL;
2685 }
2686 np->augments = strdup(np->indexes->ilabel);
2687 free_indexes(&np->indexes);
2688 break;
2689 case DEFVAL:
2690 /*
2691 * Mark's defVal section
2692 */
2693 type = get_token(fp, quoted_string_buffer, MAXTOKEN);
2694 if (type != LEFTBRACKET) {
2695 print_error("Bad DEFAULTVALUE", quoted_string_buffer,
2696 type);
2697 free_node(np);
2698 return NULL;
2699 }
2700
2701 {
2702 int level = 1;
2703 char defbuf[512];
2704
2705 defbuf[0] = 0;
2706 while (1) {
2707 type = get_token(fp, quoted_string_buffer, MAXTOKEN);
2708 if ((type == RIGHTBRACKET && --level == 0)
2709 || type == ENDOFFILE)
2710 break;
2711 else if (type == LEFTBRACKET)
2712 level++;
2713 if (type == QUOTESTRING)
2714 strlcat(defbuf, "\\\"", sizeof(defbuf));
2715 strlcat(defbuf, quoted_string_buffer, sizeof(defbuf));
2716 if (type == QUOTESTRING)
2717 strlcat(defbuf, "\\\"", sizeof(defbuf));
2718 strlcat(defbuf, " ", sizeof(defbuf));
2719 }
2720
2721 if (type != RIGHTBRACKET) {
2722 print_error("Bad DEFAULTVALUE", quoted_string_buffer,
2723 type);
2724 free_node(np);
2725 return NULL;
2726 }
2727
2728 defbuf[strlen(defbuf) - 1] = 0;
2729 np->defaultValue = strdup(defbuf);
2730 }
2731
2732 break;
2733
2734 case NUM_ENTRIES:
2735 if (tossObjectIdentifier(fp) != OBJID) {
2736 print_error("Bad Object Identifier", token, type);
2737 free_node(np);
2738 return NULL;
2739 }
2740 break;
2741
2742 default:
2743 print_error("Bad format of optional clauses", token, type);
2744 free_node(np);
2745 return NULL;
2746
2747 }
2748 type = get_token(fp, token, MAXTOKEN);
2749 }
2750 if (type != EQUALS) {
2751 print_error("Bad format", token, type);
2752 free_node(np);
2753 return NULL;
2754 }
2755 return merge_parse_objectid(np, fp, name);
2756 }
2757
2758 /*
2759 * Parses an OBJECT GROUP macro.
2760 * Returns 0 on error.
2761 *
2762 * Also parses object-identity, since they are similar (ignore STATUS).
2763 * - WJH 10/96
2764 */
2765 static struct node *
parse_objectgroup(FILE * fp,char * name,int what,struct objgroup ** ol)2766 parse_objectgroup(FILE * fp, char *name, int what, struct objgroup **ol)
2767 {
2768 int type;
2769 char token[MAXTOKEN];
2770 char quoted_string_buffer[MAXQUOTESTR];
2771 struct node *np;
2772
2773 np = alloc_node(current_module);
2774 if (np == NULL)
2775 return (NULL);
2776 type = get_token(fp, token, MAXTOKEN);
2777 if (type == what) {
2778 type = get_token(fp, token, MAXTOKEN);
2779 if (type != LEFTBRACKET) {
2780 print_error("Expected \"{\"", token, type);
2781 goto skip;
2782 }
2783 do {
2784 struct objgroup *o;
2785 type = get_token(fp, token, MAXTOKEN);
2786 if (type != LABEL) {
2787 print_error("Bad identifier", token, type);
2788 goto skip;
2789 }
2790 o = (struct objgroup *) malloc(sizeof(struct objgroup));
2791 if (!o) {
2792 print_error("Resource failure", token, type);
2793 goto skip;
2794 }
2795 o->line = mibLine;
2796 o->name = strdup(token);
2797 o->next = *ol;
2798 *ol = o;
2799 type = get_token(fp, token, MAXTOKEN);
2800 } while (type == COMMA);
2801 if (type != RIGHTBRACKET) {
2802 print_error("Expected \"}\" after list", token, type);
2803 goto skip;
2804 }
2805 type = get_token(fp, token, type);
2806 }
2807 if (type != STATUS) {
2808 print_error("Expected STATUS", token, type);
2809 goto skip;
2810 }
2811 type = get_token(fp, token, MAXTOKEN);
2812 if (type != CURRENT && type != DEPRECATED && type != OBSOLETE) {
2813 print_error("Bad STATUS value", token, type);
2814 goto skip;
2815 }
2816 type = get_token(fp, token, MAXTOKEN);
2817 if (type != DESCRIPTION) {
2818 print_error("Expected DESCRIPTION", token, type);
2819 goto skip;
2820 }
2821 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2822 if (type != QUOTESTRING) {
2823 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
2824 free_node(np);
2825 return NULL;
2826 }
2827 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
2828 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
2829 np->description = strdup(quoted_string_buffer);
2830 }
2831 type = get_token(fp, token, MAXTOKEN);
2832 if (type == REFERENCE) {
2833 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2834 if (type != QUOTESTRING) {
2835 print_error("Bad REFERENCE", quoted_string_buffer, type);
2836 free_node(np);
2837 return NULL;
2838 }
2839 np->reference = strdup(quoted_string_buffer);
2840 type = get_token(fp, token, MAXTOKEN);
2841 }
2842 if (type != EQUALS)
2843 print_error("Expected \"::=\"", token, type);
2844 skip:
2845 while (type != EQUALS && type != ENDOFFILE)
2846 type = get_token(fp, token, MAXTOKEN);
2847
2848 return merge_parse_objectid(np, fp, name);
2849 }
2850
2851 /*
2852 * Parses a NOTIFICATION-TYPE macro.
2853 * Returns 0 on error.
2854 */
2855 static struct node *
parse_notificationDefinition(FILE * fp,char * name)2856 parse_notificationDefinition(FILE * fp, char *name)
2857 {
2858 register int type;
2859 char token[MAXTOKEN];
2860 char quoted_string_buffer[MAXQUOTESTR];
2861 register struct node *np;
2862
2863 np = alloc_node(current_module);
2864 if (np == NULL)
2865 return (NULL);
2866 type = get_token(fp, token, MAXTOKEN);
2867 while (type != EQUALS && type != ENDOFFILE) {
2868 switch (type) {
2869 case DESCRIPTION:
2870 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2871 if (type != QUOTESTRING) {
2872 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
2873 free_node(np);
2874 return NULL;
2875 }
2876 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
2877 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
2878 np->description = strdup(quoted_string_buffer);
2879 }
2880 break;
2881 case REFERENCE:
2882 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2883 if (type != QUOTESTRING) {
2884 print_error("Bad REFERENCE", quoted_string_buffer, type);
2885 free_node(np);
2886 return NULL;
2887 }
2888 np->reference = strdup(quoted_string_buffer);
2889 break;
2890 case OBJECTS:
2891 np->varbinds = getVarbinds(fp, &np->varbinds);
2892 if (!np->varbinds) {
2893 print_error("Bad OBJECTS list", token, type);
2894 free_node(np);
2895 return NULL;
2896 }
2897 break;
2898 default:
2899 /*
2900 * NOTHING
2901 */
2902 break;
2903 }
2904 type = get_token(fp, token, MAXTOKEN);
2905 }
2906 return merge_parse_objectid(np, fp, name);
2907 }
2908
2909 /*
2910 * Parses a TRAP-TYPE macro.
2911 * Returns 0 on error.
2912 */
2913 static struct node *
parse_trapDefinition(FILE * fp,char * name)2914 parse_trapDefinition(FILE * fp, char *name)
2915 {
2916 register int type;
2917 char token[MAXTOKEN];
2918 char quoted_string_buffer[MAXQUOTESTR];
2919 register struct node *np;
2920
2921 np = alloc_node(current_module);
2922 if (np == NULL)
2923 return (NULL);
2924 type = get_token(fp, token, MAXTOKEN);
2925 while (type != EQUALS && type != ENDOFFILE) {
2926 switch (type) {
2927 case DESCRIPTION:
2928 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2929 if (type != QUOTESTRING) {
2930 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
2931 free_node(np);
2932 return NULL;
2933 }
2934 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
2935 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
2936 np->description = strdup(quoted_string_buffer);
2937 }
2938 break;
2939 case REFERENCE:
2940 /* I'm not sure REFERENCEs are legal in smiv1 traps??? */
2941 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2942 if (type != QUOTESTRING) {
2943 print_error("Bad REFERENCE", quoted_string_buffer, type);
2944 free_node(np);
2945 return NULL;
2946 }
2947 np->reference = strdup(quoted_string_buffer);
2948 break;
2949 case ENTERPRISE:
2950 type = get_token(fp, token, MAXTOKEN);
2951 if (type == LEFTBRACKET) {
2952 type = get_token(fp, token, MAXTOKEN);
2953 if (type != LABEL) {
2954 print_error("Bad Trap Format", token, type);
2955 free_node(np);
2956 return NULL;
2957 }
2958 np->parent = strdup(token);
2959 /*
2960 * Get right bracket
2961 */
2962 type = get_token(fp, token, MAXTOKEN);
2963 } else if (type == LABEL) {
2964 np->parent = strdup(token);
2965 } else {
2966 free_node(np);
2967 return NULL;
2968 }
2969 break;
2970 case VARIABLES:
2971 np->varbinds = getVarbinds(fp, &np->varbinds);
2972 if (!np->varbinds) {
2973 print_error("Bad VARIABLES list", token, type);
2974 free_node(np);
2975 return NULL;
2976 }
2977 break;
2978 default:
2979 /*
2980 * NOTHING
2981 */
2982 break;
2983 }
2984 type = get_token(fp, token, MAXTOKEN);
2985 }
2986 type = get_token(fp, token, MAXTOKEN);
2987
2988 np->label = strdup(name);
2989
2990 if (type != NUMBER) {
2991 print_error("Expected a Number", token, type);
2992 free_node(np);
2993 return NULL;
2994 }
2995 np->subid = strtoul(token, NULL, 10);
2996 np->next = alloc_node(current_module);
2997 if (np->next == NULL) {
2998 free_node(np);
2999 return (NULL);
3000 }
3001
3002 /* Catch the syntax error */
3003 if (np->parent == NULL) {
3004 free_node(np->next);
3005 free_node(np);
3006 gMibError = MODULE_SYNTAX_ERROR;
3007 return (NULL);
3008 }
3009
3010 np->next->parent = np->parent;
3011 np->parent = (char *) malloc(strlen(np->parent) + 2);
3012 if (np->parent == NULL) {
3013 free_node(np->next);
3014 free_node(np);
3015 return (NULL);
3016 }
3017 strcpy(np->parent, np->next->parent);
3018 strcat(np->parent, "#");
3019 np->next->label = strdup(np->parent);
3020 return np;
3021 }
3022
3023
3024 /*
3025 * Parses a compliance macro
3026 * Returns 0 on error.
3027 */
3028 static int
eat_syntax(FILE * fp,char * token,int maxtoken)3029 eat_syntax(FILE * fp, char *token, int maxtoken)
3030 {
3031 int type, nexttype;
3032 struct node *np = alloc_node(current_module);
3033 char nexttoken[MAXTOKEN];
3034
3035 if (!np)
3036 return 0;
3037
3038 type = get_token(fp, token, maxtoken);
3039 nexttype = get_token(fp, nexttoken, MAXTOKEN);
3040 switch (type) {
3041 case INTEGER:
3042 case INTEGER32:
3043 case UINTEGER32:
3044 case UNSIGNED32:
3045 case COUNTER:
3046 case GAUGE:
3047 case BITSTRING:
3048 case LABEL:
3049 if (nexttype == LEFTBRACKET) {
3050 /*
3051 * if there is an enumeration list, parse it
3052 */
3053 np->enums = parse_enumlist(fp, &np->enums);
3054 nexttype = get_token(fp, nexttoken, MAXTOKEN);
3055 } else if (nexttype == LEFTPAREN) {
3056 /*
3057 * if there is a range list, parse it
3058 */
3059 np->ranges = parse_ranges(fp, &np->ranges);
3060 nexttype = get_token(fp, nexttoken, MAXTOKEN);
3061 }
3062 break;
3063 case OCTETSTR:
3064 case KW_OPAQUE:
3065 /*
3066 * parse any SIZE specification
3067 */
3068 if (nexttype == LEFTPAREN) {
3069 nexttype = get_token(fp, nexttoken, MAXTOKEN);
3070 if (nexttype == SIZE) {
3071 nexttype = get_token(fp, nexttoken, MAXTOKEN);
3072 if (nexttype == LEFTPAREN) {
3073 np->ranges = parse_ranges(fp, &np->ranges);
3074 nexttype = get_token(fp, nexttoken, MAXTOKEN); /* ) */
3075 if (nexttype == RIGHTPAREN) {
3076 nexttype = get_token(fp, nexttoken, MAXTOKEN);
3077 break;
3078 }
3079 }
3080 }
3081 print_error("Bad SIZE syntax", token, type);
3082 free_node(np);
3083 return nexttype;
3084 }
3085 break;
3086 case OBJID:
3087 case NETADDR:
3088 case IPADDR:
3089 case TIMETICKS:
3090 case NUL:
3091 case NSAPADDRESS:
3092 case COUNTER64:
3093 break;
3094 default:
3095 print_error("Bad syntax", token, type);
3096 free_node(np);
3097 return nexttype;
3098 }
3099 free_node(np);
3100 return nexttype;
3101 }
3102
3103 static int
compliance_lookup(const char * name,int modid)3104 compliance_lookup(const char *name, int modid)
3105 {
3106 if (modid == -1) {
3107 struct objgroup *op =
3108 (struct objgroup *) malloc(sizeof(struct objgroup));
3109 if (!op)
3110 return 0;
3111 op->next = objgroups;
3112 op->name = strdup(name);
3113 op->line = mibLine;
3114 objgroups = op;
3115 return 1;
3116 } else
3117 return find_tree_node(name, modid) != NULL;
3118 }
3119
3120 static struct node *
parse_compliance(FILE * fp,char * name)3121 parse_compliance(FILE * fp, char *name)
3122 {
3123 int type;
3124 char token[MAXTOKEN];
3125 char quoted_string_buffer[MAXQUOTESTR];
3126 struct node *np;
3127
3128 np = alloc_node(current_module);
3129 if (np == NULL)
3130 return (NULL);
3131 type = get_token(fp, token, MAXTOKEN);
3132 if (type != STATUS) {
3133 print_error("Expected STATUS", token, type);
3134 goto skip;
3135 }
3136 type = get_token(fp, token, MAXTOKEN);
3137 if (type != CURRENT && type != DEPRECATED && type != OBSOLETE) {
3138 print_error("Bad STATUS", token, type);
3139 goto skip;
3140 }
3141 type = get_token(fp, token, MAXTOKEN);
3142 if (type != DESCRIPTION) {
3143 print_error("Expected DESCRIPTION", token, type);
3144 goto skip;
3145 }
3146 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3147 if (type != QUOTESTRING) {
3148 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3149 goto skip;
3150 }
3151 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
3152 NETSNMP_DS_LIB_SAVE_MIB_DESCRS))
3153 np->description = strdup(quoted_string_buffer);
3154 type = get_token(fp, token, MAXTOKEN);
3155 if (type == REFERENCE) {
3156 type = get_token(fp, quoted_string_buffer, MAXTOKEN);
3157 if (type != QUOTESTRING) {
3158 print_error("Bad REFERENCE", quoted_string_buffer, type);
3159 goto skip;
3160 }
3161 np->reference = strdup(quoted_string_buffer);
3162 type = get_token(fp, token, MAXTOKEN);
3163 }
3164 if (type != MODULE) {
3165 print_error("Expected MODULE", token, type);
3166 goto skip;
3167 }
3168 while (type == MODULE) {
3169 int modid = -1;
3170 char modname[MAXTOKEN];
3171 type = get_token(fp, token, MAXTOKEN);
3172 if (type == LABEL
3173 && strcmp(token, module_name(current_module, modname))) {
3174 modid = read_module_internal(token);
3175 if (modid != MODULE_LOADED_OK
3176 && modid != MODULE_ALREADY_LOADED) {
3177 print_error("Unknown module", token, type);
3178 goto skip;
3179 }
3180 modid = which_module(token);
3181 type = get_token(fp, token, MAXTOKEN);
3182 }
3183 if (type == MANDATORYGROUPS) {
3184 type = get_token(fp, token, MAXTOKEN);
3185 if (type != LEFTBRACKET) {
3186 print_error("Expected \"{\"", token, type);
3187 goto skip;
3188 }
3189 do {
3190 type = get_token(fp, token, MAXTOKEN);
3191 if (type != LABEL) {
3192 print_error("Bad group name", token, type);
3193 goto skip;
3194 }
3195 if (!compliance_lookup(token, modid))
3196 print_error("Unknown group", token, type);
3197 type = get_token(fp, token, MAXTOKEN);
3198 } while (type == COMMA);
3199 if (type != RIGHTBRACKET) {
3200 print_error("Expected \"}\"", token, type);
3201 goto skip;
3202 }
3203 type = get_token(fp, token, MAXTOKEN);
3204 }
3205 while (type == GROUP || type == OBJECT) {
3206 if (type == GROUP) {
3207 type = get_token(fp, token, MAXTOKEN);
3208 if (type != LABEL) {
3209 print_error("Bad group name", token, type);
3210 goto skip;
3211 }
3212 if (!compliance_lookup(token, modid))
3213 print_error("Unknown group", token, type);
3214 type = get_token(fp, token, MAXTOKEN);
3215 } else {
3216 type = get_token(fp, token, MAXTOKEN);
3217 if (type != LABEL) {
3218 print_error("Bad object name", token, type);
3219 goto skip;
3220 }
3221 if (!compliance_lookup(token, modid))
3222 print_error("Unknown group", token, type);
3223 type = get_token(fp, token, MAXTOKEN);
3224 if (type == SYNTAX)
3225 type = eat_syntax(fp, token, MAXTOKEN);
3226 if (type == WRSYNTAX)
3227 type = eat_syntax(fp, token, MAXTOKEN);
3228 if (type == MINACCESS) {
3229 type = get_token(fp, token, MAXTOKEN);
3230 if (type != NOACCESS && type != ACCNOTIFY
3231 && type != READONLY && type != WRITEONLY
3232 && type != READCREATE && type != READWRITE) {
3233 print_error("Bad MIN-ACCESS spec", token, type);
3234 goto skip;
3235 }
3236 type = get_token(fp, token, MAXTOKEN);
3237 }
3238 }
3239 if (type != DESCRIPTION) {
3240 print_error("Expected DESCRIPTION", token, type);
3241 goto skip;
3242 }
3243 type = get_token(fp, token, MAXTOKEN);
3244 if (type != QUOTESTRING) {
3245 print_error("Bad DESCRIPTION", token, type);
3246 goto skip;
3247 }
3248 type = get_token(fp, token, MAXTOKEN);
3249 }
3250 }
3251 skip:
3252 while (type != EQUALS && type != ENDOFFILE)
3253 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3254
3255 return merge_parse_objectid(np, fp, name);
3256 }
3257
3258
3259 /*
3260 * Parses a capabilities macro
3261 * Returns 0 on error.
3262 */
3263 static struct node *
parse_capabilities(FILE * fp,char * name)3264 parse_capabilities(FILE * fp, char *name)
3265 {
3266 int type;
3267 char token[MAXTOKEN];
3268 char quoted_string_buffer[MAXQUOTESTR];
3269 struct node *np;
3270
3271 np = alloc_node(current_module);
3272 if (np == NULL)
3273 return (NULL);
3274 type = get_token(fp, token, MAXTOKEN);
3275 if (type != PRODREL) {
3276 print_error("Expected PRODUCT-RELEASE", token, type);
3277 goto skip;
3278 }
3279 type = get_token(fp, token, MAXTOKEN);
3280 if (type != QUOTESTRING) {
3281 print_error("Expected STRING after PRODUCT-RELEASE", token, type);
3282 goto skip;
3283 }
3284 type = get_token(fp, token, MAXTOKEN);
3285 if (type != STATUS) {
3286 print_error("Expected STATUS", token, type);
3287 goto skip;
3288 }
3289 type = get_token(fp, token, MAXTOKEN);
3290 if (type != CURRENT && type != OBSOLETE) {
3291 print_error("STATUS should be current or obsolete", token, type);
3292 goto skip;
3293 }
3294 type = get_token(fp, token, MAXTOKEN);
3295 if (type != DESCRIPTION) {
3296 print_error("Expected DESCRIPTION", token, type);
3297 goto skip;
3298 }
3299 type = get_token(fp, quoted_string_buffer, MAXTOKEN);
3300 if (type != QUOTESTRING) {
3301 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3302 goto skip;
3303 }
3304 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
3305 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
3306 np->description = strdup(quoted_string_buffer);
3307 }
3308 type = get_token(fp, token, MAXTOKEN);
3309 if (type == REFERENCE) {
3310 type = get_token(fp, quoted_string_buffer, MAXTOKEN);
3311 if (type != QUOTESTRING) {
3312 print_error("Bad REFERENCE", quoted_string_buffer, type);
3313 goto skip;
3314 }
3315 np->reference = strdup(quoted_string_buffer);
3316 type = get_token(fp, token, type);
3317 }
3318 while (type == SUPPORTS) {
3319 int modid;
3320 struct tree *tp;
3321
3322 type = get_token(fp, token, MAXTOKEN);
3323 if (type != LABEL) {
3324 print_error("Bad module name", token, type);
3325 goto skip;
3326 }
3327 modid = read_module_internal(token);
3328 if (modid != MODULE_LOADED_OK && modid != MODULE_ALREADY_LOADED) {
3329 print_error("Module not found", token, type);
3330 goto skip;
3331 }
3332 modid = which_module(token);
3333 type = get_token(fp, token, MAXTOKEN);
3334 if (type != INCLUDES) {
3335 print_error("Expected INCLUDES", token, type);
3336 goto skip;
3337 }
3338 type = get_token(fp, token, MAXTOKEN);
3339 if (type != LEFTBRACKET) {
3340 print_error("Expected \"{\"", token, type);
3341 goto skip;
3342 }
3343 do {
3344 type = get_token(fp, token, MAXTOKEN);
3345 if (type != LABEL) {
3346 print_error("Expected group name", token, type);
3347 goto skip;
3348 }
3349 tp = find_tree_node(token, modid);
3350 if (!tp)
3351 print_error("Group not found in module", token, type);
3352 type = get_token(fp, token, MAXTOKEN);
3353 } while (type == COMMA);
3354 if (type != RIGHTBRACKET) {
3355 print_error("Expected \"}\" after group list", token, type);
3356 goto skip;
3357 }
3358 type = get_token(fp, token, MAXTOKEN);
3359 while (type == VARIATION) {
3360 type = get_token(fp, token, MAXTOKEN);
3361 if (type != LABEL) {
3362 print_error("Bad object name", token, type);
3363 goto skip;
3364 }
3365 tp = find_tree_node(token, modid);
3366 if (!tp)
3367 print_error("Object not found in module", token, type);
3368 type = get_token(fp, token, MAXTOKEN);
3369 if (type == SYNTAX) {
3370 type = eat_syntax(fp, token, MAXTOKEN);
3371 }
3372 if (type == WRSYNTAX) {
3373 type = eat_syntax(fp, token, MAXTOKEN);
3374 }
3375 if (type == ACCESS) {
3376 type = get_token(fp, token, MAXTOKEN);
3377 if (type != ACCNOTIFY && type != READONLY
3378 && type != READWRITE && type != READCREATE
3379 && type != WRITEONLY && type != NOTIMPL) {
3380 print_error("Bad ACCESS", token, type);
3381 goto skip;
3382 }
3383 type = get_token(fp, token, MAXTOKEN);
3384 }
3385 if (type == CREATEREQ) {
3386 type = get_token(fp, token, MAXTOKEN);
3387 if (type != LEFTBRACKET) {
3388 print_error("Expected \"{\"", token, type);
3389 goto skip;
3390 }
3391 do {
3392 type = get_token(fp, token, MAXTOKEN);
3393 if (type != LABEL) {
3394 print_error("Bad object name in list", token,
3395 type);
3396 goto skip;
3397 }
3398 type = get_token(fp, token, MAXTOKEN);
3399 } while (type == COMMA);
3400 if (type != RIGHTBRACKET) {
3401 print_error("Expected \"}\" after list", token, type);
3402 goto skip;
3403 }
3404 type = get_token(fp, token, MAXTOKEN);
3405 }
3406 if (type == DEFVAL) {
3407 int level = 1;
3408 type = get_token(fp, token, MAXTOKEN);
3409 if (type != LEFTBRACKET) {
3410 print_error("Expected \"{\" after DEFVAL", token,
3411 type);
3412 goto skip;
3413 }
3414 do {
3415 type = get_token(fp, token, MAXTOKEN);
3416 if (type == LEFTBRACKET)
3417 level++;
3418 else if (type == RIGHTBRACKET)
3419 level--;
3420 } while ((type != RIGHTBRACKET || level != 0)
3421 && type != ENDOFFILE);
3422 if (type != RIGHTBRACKET) {
3423 print_error("Missing \"}\" after DEFVAL", token, type);
3424 goto skip;
3425 }
3426 type = get_token(fp, token, MAXTOKEN);
3427 }
3428 if (type != DESCRIPTION) {
3429 print_error("Expected DESCRIPTION", token, type);
3430 goto skip;
3431 }
3432 type = get_token(fp, quoted_string_buffer, MAXTOKEN);
3433 if (type != QUOTESTRING) {
3434 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3435 goto skip;
3436 }
3437 type = get_token(fp, token, MAXTOKEN);
3438 }
3439 }
3440 if (type != EQUALS)
3441 print_error("Expected \"::=\"", token, type);
3442 skip:
3443 while (type != EQUALS && type != ENDOFFILE) {
3444 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3445 }
3446 return merge_parse_objectid(np, fp, name);
3447 }
3448
3449 /*
3450 * Parses a module identity macro
3451 * Returns 0 on error.
3452 */
3453 static void
check_utc(const char * utc)3454 check_utc(const char *utc)
3455 {
3456 int len, year, month, day, hour, minute;
3457
3458 len = strlen(utc);
3459 if (utc[len - 1] != 'Z' && utc[len - 1] != 'z') {
3460 print_error("Timestamp should end with Z", utc, QUOTESTRING);
3461 return;
3462 }
3463 if (len == 11) {
3464 len =
3465 sscanf(utc, "%2d%2d%2d%2d%2dZ", &year, &month, &day, &hour,
3466 &minute);
3467 year += 1900;
3468 } else if (len == 13)
3469 len =
3470 sscanf(utc, "%4d%2d%2d%2d%2dZ", &year, &month, &day, &hour,
3471 &minute);
3472 else {
3473 print_error("Bad timestamp format (11 or 13 characters)",
3474 utc, QUOTESTRING);
3475 return;
3476 }
3477 if (len != 5) {
3478 print_error("Bad timestamp format", utc, QUOTESTRING);
3479 return;
3480 }
3481 if (month < 1 || month > 12)
3482 print_error("Bad month in timestamp", utc, QUOTESTRING);
3483 if (day < 1 || day > 31)
3484 print_error("Bad day in timestamp", utc, QUOTESTRING);
3485 if (hour < 0 || hour > 23)
3486 print_error("Bad hour in timestamp", utc, QUOTESTRING);
3487 if (minute < 0 || minute > 59)
3488 print_error("Bad minute in timestamp", utc, QUOTESTRING);
3489 }
3490
3491 static struct node *
parse_moduleIdentity(FILE * fp,char * name)3492 parse_moduleIdentity(FILE * fp, char *name)
3493 {
3494 register int type;
3495 char token[MAXTOKEN];
3496 char quoted_string_buffer[MAXQUOTESTR];
3497 register struct node *np;
3498
3499 np = alloc_node(current_module);
3500 if (np == NULL)
3501 return (NULL);
3502 type = get_token(fp, token, MAXTOKEN);
3503 if (type != LASTUPDATED) {
3504 print_error("Expected LAST-UPDATED", token, type);
3505 goto skip;
3506 }
3507 type = get_token(fp, token, MAXTOKEN);
3508 if (type != QUOTESTRING) {
3509 print_error("Need STRING for LAST-UPDATED", token, type);
3510 goto skip;
3511 }
3512 check_utc(token);
3513 type = get_token(fp, token, MAXTOKEN);
3514 if (type != ORGANIZATION) {
3515 print_error("Expected ORGANIZATION", token, type);
3516 goto skip;
3517 }
3518 type = get_token(fp, token, MAXTOKEN);
3519 if (type != QUOTESTRING) {
3520 print_error("Bad ORGANIZATION", token, type);
3521 goto skip;
3522 }
3523 type = get_token(fp, token, MAXTOKEN);
3524 if (type != CONTACTINFO) {
3525 print_error("Expected CONTACT-INFO", token, type);
3526 goto skip;
3527 }
3528 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3529 if (type != QUOTESTRING) {
3530 print_error("Bad CONTACT-INFO", quoted_string_buffer, type);
3531 goto skip;
3532 }
3533 type = get_token(fp, token, MAXTOKEN);
3534 if (type != DESCRIPTION) {
3535 print_error("Expected DESCRIPTION", token, type);
3536 goto skip;
3537 }
3538 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3539 if (type != QUOTESTRING) {
3540 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3541 goto skip;
3542 }
3543 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
3544 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
3545 np->description = strdup(quoted_string_buffer);
3546 }
3547 type = get_token(fp, token, MAXTOKEN);
3548 while (type == REVISION) {
3549 type = get_token(fp, token, MAXTOKEN);
3550 if (type != QUOTESTRING) {
3551 print_error("Bad REVISION", token, type);
3552 goto skip;
3553 }
3554 check_utc(token);
3555 type = get_token(fp, token, MAXTOKEN);
3556 if (type != DESCRIPTION) {
3557 print_error("Expected DESCRIPTION", token, type);
3558 goto skip;
3559 }
3560 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3561 if (type != QUOTESTRING) {
3562 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3563 goto skip;
3564 }
3565 type = get_token(fp, token, MAXTOKEN);
3566 }
3567 if (type != EQUALS)
3568 print_error("Expected \"::=\"", token, type);
3569 skip:
3570 while (type != EQUALS && type != ENDOFFILE) {
3571 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3572 }
3573 return merge_parse_objectid(np, fp, name);
3574 }
3575
3576
3577 /*
3578 * Parses a MACRO definition
3579 * Expect BEGIN, discard everything to end.
3580 * Returns 0 on error.
3581 */
3582 static struct node *
parse_macro(FILE * fp,char * name)3583 parse_macro(FILE * fp, char *name)
3584 {
3585 register int type;
3586 char token[MAXTOKEN];
3587 struct node *np;
3588 int iLine = mibLine;
3589
3590 np = alloc_node(current_module);
3591 if (np == NULL)
3592 return (NULL);
3593 type = get_token(fp, token, sizeof(token));
3594 while (type != EQUALS && type != ENDOFFILE) {
3595 type = get_token(fp, token, sizeof(token));
3596 }
3597 if (type != EQUALS) {
3598 if (np)
3599 free_node(np);
3600 return NULL;
3601 }
3602 while (type != BEGIN && type != ENDOFFILE) {
3603 type = get_token(fp, token, sizeof(token));
3604 }
3605 if (type != BEGIN) {
3606 if (np)
3607 free_node(np);
3608 return NULL;
3609 }
3610 while (type != END && type != ENDOFFILE) {
3611 type = get_token(fp, token, sizeof(token));
3612 }
3613 if (type != END) {
3614 if (np)
3615 free_node(np);
3616 return NULL;
3617 }
3618
3619 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
3620 NETSNMP_DS_LIB_MIB_WARNINGS)) {
3621 snmp_log(LOG_WARNING,
3622 "%s MACRO (lines %d..%d parsed and ignored).\n", name,
3623 iLine, mibLine);
3624 }
3625
3626 return np;
3627 }
3628
3629 /*
3630 * Parses a module import clause
3631 * loading any modules referenced
3632 */
3633 static void
parse_imports(FILE * fp)3634 parse_imports(FILE * fp)
3635 {
3636 register int type;
3637 char token[MAXTOKEN];
3638 char modbuf[256];
3639 #define MAX_IMPORTS 256
3640 struct module_import import_list[MAX_IMPORTS];
3641 int this_module;
3642 struct module *mp;
3643
3644 int import_count = 0; /* Total number of imported descriptors */
3645 int i = 0, old_i; /* index of first import from each module */
3646
3647 type = get_token(fp, token, MAXTOKEN);
3648
3649 /*
3650 * Parse the IMPORTS clause
3651 */
3652 while (type != SEMI && type != ENDOFFILE) {
3653 if (type == LABEL) {
3654 if (import_count == MAX_IMPORTS) {
3655 print_error("Too many imported symbols", token, type);
3656 do {
3657 type = get_token(fp, token, MAXTOKEN);
3658 } while (type != SEMI && type != ENDOFFILE);
3659 return;
3660 }
3661 import_list[import_count++].label = strdup(token);
3662 } else if (type == FROM) {
3663 type = get_token(fp, token, MAXTOKEN);
3664 if (import_count == i) { /* All imports are handled internally */
3665 type = get_token(fp, token, MAXTOKEN);
3666 continue;
3667 }
3668 this_module = which_module(token);
3669
3670 for (old_i = i; i < import_count; ++i)
3671 import_list[i].modid = this_module;
3672
3673 /*
3674 * Recursively read any pre-requisite modules
3675 */
3676 if (read_module_internal(token) == MODULE_NOT_FOUND) {
3677 int found = 0;
3678 for (; old_i < import_count; ++old_i) {
3679 found += read_import_replacements(token, &import_list[old_i]);
3680 }
3681 if (!found)
3682 print_module_not_found(token);
3683 }
3684 }
3685 type = get_token(fp, token, MAXTOKEN);
3686 }
3687
3688 /* Initialize modid in case the module name was missing. */
3689 for (; i < import_count; ++i)
3690 import_list[i].modid = -1;
3691
3692 /*
3693 * Save the import information
3694 * in the global module table
3695 */
3696 for (mp = module_head; mp; mp = mp->next)
3697 if (mp->modid == current_module) {
3698 if (import_count == 0)
3699 return;
3700 if (mp->imports && (mp->imports != root_imports)) {
3701 /*
3702 * this can happen if all modules are in one source file.
3703 */
3704 for (i = 0; i < mp->no_imports; ++i) {
3705 DEBUGMSGTL(("parse-mibs",
3706 "#### freeing Module %d '%s' %d\n",
3707 mp->modid, mp->imports[i].label,
3708 mp->imports[i].modid));
3709 free((char *) mp->imports[i].label);
3710 }
3711 free((char *) mp->imports);
3712 }
3713 mp->imports = (struct module_import *)
3714 calloc(import_count, sizeof(struct module_import));
3715 if (mp->imports == NULL)
3716 return;
3717 for (i = 0; i < import_count; ++i) {
3718 mp->imports[i].label = import_list[i].label;
3719 mp->imports[i].modid = import_list[i].modid;
3720 DEBUGMSGTL(("parse-mibs",
3721 "#### adding Module %d '%s' %d\n", mp->modid,
3722 mp->imports[i].label, mp->imports[i].modid));
3723 }
3724 mp->no_imports = import_count;
3725 return;
3726 }
3727
3728 /*
3729 * Shouldn't get this far
3730 */
3731 print_module_not_found(module_name(current_module, modbuf));
3732 return;
3733 }
3734
3735
3736
3737 /*
3738 * MIB module handling routines
3739 */
3740
3741 static void
dump_module_list(void)3742 dump_module_list(void)
3743 {
3744 struct module *mp = module_head;
3745
3746 DEBUGMSGTL(("parse-mibs", "Module list:\n"));
3747 while (mp) {
3748 DEBUGMSGTL(("parse-mibs", " %s %d %s %d\n", mp->name, mp->modid,
3749 mp->file, mp->no_imports));
3750 mp = mp->next;
3751 }
3752 }
3753
3754 int
which_module(const char * name)3755 which_module(const char *name)
3756 {
3757 struct module *mp;
3758
3759 for (mp = module_head; mp; mp = mp->next)
3760 if (!label_compare(mp->name, name))
3761 return (mp->modid);
3762
3763 DEBUGMSGTL(("parse-mibs", "Module %s not found\n", name));
3764 return (-1);
3765 }
3766
3767 /*
3768 * module_name - copy module name to user buffer, return ptr to same.
3769 */
3770 char *
module_name(int modid,char * cp)3771 module_name(int modid, char *cp)
3772 {
3773 struct module *mp;
3774
3775 for (mp = module_head; mp; mp = mp->next)
3776 if (mp->modid == modid) {
3777 strcpy(cp, mp->name);
3778 return (cp);
3779 }
3780
3781 if (modid != -1) DEBUGMSGTL(("parse-mibs", "Module %d not found\n", modid));
3782 sprintf(cp, "#%d", modid);
3783 return (cp);
3784 }
3785
3786 /*
3787 * Backwards compatability
3788 * Read newer modules that replace the one specified:-
3789 * either all of them (read_module_replacements),
3790 * or those relating to a specified identifier (read_import_replacements)
3791 * plus an interface to add new replacement requirements
3792 */
3793 netsnmp_feature_child_of(parse_add_module_replacement, netsnmp_unused);
3794 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_ADD_MODULE_REPLACEMENT
3795 void
add_module_replacement(const char * old_module,const char * new_module_name,const char * tag,int len)3796 add_module_replacement(const char *old_module,
3797 const char *new_module_name,
3798 const char *tag, int len)
3799 {
3800 struct module_compatability *mcp;
3801
3802 mcp = (struct module_compatability *)
3803 calloc(1, sizeof(struct module_compatability));
3804 if (mcp == NULL)
3805 return;
3806
3807 mcp->old_module = strdup(old_module);
3808 mcp->new_module = strdup(new_module_name);
3809 if (tag)
3810 mcp->tag = strdup(tag);
3811 mcp->tag_len = len;
3812
3813 mcp->next = module_map_head;
3814 module_map_head = mcp;
3815 }
3816 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_ADD_MODULE_REPLACEMENT */
3817
3818 static int
read_module_replacements(const char * name)3819 read_module_replacements(const char *name)
3820 {
3821 struct module_compatability *mcp;
3822
3823 for (mcp = module_map_head; mcp; mcp = mcp->next) {
3824 if (!label_compare(mcp->old_module, name)) {
3825 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
3826 NETSNMP_DS_LIB_MIB_WARNINGS)) {
3827 snmp_log(LOG_WARNING,
3828 "Loading replacement module %s for %s (%s)\n",
3829 mcp->new_module, name, File);
3830 }
3831 (void) netsnmp_read_module(mcp->new_module);
3832 return 1;
3833 }
3834 }
3835 return 0;
3836 }
3837
3838 static int
read_import_replacements(const char * old_module_name,struct module_import * identifier)3839 read_import_replacements(const char *old_module_name,
3840 struct module_import *identifier)
3841 {
3842 struct module_compatability *mcp;
3843
3844 /*
3845 * Look for matches first
3846 */
3847 for (mcp = module_map_head; mcp; mcp = mcp->next) {
3848 if (!label_compare(mcp->old_module, old_module_name)) {
3849
3850 if ( /* exact match */
3851 (mcp->tag_len == 0 &&
3852 (mcp->tag == NULL ||
3853 !label_compare(mcp->tag, identifier->label))) ||
3854 /*
3855 * prefix match
3856 */
3857 (mcp->tag_len != 0 &&
3858 !strncmp(mcp->tag, identifier->label, mcp->tag_len))
3859 ) {
3860
3861 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
3862 NETSNMP_DS_LIB_MIB_WARNINGS)) {
3863 snmp_log(LOG_WARNING,
3864 "Importing %s from replacement module %s instead of %s (%s)\n",
3865 identifier->label, mcp->new_module,
3866 old_module_name, File);
3867 }
3868 (void) netsnmp_read_module(mcp->new_module);
3869 identifier->modid = which_module(mcp->new_module);
3870 return 1; /* finished! */
3871 }
3872 }
3873 }
3874
3875 /*
3876 * If no exact match, load everything relevant
3877 */
3878 return read_module_replacements(old_module_name);
3879 }
3880
3881
3882 /*
3883 * Read in the named module
3884 * Returns the root of the whole tree
3885 * (by analogy with 'read_mib')
3886 */
3887 static int
read_module_internal(const char * name)3888 read_module_internal(const char *name)
3889 {
3890 struct module *mp;
3891 FILE *fp;
3892 struct node *np;
3893
3894 netsnmp_init_mib_internals();
3895
3896 for (mp = module_head; mp; mp = mp->next)
3897 if (!label_compare(mp->name, name)) {
3898 const char *oldFile = File;
3899 int oldLine = mibLine;
3900 int oldModule = current_module;
3901
3902 if (mp->no_imports != -1) {
3903 DEBUGMSGTL(("parse-mibs", "Module %s already loaded\n",
3904 name));
3905 return MODULE_ALREADY_LOADED;
3906 }
3907 if ((fp = fopen(mp->file, "r")) == NULL) {
3908 int rval;
3909 if (errno == ENOTDIR || errno == ENOENT)
3910 rval = MODULE_NOT_FOUND;
3911 else
3912 rval = MODULE_LOAD_FAILED;
3913 snmp_log_perror(mp->file);
3914 return rval;
3915 }
3916 #ifdef HAVE_FLOCKFILE
3917 flockfile(fp);
3918 #endif
3919 mp->no_imports = 0; /* Note that we've read the file */
3920 File = mp->file;
3921 mibLine = 1;
3922 current_module = mp->modid;
3923 /*
3924 * Parse the file
3925 */
3926 np = parse(fp, NULL);
3927 #ifdef HAVE_FUNLOCKFILE
3928 funlockfile(fp);
3929 #endif
3930 fclose(fp);
3931 File = oldFile;
3932 mibLine = oldLine;
3933 current_module = oldModule;
3934 if ((np == NULL) && (gMibError == MODULE_SYNTAX_ERROR) )
3935 return MODULE_SYNTAX_ERROR;
3936 return MODULE_LOADED_OK;
3937 }
3938
3939 return MODULE_NOT_FOUND;
3940 }
3941
3942 void
adopt_orphans(void)3943 adopt_orphans(void)
3944 {
3945 struct node *np, *onp;
3946 struct tree *tp;
3947 int i, adopted = 1;
3948
3949 if (!orphan_nodes)
3950 return;
3951 init_node_hash(orphan_nodes);
3952 orphan_nodes = NULL;
3953
3954 while (adopted) {
3955 adopted = 0;
3956 for (i = 0; i < NHASHSIZE; i++)
3957 if (nbuckets[i]) {
3958 for (np = nbuckets[i]; np != NULL; np = np->next) {
3959 tp = find_tree_node(np->parent, -1);
3960 if (tp) {
3961 do_subtree(tp, &np);
3962 adopted = 1;
3963 /*
3964 * if do_subtree adopted the entire bucket, stop
3965 */
3966 if(NULL == nbuckets[i])
3967 break;
3968
3969 /*
3970 * do_subtree may modify nbuckets, and if np
3971 * was adopted, np->next probably isn't an orphan
3972 * anymore. if np is still in the bucket (do_subtree
3973 * didn't adopt it) keep on plugging. otherwise
3974 * start over, at the top of the bucket.
3975 */
3976 for(onp = nbuckets[i]; onp; onp = onp->next)
3977 if(onp == np)
3978 break;
3979 if(NULL == onp) { /* not in the list */
3980 np = nbuckets[i]; /* start over */
3981 }
3982 }
3983 }
3984 }
3985 }
3986
3987 /*
3988 * Report on outstanding orphans
3989 * and link them back into the orphan list
3990 */
3991 for (i = 0; i < NHASHSIZE; i++)
3992 if (nbuckets[i]) {
3993 if (orphan_nodes)
3994 onp = np->next = nbuckets[i];
3995 else
3996 onp = orphan_nodes = nbuckets[i];
3997 nbuckets[i] = NULL;
3998 while (onp) {
3999 char modbuf[256];
4000 snmp_log(LOG_WARNING,
4001 "Cannot adopt OID in %s: %s ::= { %s %ld }\n",
4002 module_name(onp->modid, modbuf),
4003 (onp->label ? onp->label : "<no label>"),
4004 (onp->parent ? onp->parent : "<no parent>"),
4005 onp->subid);
4006
4007 np = onp;
4008 onp = onp->next;
4009 }
4010 }
4011 }
4012
4013 #ifndef NETSNMP_NO_LEGACY_DEFINITIONS
4014 struct tree *
read_module(const char * name)4015 read_module(const char *name)
4016 {
4017 return netsnmp_read_module(name);
4018 }
4019 #endif
4020
4021 struct tree *
netsnmp_read_module(const char * name)4022 netsnmp_read_module(const char *name)
4023 {
4024 int status = 0;
4025 status = read_module_internal(name);
4026
4027 if (status == MODULE_NOT_FOUND) {
4028 if (!read_module_replacements(name))
4029 print_module_not_found(name);
4030 } else if (status == MODULE_SYNTAX_ERROR) {
4031 gMibError = 0;
4032 gLoop = 1;
4033
4034 strncat(gMibNames, " ", sizeof(gMibNames) - strlen(gMibNames) - 1);
4035 strncat(gMibNames, name, sizeof(gMibNames) - strlen(gMibNames) - 1);
4036 }
4037
4038 return tree_head;
4039 }
4040
4041 /*
4042 * Prototype definition
4043 */
4044 void unload_module_by_ID(int modID, struct tree *tree_top);
4045
4046 void
unload_module_by_ID(int modID,struct tree * tree_top)4047 unload_module_by_ID(int modID, struct tree *tree_top)
4048 {
4049 struct tree *tp, *next;
4050 int i;
4051
4052 for (tp = tree_top; tp; tp = next) {
4053 /*
4054 * Essentially, this is equivalent to the code fragment:
4055 * if (tp->modID == modID)
4056 * tp->number_modules--;
4057 * but handles one tree node being part of several modules,
4058 * and possible multiple copies of the same module ID.
4059 */
4060 int nmod = tp->number_modules;
4061 if (nmod > 0) { /* in some module */
4062 /*
4063 * Remove all copies of this module ID
4064 */
4065 int cnt = 0, *pi1, *pi2 = tp->module_list;
4066 for (i = 0, pi1 = pi2; i < nmod; i++, pi2++) {
4067 if (*pi2 == modID)
4068 continue;
4069 cnt++;
4070 *pi1++ = *pi2;
4071 }
4072 if (nmod != cnt) { /* in this module */
4073 /*
4074 * if ( (nmod - cnt) > 1)
4075 * printf("Dup modid %d, %d times, '%s'\n", tp->modid, (nmod-cnt), tp->label); fflush(stdout); ?* XXDEBUG
4076 */
4077 tp->number_modules = cnt;
4078 switch (cnt) {
4079 case 0:
4080 tp->module_list[0] = -1; /* Mark unused, */
4081 /* FALL THROUGH */
4082
4083 case 1: /* save the remaining module */
4084 if (&(tp->modid) != tp->module_list) {
4085 tp->modid = tp->module_list[0];
4086 free(tp->module_list);
4087 tp->module_list = &(tp->modid);
4088 }
4089 break;
4090
4091 default:
4092 break;
4093 }
4094 } /* if tree node is in this module */
4095 }
4096 /*
4097 * if tree node is in some module
4098 */
4099 next = tp->next_peer;
4100
4101
4102 /*
4103 * OK - that's dealt with *this* node.
4104 * Now let's look at the children.
4105 * (Isn't recursion wonderful!)
4106 */
4107 if (tp->child_list)
4108 unload_module_by_ID(modID, tp->child_list);
4109
4110
4111 if (tp->number_modules == 0) {
4112 /*
4113 * This node isn't needed any more (except perhaps
4114 * for the sake of the children)
4115 */
4116 if (tp->child_list == NULL) {
4117 unlink_tree(tp);
4118 free_tree(tp);
4119 } else {
4120 free_partial_tree(tp, TRUE);
4121 }
4122 }
4123 }
4124 }
4125
4126 #ifndef NETSNMP_NO_LEGACY_DEFINITIONS
4127 int
unload_module(const char * name)4128 unload_module(const char *name)
4129 {
4130 return netsnmp_unload_module(name);
4131 }
4132 #endif
4133
4134 int
netsnmp_unload_module(const char * name)4135 netsnmp_unload_module(const char *name)
4136 {
4137 struct module *mp;
4138 int modID = -1;
4139
4140 for (mp = module_head; mp; mp = mp->next)
4141 if (!label_compare(mp->name, name)) {
4142 modID = mp->modid;
4143 break;
4144 }
4145
4146 if (modID == -1) {
4147 DEBUGMSGTL(("unload-mib", "Module %s not found to unload\n",
4148 name));
4149 return MODULE_NOT_FOUND;
4150 }
4151 unload_module_by_ID(modID, tree_head);
4152 mp->no_imports = -1; /* mark as unloaded */
4153 return MODULE_LOADED_OK; /* Well, you know what I mean! */
4154 }
4155
4156 /*
4157 * Clear module map, tree nodes, textual convention table.
4158 */
4159 void
unload_all_mibs(void)4160 unload_all_mibs(void)
4161 {
4162 struct module *mp;
4163 struct module_compatability *mcp;
4164 struct tc *ptc;
4165 unsigned int i;
4166
4167 for (mcp = module_map_head; mcp; mcp = module_map_head) {
4168 if (mcp == module_map)
4169 break;
4170 module_map_head = mcp->next;
4171 if (mcp->tag) free(NETSNMP_REMOVE_CONST(char *, mcp->tag));
4172 free(NETSNMP_REMOVE_CONST(char *, mcp->old_module));
4173 free(NETSNMP_REMOVE_CONST(char *, mcp->new_module));
4174 free(mcp);
4175 }
4176
4177 for (mp = module_head; mp; mp = module_head) {
4178 struct module_import *mi = mp->imports;
4179 if (mi) {
4180 for (i = 0; i < (unsigned int)mp->no_imports; ++i) {
4181 SNMP_FREE((mi + i)->label);
4182 }
4183 mp->no_imports = 0;
4184 if (mi == root_imports)
4185 memset(mi, 0, sizeof(*mi));
4186 else
4187 free(mi);
4188 }
4189
4190 unload_module_by_ID(mp->modid, tree_head);
4191 module_head = mp->next;
4192 free(mp->name);
4193 free(mp->file);
4194 free(mp);
4195 }
4196 unload_module_by_ID(-1, tree_head);
4197 /*
4198 * tree nodes are cleared
4199 */
4200
4201 for (i = 0, ptc = tclist; i < tc_alloc; i++, ptc++) {
4202 if (ptc->type == 0)
4203 continue;
4204 free_enums(&ptc->enums);
4205 free_ranges(&ptc->ranges);
4206 free(ptc->descriptor);
4207 if (ptc->hint)
4208 free(ptc->hint);
4209 if (ptc->description)
4210 free(ptc->description);
4211 }
4212 memset(tclist, 0, tc_alloc * sizeof(struct tc));
4213
4214 memset(buckets, 0, sizeof(buckets));
4215 memset(nbuckets, 0, sizeof(nbuckets));
4216 memset(tbuckets, 0, sizeof(tbuckets));
4217
4218 for (i = 0; i < sizeof(root_imports) / sizeof(root_imports[0]); i++) {
4219 SNMP_FREE(root_imports[i].label);
4220 }
4221
4222 max_module = 0;
4223 current_module = 0;
4224 module_map_head = NULL;
4225 SNMP_FREE(last_err_module);
4226 }
4227
4228 static void
new_module(const char * name,const char * file)4229 new_module(const char *name, const char *file)
4230 {
4231 struct module *mp;
4232
4233 for (mp = module_head; mp; mp = mp->next)
4234 if (!label_compare(mp->name, name)) {
4235 DEBUGMSGTL(("parse-mibs", " Module %s already noted\n", name));
4236 /*
4237 * Not the same file
4238 */
4239 if (label_compare(mp->file, file)) {
4240 DEBUGMSGTL(("parse-mibs", " %s is now in %s\n",
4241 name, file));
4242 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
4243 NETSNMP_DS_LIB_MIB_WARNINGS)) {
4244 snmp_log(LOG_WARNING,
4245 "Warning: Module %s was in %s now is %s\n",
4246 name, mp->file, file);
4247 }
4248
4249 /*
4250 * Use the new one in preference
4251 */
4252 free(mp->file);
4253 mp->file = strdup(file);
4254 }
4255 return;
4256 }
4257
4258 /*
4259 * Add this module to the list
4260 */
4261 DEBUGMSGTL(("parse-mibs", " Module %d %s is in %s\n", max_module,
4262 name, file));
4263 mp = (struct module *) calloc(1, sizeof(struct module));
4264 if (mp == NULL)
4265 return;
4266 mp->name = strdup(name);
4267 mp->file = strdup(file);
4268 mp->imports = NULL;
4269 mp->no_imports = -1; /* Not yet loaded */
4270 mp->modid = max_module;
4271 ++max_module;
4272
4273 mp->next = module_head; /* Or add to the *end* of the list? */
4274 module_head = mp;
4275 }
4276
4277
4278 static void
scan_objlist(struct node * root,struct module * mp,struct objgroup * list,const char * error)4279 scan_objlist(struct node *root, struct module *mp, struct objgroup *list, const char *error)
4280 {
4281 int oLine = mibLine;
4282
4283 while (list) {
4284 struct objgroup *gp = list;
4285 struct node *np;
4286 list = list->next;
4287 np = root;
4288 while (np)
4289 if (label_compare(np->label, gp->name))
4290 np = np->next;
4291 else
4292 break;
4293 if (!np) {
4294 int i;
4295 struct module_import *mip;
4296 /* if not local, check if it was IMPORTed */
4297 for (i = 0, mip = mp->imports; i < mp->no_imports; i++, mip++)
4298 if (strcmp(mip->label, gp->name) == 0)
4299 break;
4300 if (i == mp->no_imports) {
4301 mibLine = gp->line;
4302 print_error(error, gp->name, QUOTESTRING);
4303 }
4304 }
4305 free(gp->name);
4306 free(gp);
4307 }
4308 mibLine = oLine;
4309 }
4310
4311 /*
4312 * Parses a mib file and returns a linked list of nodes found in the file.
4313 * Returns NULL on error.
4314 */
4315 static struct node *
parse(FILE * fp,struct node * root)4316 parse(FILE * fp, struct node *root)
4317 {
4318 #ifdef TEST
4319 extern void xmalloc_stats(FILE *);
4320 #endif
4321 char token[MAXTOKEN];
4322 char name[MAXTOKEN+1];
4323 int type = LABEL;
4324 int lasttype = LABEL;
4325
4326 #define BETWEEN_MIBS 1
4327 #define IN_MIB 2
4328 int state = BETWEEN_MIBS;
4329 struct node *np, *nnp;
4330 struct objgroup *oldgroups = NULL, *oldobjects = NULL, *oldnotifs =
4331 NULL;
4332
4333 DEBUGMSGTL(("parse-file", "Parsing file: %s...\n", File));
4334
4335 if (last_err_module)
4336 free(last_err_module);
4337 last_err_module = NULL;
4338
4339 np = root;
4340 if (np != NULL) {
4341 /*
4342 * now find end of chain
4343 */
4344 while (np->next)
4345 np = np->next;
4346 }
4347
4348 while (type != ENDOFFILE) {
4349 if (lasttype == CONTINUE)
4350 lasttype = type;
4351 else
4352 type = lasttype = get_token(fp, token, MAXTOKEN);
4353
4354 switch (type) {
4355 case END:
4356 if (state != IN_MIB) {
4357 print_error("Error, END before start of MIB", NULL, type);
4358 gMibError = MODULE_SYNTAX_ERROR;
4359 return NULL;
4360 } else {
4361 struct module *mp;
4362 #ifdef TEST
4363 printf("\nNodes for Module %s:\n", name);
4364 print_nodes(stdout, root);
4365 #endif
4366 for (mp = module_head; mp; mp = mp->next)
4367 if (mp->modid == current_module)
4368 break;
4369 scan_objlist(root, mp, objgroups, "Undefined OBJECT-GROUP");
4370 scan_objlist(root, mp, objects, "Undefined OBJECT");
4371 scan_objlist(root, mp, notifs, "Undefined NOTIFICATION");
4372 objgroups = oldgroups;
4373 objects = oldobjects;
4374 notifs = oldnotifs;
4375 do_linkup(mp, root);
4376 np = root = NULL;
4377 }
4378 state = BETWEEN_MIBS;
4379 #ifdef TEST
4380 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
4381 NETSNMP_DS_LIB_MIB_WARNINGS)) {
4382 /* xmalloc_stats(stderr); */
4383 }
4384 #endif
4385 continue;
4386 case IMPORTS:
4387 parse_imports(fp);
4388 continue;
4389 case EXPORTS:
4390 while (type != SEMI && type != ENDOFFILE)
4391 type = get_token(fp, token, MAXTOKEN);
4392 continue;
4393 case LABEL:
4394 case INTEGER:
4395 case INTEGER32:
4396 case UINTEGER32:
4397 case UNSIGNED32:
4398 case COUNTER:
4399 case COUNTER64:
4400 case GAUGE:
4401 case IPADDR:
4402 case NETADDR:
4403 case NSAPADDRESS:
4404 case OBJSYNTAX:
4405 case APPSYNTAX:
4406 case SIMPLESYNTAX:
4407 case OBJNAME:
4408 case NOTIFNAME:
4409 case KW_OPAQUE:
4410 case TIMETICKS:
4411 break;
4412 case ENDOFFILE:
4413 continue;
4414 default:
4415 strlcpy(name, token, sizeof(name));
4416 type = get_token(fp, token, MAXTOKEN);
4417 nnp = NULL;
4418 if (type == MACRO) {
4419 nnp = parse_macro(fp, name);
4420 if (nnp == NULL) {
4421 print_error("Bad parse of MACRO", NULL, type);
4422 gMibError = MODULE_SYNTAX_ERROR;
4423 /*
4424 * return NULL;
4425 */
4426 }
4427 free_node(nnp); /* IGNORE */
4428 nnp = NULL;
4429 } else
4430 print_error(name, "is a reserved word", lasttype);
4431 continue; /* see if we can parse the rest of the file */
4432 }
4433 strlcpy(name, token, sizeof(name));
4434 type = get_token(fp, token, MAXTOKEN);
4435 nnp = NULL;
4436
4437 /*
4438 * Handle obsolete method to assign an object identifier to a
4439 * module
4440 */
4441 if (lasttype == LABEL && type == LEFTBRACKET) {
4442 while (type != RIGHTBRACKET && type != ENDOFFILE)
4443 type = get_token(fp, token, MAXTOKEN);
4444 if (type == ENDOFFILE) {
4445 print_error("Expected \"}\"", token, type);
4446 gMibError = MODULE_SYNTAX_ERROR;
4447 return NULL;
4448 }
4449 type = get_token(fp, token, MAXTOKEN);
4450 }
4451
4452 switch (type) {
4453 case DEFINITIONS:
4454 if (state != BETWEEN_MIBS) {
4455 print_error("Error, nested MIBS", NULL, type);
4456 gMibError = MODULE_SYNTAX_ERROR;
4457 return NULL;
4458 }
4459 state = IN_MIB;
4460 current_module = which_module(name);
4461 oldgroups = objgroups;
4462 objgroups = NULL;
4463 oldobjects = objects;
4464 objects = NULL;
4465 oldnotifs = notifs;
4466 notifs = NULL;
4467 if (current_module == -1) {
4468 new_module(name, File);
4469 current_module = which_module(name);
4470 }
4471 DEBUGMSGTL(("parse-mibs", "Parsing MIB: %d %s\n",
4472 current_module, name));
4473 while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE)
4474 if (type == BEGIN)
4475 break;
4476 break;
4477 case OBJTYPE:
4478 nnp = parse_objecttype(fp, name);
4479 if (nnp == NULL) {
4480 print_error("Bad parse of OBJECT-TYPE", NULL, type);
4481 gMibError = MODULE_SYNTAX_ERROR;
4482 return NULL;
4483 }
4484 break;
4485 case OBJGROUP:
4486 nnp = parse_objectgroup(fp, name, OBJECTS, &objects);
4487 if (nnp == NULL) {
4488 print_error("Bad parse of OBJECT-GROUP", NULL, type);
4489 gMibError = MODULE_SYNTAX_ERROR;
4490 return NULL;
4491 }
4492 break;
4493 case NOTIFGROUP:
4494 nnp = parse_objectgroup(fp, name, NOTIFICATIONS, ¬ifs);
4495 if (nnp == NULL) {
4496 print_error("Bad parse of NOTIFICATION-GROUP", NULL, type);
4497 gMibError = MODULE_SYNTAX_ERROR;
4498 return NULL;
4499 }
4500 break;
4501 case TRAPTYPE:
4502 nnp = parse_trapDefinition(fp, name);
4503 if (nnp == NULL) {
4504 print_error("Bad parse of TRAP-TYPE", NULL, type);
4505 gMibError = MODULE_SYNTAX_ERROR;
4506 return NULL;
4507 }
4508 break;
4509 case NOTIFTYPE:
4510 nnp = parse_notificationDefinition(fp, name);
4511 if (nnp == NULL) {
4512 print_error("Bad parse of NOTIFICATION-TYPE", NULL, type);
4513 gMibError = MODULE_SYNTAX_ERROR;
4514 return NULL;
4515 }
4516 break;
4517 case COMPLIANCE:
4518 nnp = parse_compliance(fp, name);
4519 if (nnp == NULL) {
4520 print_error("Bad parse of MODULE-COMPLIANCE", NULL, type);
4521 gMibError = MODULE_SYNTAX_ERROR;
4522 return NULL;
4523 }
4524 break;
4525 case AGENTCAP:
4526 nnp = parse_capabilities(fp, name);
4527 if (nnp == NULL) {
4528 print_error("Bad parse of AGENT-CAPABILITIES", NULL, type);
4529 gMibError = MODULE_SYNTAX_ERROR;
4530 return NULL;
4531 }
4532 break;
4533 case MACRO:
4534 nnp = parse_macro(fp, name);
4535 if (nnp == NULL) {
4536 print_error("Bad parse of MACRO", NULL, type);
4537 gMibError = MODULE_SYNTAX_ERROR;
4538 /*
4539 * return NULL;
4540 */
4541 }
4542 free_node(nnp); /* IGNORE */
4543 nnp = NULL;
4544 break;
4545 case MODULEIDENTITY:
4546 nnp = parse_moduleIdentity(fp, name);
4547 if (nnp == NULL) {
4548 print_error("Bad parse of MODULE-IDENTITY", NULL, type);
4549 gMibError = MODULE_SYNTAX_ERROR;
4550 return NULL;
4551 }
4552 break;
4553 case OBJIDENTITY:
4554 nnp = parse_objectgroup(fp, name, OBJECTS, &objects);
4555 if (nnp == NULL) {
4556 print_error("Bad parse of OBJECT-IDENTITY", NULL, type);
4557 gMibError = MODULE_SYNTAX_ERROR;
4558 return NULL;
4559 }
4560 break;
4561 case OBJECT:
4562 type = get_token(fp, token, MAXTOKEN);
4563 if (type != IDENTIFIER) {
4564 print_error("Expected IDENTIFIER", token, type);
4565 gMibError = MODULE_SYNTAX_ERROR;
4566 return NULL;
4567 }
4568 type = get_token(fp, token, MAXTOKEN);
4569 if (type != EQUALS) {
4570 print_error("Expected \"::=\"", token, type);
4571 gMibError = MODULE_SYNTAX_ERROR;
4572 return NULL;
4573 }
4574 nnp = parse_objectid(fp, name);
4575 if (nnp == NULL) {
4576 print_error("Bad parse of OBJECT IDENTIFIER", NULL, type);
4577 gMibError = MODULE_SYNTAX_ERROR;
4578 return NULL;
4579 }
4580 break;
4581 case EQUALS:
4582 nnp = parse_asntype(fp, name, &type, token);
4583 lasttype = CONTINUE;
4584 break;
4585 case ENDOFFILE:
4586 break;
4587 default:
4588 print_error("Bad operator", token, type);
4589 gMibError = MODULE_SYNTAX_ERROR;
4590 return NULL;
4591 }
4592 if (nnp) {
4593 if (np)
4594 np->next = nnp;
4595 else
4596 np = root = nnp;
4597 while (np->next)
4598 np = np->next;
4599 if (np->type == TYPE_OTHER)
4600 np->type = type;
4601 }
4602 }
4603 DEBUGMSGTL(("parse-file", "End of file (%s)\n", File));
4604 return root;
4605 }
4606
4607 /*
4608 * return zero if character is not a label character.
4609 */
4610 static int
is_labelchar(int ich)4611 is_labelchar(int ich)
4612 {
4613 netsnmp_assert(ich == EOF || (0 <= ich && ich < 256));
4614 if ((isalnum(ich)) || (ich == '-'))
4615 return 1;
4616 if (ich == '_' && netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
4617 NETSNMP_DS_LIB_MIB_PARSE_LABEL)) {
4618 return 1;
4619 }
4620
4621 return 0;
4622 }
4623
4624 /**
4625 * Read a single character from a file. Assumes that the caller has invoked
4626 * flockfile(). Uses fgetc_unlocked() instead of getc() since the former is
4627 * implemented as an inline function in glibc. See also bug 3447196
4628 * (http://sourceforge.net/tracker/?func=detail&aid=3447196&group_id=12694&atid=112694).
4629 */
netsnmp_getc(FILE * stream)4630 static int netsnmp_getc(FILE *stream)
4631 {
4632 #ifdef HAVE_FGETC_UNLOCKED
4633 return fgetc_unlocked(stream);
4634 #else
4635 return getc(stream);
4636 #endif
4637 }
4638
4639 /*
4640 * Parses a token from the file. The type of the token parsed is returned,
4641 * and the text is placed in the string pointed to by token.
4642 * Warning: this method may recurse.
4643 */
4644 static int
get_token(FILE * fp,char * token,int maxtlen)4645 get_token(FILE * fp, char *token, int maxtlen)
4646 {
4647 register int ch, ch_next;
4648 register char *cp = token;
4649 register int hash = 0;
4650 register struct tok *tp;
4651 int too_long = 0;
4652 enum { bdigits, xdigits, other } seenSymbols;
4653
4654 /*
4655 * skip all white space
4656 */
4657 do {
4658 ch = netsnmp_getc(fp);
4659 if (ch == '\n')
4660 mibLine++;
4661 }
4662 while (isspace(ch) && ch != EOF);
4663 *cp++ = ch;
4664 *cp = '\0';
4665 switch (ch) {
4666 case EOF:
4667 return ENDOFFILE;
4668 case '"':
4669 return parseQuoteString(fp, token, maxtlen);
4670 case '\'': /* binary or hex constant */
4671 seenSymbols = bdigits;
4672 while ((ch = netsnmp_getc(fp)) != EOF && ch != '\'') {
4673 switch (seenSymbols) {
4674 case bdigits:
4675 if (ch == '0' || ch == '1')
4676 break;
4677 seenSymbols = xdigits;
4678 /* FALL THROUGH */
4679 case xdigits:
4680 if (isxdigit(ch))
4681 break;
4682 seenSymbols = other;
4683 case other:
4684 break;
4685 }
4686 if (cp - token < maxtlen - 2)
4687 *cp++ = ch;
4688 }
4689 if (ch == '\'') {
4690 unsigned long val = 0;
4691 char *run = token + 1;
4692 ch = netsnmp_getc(fp);
4693 switch (ch) {
4694 case EOF:
4695 return ENDOFFILE;
4696 case 'b':
4697 case 'B':
4698 if (seenSymbols > bdigits) {
4699 *cp++ = '\'';
4700 *cp = 0;
4701 return LABEL;
4702 }
4703 while (run != cp)
4704 val = val * 2 + *run++ - '0';
4705 break;
4706 case 'h':
4707 case 'H':
4708 if (seenSymbols > xdigits) {
4709 *cp++ = '\'';
4710 *cp = 0;
4711 return LABEL;
4712 }
4713 while (run != cp) {
4714 ch = *run++;
4715 if ('0' <= ch && ch <= '9')
4716 val = val * 16 + ch - '0';
4717 else if ('a' <= ch && ch <= 'f')
4718 val = val * 16 + ch - 'a' + 10;
4719 else if ('A' <= ch && ch <= 'F')
4720 val = val * 16 + ch - 'A' + 10;
4721 }
4722 break;
4723 default:
4724 *cp++ = '\'';
4725 *cp = 0;
4726 return LABEL;
4727 }
4728 sprintf(token, "%ld", val);
4729 return NUMBER;
4730 } else
4731 return LABEL;
4732 case '(':
4733 return LEFTPAREN;
4734 case ')':
4735 return RIGHTPAREN;
4736 case '{':
4737 return LEFTBRACKET;
4738 case '}':
4739 return RIGHTBRACKET;
4740 case '[':
4741 return LEFTSQBRACK;
4742 case ']':
4743 return RIGHTSQBRACK;
4744 case ';':
4745 return SEMI;
4746 case ',':
4747 return COMMA;
4748 case '|':
4749 return BAR;
4750 case '.':
4751 ch_next = netsnmp_getc(fp);
4752 if (ch_next == '.')
4753 return RANGE;
4754 ungetc(ch_next, fp);
4755 return LABEL;
4756 case ':':
4757 ch_next = netsnmp_getc(fp);
4758 if (ch_next != ':') {
4759 ungetc(ch_next, fp);
4760 return LABEL;
4761 }
4762 ch_next = netsnmp_getc(fp);
4763 if (ch_next != '=') {
4764 ungetc(ch_next, fp);
4765 return LABEL;
4766 }
4767 return EQUALS;
4768 case '-':
4769 ch_next = netsnmp_getc(fp);
4770 if (ch_next == '-') {
4771 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
4772 NETSNMP_DS_LIB_MIB_COMMENT_TERM)) {
4773 /*
4774 * Treat the rest of this line as a comment.
4775 */
4776 while ((ch_next != EOF) && (ch_next != '\n'))
4777 ch_next = netsnmp_getc(fp);
4778 } else {
4779 /*
4780 * Treat the rest of the line or until another '--' as a comment
4781 */
4782 /*
4783 * (this is the "technically" correct way to parse comments)
4784 */
4785 ch = ' ';
4786 ch_next = netsnmp_getc(fp);
4787 while (ch_next != EOF && ch_next != '\n' &&
4788 (ch != '-' || ch_next != '-')) {
4789 ch = ch_next;
4790 ch_next = netsnmp_getc(fp);
4791 }
4792 }
4793 if (ch_next == EOF)
4794 return ENDOFFILE;
4795 if (ch_next == '\n')
4796 mibLine++;
4797 return get_token(fp, token, maxtlen);
4798 }
4799 ungetc(ch_next, fp);
4800 /* fallthrough */
4801 default:
4802 /*
4803 * Accumulate characters until end of token is found. Then attempt to
4804 * match this token as a reserved word. If a match is found, return the
4805 * type. Else it is a label.
4806 */
4807 if (!is_labelchar(ch))
4808 return LABEL;
4809 hash += tolower(ch);
4810 more:
4811 while (is_labelchar(ch_next = netsnmp_getc(fp))) {
4812 hash += tolower(ch_next);
4813 if (cp - token < maxtlen - 1)
4814 *cp++ = ch_next;
4815 else
4816 too_long = 1;
4817 }
4818 ungetc(ch_next, fp);
4819 *cp = '\0';
4820
4821 if (too_long)
4822 print_error("Warning: token too long", token, CONTINUE);
4823 for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
4824 if ((tp->hash == hash) && (!label_compare(tp->name, token)))
4825 break;
4826 }
4827 if (tp) {
4828 if (tp->token != CONTINUE)
4829 return (tp->token);
4830 while (isspace((ch_next = netsnmp_getc(fp))))
4831 if (ch_next == '\n')
4832 mibLine++;
4833 if (ch_next == EOF)
4834 return ENDOFFILE;
4835 if (isalnum(ch_next)) {
4836 *cp++ = ch_next;
4837 hash += tolower(ch_next);
4838 goto more;
4839 }
4840 }
4841 if (token[0] == '-' || isdigit((unsigned char)(token[0]))) {
4842 for (cp = token + 1; *cp; cp++)
4843 if (!isdigit((unsigned char)(*cp)))
4844 return LABEL;
4845 return NUMBER;
4846 }
4847 return LABEL;
4848 }
4849 }
4850
4851 netsnmp_feature_child_of(parse_get_token, netsnmp_unused);
4852 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_GET_TOKEN
4853 int
snmp_get_token(FILE * fp,char * token,int maxtlen)4854 snmp_get_token(FILE * fp, char *token, int maxtlen)
4855 {
4856 return get_token(fp, token, maxtlen);
4857 }
4858 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_GET_TOKEN */
4859
4860 int
add_mibfile(const char * tmpstr,const char * d_name)4861 add_mibfile(const char* tmpstr, const char* d_name)
4862 {
4863 FILE *fp;
4864 char token[MAXTOKEN], token2[MAXTOKEN];
4865
4866 /*
4867 * which module is this
4868 */
4869 if ((fp = fopen(tmpstr, "r")) == NULL) {
4870 snmp_log_perror(tmpstr);
4871 return 1;
4872 }
4873 DEBUGMSGTL(("parse-mibs", "Checking file: %s...\n",
4874 tmpstr));
4875 mibLine = 1;
4876 File = tmpstr;
4877 if (get_token(fp, token, MAXTOKEN) != LABEL) {
4878 fclose(fp);
4879 return 1;
4880 }
4881 /*
4882 * simple test for this being a MIB
4883 */
4884 if (get_token(fp, token2, MAXTOKEN) == DEFINITIONS) {
4885 new_module(token, tmpstr);
4886 fclose(fp);
4887 return 0;
4888 } else {
4889 fclose(fp);
4890 return 1;
4891 }
4892 }
4893
elemcmp(const void * a,const void * b)4894 static int elemcmp(const void *a, const void *b)
4895 {
4896 const char *const *s1 = a, *const *s2 = b;
4897
4898 return strcmp(*s1, *s2);
4899 }
4900
4901 /*
4902 * Scan a directory and return all filenames found as an array of pointers to
4903 * directory entries (@result).
4904 */
scan_directory(char *** result,const char * dirname)4905 static int scan_directory(char ***result, const char *dirname)
4906 {
4907 DIR *dir, *dir2;
4908 struct dirent *file;
4909 char **filenames = NULL;
4910 int fname_len, i, filename_count = 0, array_size = 0;
4911 char *tmpstr;
4912
4913 *result = NULL;
4914
4915 dir = opendir(dirname);
4916 if (!dir)
4917 return -1;
4918
4919 while ((file = readdir(dir))) {
4920 /*
4921 * Only parse file names that don't begin with a '.'
4922 * Also skip files ending in '~', or starting/ending
4923 * with '#' which are typically editor backup files.
4924 */
4925 fname_len = strlen(file->d_name);
4926 if (fname_len > 0 && file->d_name[0] != '.'
4927 && file->d_name[0] != '#'
4928 && file->d_name[fname_len-1] != '#'
4929 && file->d_name[fname_len-1] != '~') {
4930 if (asprintf(&tmpstr, "%s/%s", dirname, file->d_name) < 0)
4931 continue;
4932 dir2 = opendir(tmpstr);
4933 if (dir2) {
4934 /* file is a directory, don't read it */
4935 closedir(dir2);
4936 } else {
4937 if (filename_count >= array_size) {
4938 char **new_filenames;
4939
4940 array_size = (array_size + 16) * 2;
4941 new_filenames = realloc(filenames,
4942 array_size * sizeof(filenames[0]));
4943 if (!new_filenames) {
4944 free(tmpstr);
4945 for (i = 0; i < filename_count; i++)
4946 free(filenames[i]);
4947 free(filenames);
4948 closedir(dir);
4949 return -1;
4950 }
4951 filenames = new_filenames;
4952 }
4953 filenames[filename_count++] = tmpstr;
4954 tmpstr = NULL;
4955 }
4956 free(tmpstr);
4957 }
4958 }
4959 closedir(dir);
4960
4961 if (filenames)
4962 qsort(filenames, filename_count, sizeof(filenames[0]), elemcmp);
4963 *result = filenames;
4964
4965 return filename_count;
4966 }
4967
4968 /* For Win32 platforms, the directory does not maintain a last modification
4969 * date that we can compare with the modification date of the .index file.
4970 * Therefore there is no way to know whether any .index file is valid.
4971 * This is the reason for the #if !(defined(WIN32) || defined(cygwin))
4972 * in the add_mibdir function
4973 */
4974 int
add_mibdir(const char * dirname)4975 add_mibdir(const char *dirname)
4976 {
4977 const char *oldFile = File;
4978 char **filenames;
4979 int count = 0;
4980 int filename_count, i;
4981
4982 DEBUGMSGTL(("parse-mibs", "Scanning directory %s\n", dirname));
4983
4984 filename_count = scan_directory(&filenames, dirname);
4985
4986 if (filename_count >= 0) {
4987 for (i = 0; i < filename_count; i++) {
4988 if (add_mibfile(filenames[i], strrchr(filenames[i], '/')) == 0)
4989 count++;
4990 free(filenames[i]);
4991 }
4992 File = oldFile;
4993 free(filenames);
4994 return (count);
4995 }
4996 else
4997 DEBUGMSGTL(("parse-mibs","cannot open MIB directory %s\n", dirname));
4998
4999 return (-1);
5000 }
5001
5002
5003 /*
5004 * Returns the root of the whole tree
5005 * (for backwards compatability)
5006 */
5007 struct tree *
read_mib(const char * filename)5008 read_mib(const char *filename)
5009 {
5010 FILE *fp;
5011 char token[MAXTOKEN];
5012
5013 fp = fopen(filename, "r");
5014 if (fp == NULL) {
5015 snmp_log_perror(filename);
5016 return NULL;
5017 }
5018 mibLine = 1;
5019 File = filename;
5020 DEBUGMSGTL(("parse-mibs", "Parsing file: %s...\n", filename));
5021 if (get_token(fp, token, MAXTOKEN) != LABEL) {
5022 snmp_log(LOG_ERR, "Failed to parse MIB file %s\n", filename);
5023 fclose(fp);
5024 return NULL;
5025 }
5026 fclose(fp);
5027 new_module(token, filename);
5028 (void) netsnmp_read_module(token);
5029
5030 return tree_head;
5031 }
5032
5033
5034 struct tree *
read_all_mibs(void)5035 read_all_mibs(void)
5036 {
5037 struct module *mp;
5038
5039 for (mp = module_head; mp; mp = mp->next)
5040 if (mp->no_imports == -1)
5041 netsnmp_read_module(mp->name);
5042 adopt_orphans();
5043
5044 /* If entered the syntax error loop in "read_module()" */
5045 if (gLoop == 1) {
5046 gLoop = 0;
5047 free(gpMibErrorString);
5048 gpMibErrorString = NULL;
5049 if (asprintf(&gpMibErrorString, "Error in parsing MIB module(s): %s !"
5050 " Unable to load corresponding MIB(s)", gMibNames) < 0) {
5051 snmp_log(LOG_CRIT,
5052 "failed to allocated memory for gpMibErrorString\n");
5053 }
5054 }
5055
5056 /* Caller's responsibility to free this memory */
5057 tree_head->parseErrorString = gpMibErrorString;
5058
5059 return tree_head;
5060 }
5061
5062
5063 #ifdef TEST
main(int argc,char * argv[])5064 int main(int argc, char *argv[])
5065 {
5066 int i;
5067 struct tree *tp;
5068 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_WARNINGS, 2);
5069
5070 netsnmp_init_mib();
5071
5072 if (argc == 1)
5073 (void) read_all_mibs();
5074 else
5075 for (i = 1; i < argc; i++)
5076 read_mib(argv[i]);
5077
5078 for (tp = tree_head; tp; tp = tp->next_peer)
5079 print_subtree(stdout, tp, 0);
5080 free_tree(tree_head);
5081
5082 return 0;
5083 }
5084 #endif /* TEST */
5085
5086 static int
parseQuoteString(FILE * fp,char * token,int maxtlen)5087 parseQuoteString(FILE * fp, char *token, int maxtlen)
5088 {
5089 register int ch;
5090 int count = 0;
5091 int too_long = 0;
5092 char *token_start = token;
5093
5094 for (ch = netsnmp_getc(fp); ch != EOF; ch = netsnmp_getc(fp)) {
5095 if (ch == '\r')
5096 continue;
5097 if (ch == '\n') {
5098 mibLine++;
5099 } else if (ch == '"') {
5100 *token = '\0';
5101 if (too_long && netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
5102 NETSNMP_DS_LIB_MIB_WARNINGS) > 1) {
5103 /*
5104 * show short form for brevity sake
5105 */
5106 char ch_save = *(token_start + 50);
5107 *(token_start + 50) = '\0';
5108 print_error("Warning: string too long",
5109 token_start, QUOTESTRING);
5110 *(token_start + 50) = ch_save;
5111 }
5112 return QUOTESTRING;
5113 }
5114 /*
5115 * maximum description length check. If greater, keep parsing
5116 * but truncate the string
5117 */
5118 if (++count < maxtlen)
5119 *token++ = ch;
5120 else
5121 too_long = 1;
5122 }
5123
5124 return 0;
5125 }
5126
5127 /*
5128 * struct index_list *
5129 * getIndexes(FILE *fp):
5130 * This routine parses a string like { blah blah blah } and returns a
5131 * list of the strings enclosed within it.
5132 *
5133 */
5134 static struct index_list *
getIndexes(FILE * fp,struct index_list ** retp)5135 getIndexes(FILE * fp, struct index_list **retp)
5136 {
5137 int type;
5138 char token[MAXTOKEN];
5139 char nextIsImplied = 0;
5140
5141 struct index_list *mylist = NULL;
5142 struct index_list **mypp = &mylist;
5143
5144 free_indexes(retp);
5145
5146 type = get_token(fp, token, MAXTOKEN);
5147
5148 if (type != LEFTBRACKET) {
5149 return NULL;
5150 }
5151
5152 type = get_token(fp, token, MAXTOKEN);
5153 while (type != RIGHTBRACKET && type != ENDOFFILE) {
5154 if ((type == LABEL) || (type & SYNTAX_MASK)) {
5155 *mypp =
5156 (struct index_list *) calloc(1, sizeof(struct index_list));
5157 if (*mypp) {
5158 (*mypp)->ilabel = strdup(token);
5159 (*mypp)->isimplied = nextIsImplied;
5160 mypp = &(*mypp)->next;
5161 nextIsImplied = 0;
5162 }
5163 } else if (type == IMPLIED) {
5164 nextIsImplied = 1;
5165 }
5166 type = get_token(fp, token, MAXTOKEN);
5167 }
5168
5169 *retp = mylist;
5170 return mylist;
5171 }
5172
5173 static struct varbind_list *
getVarbinds(FILE * fp,struct varbind_list ** retp)5174 getVarbinds(FILE * fp, struct varbind_list **retp)
5175 {
5176 int type;
5177 char token[MAXTOKEN];
5178
5179 struct varbind_list *mylist = NULL;
5180 struct varbind_list **mypp = &mylist;
5181
5182 free_varbinds(retp);
5183
5184 type = get_token(fp, token, MAXTOKEN);
5185
5186 if (type != LEFTBRACKET) {
5187 return NULL;
5188 }
5189
5190 type = get_token(fp, token, MAXTOKEN);
5191 while (type != RIGHTBRACKET && type != ENDOFFILE) {
5192 if ((type == LABEL) || (type & SYNTAX_MASK)) {
5193 *mypp =
5194 (struct varbind_list *) calloc(1,
5195 sizeof(struct
5196 varbind_list));
5197 if (*mypp) {
5198 (*mypp)->vblabel = strdup(token);
5199 mypp = &(*mypp)->next;
5200 }
5201 }
5202 type = get_token(fp, token, MAXTOKEN);
5203 }
5204
5205 *retp = mylist;
5206 return mylist;
5207 }
5208
5209 static void
free_indexes(struct index_list ** spp)5210 free_indexes(struct index_list **spp)
5211 {
5212 if (spp && *spp) {
5213 struct index_list *pp, *npp;
5214
5215 pp = *spp;
5216 *spp = NULL;
5217
5218 while (pp) {
5219 npp = pp->next;
5220 if (pp->ilabel)
5221 free(pp->ilabel);
5222 free(pp);
5223 pp = npp;
5224 }
5225 }
5226 }
5227
5228 static void
free_varbinds(struct varbind_list ** spp)5229 free_varbinds(struct varbind_list **spp)
5230 {
5231 if (spp && *spp) {
5232 struct varbind_list *pp, *npp;
5233
5234 pp = *spp;
5235 *spp = NULL;
5236
5237 while (pp) {
5238 npp = pp->next;
5239 if (pp->vblabel)
5240 free(pp->vblabel);
5241 free(pp);
5242 pp = npp;
5243 }
5244 }
5245 }
5246
5247 static void
free_ranges(struct range_list ** spp)5248 free_ranges(struct range_list **spp)
5249 {
5250 if (spp && *spp) {
5251 struct range_list *pp, *npp;
5252
5253 pp = *spp;
5254 *spp = NULL;
5255
5256 while (pp) {
5257 npp = pp->next;
5258 free(pp);
5259 pp = npp;
5260 }
5261 }
5262 }
5263
5264 static void
free_enums(struct enum_list ** spp)5265 free_enums(struct enum_list **spp)
5266 {
5267 if (spp && *spp) {
5268 struct enum_list *pp, *npp;
5269
5270 pp = *spp;
5271 *spp = NULL;
5272
5273 while (pp) {
5274 npp = pp->next;
5275 if (pp->label)
5276 free(pp->label);
5277 free(pp);
5278 pp = npp;
5279 }
5280 }
5281 }
5282
5283 static struct enum_list *
copy_enums(struct enum_list * sp)5284 copy_enums(struct enum_list *sp)
5285 {
5286 struct enum_list *xp = NULL, **spp = &xp;
5287
5288 while (sp) {
5289 *spp = (struct enum_list *) calloc(1, sizeof(struct enum_list));
5290 if (!*spp)
5291 break;
5292 (*spp)->label = strdup(sp->label);
5293 (*spp)->value = sp->value;
5294 spp = &(*spp)->next;
5295 sp = sp->next;
5296 }
5297 return (xp);
5298 }
5299
5300 static struct range_list *
copy_ranges(struct range_list * sp)5301 copy_ranges(struct range_list *sp)
5302 {
5303 struct range_list *xp = NULL, **spp = &xp;
5304
5305 while (sp) {
5306 *spp = (struct range_list *) calloc(1, sizeof(struct range_list));
5307 if (!*spp)
5308 break;
5309 (*spp)->low = sp->low;
5310 (*spp)->high = sp->high;
5311 spp = &(*spp)->next;
5312 sp = sp->next;
5313 }
5314 return (xp);
5315 }
5316
5317 /*
5318 * This routine parses a string like { blah blah blah } and returns OBJID if
5319 * it is well formed, and NULL if not.
5320 */
5321 static int
tossObjectIdentifier(FILE * fp)5322 tossObjectIdentifier(FILE * fp)
5323 {
5324 int type;
5325 char token[MAXTOKEN];
5326 int bracketcount = 1;
5327
5328 type = get_token(fp, token, MAXTOKEN);
5329
5330 if (type != LEFTBRACKET)
5331 return 0;
5332 while ((type != RIGHTBRACKET || bracketcount > 0) && type != ENDOFFILE) {
5333 type = get_token(fp, token, MAXTOKEN);
5334 if (type == LEFTBRACKET)
5335 bracketcount++;
5336 else if (type == RIGHTBRACKET)
5337 bracketcount--;
5338 }
5339
5340 if (type == RIGHTBRACKET)
5341 return OBJID;
5342 else
5343 return 0;
5344 }
5345
5346 /* Find node in any MIB module
5347 Used by Perl modules */
5348 struct tree *
find_node(const char * name,struct tree * subtree)5349 find_node(const char *name, struct tree *subtree)
5350 { /* Unused */
5351 return (find_tree_node(name, -1));
5352 }
5353
5354 netsnmp_feature_child_of(parse_find_node2, netsnmp_unused);
5355 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_FIND_NODE2
5356 struct tree *
find_node2(const char * name,const char * module)5357 find_node2(const char *name, const char *module)
5358 {
5359 int modid = -1;
5360 if (module) {
5361 modid = which_module(module);
5362 }
5363 if (modid == -1)
5364 {
5365 return (NULL);
5366 }
5367 return (find_tree_node(name, modid));
5368 }
5369 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_FIND_NODE2 */
5370
5371 #ifndef NETSNMP_FEATURE_REMOVE_FIND_MODULE
5372 /* Used in the perl module */
5373 struct module *
find_module(int mid)5374 find_module(int mid)
5375 {
5376 struct module *mp;
5377
5378 for (mp = module_head; mp != NULL; mp = mp->next) {
5379 if (mp->modid == mid)
5380 break;
5381 }
5382 return mp;
5383 }
5384 #endif /* NETSNMP_FEATURE_REMOVE_FIND_MODULE */
5385
5386
5387 static char leave_indent[256];
5388 static int leave_was_simple;
5389
5390 static void
print_mib_leaves(FILE * f,struct tree * tp,int width)5391 print_mib_leaves(FILE * f, struct tree *tp, int width)
5392 {
5393 struct tree *ntp;
5394 char *ip = leave_indent + strlen(leave_indent) - 1;
5395 char last_ipch = *ip;
5396
5397 *ip = '+';
5398 if (tp->type == TYPE_OTHER || tp->type > TYPE_SIMPLE_LAST) {
5399 fprintf(f, "%s--%s(%ld)\n", leave_indent, tp->label, tp->subid);
5400 if (tp->indexes) {
5401 struct index_list *xp = tp->indexes;
5402 int first = 1, cpos = 0, len, cmax =
5403 width - strlen(leave_indent) - 12;
5404 *ip = last_ipch;
5405 fprintf(f, "%s | Index: ", leave_indent);
5406 while (xp) {
5407 if (first)
5408 first = 0;
5409 else
5410 fprintf(f, ", ");
5411 cpos += (len = strlen(xp->ilabel) + 2);
5412 if (cpos > cmax) {
5413 fprintf(f, "\n");
5414 fprintf(f, "%s | ", leave_indent);
5415 cpos = len;
5416 }
5417 fprintf(f, "%s", xp->ilabel);
5418 xp = xp->next;
5419 }
5420 fprintf(f, "\n");
5421 *ip = '+';
5422 }
5423 } else {
5424 const char *acc, *typ;
5425 int size = 0;
5426 switch (tp->access) {
5427 case MIB_ACCESS_NOACCESS:
5428 acc = "----";
5429 break;
5430 case MIB_ACCESS_READONLY:
5431 acc = "-R--";
5432 break;
5433 case MIB_ACCESS_WRITEONLY:
5434 acc = "--W-";
5435 break;
5436 case MIB_ACCESS_READWRITE:
5437 acc = "-RW-";
5438 break;
5439 case MIB_ACCESS_NOTIFY:
5440 acc = "---N";
5441 break;
5442 case MIB_ACCESS_CREATE:
5443 acc = "CR--";
5444 break;
5445 default:
5446 acc = " ";
5447 break;
5448 }
5449 switch (tp->type) {
5450 case TYPE_OBJID:
5451 typ = "ObjID ";
5452 break;
5453 case TYPE_OCTETSTR:
5454 typ = "String ";
5455 size = 1;
5456 break;
5457 case TYPE_INTEGER:
5458 if (tp->enums)
5459 typ = "EnumVal ";
5460 else
5461 typ = "INTEGER ";
5462 break;
5463 case TYPE_NETADDR:
5464 typ = "NetAddr ";
5465 break;
5466 case TYPE_IPADDR:
5467 typ = "IpAddr ";
5468 break;
5469 case TYPE_COUNTER:
5470 typ = "Counter ";
5471 break;
5472 case TYPE_GAUGE:
5473 typ = "Gauge ";
5474 break;
5475 case TYPE_TIMETICKS:
5476 typ = "TimeTicks";
5477 break;
5478 case TYPE_OPAQUE:
5479 typ = "Opaque ";
5480 size = 1;
5481 break;
5482 case TYPE_NULL:
5483 typ = "Null ";
5484 break;
5485 case TYPE_COUNTER64:
5486 typ = "Counter64";
5487 break;
5488 case TYPE_BITSTRING:
5489 typ = "BitString";
5490 break;
5491 case TYPE_NSAPADDRESS:
5492 typ = "NsapAddr ";
5493 break;
5494 case TYPE_UNSIGNED32:
5495 typ = "Unsigned ";
5496 break;
5497 case TYPE_UINTEGER:
5498 typ = "UInteger ";
5499 break;
5500 case TYPE_INTEGER32:
5501 typ = "Integer32";
5502 break;
5503 default:
5504 typ = " ";
5505 break;
5506 }
5507 fprintf(f, "%s-- %s %s %s(%ld)\n", leave_indent, acc, typ,
5508 tp->label, tp->subid);
5509 *ip = last_ipch;
5510 if (tp->tc_index >= 0)
5511 fprintf(f, "%s Textual Convention: %s\n", leave_indent,
5512 tclist[tp->tc_index].descriptor);
5513 if (tp->enums) {
5514 struct enum_list *ep = tp->enums;
5515 int cpos = 0, cmax =
5516 width - strlen(leave_indent) - 16;
5517 fprintf(f, "%s Values: ", leave_indent);
5518 while (ep) {
5519 char buf[80];
5520 int bufw;
5521 if (ep != tp->enums)
5522 fprintf(f, ", ");
5523 snprintf(buf, sizeof(buf), "%s(%d)", ep->label, ep->value);
5524 buf[ sizeof(buf)-1 ] = 0;
5525 cpos += (bufw = strlen(buf) + 2);
5526 if (cpos >= cmax) {
5527 fprintf(f, "\n%s ", leave_indent);
5528 cpos = bufw;
5529 }
5530 fprintf(f, "%s", buf);
5531 ep = ep->next;
5532 }
5533 fprintf(f, "\n");
5534 }
5535 if (tp->ranges) {
5536 struct range_list *rp = tp->ranges;
5537 if (size)
5538 fprintf(f, "%s Size: ", leave_indent);
5539 else
5540 fprintf(f, "%s Range: ", leave_indent);
5541 while (rp) {
5542 if (rp != tp->ranges)
5543 fprintf(f, " | ");
5544 print_range_value(f, tp->type, rp);
5545 rp = rp->next;
5546 }
5547 fprintf(f, "\n");
5548 }
5549 }
5550 *ip = last_ipch;
5551 strcat(leave_indent, " |");
5552 leave_was_simple = tp->type != TYPE_OTHER;
5553
5554 {
5555 int i, j, count = 0;
5556 struct leave {
5557 oid id;
5558 struct tree *tp;
5559 } *leaves, *lp;
5560
5561 for (ntp = tp->child_list; ntp; ntp = ntp->next_peer)
5562 count++;
5563 if (count) {
5564 leaves = (struct leave *) calloc(count, sizeof(struct leave));
5565 if (!leaves)
5566 return;
5567 for (ntp = tp->child_list, count = 0; ntp;
5568 ntp = ntp->next_peer) {
5569 for (i = 0, lp = leaves; i < count; i++, lp++)
5570 if (lp->id >= ntp->subid)
5571 break;
5572 for (j = count; j > i; j--)
5573 leaves[j] = leaves[j - 1];
5574 lp->id = ntp->subid;
5575 lp->tp = ntp;
5576 count++;
5577 }
5578 for (i = 1, lp = leaves; i <= count; i++, lp++) {
5579 if (!leave_was_simple || lp->tp->type == 0)
5580 fprintf(f, "%s\n", leave_indent);
5581 if (i == count)
5582 ip[3] = ' ';
5583 print_mib_leaves(f, lp->tp, width);
5584 }
5585 free(leaves);
5586 leave_was_simple = 0;
5587 }
5588 }
5589 ip[1] = 0;
5590 }
5591
5592 void
print_mib_tree(FILE * f,struct tree * tp,int width)5593 print_mib_tree(FILE * f, struct tree *tp, int width)
5594 {
5595 leave_indent[0] = ' ';
5596 leave_indent[1] = 0;
5597 leave_was_simple = 1;
5598 print_mib_leaves(f, tp, width);
5599 }
5600
5601
5602 /*
5603 * Merge the parsed object identifier with the existing node.
5604 * If there is a problem with the identifier, release the existing node.
5605 */
5606 static struct node *
merge_parse_objectid(struct node * np,FILE * fp,char * name)5607 merge_parse_objectid(struct node *np, FILE * fp, char *name)
5608 {
5609 struct node *nnp;
5610 /*
5611 * printf("merge defval --> %s\n",np->defaultValue);
5612 */
5613 nnp = parse_objectid(fp, name);
5614 if (nnp) {
5615
5616 /*
5617 * apply last OID sub-identifier data to the information
5618 */
5619 /*
5620 * already collected for this node.
5621 */
5622 struct node *headp, *nextp;
5623 int ncount = 0;
5624 nextp = headp = nnp;
5625 while (nnp->next) {
5626 nextp = nnp;
5627 ncount++;
5628 nnp = nnp->next;
5629 }
5630
5631 np->label = nnp->label;
5632 np->subid = nnp->subid;
5633 np->modid = nnp->modid;
5634 np->parent = nnp->parent;
5635 if (nnp->filename != NULL) {
5636 free(nnp->filename);
5637 }
5638 free(nnp);
5639
5640 if (ncount) {
5641 nextp->next = np;
5642 np = headp;
5643 }
5644 } else {
5645 free_node(np);
5646 np = NULL;
5647 }
5648
5649 return np;
5650 }
5651
5652 /*
5653 * transfer data to tree from node
5654 *
5655 * move pointers for alloc'd data from np to tp.
5656 * this prevents them from being freed when np is released.
5657 * parent member is not moved.
5658 *
5659 * CAUTION: nodes may be repeats of existing tree nodes.
5660 * This can happen especially when resolving IMPORT clauses.
5661 *
5662 */
5663 static void
tree_from_node(struct tree * tp,struct node * np)5664 tree_from_node(struct tree *tp, struct node *np)
5665 {
5666 free_partial_tree(tp, FALSE);
5667
5668 tp->label = np->label;
5669 np->label = NULL;
5670 tp->enums = np->enums;
5671 np->enums = NULL;
5672 tp->ranges = np->ranges;
5673 np->ranges = NULL;
5674 tp->indexes = np->indexes;
5675 np->indexes = NULL;
5676 tp->augments = np->augments;
5677 np->augments = NULL;
5678 tp->varbinds = np->varbinds;
5679 np->varbinds = NULL;
5680 tp->hint = np->hint;
5681 np->hint = NULL;
5682 tp->units = np->units;
5683 np->units = NULL;
5684 tp->description = np->description;
5685 np->description = NULL;
5686 tp->reference = np->reference;
5687 np->reference = NULL;
5688 tp->defaultValue = np->defaultValue;
5689 np->defaultValue = NULL;
5690 tp->subid = np->subid;
5691 tp->tc_index = np->tc_index;
5692 tp->type = translation_table[np->type];
5693 tp->access = np->access;
5694 tp->status = np->status;
5695
5696 set_function(tp);
5697 }
5698
5699 #endif /* NETSNMP_DISABLE_MIB_LOADING */
5700