Coverage Report

Created: 2026-10-19 06:45

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