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, &notifs);
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