Coverage Report

Created: 2026-10-17 06:54

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.0k
#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.09M
#define SYNTAX_MASK     0x80
158
/*
159
 * types of tokens
160
 * Tokens with the SYNTAX_MASK bit set are syntax tokens 
161
 */
162
2.40M
#define CONTINUE    -1
163
8.21M
#define ENDOFFILE   0
164
10.2M
#define LABEL       1
165
#define SUBTREE     2
166
85.0k
#define SYNTAX      3
167
16.2k
#define OBJID       (4 | SYNTAX_MASK)
168
15.8k
#define OCTETSTR    (5 | SYNTAX_MASK)
169
232k
#define INTEGER     (6 | SYNTAX_MASK)
170
234k
#define NETADDR     (7 | SYNTAX_MASK)
171
234k
#define IPADDR      (8 | SYNTAX_MASK)
172
235k
#define COUNTER     (9 | SYNTAX_MASK)
173
237k
#define GAUGE       (10 | SYNTAX_MASK)
174
239k
#define TIMETICKS   (11 | SYNTAX_MASK)
175
239k
#define KW_OPAQUE   (12 | SYNTAX_MASK)
176
15.4k
#define NUL         (13 | SYNTAX_MASK)
177
235k
#define SEQUENCE    14
178
914
#define OF          15          /* SEQUENCE OF */
179
11.3k
#define OBJTYPE     16
180
16.3k
#define ACCESS      17
181
28.1k
#define READONLY    18
182
20.0k
#define READWRITE   19
183
20.1k
#define WRITEONLY   20
184
#ifdef NOACCESS
185
#undef NOACCESS                 /* agent 'NOACCESS' token */
186
#endif
187
19.0k
#define NOACCESS    21
188
43.5k
#define STATUS      22
189
22.1k
#define MANDATORY   23
190
12.0k
#define KW_OPTIONAL    24
191
14.7k
#define OBSOLETE    25
192
/*
193
 * #define RECOMMENDED 26 
194
 */
195
#define PUNCT       27
196
3.23M
#define EQUALS      28
197
799k
#define NUMBER      29
198
4.46M
#define LEFTBRACKET 30
199
12.1M
#define RIGHTBRACKET 31
200
1.36M
#define LEFTPAREN   32
201
59.1k
#define RIGHTPAREN  33
202
59.9k
#define COMMA       34
203
108k
#define DESCRIPTION 35
204
1.57M
#define QUOTESTRING 36
205
3.89k
#define INDEX       37
206
5.24k
#define DEFVAL      38
207
39.2k
#define DEPRECATED  39
208
6.77k
#define SIZE        40
209
18.9k
#define BITSTRING   (41 | SYNTAX_MASK)
210
236k
#define NSAPADDRESS (42 | SYNTAX_MASK)
211
234k
#define COUNTER64   (43 | SYNTAX_MASK)
212
17.5k
#define OBJGROUP    44
213
21.4k
#define NOTIFTYPE   45
214
518
#define AUGMENTS    46
215
30.2k
#define COMPLIANCE  47
216
16.7k
#define READCREATE  48
217
11.3k
#define UNITS       49
218
23.3k
#define REFERENCE   50
219
230
#define NUM_ENTRIES 51
220
19.6k
#define MODULEIDENTITY 52
221
6.63k
#define LASTUPDATED 53
222
5.52k
#define ORGANIZATION 54
223
3.15k
#define CONTACTINFO 55
224
232k
#define UINTEGER32 (56 | SYNTAX_MASK)
225
77.4k
#define CURRENT     57
226
48.0k
#define DEFINITIONS 58
227
71.7k
#define END         59
228
1.29M
#define SEMI        60
229
13.6k
#define TRAPTYPE    61
230
900
#define ENTERPRISE  62
231
/*
232
 * #define DISPLAYSTR (63 | SYNTAX_MASK) 
233
 */
234
977k
#define BEGIN       64
235
7.05k
#define IMPORTS     65
236
240
#define EXPORTS     66
237
6.42k
#define ACCNOTIFY   67
238
42.9k
#define BAR         68
239
52.1k
#define RANGE       69
240
27.5k
#define CONVENTION  70
241
28.9k
#define DISPLAYHINT 71
242
59.0k
#define FROM        72
243
25.9k
#define AGENTCAP    73
244
51.7k
#define MACRO       74
245
14.7k
#define IMPLIED     75
246
9.19k
#define SUPPORTS    76
247
7.45k
#define INCLUDES    77
248
6.58k
#define VARIATION   78
249
2.59k
#define REVISION    79
250
472
#define NOTIMPL     80
251
13.9k
#define OBJECTS     81
252
586
#define NOTIFICATIONS 82
253
27.6k
#define MODULE      83
254
8.64k
#define MINACCESS   84
255
12.9k
#define PRODREL     85
256
13.6k
#define WRSYNTAX    86
257
4.61k
#define CREATEREQ   87
258
13.5k
#define NOTIFGROUP  88
259
12.6k
#define MANDATORYGROUPS 89
260
38.7k
#define GROUP     90
261
53.0k
#define OBJECT      91
262
3.67k
#define IDENTIFIER  92
263
116k
#define CHOICE      93
264
40.1k
#define LEFTSQBRACK 95
265
94.0k
#define RIGHTSQBRACK  96
266
3.90k
#define IMPLICIT    97
267
221k
#define APPSYNTAX (98 | SYNTAX_MASK)
268
221k
#define OBJSYNTAX (99 | SYNTAX_MASK)
269
222k
#define SIMPLESYNTAX  (100 | SYNTAX_MASK)
270
222k
#define OBJNAME   (101 | SYNTAX_MASK)
271
223k
#define NOTIFNAME (102 | SYNTAX_MASK)
272
300
#define VARIABLES 103
273
233k
#define UNSIGNED32  (104 | SYNTAX_MASK)
274
231k
#define INTEGER32 (105 | SYNTAX_MASK)
275
14.1k
#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
379k
#define MODULE_NOT_FOUND  0
514
42.3k
#define MODULE_LOADED_OK  1
515
24.4k
#define MODULE_ALREADY_LOADED 2
516
/*
517
 * #define MODULE_LOAD_FAILED   3       
518
 */
519
0
#define MODULE_LOAD_FAILED  MODULE_NOT_FOUND
520
39.2k
#define MODULE_SYNTAX_ERROR     4
521
522
int gMibError = 0,gLoop = 0;
523
static char *gpMibErrorString;
524
char gMibNames[STRINGMAX];
525
526
3.18M
#define HASHSIZE        32
527
3.18M
#define BUCKET(x)       (x & (HASHSIZE-1))
528
529
14.3M
#define NHASHSIZE    128
530
5.67M
#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.28k
#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
55
{
637
55
    if (options) {
638
2.01k
        while (*options) {
639
1.99k
            switch (*options) {
640
421
            case 'u':
641
421
                netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_PARSE_LABEL,
642
421
                               !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
643
421
                                               NETSNMP_DS_LIB_MIB_PARSE_LABEL));
644
421
                break;
645
646
466
            case 'c':
647
466
                netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID,
648
466
            NETSNMP_DS_LIB_MIB_COMMENT_TERM);
649
466
                break;
650
651
256
            case 'e':
652
256
                netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID,
653
256
            NETSNMP_DS_LIB_MIB_ERRORS);
654
256
                break;
655
656
279
            case 'w':
657
279
                netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
658
279
           NETSNMP_DS_LIB_MIB_WARNINGS, 1);
659
279
                break;
660
661
251
            case 'W':
662
251
                netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
663
251
           NETSNMP_DS_LIB_MIB_WARNINGS, 2);
664
251
                break;
665
666
161
            case 'd':
667
161
                netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, 
668
161
            NETSNMP_DS_LIB_SAVE_MIB_DESCRS);
669
161
                break;
670
671
129
            case 'R':
672
129
                netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, 
673
129
            NETSNMP_DS_LIB_MIB_REPLACE);
674
129
                break;
675
676
29
            default:
677
                /*
678
                 * return at the unknown option 
679
                 */
680
29
                return options;
681
1.99k
            }
682
1.96k
            options++;
683
1.96k
        }
684
55
    }
685
26
    return NULL;
686
55
}
687
688
static int
689
name_hash(const char *name)
690
6.87M
{
691
6.87M
    int             hash = 0;
692
6.87M
    const char     *cp;
693
694
6.87M
    if (!name)
695
0
        return 0;
696
39.4M
    for (cp = name; *cp; cp++)
697
32.5M
        hash += tolower((unsigned char)(*cp));
698
6.87M
    return (hash);
699
6.87M
}
700
701
void
702
netsnmp_init_mib_internals(void)
703
218k
{
704
218k
    register struct tok *tp;
705
218k
    register int    b, i;
706
218k
    int             max_modc;
707
708
218k
    if (tree_head)
709
205k
        return;
710
711
    /*
712
     * Set up hash list of pre-defined tokens
713
     */
714
12.9k
    memset(buckets, 0, sizeof(buckets));
715
1.20M
    for (tp = tokens; tp->name; tp++) {
716
1.19M
        tp->hash = name_hash(tp->name);
717
1.19M
        b = BUCKET(tp->hash);
718
1.19M
        if (buckets[b])
719
779k
            tp->next = buckets[b];      /* BUG ??? */
720
1.19M
        buckets[b] = tp;
721
1.19M
    }
722
723
    /*
724
     * Initialise other internal structures
725
     */
726
727
12.9k
    max_modc = sizeof(module_map) / sizeof(module_map[0]) - 1;
728
285k
    for (i = 0; i < max_modc; ++i)
729
272k
        module_map[i].next = &(module_map[i + 1]);
730
12.9k
    module_map[max_modc].next = NULL;
731
12.9k
    module_map_head = module_map;
732
733
12.9k
    memset(nbuckets, 0, sizeof(nbuckets));
734
12.9k
    memset(tbuckets, 0, sizeof(tbuckets));
735
12.9k
    free(tclist);
736
12.9k
    tc_alloc = TC_INCR;
737
12.9k
    tclist = calloc(tc_alloc, sizeof(struct tc));
738
12.9k
    build_translation_table();
739
12.9k
    init_tree_roots();          /* Set up initial roots */
740
    /*
741
     * Relies on 'add_mibdir' having set up the modules 
742
     */
743
12.9k
}
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
36.3k
{
756
36.3k
    struct node    *np, *nextp;
757
36.3k
    int             hash;
758
759
36.3k
    memset(nbuckets, 0, sizeof(nbuckets));
760
1.27M
    for (np = nodes; np;) {
761
1.23M
        nextp = np->next;
762
1.23M
        hash = NBUCKET(name_hash(np->parent));
763
1.23M
        np->next = nbuckets[hash];
764
1.23M
        nbuckets[hash] = np;
765
1.23M
        np = nextp;
766
1.23M
    }
767
36.3k
}
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.43M
{
784
1.43M
    erroneousMibs++;
785
1.43M
    if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
786
1.43M
                                NETSNMP_DS_LIB_MIB_ERRORS))
787
1.25M
  return;
788
184k
    DEBUGMSGTL(("parse-mibs", "\n"));
789
184k
    if (type == ENDOFFILE)
790
435
        snmp_log(LOG_ERR, "%s (EOF): At line %d in %s\n", str, mibLine,
791
435
                 File);
792
184k
    else if (token && *token)
793
183k
        snmp_log(LOG_ERR, "%s (%s): At line %d in %s\n", str, token,
794
183k
                 mibLine, File);
795
519
    else
796
519
        snmp_log(LOG_ERR, "%s: At line %d in %s\n", str, mibLine, File);
797
184k
}
798
799
static void
800
print_module_not_found(const char *cp)
801
176k
{
802
176k
    if (first_err_module) {
803
4.20k
        snmp_log(LOG_ERR, "MIB search path: %s\n",
804
4.20k
                           netsnmp_get_mib_directory());
805
4.20k
        first_err_module = 0;
806
4.20k
    }
807
176k
    if (!last_err_module || strcmp(cp, last_err_module))
808
165k
        print_error("Cannot find module", cp, CONTINUE);
809
176k
    if (last_err_module)
810
169k
        free(last_err_module);
811
176k
    last_err_module = strdup(cp);
812
176k
}
813
814
static struct node *
815
alloc_node(int modid)
816
1.44M
{
817
1.44M
    struct node    *np;
818
819
1.44M
    np = calloc(1, sizeof(struct node));
820
1.44M
    if (!np)
821
0
        return NULL;
822
823
1.44M
    np->tc_index = -1;
824
1.44M
    np->modid = modid;
825
1.44M
    np->filename = strdup(File);
826
1.44M
    np->lineno = mibLine;
827
828
1.44M
    return np;
829
1.44M
}
830
831
static void
832
unlink_tbucket(struct tree *tp)
833
499k
{
834
499k
    int             hash = NBUCKET(name_hash(tp->label));
835
499k
    struct tree    *otp = NULL, *ntp = tbuckets[hash];
836
837
25.8M
    while (ntp && ntp != tp) {
838
25.3M
        otp = ntp;
839
25.3M
        ntp = ntp->next;
840
25.3M
    }
841
499k
    if (!ntp)
842
554
        snmp_log(LOG_EMERG, "Can't find %s in tbuckets\n", tp->label);
843
499k
    else if (otp)
844
232k
        otp->next = ntp->next;
845
266k
    else
846
266k
        tbuckets[hash] = tp->next;
847
499k
}
848
849
static void
850
unlink_tree(struct tree *tp)
851
461k
{
852
461k
    struct tree    *otp = NULL, *ntp = tp->parent;
853
854
461k
    if (!ntp) {                 /* this tree has no parent */
855
38.9k
        DEBUGMSGTL(("unlink_tree", "Tree node %s has no parent\n",
856
38.9k
                    tp->label));
857
422k
    } else {
858
422k
        child_index_modified(ntp, NULL);
859
422k
        ntp = ntp->child_list;
860
861
6.07M
        while (ntp && ntp != tp) {
862
5.65M
            otp = ntp;
863
5.65M
            ntp = ntp->next_peer;
864
5.65M
        }
865
422k
        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
422k
        else if (otp)
869
70.7k
            otp->next_peer = ntp->next_peer;
870
352k
        else
871
352k
            tp->parent->child_list = tp->next_peer;
872
422k
    }
873
874
461k
    if (tree_head == tp)
875
38.9k
        tree_head = tp->next_peer;
876
461k
}
877
878
static void
879
free_partial_tree(struct tree *tp, int keep_label)
880
949k
{
881
949k
    if (!tp)
882
0
        return;
883
884
    /*
885
     * remove the data from this tree node 
886
     */
887
949k
    free_enums(&tp->enums);
888
949k
    free_ranges(&tp->ranges);
889
949k
    free_indexes(&tp->indexes);
890
949k
    free_varbinds(&tp->varbinds);
891
949k
    if (!keep_label)
892
946k
        SNMP_FREE(tp->label);
893
949k
    SNMP_FREE(tp->hint);
894
949k
    SNMP_FREE(tp->units);
895
949k
    SNMP_FREE(tp->description);
896
949k
    SNMP_FREE(tp->reference);
897
949k
    SNMP_FREE(tp->augments);
898
949k
    SNMP_FREE(tp->defaultValue);
899
949k
}
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
486k
{
908
486k
    if (!Tree)
909
0
        return;
910
911
486k
    unlink_tbucket(Tree);
912
486k
    free_partial_tree(Tree, FALSE);
913
486k
    if (Tree->module_list != &Tree->modid)
914
5.39k
        free(Tree->module_list);
915
486k
    free(Tree);
916
486k
}
917
918
static void
919
free_node(struct node *np)
920
1.38M
{
921
1.38M
    if (!np)
922
87
        return;
923
924
1.38M
    free_enums(&np->enums);
925
1.38M
    free_ranges(&np->ranges);
926
1.38M
    free_indexes(&np->indexes);
927
1.38M
    free_varbinds(&np->varbinds);
928
1.38M
    free(np->label);
929
1.38M
    free(np->hint);
930
1.38M
    free(np->units);
931
1.38M
    free(np->description);
932
1.38M
    free(np->reference);
933
1.38M
    free(np->defaultValue);
934
1.38M
    free(np->parent);
935
1.38M
    free(np->augments);
936
1.38M
    free(np->filename);
937
1.38M
    free(np);
938
1.38M
}
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
12.9k
{
1076
12.9k
    int             count;
1077
1078
3.33M
    for (count = 0; count < 256; count++) {
1079
3.32M
        switch (count) {
1080
12.9k
        case OBJID:
1081
12.9k
            translation_table[count] = TYPE_OBJID;
1082
12.9k
            break;
1083
12.9k
        case OCTETSTR:
1084
12.9k
            translation_table[count] = TYPE_OCTETSTR;
1085
12.9k
            break;
1086
12.9k
        case INTEGER:
1087
12.9k
            translation_table[count] = TYPE_INTEGER;
1088
12.9k
            break;
1089
12.9k
        case NETADDR:
1090
12.9k
            translation_table[count] = TYPE_NETADDR;
1091
12.9k
            break;
1092
12.9k
        case IPADDR:
1093
12.9k
            translation_table[count] = TYPE_IPADDR;
1094
12.9k
            break;
1095
12.9k
        case COUNTER:
1096
12.9k
            translation_table[count] = TYPE_COUNTER;
1097
12.9k
            break;
1098
12.9k
        case GAUGE:
1099
12.9k
            translation_table[count] = TYPE_GAUGE;
1100
12.9k
            break;
1101
12.9k
        case TIMETICKS:
1102
12.9k
            translation_table[count] = TYPE_TIMETICKS;
1103
12.9k
            break;
1104
12.9k
        case KW_OPAQUE:
1105
12.9k
            translation_table[count] = TYPE_OPAQUE;
1106
12.9k
            break;
1107
12.9k
        case NUL:
1108
12.9k
            translation_table[count] = TYPE_NULL;
1109
12.9k
            break;
1110
12.9k
        case COUNTER64:
1111
12.9k
            translation_table[count] = TYPE_COUNTER64;
1112
12.9k
            break;
1113
12.9k
        case BITSTRING:
1114
12.9k
            translation_table[count] = TYPE_BITSTRING;
1115
12.9k
            break;
1116
12.9k
        case NSAPADDRESS:
1117
12.9k
            translation_table[count] = TYPE_NSAPADDRESS;
1118
12.9k
            break;
1119
12.9k
        case INTEGER32:
1120
12.9k
            translation_table[count] = TYPE_INTEGER32;
1121
12.9k
            break;
1122
12.9k
        case UINTEGER32:
1123
12.9k
            translation_table[count] = TYPE_UINTEGER;
1124
12.9k
            break;
1125
12.9k
        case UNSIGNED32:
1126
12.9k
            translation_table[count] = TYPE_UNSIGNED32;
1127
12.9k
            break;
1128
12.9k
        case TRAPTYPE:
1129
12.9k
            translation_table[count] = TYPE_TRAPTYPE;
1130
12.9k
            break;
1131
12.9k
        case NOTIFTYPE:
1132
12.9k
            translation_table[count] = TYPE_NOTIFTYPE;
1133
12.9k
            break;
1134
12.9k
        case NOTIFGROUP:
1135
12.9k
            translation_table[count] = TYPE_NOTIFGROUP;
1136
12.9k
            break;
1137
12.9k
        case OBJGROUP:
1138
12.9k
            translation_table[count] = TYPE_OBJGROUP;
1139
12.9k
            break;
1140
12.9k
        case MODULEIDENTITY:
1141
12.9k
            translation_table[count] = TYPE_MODID;
1142
12.9k
            break;
1143
12.9k
        case OBJIDENTITY:
1144
12.9k
            translation_table[count] = TYPE_OBJIDENTITY;
1145
12.9k
            break;
1146
12.9k
        case AGENTCAP:
1147
12.9k
            translation_table[count] = TYPE_AGENTCAP;
1148
12.9k
            break;
1149
12.9k
        case COMPLIANCE:
1150
12.9k
            translation_table[count] = TYPE_MODCOMP;
1151
12.9k
            break;
1152
3.01M
        default:
1153
3.01M
            translation_table[count] = TYPE_OTHER;
1154
3.01M
            break;
1155
3.32M
        }
1156
3.32M
    }
1157
12.9k
}
1158
1159
static void
1160
init_tree_roots(void)
1161
12.9k
{
1162
12.9k
    struct tree    *tp, *lasttp;
1163
12.9k
    int             base_modid;
1164
12.9k
    int             hash;
1165
1166
12.9k
    base_modid = which_module("SNMPv2-SMI");
1167
12.9k
    if (base_modid == -1)
1168
12.9k
        base_modid = which_module("RFC1155-SMI");
1169
12.9k
    if (base_modid == -1)
1170
12.9k
        base_modid = which_module("RFC1213-MIB");
1171
1172
    /*
1173
     * build root node 
1174
     */
1175
12.9k
    tp = calloc(1, sizeof(struct tree));
1176
12.9k
    if (tp == NULL)
1177
0
        return;
1178
12.9k
    tp->label = strdup("joint-iso-ccitt");
1179
12.9k
    tp->modid = base_modid;
1180
12.9k
    tp->number_modules = 1;
1181
12.9k
    tp->module_list = &(tp->modid);
1182
12.9k
    tp->subid = 2;
1183
12.9k
    tp->tc_index = -1;
1184
12.9k
    set_function(tp);           /* from mib.c */
1185
12.9k
    hash = NBUCKET(name_hash(tp->label));
1186
12.9k
    tp->next = tbuckets[hash];
1187
12.9k
    tbuckets[hash] = tp;
1188
12.9k
    lasttp = tp;
1189
12.9k
    root_imports[0].label = strdup(tp->label);
1190
12.9k
    root_imports[0].modid = base_modid;
1191
1192
    /*
1193
     * build root node 
1194
     */
1195
12.9k
    tp = calloc(1, sizeof(struct tree));
1196
12.9k
    if (tp == NULL)
1197
0
        return;
1198
12.9k
    tp->next_peer = lasttp;
1199
12.9k
    tp->label = strdup("ccitt");
1200
12.9k
    tp->modid = base_modid;
1201
12.9k
    tp->number_modules = 1;
1202
12.9k
    tp->module_list = &(tp->modid);
1203
12.9k
    tp->subid = 0;
1204
12.9k
    tp->tc_index = -1;
1205
12.9k
    set_function(tp);           /* from mib.c */
1206
12.9k
    hash = NBUCKET(name_hash(tp->label));
1207
12.9k
    tp->next = tbuckets[hash];
1208
12.9k
    tbuckets[hash] = tp;
1209
12.9k
    lasttp = tp;
1210
12.9k
    root_imports[1].label = strdup(tp->label);
1211
12.9k
    root_imports[1].modid = base_modid;
1212
1213
    /*
1214
     * build root node 
1215
     */
1216
12.9k
    tp = calloc(1, sizeof(struct tree));
1217
12.9k
    if (tp == NULL)
1218
0
        return;
1219
12.9k
    tp->next_peer = lasttp;
1220
12.9k
    tp->label = strdup("iso");
1221
12.9k
    tp->modid = base_modid;
1222
12.9k
    tp->number_modules = 1;
1223
12.9k
    tp->module_list = &(tp->modid);
1224
12.9k
    tp->subid = 1;
1225
12.9k
    tp->tc_index = -1;
1226
12.9k
    set_function(tp);           /* from mib.c */
1227
12.9k
    hash = NBUCKET(name_hash(tp->label));
1228
12.9k
    tp->next = tbuckets[hash];
1229
12.9k
    tbuckets[hash] = tp;
1230
12.9k
    lasttp = tp;
1231
12.9k
    root_imports[2].label = strdup(tp->label);
1232
12.9k
    root_imports[2].modid = base_modid;
1233
1234
12.9k
    tree_head = tp;
1235
12.9k
}
1236
1237
#ifdef STRICT_MIB_PARSEING
1238
#define label_compare strcasecmp
1239
#else
1240
367M
#define label_compare strcmp
1241
#endif
1242
1243
1244
struct tree    *
1245
find_tree_node(const char *name, int modid)
1246
1.77M
{
1247
1.77M
    struct tree    *tp, *headtp;
1248
1.77M
    int             count, *int_p;
1249
1250
1.77M
    if (!name || !*name)
1251
198k
        return (NULL);
1252
1253
1.57M
    headtp = tbuckets[NBUCKET(name_hash(name))];
1254
9.35M
    for (tp = headtp; tp; tp = tp->next) {
1255
8.11M
        if (tp->label && !label_compare(tp->label, name)) {
1256
1257
2.84M
            if (modid == -1)    /* Any module */
1258
106k
                return (tp);
1259
1260
2.74M
            for (int_p = tp->module_list, count = 0;
1261
34.6M
                 count < tp->number_modules; ++count, ++int_p)
1262
32.1M
                if (*int_p == modid)
1263
236k
                    return (tp);
1264
2.74M
        }
1265
8.11M
    }
1266
1267
1.23M
    return (NULL);
1268
1.57M
}
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.72k
#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
15
#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.66k
{
1293
1.66k
    int             depth = 0;
1294
1295
34.3k
    for (; *key; key++) {
1296
32.7k
        switch (*key) {
1297
27
        case '\\':
1298
27
            if (!key[1])
1299
3
                return 0;
1300
24
            key++;
1301
24
            break;
1302
15
        case '(':
1303
15
            if (++depth > MAX_REGEX_NESTING_DEPTH)
1304
0
                return 1;
1305
15
            break;
1306
15
        case ')':
1307
6
            if (depth > 0)
1308
0
                depth--;
1309
6
            break;
1310
32.7k
        }
1311
32.7k
    }
1312
1.65k
    return 0;
1313
1.66k
}
1314
#endif
1315
1316
static          u_int
1317
compute_match(const char *search_base, const char *key)
1318
1.66k
{
1319
1.66k
#if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
1320
1.66k
    int             rc;
1321
1.66k
    regex_t         parsetree;
1322
1.66k
    regmatch_t      pmatch;
1323
1324
1.66k
    if (regex_nesting_too_deep(key))
1325
0
        return MAX_BAD;
1326
1.66k
    rc = regcomp(&parsetree, key, REG_ICASE | REG_EXTENDED);
1327
1.66k
    if (rc == 0)
1328
1.53k
        rc = regexec(&parsetree, search_base, 1, &pmatch, 0);
1329
1.66k
    regfree(&parsetree);
1330
1.66k
    if (rc == 0) {
1331
        /*
1332
         * found 
1333
         */
1334
82
        return pmatch.rm_so;
1335
82
    }
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.58k
    return MAX_BAD;
1371
1.66k
}
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
574
{
1389
574
    struct tree    *tp, *best_so_far = NULL, *retptr;
1390
574
    u_int           old_match = MAX_BAD, new_match = MAX_BAD;
1391
1392
574
    if (!pattrn || !*pattrn)
1393
6
        return (NULL);
1394
1395
568
    if (!tree_top)
1396
1
        tree_top = get_tree_head();
1397
1398
2.20k
    for (tp = tree_top; tp; tp = tp->next_peer) {
1399
1.66k
        if (!tp->reported && tp->label)
1400
1.66k
            new_match = compute_match(tp->label, pattrn);
1401
1.66k
        tp->reported = 1;
1402
1403
1.66k
        if (new_match < old_match) {
1404
67
            best_so_far = tp;
1405
67
            old_match = new_match;
1406
67
        }
1407
1.66k
        if (new_match == 0)
1408
30
            break;              /* this is the best result we can get */
1409
1.63k
        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.63k
    }
1420
568
    if (match)
1421
0
        *match = old_match;
1422
568
    return (best_so_far);
1423
574
}
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
101k
{
1432
101k
    struct tree    *child1, *child2, *previous;
1433
1434
101k
    child_index_modified(tp1, NULL);
1435
101k
    child_index_modified(tp2, NULL);
1436
141k
    for (child1 = tp1->child_list; child1;) {
1437
1438
40.3k
        for (child2 = tp2->child_list, previous = NULL;
1439
75.8k
             child2; previous = child2, child2 = child2->next_peer) {
1440
1441
65.9k
            if (child1->subid == child2->subid) {
1442
                /*
1443
                 * Found 'matching' children,
1444
                 *  so merge them
1445
                 */
1446
59.5k
                if (!strncmp(child1->label, ANON, ANON_LEN)) {
1447
182
                    merge_anon_children(child1, child2);
1448
1449
182
                    child1->child_list = NULL;
1450
182
                    previous = child1;  /* Finished with 'child1' */
1451
182
                    child1 = child1->next_peer;
1452
182
                    free_tree(previous);
1453
182
                    goto next;
1454
182
                }
1455
1456
59.3k
                else if (!strncmp(child2->label, ANON, ANON_LEN)) {
1457
75
                    merge_anon_children(child2, child1);
1458
1459
75
                    if (previous)
1460
6
                        previous->next_peer = child2->next_peer;
1461
69
                    else
1462
69
                        tp2->child_list = child2->next_peer;
1463
75
                    free_tree(child2);
1464
1465
75
                    previous = child1;  /* Move 'child1' to 'tp2' */
1466
75
                    child1 = child1->next_peer;
1467
75
                    previous->next_peer = tp2->child_list;
1468
75
                    tp2->child_list = previous;
1469
75
                    for (previous = tp2->child_list;
1470
168
                         previous; previous = previous->next_peer)
1471
93
                        previous->parent = tp2;
1472
75
                    goto next;
1473
59.2k
                } else if (!label_compare(child1->label, child2->label)) {
1474
29.1k
                    if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
1475
29.1k
             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
29.1k
                    continue;
1482
30.1k
                } else {
1483
                    /*
1484
                     * Two copies of the same node.
1485
                     * 'child2' adopts the children of 'child1'
1486
                     */
1487
1488
30.1k
                    child_index_modified(child1, NULL);
1489
30.1k
                    child_index_modified(child2, NULL);
1490
30.1k
                    if (child2->child_list) {
1491
670
                        for (previous = child2->child_list; previous->next_peer; previous = previous->next_peer);       /* Find the end of the list */
1492
333
                        previous->next_peer = child1->child_list;
1493
333
                    } else
1494
29.8k
                        child2->child_list = child1->child_list;
1495
30.1k
                    for (previous = child1->child_list;
1496
48.7k
                         previous; previous = previous->next_peer)
1497
18.5k
                        previous->parent = child2;
1498
30.1k
                    child1->child_list = NULL;
1499
1500
30.1k
                    previous = child1;  /* Finished with 'child1' */
1501
30.1k
                    child1 = child1->next_peer;
1502
30.1k
                    free_tree(previous);
1503
30.1k
                    goto next;
1504
30.1k
                }
1505
59.5k
            }
1506
65.9k
        }
1507
        /*
1508
         * If no match, move 'child1' to 'tp2' child_list
1509
         */
1510
9.91k
        if (child1) {
1511
9.91k
            previous = child1;
1512
9.91k
            child1 = child1->next_peer;
1513
9.91k
            previous->parent = tp2;
1514
9.91k
            previous->next_peer = tp2->child_list;
1515
9.91k
            tp2->child_list = previous;
1516
9.91k
        }
1517
40.3k
      next:;
1518
40.3k
    }
1519
101k
}
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.14M
{
1559
1.14M
    struct child_index *ci;
1560
1561
10.1M
    for (ci = active_child_indexes; ci; ci = ci->up)
1562
9.00M
        if (ci->parent == parent && ci != except)
1563
103k
            ci->valid = 0;
1564
1.14M
}
1565
1566
static size_t
1567
child_hash(const struct child_index *ci, u_long subid)
1568
28.4M
{
1569
28.4M
    return (size_t)((subid ^ (subid >> 17)) * 2654435761u) & (ci->size - 1);
1570
28.4M
}
1571
1572
static void
1573
child_index_clear(struct child_index *ci)
1574
757k
{
1575
757k
    size_t          i;
1576
1577
25.0M
    for (i = 0; i < ci->size; i++) {
1578
24.2M
        struct child_entry *ce, *next;
1579
1580
24.7M
        for (ce = ci->buckets[i]; ce; ce = next) {
1581
461k
            next = ce->next;
1582
461k
            free(ce);
1583
461k
        }
1584
24.2M
    }
1585
757k
    free(ci->buckets);
1586
757k
    ci->buckets = NULL;
1587
757k
    ci->size = 0;
1588
757k
    ci->count = 0;
1589
757k
    ci->tail = NULL;
1590
757k
    ci->valid = 0;
1591
757k
}
1592
1593
static struct child_entry *
1594
child_index_find(const struct child_index *ci, u_long subid)
1595
27.9M
{
1596
27.9M
    struct child_entry *ce;
1597
1598
28.0M
    for (ce = ci->buckets[child_hash(ci, subid)]; ce; ce = ce->next)
1599
27.4M
        if (ce->first->subid == subid)
1600
27.3M
            return ce;
1601
582k
    return NULL;
1602
27.9M
}
1603
1604
static int
1605
child_index_grow(struct child_index *ci)
1606
379k
{
1607
379k
    struct child_index new_ci = *ci;
1608
379k
    size_t          i;
1609
1610
379k
    new_ci.size = ci->size ? 2 * ci->size : 64;
1611
379k
    new_ci.buckets = calloc(new_ci.size, sizeof(*new_ci.buckets));
1612
379k
    if (!new_ci.buckets)
1613
0
        return -1;
1614
379k
    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
379k
    free(ci->buckets);
1627
379k
    ci->buckets = new_ci.buckets;
1628
379k
    ci->size = new_ci.size;
1629
379k
    return 0;
1630
379k
}
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
461k
{
1639
461k
    struct child_entry *ce, **head;
1640
1641
461k
    if (ci->count >= ci->size / 2 && child_index_grow(ci) < 0)
1642
0
        return -1;
1643
461k
    ce = malloc(sizeof(*ce));
1644
461k
    if (!ce)
1645
0
        return -1;
1646
461k
    ce->first = tp;
1647
461k
    ce->pred = pred;
1648
461k
    head = &ci->buckets[child_hash(ci, tp->subid)];
1649
461k
    ce->next = *head;
1650
461k
    *head = ce;
1651
461k
    ci->count++;
1652
461k
    return 0;
1653
461k
}
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
379k
{
1662
379k
    struct tree    *tp, *pred = NULL;
1663
1664
379k
    child_index_clear(ci);
1665
379k
    if (child_index_grow(ci) < 0)
1666
0
        return;
1667
27.0M
    for (tp = ci->parent->child_list; tp; pred = tp, tp = tp->next_peer) {
1668
26.6M
        if (!child_index_find(ci, tp->subid) &&
1669
340k
            child_index_add(ci, tp, pred) < 0) {
1670
0
            child_index_clear(ci);
1671
0
            return;
1672
0
        }
1673
26.6M
    }
1674
379k
    ci->tail = pred;
1675
379k
    ci->valid = 1;
1676
379k
}
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
100k
{
1685
100k
    struct tree    *next = tp->next_peer;
1686
100k
    int             keep = ci && ci->valid && ci->parent == tp->parent;
1687
100k
    struct child_entry *ce;
1688
1689
100k
    unlink_tree(tp);
1690
100k
    if (!keep || !next || next->subid != tp->subid)
1691
640
        return;
1692
100k
    ce = child_index_find(ci, tp->subid);
1693
100k
    if (ce && ce->first == tp) {
1694
100k
        ce->first = next;
1695
100k
        ci->valid = 1;
1696
100k
    }
1697
100k
}
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.22M
{
1707
1.22M
    struct tree    *tp, *anon_tp = NULL;
1708
1.22M
    struct tree    *xroot = root;
1709
1.22M
    struct node    *np, **headp;
1710
1.22M
    struct node    *oldnp = NULL, *child_list = NULL, *childp = NULL;
1711
1.22M
    int             hash;
1712
1.22M
    int            *int_p;
1713
1.22M
    int             depth = 0;
1714
1.22M
    struct tree    *p;
1715
1.22M
    struct child_index *ci = NULL;
1716
1717
29.1M
    for (p = root; p; p = p->parent) {
1718
27.9M
        depth++;
1719
27.9M
        if (depth >= MAX_OID_LEN) {
1720
5.66k
            snmp_log(LOG_ERR, "MIB tree depth exceeds MAX_OID_LEN (%d); aborting subtree parsing\n", MAX_OID_LEN);
1721
5.66k
            return;
1722
5.66k
        }
1723
27.9M
    }
1724
1725
265M
    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
264M
        xroot = xroot->next_peer;
1731
264M
    }
1732
1733
1.21M
    tp = root;
1734
1.21M
    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
46.8M
    for (np = *headp; np; np = np->next) {
1740
45.6M
        if (!label_compare(tp->label, np->parent)) {
1741
            /*
1742
             * take this node out of the node list 
1743
             */
1744
779k
            if (oldnp == NULL) {
1745
587k
                *headp = np->next;      /* fix root of node list */
1746
587k
            } else {
1747
192k
                oldnp->next = np->next; /* link around this node */
1748
192k
            }
1749
779k
            if (child_list)
1750
400k
                childp->next = np;
1751
378k
            else
1752
378k
                child_list = np;
1753
779k
            childp = np;
1754
44.8M
        } else {
1755
44.8M
            oldnp = np;
1756
44.8M
        }
1757
1758
45.6M
    }
1759
1.21M
    if (childp)
1760
378k
        childp->next = NULL;
1761
1.21M
    if (child_list) {
1762
        /*
1763
         * If this allocation fails, fall back to linear child list scans.
1764
         */
1765
378k
        ci = calloc(1, sizeof(*ci));
1766
378k
        if (ci) {
1767
378k
            ci->parent = xroot;
1768
378k
            ci->up = active_child_indexes;
1769
378k
            active_child_indexes = ci;
1770
378k
        }
1771
378k
    }
1772
    /*
1773
     * Take each element in the child list and place it into the tree.
1774
     */
1775
1.99M
    for (np = child_list; np; np = np->next) {
1776
779k
        struct tree    *otp = NULL;
1777
779k
        struct tree    *xxroot = xroot;
1778
779k
        int             indexed = 0;
1779
779k
        anon_tp = NULL;
1780
779k
        tp = xroot->child_list;
1781
1782
779k
        if (np->subid == -1) {
1783
            /*
1784
             * name ::= { parent } 
1785
             */
1786
1.88k
            np->subid = xroot->subid;
1787
1.88k
            tp = xroot;
1788
1.88k
            xxroot = xroot->parent;
1789
777k
        } else if (ci) {
1790
777k
            if (!ci->valid)
1791
379k
                child_index_build(ci);
1792
777k
            indexed = ci->valid;
1793
777k
        }
1794
1795
779k
        if (indexed) {
1796
777k
            struct child_entry *ce = child_index_find(ci, np->subid);
1797
1798
777k
            if (ce) {
1799
656k
                tp = ce->first;
1800
656k
                otp = ce->pred;
1801
656k
            } else {
1802
121k
                tp = NULL;
1803
121k
                otp = ci->tail;
1804
121k
            }
1805
777k
        } else {
1806
1.88k
            while (tp) {
1807
1.88k
                if (tp->subid == np->subid)
1808
1.88k
                    break;
1809
0
                else {
1810
0
                    otp = tp;
1811
0
                    tp = tp->next_peer;
1812
0
                }
1813
1.88k
            }
1814
1.88k
        }
1815
779k
        if (tp) {
1816
658k
            if (!label_compare(tp->label, np->label)) {
1817
                /*
1818
                 * Update list of modules 
1819
                 */
1820
325k
                int_p = malloc((tp->number_modules + 1) * sizeof(int));
1821
325k
                if (int_p == NULL)
1822
0
                    goto cleanup;
1823
325k
                memcpy(int_p, tp->module_list,
1824
325k
                       tp->number_modules * sizeof(int));
1825
325k
                int_p[tp->number_modules] = np->modid;
1826
325k
                if (tp->module_list != &tp->modid)
1827
258k
                    free(tp->module_list);
1828
325k
                ++tp->number_modules;
1829
325k
                tp->module_list = int_p;
1830
1831
325k
                if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
1832
325k
             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
325k
                do_subtree(tp, nodes);
1842
325k
                continue;
1843
325k
            }
1844
332k
            if (!strncmp(np->label, ANON, ANON_LEN) ||
1845
238k
                !strncmp(tp->label, ANON, ANON_LEN)) {
1846
101k
                anon_tp = tp;   /* Need to merge these two trees later */
1847
231k
            } else if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
1848
231k
            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
332k
        }
1855
1856
453k
        tp = calloc(1, sizeof(struct tree));
1857
453k
        if (tp == NULL)
1858
0
            goto cleanup;
1859
453k
        tp->parent = xxroot;
1860
453k
        tp->modid = np->modid;
1861
453k
        tp->number_modules = 1;
1862
453k
        tp->module_list = &(tp->modid);
1863
453k
        tree_from_node(tp, np);
1864
453k
        if (!otp && !xxroot) {
1865
554
          free_tree(tp);
1866
554
          goto cleanup;
1867
554
        }
1868
453k
        tp->next_peer = otp ? otp->next_peer : xxroot->child_list;
1869
453k
        if (otp)
1870
101k
            otp->next_peer = tp;
1871
352k
        else
1872
352k
            xxroot->child_list = tp;
1873
453k
        child_index_modified(xxroot, ci);
1874
453k
        if (indexed) {
1875
452k
            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
452k
            if (ce) {
1882
330k
                ce->first = tp;
1883
330k
            } else {
1884
121k
                ci->tail = tp;
1885
121k
                if (child_index_add(ci, tp, otp) < 0)
1886
0
                    child_index_clear(ci);
1887
121k
            }
1888
452k
        }
1889
453k
        hash = NBUCKET(name_hash(tp->label));
1890
453k
        tp->next = tbuckets[hash];
1891
453k
        tbuckets[hash] = tp;
1892
453k
        do_subtree(tp, nodes);
1893
1894
453k
        if (anon_tp) {
1895
101k
            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.9k
                merge_anon_children(tp, anon_tp);
1901
1902
                /*
1903
                 * unlink and destroy tp 
1904
                 */
1905
93.9k
                unlink_indexed_tree(ci, tp);
1906
93.9k
                free_tree(tp);
1907
93.9k
            } else if (!strncmp(anon_tp->label, ANON, ANON_LEN)) {
1908
6.84k
                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
6.84k
                merge_anon_children(anon_tp, tp);
1915
1916
                /*
1917
                 * unlink anon_tp from the hash 
1918
                 */
1919
6.84k
                unlink_tbucket(anon_tp);
1920
1921
                /*
1922
                 * get rid of old contents of anon_tp 
1923
                 */
1924
6.84k
                free_partial_tree(anon_tp, FALSE);
1925
1926
                /*
1927
                 * put in the current information 
1928
                 */
1929
6.84k
                anon_tp->label = tp->label;
1930
6.84k
                child_index_modified(anon_tp, NULL);
1931
6.84k
                anon_tp->child_list = tp->child_list;
1932
6.84k
                anon_tp->modid = tp->modid;
1933
6.84k
                anon_tp->tc_index = tp->tc_index;
1934
6.84k
                anon_tp->type = tp->type;
1935
6.84k
                anon_tp->enums = tp->enums;
1936
6.84k
                anon_tp->indexes = tp->indexes;
1937
6.84k
                anon_tp->augments = tp->augments;
1938
6.84k
                anon_tp->varbinds = tp->varbinds;
1939
6.84k
                anon_tp->ranges = tp->ranges;
1940
6.84k
                anon_tp->hint = tp->hint;
1941
6.84k
                anon_tp->units = tp->units;
1942
6.84k
                anon_tp->description = tp->description;
1943
6.84k
                anon_tp->reference = tp->reference;
1944
6.84k
                anon_tp->defaultValue = tp->defaultValue;
1945
6.84k
                anon_tp->parent = tp->parent;
1946
1947
6.84k
                set_function(anon_tp);
1948
1949
                /*
1950
                 * update parent pointer in moved children 
1951
                 */
1952
6.84k
                ntp = anon_tp->child_list;
1953
17.1k
                while (ntp) {
1954
10.2k
                    ntp->parent = anon_tp;
1955
10.2k
                    ntp = ntp->next_peer;
1956
10.2k
                }
1957
1958
                /*
1959
                 * hash in anon_tp in its new place 
1960
                 */
1961
6.84k
                hash = NBUCKET(name_hash(anon_tp->label));
1962
6.84k
                anon_tp->next = tbuckets[hash];
1963
6.84k
                tbuckets[hash] = anon_tp;
1964
1965
                /*
1966
                 * unlink and destroy tp 
1967
                 */
1968
6.84k
                unlink_tbucket(tp);
1969
6.84k
                unlink_indexed_tree(ci, tp);
1970
6.84k
                free(tp);
1971
6.84k
            } else {
1972
                /*
1973
                 * Uh?  One of these two should have been anonymous! 
1974
                 */
1975
640
                if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
1976
640
               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
640
            }
1982
101k
            anon_tp = NULL;
1983
101k
        }
1984
453k
    }
1985
1.21M
cleanup:
1986
1.21M
    if (ci) {
1987
378k
        netsnmp_assert(active_child_indexes == ci);
1988
378k
        active_child_indexes = ci->up;
1989
378k
        child_index_clear(ci);
1990
378k
        free(ci);
1991
378k
    }
1992
    /*
1993
     * free all nodes that were copied into tree 
1994
     */
1995
1.21M
    oldnp = NULL;
1996
1.99M
    for (np = child_list; np; np = np->next) {
1997
779k
        if (oldnp)
1998
400k
            free_node(oldnp);
1999
779k
        oldnp = np;
2000
779k
    }
2001
1.21M
    if (oldnp)
2002
378k
        free_node(oldnp);
2003
1.21M
}
2004
2005
static void
2006
do_linkup(struct module *mp, struct node *np)
2007
36.0k
{
2008
36.0k
    struct module_import *mip;
2009
36.0k
    struct node    *onp, *oldp, *newp;
2010
36.0k
    struct tree    *tp;
2011
36.0k
    int             i, more;
2012
    /*
2013
     * All modules implicitly import
2014
     *   the roots of the tree
2015
     */
2016
36.0k
    if (snmp_get_do_debugging() > 1)
2017
0
        dump_module_list();
2018
36.0k
    DEBUGMSGTL(("parse-mibs", "Processing IMPORTS for module %d %s\n",
2019
36.0k
                mp->modid, mp->name));
2020
36.0k
    if (mp->no_imports == 0) {
2021
5.28k
        mp->no_imports = NUMBER_OF_ROOT_NODES;
2022
5.28k
        mp->imports = root_imports;
2023
5.28k
    }
2024
2025
    /*
2026
     * Build the tree
2027
     */
2028
36.0k
    init_node_hash(np);
2029
1.79M
    for (i = 0, mip = mp->imports; i < mp->no_imports; ++i, ++mip) {
2030
1.75M
        char            modbuf[256];
2031
1.75M
        DEBUGMSGTL(("parse-mibs", "  Processing import: %s\n",
2032
1.75M
                    mip->label));
2033
1.75M
        if (get_tc_index(mip->label, mip->modid) != -1)
2034
3.93k
            continue;
2035
1.75M
        tp = find_tree_node(mip->label, mip->modid);
2036
1.75M
        if (!tp) {
2037
1.40M
      if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_ERRORS))
2038
509
                snmp_log(LOG_WARNING,
2039
509
                         "Did not find '%s' in module %s (%s)\n",
2040
509
                         mip->label, module_name(mip->modid, modbuf),
2041
509
                         File);
2042
1.40M
            continue;
2043
1.40M
        }
2044
341k
        do_subtree(tp, &np);
2045
341k
    }
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
36.0k
    if (!np)
2054
2.69k
        return;
2055
133k
    for (tp = tree_head; tp; tp = tp->next_peer)
2056
100k
        do_subtree(tp, &np);
2057
33.3k
    if (!np)
2058
0
        return;
2059
2060
    /*
2061
     * quietly move all internal references to the orphan list 
2062
     */
2063
33.3k
    oldp = orphan_nodes;
2064
4.30M
    for (i = 0; i < NHASHSIZE; i++) {
2065
4.27M
        struct node    *next_onp;
2066
4.53M
        for (onp = nbuckets[i]; onp; onp = next_onp) {
2067
257k
            struct node    *op = NULL;
2068
257k
            int             hash = NBUCKET(name_hash(onp->label));
2069
2070
257k
            next_onp = onp->next;
2071
257k
            np = nbuckets[hash];
2072
190M
            while (np) {
2073
190M
                if (label_compare(onp->label, np->parent)) {
2074
189M
                    op = np;
2075
189M
                    np = np->next;
2076
189M
                } else {
2077
328k
                    if (np == next_onp)
2078
14.3k
                        next_onp = np->next;
2079
328k
                    if (op)
2080
115k
                        op->next = np->next;
2081
213k
                    else
2082
213k
                        nbuckets[hash] = np->next;
2083
328k
                    DEBUGMSGTL(("parse-mibs", "Moving %s to orphanage", np->label));
2084
328k
                    np->next = orphan_nodes;
2085
328k
                    orphan_nodes = np;
2086
328k
                    np = op ? op->next : nbuckets[hash];
2087
328k
                }
2088
190M
            }
2089
257k
        }
2090
4.27M
    }
2091
38.1k
    do {
2092
38.1k
        newp = orphan_nodes;
2093
38.1k
        more = 0;
2094
432k
        for (onp = orphan_nodes; onp != oldp; onp = onp->next) {
2095
393k
            struct node    *op = NULL;
2096
393k
            int             hash = NBUCKET(name_hash(onp->label));
2097
2098
393k
            np = nbuckets[hash];
2099
40.1M
            while (np) {
2100
39.8M
                if (label_compare(onp->label, np->parent)) {
2101
39.7M
                    op = np;
2102
39.7M
                    np = np->next;
2103
39.7M
                } else {
2104
65.2k
                    if (op)
2105
28.0k
                        op->next = np->next;
2106
37.2k
                    else
2107
37.2k
                        nbuckets[hash] = np->next;
2108
65.2k
                    np->next = orphan_nodes;
2109
65.2k
                    orphan_nodes = np;
2110
65.2k
                    np = op ? op->next : nbuckets[hash];
2111
65.2k
                    more = 1;
2112
65.2k
                }
2113
39.8M
            }
2114
393k
        }
2115
38.1k
        oldp = newp;
2116
38.1k
    } while (more);
2117
2118
    /*
2119
     * complain about left over nodes 
2120
     */
2121
4.30M
    for (i = 0; i < NHASHSIZE; i++)
2122
4.27M
        if (nbuckets[i]) {
2123
82.4k
            for (onp = nbuckets[i]; onp; onp = onp->next) {
2124
56.5k
                snmp_log(LOG_WARNING,
2125
56.5k
                         "Cannot resolve OID in %s: %s ::= { %s %ld } at line %d in %s\n",
2126
56.5k
                         (mp->name ? mp->name : "<no module>"),
2127
56.5k
                         (onp->label ? onp->label : "<no label>"),
2128
56.5k
                         (onp->parent ? onp->parent : "<no parent>"),
2129
56.5k
                         onp->subid, onp->lineno, onp->filename);
2130
56.5k
                np = onp;
2131
56.5k
            }
2132
25.9k
            np->next = orphan_nodes;
2133
25.9k
            orphan_nodes = nbuckets[i];
2134
25.9k
            nbuckets[i] = NULL;
2135
25.9k
        }
2136
33.3k
    return;
2137
33.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
147k
{
2154
147k
    struct subid_s *id = id_arg;
2155
147k
    int             i, count, type;
2156
147k
    char            token[MAXTOKEN];
2157
2158
147k
    if ((type = get_token(fp, token, MAXTOKEN)) != LEFTBRACKET) {
2159
2.25k
        print_error("Expected \"{\"", token, type);
2160
2.25k
        return 0;
2161
2.25k
    }
2162
144k
    type = get_token(fp, token, MAXTOKEN);
2163
1.72M
    for (count = 0; count < length; count++, id++) {
2164
1.72M
        id->label = NULL;
2165
1.72M
        id->modid = current_module;
2166
1.72M
        id->subid = -1;
2167
1.72M
        if (type == RIGHTBRACKET)
2168
133k
            return count;
2169
1.59M
        if (type == LABEL) {
2170
            /*
2171
             * this entry has a label 
2172
             */
2173
1.26M
            id->label = strdup(token);
2174
1.26M
            type = get_token(fp, token, MAXTOKEN);
2175
1.26M
            if (type == LEFTPAREN) {
2176
1.20k
                type = get_token(fp, token, MAXTOKEN);
2177
1.20k
                if (type == NUMBER) {
2178
800
                    id->subid = strtoul(token, NULL, 10);
2179
800
                    if ((type =
2180
800
                         get_token(fp, token, MAXTOKEN)) != RIGHTPAREN) {
2181
505
                        print_error("Expected a closing parenthesis",
2182
505
                                    token, type);
2183
505
                        goto free_labels;
2184
505
                    }
2185
800
                } else {
2186
406
                    print_error("Expected a number", token, type);
2187
406
                    goto free_labels;
2188
406
                }
2189
1.26M
            } else {
2190
1.26M
                continue;
2191
1.26M
            }
2192
1.26M
        } else if (type == NUMBER) {
2193
            /*
2194
             * this entry  has just an integer sub-identifier 
2195
             */
2196
321k
            id->subid = strtoul(token, NULL, 10);
2197
321k
        } else {
2198
10.0k
            print_error("Expected label or number", token, type);
2199
10.0k
            goto free_labels;
2200
10.0k
        }
2201
321k
        type = get_token(fp, token, MAXTOKEN);
2202
321k
    }
2203
540
    print_error("Too long OID", token, type);
2204
540
    --count;
2205
2206
11.5k
free_labels:
2207
78.2k
    for (i = 0; i <= count; i++) {
2208
66.6k
        free(id_arg[i].label);
2209
66.6k
        id_arg[i].label = NULL;
2210
66.6k
    }
2211
2212
11.5k
    return 0;
2213
540
}
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
147k
{
2240
147k
    register int    count;
2241
147k
    register struct subid_s *op, *nop;
2242
147k
    int             length;
2243
147k
    struct subid_s  loid[32];
2244
147k
    struct node    *np, *root = NULL, *oldnp = NULL;
2245
147k
    struct tree    *tp;
2246
2247
147k
    if ((length = getoid(fp, loid, 32)) == 0) {
2248
13.7k
        print_error("Bad object identifier", NULL, CONTINUE);
2249
13.7k
        return NULL;
2250
13.7k
    }
2251
2252
    /*
2253
     * Handle numeric-only object identifiers,
2254
     *  by labeling the first sub-identifier
2255
     */
2256
133k
    op = loid;
2257
133k
    if (!op->label) {
2258
29.4k
        if (length == 1) {
2259
324
            print_error("Attempt to define a root oid", name, OBJECT);
2260
324
            return NULL;
2261
324
        }
2262
69.2k
        for (tp = tree_head; tp; tp = tp->next_peer)
2263
62.7k
            if ((int) tp->subid == op->subid) {
2264
22.6k
                op->label = strdup(tp->label);
2265
22.6k
                break;
2266
22.6k
            }
2267
29.1k
    }
2268
2269
    /*
2270
     * Handle  "label OBJECT-IDENTIFIER ::= { subid }"
2271
     */
2272
132k
    if (length == 1) {
2273
12.3k
        op = loid;
2274
12.3k
        np = alloc_node(op->modid);
2275
12.3k
        if (np == NULL)
2276
0
            return (NULL);
2277
12.3k
        np->subid = op->subid;
2278
12.3k
        np->label = strdup(name);
2279
12.3k
        np->parent = op->label;
2280
12.3k
        return np;
2281
12.3k
    }
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.51M
    for (count = 0, op = loid, nop = loid + 1; count < (length - 1);
2288
1.39M
         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.39M
        if (op->label && (nop->label || (nop->subid != -1))) {
2296
1.36M
            np = alloc_node(nop->modid);
2297
1.36M
            if (np == NULL)
2298
0
                goto err;
2299
1.36M
            if (root == NULL) {
2300
120k
                root = np;
2301
1.24M
            } else {
2302
1.24M
                netsnmp_assert(oldnp);
2303
1.24M
                oldnp->next = np;
2304
1.24M
            }
2305
1.36M
            oldnp = np;
2306
2307
1.36M
            np->parent = strdup(op->label);
2308
1.36M
            if (count == (length - 2)) {
2309
                /*
2310
                 * The name for this node is the label for this entry 
2311
                 */
2312
108k
                np->label = strdup(name);
2313
108k
                if (np->label == NULL)
2314
0
                    goto err;
2315
1.25M
            } else {
2316
1.25M
                if (!nop->label) {
2317
220k
                    if (asprintf(&nop->label, "%s%d", ANON, anonymous++) < 0)
2318
0
                        goto err;
2319
220k
                }
2320
1.25M
                np->label = strdup(nop->label);
2321
1.25M
            }
2322
1.36M
            if (nop->subid != -1)
2323
271k
                np->subid = nop->subid;
2324
1.08M
            else
2325
1.08M
                print_error("Warning: This entry is pretty silly",
2326
1.08M
                            np->label, CONTINUE);
2327
1.36M
        }                       /* end if(op->label... */
2328
1.39M
    }
2329
2330
120k
out:
2331
    /*
2332
     * free the loid array 
2333
     */
2334
1.63M
    for (count = 0, op = loid; count < length; count++, op++) {
2335
1.51M
        free(op->label);
2336
1.51M
        op->label = NULL;
2337
1.51M
    }
2338
2339
120k
    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
120k
}
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
18.5k
{
2355
18.5k
    int             i;
2356
18.5k
    struct tc      *tcp;
2357
2358
18.5k
    i = get_tc_index(descriptor, modid);
2359
18.5k
    if (tc_index)
2360
4.02k
        *tc_index = i;
2361
18.5k
    if (i != -1) {
2362
961
        tcp = &tclist[i];
2363
961
        if (ep) {
2364
606
            free_enums(ep);
2365
606
            *ep = copy_enums(tcp->enums);
2366
606
        }
2367
961
        if (rp) {
2368
606
            free_ranges(rp);
2369
606
            *rp = copy_ranges(tcp->ranges);
2370
606
        }
2371
961
        if (hint) {
2372
606
            if (*hint)
2373
0
                free(*hint);
2374
606
            *hint = (tcp->hint ? strdup(tcp->hint) : NULL);
2375
606
        }
2376
961
        return tcp->type;
2377
961
    }
2378
17.6k
    return LABEL;
2379
18.5k
}
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.77M
{
2388
1.77M
    int             i;
2389
1.77M
    struct tc      *tcp;
2390
1.77M
    struct module  *mp;
2391
1.77M
    struct module_import *mip;
2392
2393
    /*
2394
     * Check that the descriptor isn't imported
2395
     *  by searching the import list
2396
     */
2397
2398
8.66M
    for (mp = module_head; mp; mp = mp->next)
2399
8.32M
        if (mp->modid == modid)
2400
1.43M
            break;
2401
1.77M
    if (mp)
2402
75.8M
        for (i = 0, mip = mp->imports; i < mp->no_imports; ++i, ++mip) {
2403
75.3M
            if (!label_compare(mip->label, descriptor)) {
2404
                /*
2405
                 * Found it - so amend the module ID 
2406
                 */
2407
893k
                modid = mip->modid;
2408
893k
                break;
2409
893k
            }
2410
75.3M
        }
2411
2412
2413
2.55M
    for (i = 0, tcp = tclist; i < tc_alloc; i++, tcp++) {
2414
2.54M
        if (tcp->type == 0)
2415
1.76M
            break;
2416
781k
        if (!label_compare(descriptor, tcp->descriptor) &&
2417
5.84k
            ((modid == tcp->modid) || (modid == -1))) {
2418
4.89k
            return i;
2419
4.89k
        }
2420
781k
    }
2421
1.76M
    return -1;
2422
1.77M
}
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.54k
{
2459
6.54k
    register int    type;
2460
6.54k
    char            token[MAXTOKEN];
2461
6.54k
    struct enum_list *ep = NULL, **epp = &ep;
2462
2463
6.54k
    free_enums(retp);
2464
2465
33.2k
    while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE) {
2466
33.2k
        if (type == RIGHTBRACKET)
2467
3.41k
            break;
2468
        /* some enums use "deprecated" to indicate a no longer value label */
2469
        /* (EG: IP-MIB's IpAddressStatusTC) */
2470
29.8k
        if (type == LABEL || type == DEPRECATED) {
2471
            /*
2472
             * this is an enumerated label 
2473
             */
2474
11.7k
            *epp = calloc(1, sizeof(struct enum_list));
2475
11.7k
            if (*epp == NULL)
2476
0
                return (NULL);
2477
            /*
2478
             * a reasonable approximation for the length 
2479
             */
2480
11.7k
            (*epp)->label = strdup(token);
2481
11.7k
            type = get_token(fp, token, MAXTOKEN);
2482
11.7k
            if (type != LEFTPAREN) {
2483
1.75k
                print_error("Expected \"(\"", token, type);
2484
1.75k
                goto err;
2485
1.75k
            }
2486
9.99k
            type = get_token(fp, token, MAXTOKEN);
2487
9.99k
            if (type != NUMBER) {
2488
837
                print_error("Expected integer", token, type);
2489
837
                goto err;
2490
837
            }
2491
9.16k
            (*epp)->value = strtol(token, NULL, 10);
2492
9.16k
            (*epp)->lineno = mibLine;
2493
9.16k
            type = get_token(fp, token, MAXTOKEN);
2494
9.16k
            if (type != RIGHTPAREN) {
2495
463
                print_error("Expected \")\"", token, type);
2496
463
                goto err;
2497
8.69k
            } else {
2498
8.69k
                struct enum_list *op = ep;
2499
14.2k
                while (op != *epp) {
2500
8.74k
                    if (strcmp((*epp)->label, op->label) == 0) {
2501
801
                        snmp_log(LOG_ERR,
2502
801
                            "Duplicate enum label '%s' at line %d in %s. First at line %d\n",
2503
801
                            (*epp)->label, mibLine, File, op->lineno);
2504
801
                        erroneousMibs++;
2505
801
                        break;
2506
801
                    }
2507
7.94k
                    else if ((*epp)->value == op->value) {
2508
2.43k
                        snmp_log(LOG_ERR,
2509
2.43k
                            "Duplicate enum value '%d' at line %d in %s. First at line %d\n",
2510
2.43k
                            (*epp)->value, mibLine, File, op->lineno);
2511
2.43k
                        erroneousMibs++;
2512
2.43k
                        break;
2513
2.43k
                    }
2514
5.50k
                    op = op->next;
2515
5.50k
                }
2516
8.69k
            }
2517
8.69k
            epp = &(*epp)->next;
2518
8.69k
        }
2519
29.8k
    }
2520
3.49k
    if (type == ENDOFFILE) {
2521
81
        print_error("Expected \"}\"", token, type);
2522
81
        goto err;
2523
81
    }
2524
3.41k
    *retp = ep;
2525
3.41k
    return ep;
2526
2527
3.13k
err:
2528
3.13k
    free_enums(&ep);
2529
3.13k
    return NULL;
2530
3.49k
}
2531
2532
static struct range_list *
2533
parse_ranges(FILE * fp, struct range_list **retp)
2534
4.21k
{
2535
4.21k
    int             low, high;
2536
4.21k
    char            nexttoken[MAXTOKEN];
2537
4.21k
    int             nexttype;
2538
4.21k
    struct range_list *rp = NULL, **rpp = &rp;
2539
4.21k
    int             size = 0, taken = 1;
2540
2541
4.21k
    free_ranges(retp);
2542
2543
4.21k
    nexttype = get_token(fp, nexttoken, MAXTOKEN);
2544
4.21k
    if (nexttype == SIZE) {
2545
1.20k
        size = 1;
2546
1.20k
        taken = 0;
2547
1.20k
        nexttype = get_token(fp, nexttoken, MAXTOKEN);
2548
1.20k
        if (nexttype != LEFTPAREN)
2549
665
            print_error("Expected \"(\" after SIZE", nexttoken, nexttype);
2550
1.20k
    }
2551
2552
7.88k
    do {
2553
7.88k
        if (!taken)
2554
4.87k
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2555
3.01k
        else
2556
3.01k
            taken = 0;
2557
7.88k
        high = low = strtoul(nexttoken, NULL, 10);
2558
7.88k
        nexttype = get_token(fp, nexttoken, MAXTOKEN);
2559
7.88k
        if (nexttype == RANGE) {
2560
1.99k
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2561
1.99k
            errno = 0;
2562
1.99k
            high = strtoul(nexttoken, NULL, 10);
2563
1.99k
            if ( errno == ERANGE ) {
2564
377
                if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
2565
377
                                       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
377
            }
2570
1.99k
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2571
1.99k
        }
2572
7.88k
        *rpp = (struct range_list *) calloc(1, sizeof(struct range_list));
2573
7.88k
        if (*rpp == NULL)
2574
0
            break;
2575
7.88k
        (*rpp)->low = low;
2576
7.88k
        (*rpp)->high = high;
2577
7.88k
        rpp = &(*rpp)->next;
2578
2579
7.88k
    } while (nexttype == BAR);
2580
4.21k
    if (size) {
2581
1.20k
        if (nexttype != RIGHTPAREN)
2582
814
            print_error("Expected \")\" after SIZE", nexttoken, nexttype);
2583
1.20k
        nexttype = get_token(fp, nexttoken, MAXTOKEN);
2584
1.20k
    }
2585
4.21k
    if (nexttype != RIGHTPAREN)
2586
2.21k
        print_error("Expected \")\"", nexttoken, nexttype);
2587
2588
4.21k
    *retp = rp;
2589
4.21k
    return rp;
2590
4.21k
}
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
117k
{
2599
117k
    int             type, i;
2600
117k
    char            token[MAXTOKEN];
2601
117k
    char            quoted_string_buffer[MAXQUOTESTR];
2602
117k
    char           *hint = NULL;
2603
117k
    char           *descr = NULL;
2604
117k
    struct tc      *tcp;
2605
117k
    int             level;
2606
117k
    int             is_duplicate = 0;
2607
2608
117k
    type = get_token(fp, token, MAXTOKEN);
2609
117k
    if (type == SEQUENCE || type == CHOICE) {
2610
1.77k
        level = 0;
2611
1.32M
        while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE) {
2612
1.32M
            if (type == LEFTBRACKET) {
2613
66.7k
                level++;
2614
1.26M
            } else if (type == RIGHTBRACKET && --level == 0) {
2615
1.69k
                *ntype = get_token(fp, ntoken, MAXTOKEN);
2616
1.69k
                return NULL;
2617
1.69k
            }
2618
1.32M
        }
2619
83
        print_error("Expected \"}\"", token, type);
2620
83
        return NULL;
2621
115k
    } else if (type == LEFTBRACKET) {
2622
83.8k
        struct node    *np;
2623
83.8k
        int             ch_next = '{';
2624
83.8k
        ungetc(ch_next, fp);
2625
83.8k
        np = parse_objectid(fp, name);
2626
83.8k
        if (np != NULL) {
2627
72.0k
            *ntype = get_token(fp, ntoken, MAXTOKEN);
2628
72.0k
            return np;
2629
72.0k
        }
2630
11.8k
        return NULL;
2631
83.8k
    } else if (type == LEFTSQBRACK) {
2632
3.95k
        int             size = 0;
2633
76.5k
        do {
2634
76.5k
            type = get_token(fp, token, MAXTOKEN);
2635
76.5k
        } while (type != ENDOFFILE && type != RIGHTSQBRACK);
2636
3.95k
        if (type != RIGHTSQBRACK) {
2637
49
            print_error("Expected \"]\"", token, type);
2638
49
            return NULL;
2639
49
        }
2640
3.90k
        type = get_token(fp, token, MAXTOKEN);
2641
3.90k
        if (type == IMPLICIT)
2642
1.88k
            type = get_token(fp, token, MAXTOKEN);
2643
3.90k
        *ntype = get_token(fp, ntoken, MAXTOKEN);
2644
3.90k
        if (*ntype == LEFTPAREN) {
2645
3.07k
            switch (type) {
2646
1.11k
            case OCTETSTR:
2647
1.11k
                *ntype = get_token(fp, ntoken, MAXTOKEN);
2648
1.11k
                if (*ntype != SIZE) {
2649
216
                    print_error("Expected SIZE", ntoken, *ntype);
2650
216
                    return NULL;
2651
216
                }
2652
902
                size = 1;
2653
902
                *ntype = get_token(fp, ntoken, MAXTOKEN);
2654
902
                if (*ntype != LEFTPAREN) {
2655
199
                    print_error("Expected \"(\" after SIZE", ntoken,
2656
199
                                *ntype);
2657
199
                    return NULL;
2658
199
                }
2659
703
                NETSNMP_FALLTHROUGH;
2660
2.26k
            case INTEGER:
2661
2.26k
                *ntype = get_token(fp, ntoken, MAXTOKEN);
2662
4.84k
                do {
2663
4.84k
                    if (*ntype != NUMBER)
2664
2.69k
                        print_error("Expected NUMBER", ntoken, *ntype);
2665
4.84k
                    *ntype = get_token(fp, ntoken, MAXTOKEN);
2666
4.84k
                    if (*ntype == RANGE) {
2667
1.77k
                        *ntype = get_token(fp, ntoken, MAXTOKEN);
2668
1.77k
                        if (*ntype != NUMBER)
2669
548
                            print_error("Expected NUMBER", ntoken, *ntype);
2670
1.77k
                        *ntype = get_token(fp, ntoken, MAXTOKEN);
2671
1.77k
                    }
2672
4.84k
                } while (*ntype == BAR);
2673
2.26k
                if (*ntype != RIGHTPAREN) {
2674
314
                    print_error("Expected \")\"", ntoken, *ntype);
2675
314
                    return NULL;
2676
314
                }
2677
1.94k
                *ntype = get_token(fp, ntoken, MAXTOKEN);
2678
1.94k
                if (size) {
2679
698
                    if (*ntype != RIGHTPAREN) {
2680
201
                        print_error("Expected \")\" to terminate SIZE",
2681
201
                                    ntoken, *ntype);
2682
201
                        return NULL;
2683
201
                    }
2684
497
                    *ntype = get_token(fp, ntoken, MAXTOKEN);
2685
497
                }
2686
3.07k
            }
2687
3.07k
        }
2688
2.97k
        return NULL;
2689
27.5k
    } else {
2690
27.5k
        if (type == CONVENTION) {
2691
30.0k
            while (type != SYNTAX && type != ENDOFFILE) {
2692
28.9k
                if (type == DISPLAYHINT) {
2693
740
                    type = get_token(fp, token, MAXTOKEN);
2694
740
                    if (type != QUOTESTRING) {
2695
237
                        print_error("DISPLAY-HINT must be string", token,
2696
237
                                    type);
2697
503
                    } else {
2698
503
                        free(hint);
2699
503
                        hint = strdup(token);
2700
503
                    }
2701
28.1k
                } else if (type == DESCRIPTION &&
2702
319
                           netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
2703
319
                                                  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
28.1k
                    type =
2714
28.1k
                        get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2715
28.9k
            }
2716
1.11k
            type = get_token(fp, token, MAXTOKEN);
2717
1.11k
            if (type == OBJECT) {
2718
439
                type = get_token(fp, token, MAXTOKEN);
2719
439
                if (type != IDENTIFIER) {
2720
202
                    print_error("Expected IDENTIFIER", token, type);
2721
202
                    goto err;
2722
202
                }
2723
237
                type = OBJID;
2724
237
            }
2725
26.4k
        } else if (type == OBJECT) {
2726
1.78k
            type = get_token(fp, token, MAXTOKEN);
2727
1.78k
            if (type != IDENTIFIER) {
2728
327
                print_error("Expected IDENTIFIER", token, type);
2729
327
                goto err;
2730
327
            }
2731
1.45k
            type = OBJID;
2732
1.45k
        }
2733
2734
26.9k
        if (type == LABEL) {
2735
14.5k
            type = get_tc(token, current_module, NULL, NULL, NULL, NULL);
2736
14.5k
        }
2737
2738
        /*
2739
         * textual convention 
2740
         */
2741
26.9k
        tcp = NULL;
2742
26.9k
        is_duplicate = 0;
2743
2.24M
        for (i = 0; i < tc_alloc; i++) {
2744
2.22M
            if (tclist[i].type == 0) {
2745
1.76M
                if (tcp == NULL)
2746
19.5k
                    tcp = &tclist[i];
2747
1.76M
            } else if (strcmp(name, tclist[i].descriptor) == 0 &&
2748
14.0k
                       tclist[i].modid == current_module) {
2749
7.45k
                snmp_log(LOG_ERR,
2750
7.45k
                         "Duplicate TEXTUAL-CONVENTION '%s' at line %d in %s. First at line %d\n",
2751
7.45k
                         name, mibLine, File, tclist[i].lineno);
2752
7.45k
                erroneousMibs++;
2753
7.45k
                is_duplicate = 1;
2754
7.45k
                break;
2755
7.45k
            }
2756
2.22M
        }
2757
2758
26.9k
        if (is_duplicate) {
2759
7.45k
            struct range_list *dummy_ranges = NULL;
2760
7.45k
            struct enum_list *dummy_enums = NULL;
2761
2762
7.45k
            free(hint);
2763
7.45k
            free(descr);
2764
7.45k
            *ntype = get_token(fp, ntoken, MAXTOKEN);
2765
7.45k
            if (*ntype == LEFTPAREN) {
2766
1.39k
                dummy_ranges = parse_ranges(fp, &dummy_ranges);
2767
1.39k
                free_ranges(&dummy_ranges);
2768
1.39k
                *ntype = get_token(fp, ntoken, MAXTOKEN);
2769
6.06k
            } else if (*ntype == LEFTBRACKET) {
2770
2.31k
                dummy_enums = parse_enumlist(fp, &dummy_enums);
2771
2.31k
                free_enums(&dummy_enums);
2772
2.31k
                *ntype = get_token(fp, ntoken, MAXTOKEN);
2773
2.31k
            }
2774
7.45k
            return NULL;
2775
7.45k
        }
2776
2777
19.5k
        if (tcp == NULL) {
2778
19
            tclist = realloc(tclist, (tc_alloc + TC_INCR)*sizeof(struct tc));
2779
19
            memset(tclist+tc_alloc, 0, TC_INCR*sizeof(struct tc));
2780
19
            tcp = tclist + tc_alloc;
2781
19
            tc_alloc += TC_INCR;
2782
19
        }
2783
19.5k
        if (!(type & SYNTAX_MASK)) {
2784
14.1k
            print_error("Textual convention doesn't map to real type",
2785
14.1k
                        token, type);
2786
14.1k
            goto err;
2787
14.1k
        }
2788
5.43k
        tcp->modid = current_module;
2789
5.43k
        tcp->descriptor = strdup(name);
2790
5.43k
        tcp->hint = hint;
2791
5.43k
        tcp->description = descr;
2792
5.43k
        tcp->lineno = mibLine;
2793
5.43k
        tcp->type = type;
2794
5.43k
        *ntype = get_token(fp, ntoken, MAXTOKEN);
2795
5.43k
        if (*ntype == LEFTPAREN) {
2796
543
            tcp->ranges = parse_ranges(fp, &tcp->ranges);
2797
543
            *ntype = get_token(fp, ntoken, MAXTOKEN);
2798
4.88k
        } else if (*ntype == LEFTBRACKET) {
2799
            /*
2800
             * if there is an enumeration list, parse it 
2801
             */
2802
2.74k
            tcp->enums = parse_enumlist(fp, &tcp->enums);
2803
2.74k
            *ntype = get_token(fp, ntoken, MAXTOKEN);
2804
2.74k
        }
2805
5.43k
        return NULL;
2806
19.5k
    }
2807
2808
14.6k
err:
2809
14.6k
    SNMP_FREE(descr);
2810
14.6k
    SNMP_FREE(hint);
2811
14.6k
    return NULL;
2812
117k
}
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
11.3k
{
2822
11.3k
    register int    type;
2823
11.3k
    char            token[MAXTOKEN];
2824
11.3k
    char            nexttoken[MAXTOKEN];
2825
11.3k
    char            quoted_string_buffer[MAXQUOTESTR];
2826
11.3k
    int             nexttype, tctype;
2827
11.3k
    register struct node *np;
2828
2829
11.3k
    type = get_token(fp, token, MAXTOKEN);
2830
11.3k
    if (type != SYNTAX) {
2831
13
        print_error("Bad format for OBJECT-TYPE", token, type);
2832
13
        return NULL;
2833
13
    }
2834
11.3k
    np = alloc_node(current_module);
2835
11.3k
    if (np == NULL)
2836
0
        return (NULL);
2837
11.3k
    type = get_token(fp, token, MAXTOKEN);
2838
11.3k
    if (type == OBJECT) {
2839
487
        type = get_token(fp, token, MAXTOKEN);
2840
487
        if (type != IDENTIFIER) {
2841
11
            print_error("Expected IDENTIFIER", token, type);
2842
11
            free_node(np);
2843
11
            return NULL;
2844
11
        }
2845
476
        type = OBJID;
2846
476
    }
2847
11.3k
    if (type == LABEL) {
2848
4.02k
        int             tmp_index;
2849
4.02k
        tctype = get_tc(token, current_module, &tmp_index,
2850
4.02k
                        &np->enums, &np->ranges, &np->hint);
2851
4.02k
        if (tctype == LABEL &&
2852
3.41k
            netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
2853
3.41k
             NETSNMP_DS_LIB_MIB_WARNINGS) > 1) {
2854
0
            print_error("Warning: No known translation for type", token,
2855
0
                        type);
2856
0
        }
2857
4.02k
        type = tctype;
2858
4.02k
        np->tc_index = tmp_index;       /* store TC for later reference */
2859
4.02k
    }
2860
11.3k
    np->type = type;
2861
11.3k
    nexttype = get_token(fp, nexttoken, MAXTOKEN);
2862
11.3k
    switch (type) {
2863
914
    case SEQUENCE:
2864
914
        if (nexttype == OF) {
2865
509
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2866
509
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2867
2868
509
        }
2869
914
        break;
2870
970
    case INTEGER:
2871
1.68k
    case INTEGER32:
2872
2.12k
    case UINTEGER32:
2873
2.46k
    case UNSIGNED32:
2874
3.24k
    case COUNTER:
2875
3.46k
    case GAUGE:
2876
3.79k
    case BITSTRING:
2877
7.21k
    case LABEL:
2878
7.21k
        if (nexttype == LEFTBRACKET) {
2879
            /*
2880
             * if there is an enumeration list, parse it 
2881
             */
2882
818
            np->enums = parse_enumlist(fp, &np->enums);
2883
818
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2884
6.39k
        } else if (nexttype == LEFTPAREN) {
2885
            /*
2886
             * if there is a range list, parse it 
2887
             */
2888
801
            np->ranges = parse_ranges(fp, &np->ranges);
2889
801
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2890
801
        }
2891
7.21k
        break;
2892
867
    case OCTETSTR:
2893
1.04k
    case KW_OPAQUE:
2894
        /*
2895
         * parse any SIZE specification 
2896
         */
2897
1.04k
        if (nexttype == LEFTPAREN) {
2898
317
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2899
317
            if (nexttype == SIZE) {
2900
309
                nexttype = get_token(fp, nexttoken, MAXTOKEN);
2901
309
                if (nexttype == LEFTPAREN) {
2902
303
                    np->ranges = parse_ranges(fp, &np->ranges);
2903
303
                    nexttype = get_token(fp, nexttoken, MAXTOKEN);      /* ) */
2904
303
                    if (nexttype == RIGHTPAREN) {
2905
294
                        nexttype = get_token(fp, nexttoken, MAXTOKEN);
2906
294
                        break;
2907
294
                    }
2908
303
                }
2909
309
            }
2910
23
            print_error("Bad SIZE syntax", token, type);
2911
23
            free_node(np);
2912
23
            return NULL;
2913
317
        }
2914
729
        break;
2915
729
    case OBJID:
2916
1.15k
    case NETADDR:
2917
1.27k
    case IPADDR:
2918
1.43k
    case TIMETICKS:
2919
1.70k
    case NUL:
2920
1.80k
    case NSAPADDRESS:
2921
2.19k
    case COUNTER64:
2922
2.19k
        break;
2923
12
    default:
2924
12
        print_error("Bad syntax", token, type);
2925
12
        free_node(np);
2926
12
        return NULL;
2927
11.3k
    }
2928
11.3k
    if (nexttype == UNITS) {
2929
1.40k
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2930
1.40k
        if (type != QUOTESTRING) {
2931
4
            print_error("Bad UNITS", quoted_string_buffer, type);
2932
4
            free_node(np);
2933
4
            return NULL;
2934
4
        }
2935
1.39k
        np->units = strdup(quoted_string_buffer);
2936
1.39k
        nexttype = get_token(fp, nexttoken, MAXTOKEN);
2937
1.39k
    }
2938
11.3k
    if (nexttype != ACCESS) {
2939
181
        print_error("Should be ACCESS", nexttoken, nexttype);
2940
181
        free_node(np);
2941
181
        return NULL;
2942
181
    }
2943
11.1k
    type = get_token(fp, token, MAXTOKEN);
2944
11.1k
    if (type != READONLY && type != READWRITE && type != WRITEONLY
2945
4.30k
        && type != NOACCESS && type != READCREATE && type != ACCNOTIFY) {
2946
30
        print_error("Bad ACCESS type", token, type);
2947
30
        free_node(np);
2948
30
        return NULL;
2949
30
    }
2950
11.1k
    np->access = type;
2951
11.1k
    type = get_token(fp, token, MAXTOKEN);
2952
11.1k
    if (type != STATUS) {
2953
33
        print_error("Should be STATUS", token, type);
2954
33
        free_node(np);
2955
33
        return NULL;
2956
33
    }
2957
11.0k
    type = get_token(fp, token, MAXTOKEN);
2958
11.0k
    if (type != MANDATORY && type != CURRENT && type != KW_OPTIONAL &&
2959
945
        type != OBSOLETE && type != DEPRECATED) {
2960
39
        print_error("Bad STATUS", token, type);
2961
39
        free_node(np);
2962
39
        return NULL;
2963
39
    }
2964
11.0k
    np->status = type;
2965
    /*
2966
     * Optional parts of the OBJECT-TYPE macro
2967
     */
2968
11.0k
    type = get_token(fp, token, MAXTOKEN);
2969
25.6k
    while (type != EQUALS && type != ENDOFFILE) {
2970
14.8k
        switch (type) {
2971
8.39k
        case DESCRIPTION:
2972
8.39k
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2973
2974
8.39k
            if (type != QUOTESTRING) {
2975
23
                print_error("Bad DESCRIPTION", quoted_string_buffer, type);
2976
23
                free_node(np);
2977
23
                return NULL;
2978
23
            }
2979
8.36k
            if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
2980
8.36k
               NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
2981
0
                free(np->description);
2982
0
                np->description = strdup(quoted_string_buffer);
2983
0
            }
2984
8.36k
            break;
2985
2986
424
        case REFERENCE:
2987
424
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2988
424
            if (type != QUOTESTRING) {
2989
13
                print_error("Bad REFERENCE", quoted_string_buffer, type);
2990
13
                free_node(np);
2991
13
                return NULL;
2992
13
            }
2993
411
            free(np->reference);
2994
411
            np->reference = strdup(quoted_string_buffer);
2995
411
            break;
2996
3.89k
        case INDEX:
2997
3.89k
            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.89k
            np->indexes = getIndexes(fp, &np->indexes);
3004
3.89k
            if (np->indexes == NULL) {
3005
21
                print_error("Bad INDEX list", token, type);
3006
21
                free_node(np);
3007
21
                return NULL;
3008
21
            }
3009
3.87k
            break;
3010
3.87k
        case AUGMENTS:
3011
518
            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
517
            np->indexes = getIndexes(fp, &np->indexes);
3018
517
            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
515
            free(np->augments);
3024
515
            np->augments = strdup(np->indexes->ilabel);
3025
515
            free_indexes(&np->indexes);
3026
515
            break;
3027
1.29k
        case DEFVAL:
3028
            /*
3029
             * Mark's defVal section 
3030
             */
3031
1.29k
            type = get_token(fp, quoted_string_buffer,
3032
1.29k
                             sizeof(quoted_string_buffer));
3033
1.29k
            if (type != LEFTBRACKET) {
3034
6
                print_error("Bad DEFAULTVALUE", quoted_string_buffer,
3035
6
                            type);
3036
6
                free_node(np);
3037
6
                return NULL;
3038
6
            }
3039
3040
1.29k
            {
3041
1.29k
                int             level = 1;
3042
1.29k
                char            defbuf[512];
3043
3044
1.29k
                defbuf[0] = 0;
3045
639k
                while (1) {
3046
639k
                    type = get_token(fp, quoted_string_buffer,
3047
639k
                                     sizeof(quoted_string_buffer));
3048
639k
                    if ((type == RIGHTBRACKET && --level == 0)
3049
638k
                        || type == ENDOFFILE)
3050
1.29k
                        break;
3051
637k
                    else if (type == LEFTBRACKET)
3052
559k
                        level++;
3053
637k
                    if (type == QUOTESTRING)
3054
1.32k
                        strlcat(defbuf, "\\\"", sizeof(defbuf));
3055
637k
                    strlcat(defbuf, quoted_string_buffer, sizeof(defbuf));
3056
637k
                    if (type == QUOTESTRING)
3057
1.32k
                        strlcat(defbuf, "\\\"", sizeof(defbuf));
3058
637k
                    strlcat(defbuf, " ", sizeof(defbuf));
3059
637k
                }
3060
3061
1.29k
                if (type != RIGHTBRACKET) {
3062
74
                    print_error("Bad DEFAULTVALUE", quoted_string_buffer,
3063
74
                                type);
3064
74
                    free_node(np);
3065
74
                    return NULL;
3066
74
                }
3067
3068
                /*
3069
                 * Ensure strlen(defbuf) is above zero
3070
                 */
3071
1.21k
                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.21k
                defbuf[strlen(defbuf) - 1] = 0;
3078
1.21k
                free(np->defaultValue);
3079
1.21k
                np->defaultValue = strdup(defbuf);
3080
1.21k
            }
3081
3082
0
            break;
3083
3084
230
        case NUM_ENTRIES:
3085
230
            if (tossObjectIdentifier(fp) != OBJID) {
3086
33
                print_error("Bad Object Identifier", token, type);
3087
33
                free_node(np);
3088
33
                return NULL;
3089
33
            }
3090
197
            break;
3091
3092
197
        default:
3093
71
            print_error("Bad format of optional clauses", token, type);
3094
71
            free_node(np);
3095
71
            return NULL;
3096
3097
14.8k
        }
3098
14.5k
        type = get_token(fp, token, MAXTOKEN);
3099
14.5k
    }
3100
10.8k
    if (type != EQUALS) {
3101
71
        print_error("Bad format", token, type);
3102
71
        free_node(np);
3103
71
        return NULL;
3104
71
    }
3105
10.7k
    return merge_parse_objectid(np, fp, name);
3106
10.8k
}
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
6.31k
{
3118
6.31k
    int             type;
3119
6.31k
    char            token[MAXTOKEN];
3120
6.31k
    char            quoted_string_buffer[MAXQUOTESTR];
3121
6.31k
    struct node    *np;
3122
3123
6.31k
    np = alloc_node(current_module);
3124
6.31k
    if (np == NULL)
3125
0
        return (NULL);
3126
6.31k
    type = get_token(fp, token, MAXTOKEN);
3127
6.31k
    if (type == what) {
3128
3.03k
        type = get_token(fp, token, MAXTOKEN);
3129
3.03k
        if (type != LEFTBRACKET) {
3130
535
            print_error("Expected \"{\"", token, type);
3131
535
            goto skip;
3132
535
        }
3133
6.89k
        do {
3134
6.89k
            struct objgroup *o;
3135
6.89k
            type = get_token(fp, token, MAXTOKEN);
3136
6.89k
            if (type != LABEL) {
3137
375
                print_error("Bad identifier", token, type);
3138
375
                goto skip;
3139
375
            }
3140
6.52k
            o = (struct objgroup *) malloc(sizeof(struct objgroup));
3141
6.52k
            if (!o) {
3142
0
                print_error("Resource failure", token, type);
3143
0
                goto skip;
3144
0
            }
3145
6.52k
            o->line = mibLine;
3146
6.52k
            o->name = strdup(token);
3147
6.52k
            o->next = *ol;
3148
6.52k
            *ol = o;
3149
6.52k
            type = get_token(fp, token, MAXTOKEN);
3150
6.52k
        } while (type == COMMA);
3151
2.12k
        if (type != RIGHTBRACKET) {
3152
1.42k
            print_error("Expected \"}\" after list", token, type);
3153
1.42k
            goto skip;
3154
1.42k
        }
3155
697
        type = get_token(fp, token, type);
3156
697
    }
3157
3.98k
    if (type != STATUS) {
3158
1.92k
        print_error("Expected STATUS", token, type);
3159
1.92k
        goto skip;
3160
1.92k
    }
3161
2.06k
    type = get_token(fp, token, MAXTOKEN);
3162
2.06k
    if (type != CURRENT && type != DEPRECATED && type != OBSOLETE) {
3163
364
        print_error("Bad STATUS value", token, type);
3164
364
        goto skip;
3165
364
    }
3166
1.69k
    type = get_token(fp, token, MAXTOKEN);
3167
1.69k
    if (type != DESCRIPTION) {
3168
912
        print_error("Expected DESCRIPTION", token, type);
3169
912
        goto skip;
3170
912
    }
3171
784
    type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3172
784
    if (type != QUOTESTRING) {
3173
1
        print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3174
1
        free_node(np);
3175
1
        return NULL;
3176
1
    }
3177
783
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
3178
783
             NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
3179
0
        np->description = strdup(quoted_string_buffer);
3180
0
    }
3181
783
    type = get_token(fp, token, MAXTOKEN);
3182
783
    if (type == REFERENCE) {
3183
337
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3184
337
        if (type != QUOTESTRING) {
3185
9
            print_error("Bad REFERENCE", quoted_string_buffer, type);
3186
9
            free_node(np);
3187
9
            return NULL;
3188
9
        }
3189
328
        np->reference = strdup(quoted_string_buffer);
3190
328
        type = get_token(fp, token, MAXTOKEN);
3191
328
    }
3192
774
    if (type != EQUALS)
3193
366
        print_error("Expected \"::=\"", token, type);
3194
6.30k
  skip:
3195
71.8k
    while (type != EQUALS && type != ENDOFFILE)
3196
65.5k
        type = get_token(fp, token, MAXTOKEN);
3197
3198
6.30k
    return merge_parse_objectid(np, fp, name);
3199
774
}
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.42k
{
3208
8.42k
    register int    type;
3209
8.42k
    char            token[MAXTOKEN];
3210
8.42k
    char            quoted_string_buffer[MAXQUOTESTR];
3211
8.42k
    register struct node *np;
3212
3213
8.42k
    np = alloc_node(current_module);
3214
8.42k
    if (np == NULL)
3215
0
        return (NULL);
3216
8.42k
    type = get_token(fp, token, MAXTOKEN);
3217
192k
    while (type != EQUALS && type != ENDOFFILE) {
3218
184k
        switch (type) {
3219
400
        case DESCRIPTION:
3220
400
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3221
400
            if (type != QUOTESTRING) {
3222
18
                print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3223
18
                goto free_node;
3224
18
            }
3225
382
            if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
3226
382
               NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
3227
0
                free(np->description);
3228
0
                np->description = strdup(quoted_string_buffer);
3229
0
            }
3230
382
            break;
3231
291
        case REFERENCE:
3232
291
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3233
291
            if (type != QUOTESTRING) {
3234
11
                print_error("Bad REFERENCE", quoted_string_buffer, type);
3235
11
                goto free_node;
3236
11
            }
3237
280
            free(np->reference);
3238
280
            np->reference = strdup(quoted_string_buffer);
3239
280
            break;
3240
8.20k
        case OBJECTS:
3241
8.20k
            np->varbinds = getVarbinds(fp, &np->varbinds);
3242
8.20k
            if (!np->varbinds) {
3243
13
                print_error("Bad OBJECTS list", token, type);
3244
13
                goto free_node;
3245
13
            }
3246
8.18k
            break;
3247
175k
        default:
3248
            /*
3249
             * NOTHING 
3250
             */
3251
175k
            break;
3252
184k
        }
3253
184k
        type = get_token(fp, token, MAXTOKEN);
3254
184k
    }
3255
8.38k
    return merge_parse_objectid(np, fp, name);
3256
3257
42
free_node:
3258
42
    free_node(np);
3259
42
    return NULL;
3260
8.42k
}
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
643
{
3269
643
    register int    type;
3270
643
    char            token[MAXTOKEN];
3271
643
    char            quoted_string_buffer[MAXQUOTESTR];
3272
643
    register struct node *np;
3273
3274
643
    np = alloc_node(current_module);
3275
643
    if (np == NULL)
3276
0
        return (NULL);
3277
643
    type = get_token(fp, token, MAXTOKEN);
3278
75.5k
    while (type != EQUALS && type != ENDOFFILE) {
3279
74.9k
        switch (type) {
3280
216
        case DESCRIPTION:
3281
216
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3282
216
            if (type != QUOTESTRING) {
3283
17
                print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3284
17
                goto free_node;
3285
17
            }
3286
199
            if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
3287
199
               NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
3288
0
                free(np->description);
3289
0
                np->description = strdup(quoted_string_buffer);
3290
0
            }
3291
199
            break;
3292
202
        case REFERENCE:
3293
            /* I'm not sure REFERENCEs are legal in smiv1 traps??? */
3294
202
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3295
202
            if (type != QUOTESTRING) {
3296
5
                print_error("Bad REFERENCE", quoted_string_buffer, type);
3297
5
                goto free_node;
3298
5
            }
3299
197
            free(np->reference);
3300
197
            np->reference = strdup(quoted_string_buffer);
3301
197
            break;
3302
900
        case ENTERPRISE:
3303
900
            type = get_token(fp, token, MAXTOKEN);
3304
900
            if (type == LEFTBRACKET) {
3305
227
                type = get_token(fp, token, MAXTOKEN);
3306
227
                if (type != LABEL) {
3307
7
                    print_error("Bad Trap Format", token, type);
3308
7
                    goto free_node;
3309
7
                }
3310
220
                free(np->parent);
3311
220
                np->parent = strdup(token);
3312
                /*
3313
                 * Get right bracket 
3314
                 */
3315
220
                type = get_token(fp, token, MAXTOKEN);
3316
673
            } else if (type == LABEL) {
3317
660
                free(np->parent);
3318
660
                np->parent = strdup(token);
3319
660
            } else {
3320
13
                goto free_node;
3321
13
            }
3322
880
            break;
3323
880
        case VARIABLES:
3324
300
            np->varbinds = getVarbinds(fp, &np->varbinds);
3325
300
            if (!np->varbinds) {
3326
28
                print_error("Bad VARIABLES list", token, type);
3327
28
                goto free_node;
3328
28
            }
3329
272
            break;
3330
73.3k
        default:
3331
            /*
3332
             * NOTHING 
3333
             */
3334
73.3k
            break;
3335
74.9k
        }
3336
74.9k
        type = get_token(fp, token, MAXTOKEN);
3337
74.9k
    }
3338
573
    type = get_token(fp, token, MAXTOKEN);
3339
3340
573
    np->label = strdup(name);
3341
3342
573
    if (type != NUMBER) {
3343
120
        print_error("Expected a Number", token, type);
3344
120
        goto free_node;
3345
120
    }
3346
453
    np->subid = strtoul(token, NULL, 10);
3347
453
    np->next = alloc_node(current_module);
3348
453
    if (np->next == NULL)
3349
0
        goto free_node;
3350
3351
    /* Catch the syntax error */
3352
453
    if (np->parent == NULL) {
3353
5
        gMibError = MODULE_SYNTAX_ERROR;
3354
5
        goto free_next_node;
3355
5
    }
3356
3357
448
    np->next->parent = np->parent;
3358
448
    np->parent = NULL;
3359
448
    if (asprintf(&np->parent, "%s#", np->next->parent) < 0)
3360
0
        goto free_next_node;
3361
448
    np->next->label = strdup(np->parent);
3362
448
    return np;
3363
3364
5
free_next_node:
3365
5
    free_node(np->next);
3366
3367
195
free_node:
3368
195
    free_node(np);
3369
195
    return NULL;
3370
5
}
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
7.81k
{
3380
7.81k
    int             type, nexttype;
3381
7.81k
    struct node    *np = alloc_node(current_module);
3382
7.81k
    char            nexttoken[MAXTOKEN];
3383
3384
7.81k
    if (!np)
3385
0
  return 0;
3386
3387
7.81k
    type = get_token(fp, token, maxtoken);
3388
7.81k
    nexttype = get_token(fp, nexttoken, MAXTOKEN);
3389
7.81k
    switch (type) {
3390
459
    case INTEGER:
3391
804
    case INTEGER32:
3392
999
    case UINTEGER32:
3393
1.32k
    case UNSIGNED32:
3394
1.52k
    case COUNTER:
3395
1.92k
    case GAUGE:
3396
2.13k
    case BITSTRING:
3397
4.42k
    case LABEL:
3398
4.42k
        if (nexttype == LEFTBRACKET) {
3399
            /*
3400
             * if there is an enumeration list, parse it 
3401
             */
3402
668
            np->enums = parse_enumlist(fp, &np->enums);
3403
668
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
3404
3.76k
        } else if (nexttype == LEFTPAREN) {
3405
            /*
3406
             * if there is a range list, parse it 
3407
             */
3408
870
            np->ranges = parse_ranges(fp, &np->ranges);
3409
870
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
3410
870
        }
3411
4.42k
        break;
3412
926
    case OCTETSTR:
3413
1.66k
    case KW_OPAQUE:
3414
        /*
3415
         * parse any SIZE specification 
3416
         */
3417
1.66k
        if (nexttype == LEFTPAREN) {
3418
1.12k
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
3419
1.12k
            if (nexttype == SIZE) {
3420
721
                nexttype = get_token(fp, nexttoken, MAXTOKEN);
3421
721
                if (nexttype == LEFTPAREN) {
3422
307
                    np->ranges = parse_ranges(fp, &np->ranges);
3423
307
                    nexttype = get_token(fp, nexttoken, MAXTOKEN);      /* ) */
3424
307
                    if (nexttype == RIGHTPAREN) {
3425
98
                        nexttype = get_token(fp, nexttoken, MAXTOKEN);
3426
98
                        break;
3427
98
                    }
3428
307
                }
3429
721
            }
3430
1.02k
            print_error("Bad SIZE syntax", token, type);
3431
1.02k
            free_node(np);
3432
1.02k
            return nexttype;
3433
1.12k
        }
3434
543
        break;
3435
543
    case OBJID:
3436
206
    case NETADDR:
3437
412
    case IPADDR:
3438
606
    case TIMETICKS:
3439
800
    case NUL:
3440
1.05k
    case NSAPADDRESS:
3441
1.24k
    case COUNTER64:
3442
1.24k
        break;
3443
470
    default:
3444
470
        print_error("Bad syntax", token, type);
3445
470
        free_node(np);
3446
470
        return nexttype;
3447
7.81k
    }
3448
6.31k
    free_node(np);
3449
6.31k
    return nexttype;
3450
7.81k
}
3451
3452
static int
3453
compliance_lookup(const char *name, int modid)
3454
12.5k
{
3455
12.5k
    struct objgroup *op;
3456
3457
12.5k
    if (modid != -1)
3458
1.93k
        return find_tree_node(name, modid) != NULL;
3459
3460
10.6k
    op = malloc(sizeof(struct objgroup));
3461
10.6k
    if (!op)
3462
0
        return 0;
3463
3464
10.6k
    op->next = objgroups;
3465
10.6k
    op->name = strdup(name);
3466
10.6k
    if (!op->name) {
3467
0
        free(op);
3468
0
        return 0;
3469
0
    }
3470
10.6k
    op->line = mibLine;
3471
10.6k
    objgroups = op;
3472
10.6k
    return 1;
3473
10.6k
}
3474
3475
static struct node *
3476
parse_compliance(FILE * fp, char *name)
3477
17.2k
{
3478
17.2k
    int             type;
3479
17.2k
    char            token[MAXTOKEN];
3480
17.2k
    char            quoted_string_buffer[MAXQUOTESTR];
3481
17.2k
    struct node    *np;
3482
3483
17.2k
    np = alloc_node(current_module);
3484
17.2k
    if (np == NULL)
3485
0
        return (NULL);
3486
17.2k
    type = get_token(fp, token, MAXTOKEN);
3487
17.2k
    if (type != STATUS) {
3488
1.59k
        print_error("Expected STATUS", token, type);
3489
1.59k
        goto skip;
3490
1.59k
    }
3491
15.6k
    type = get_token(fp, token, MAXTOKEN);
3492
15.6k
    if (type != CURRENT && type != DEPRECATED && type != OBSOLETE) {
3493
949
        print_error("Bad STATUS", token, type);
3494
949
        goto skip;
3495
949
    }
3496
14.6k
    type = get_token(fp, token, MAXTOKEN);
3497
14.6k
    if (type != DESCRIPTION) {
3498
1.42k
        print_error("Expected DESCRIPTION", token, type);
3499
1.42k
        goto skip;
3500
1.42k
    }
3501
13.2k
    type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3502
13.2k
    if (type != QUOTESTRING) {
3503
304
        print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3504
304
        goto skip;
3505
304
    }
3506
12.9k
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
3507
12.9k
             NETSNMP_DS_LIB_SAVE_MIB_DESCRS))
3508
0
        np->description = strdup(quoted_string_buffer);
3509
12.9k
    type = get_token(fp, token, MAXTOKEN);
3510
12.9k
    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
12.6k
    if (type != MODULE) {
3521
1.56k
        print_error("Expected MODULE", token, type);
3522
1.56k
        goto skip;
3523
1.56k
    }
3524
14.9k
    while (type == MODULE) {
3525
14.1k
        int             modid = -1;
3526
14.1k
        char            modname[MAXTOKEN];
3527
14.1k
        type = get_token(fp, token, MAXTOKEN);
3528
14.1k
        if (type == LABEL
3529
3.57k
            && strcmp(token, module_name(current_module, modname))) {
3530
3.35k
            modid = read_module_internal(token);
3531
3.35k
            if (modid != MODULE_LOADED_OK
3532
3.35k
                && modid != MODULE_ALREADY_LOADED) {
3533
1.47k
                print_error("Unknown module", token, type);
3534
1.47k
                goto skip;
3535
1.47k
            }
3536
1.88k
            modid = which_module(token);
3537
1.88k
            type = get_token(fp, token, MAXTOKEN);
3538
1.88k
        }
3539
12.6k
        if (type == MANDATORYGROUPS) {
3540
2.08k
            type = get_token(fp, token, MAXTOKEN);
3541
2.08k
            if (type != LEFTBRACKET) {
3542
194
                print_error("Expected \"{\"", token, type);
3543
194
                goto skip;
3544
194
            }
3545
3.06k
            do {
3546
3.06k
                type = get_token(fp, token, MAXTOKEN);
3547
3.06k
                if (type != LABEL) {
3548
329
                    print_error("Bad group name", token, type);
3549
329
                    goto skip;
3550
329
                }
3551
2.74k
                if (!compliance_lookup(token, modid))
3552
304
                    print_error("Unknown group", token, type);
3553
2.74k
                type = get_token(fp, token, MAXTOKEN);
3554
2.74k
            } while (type == COMMA);
3555
1.55k
            if (type != RIGHTBRACKET) {
3556
401
                print_error("Expected \"}\"", token, type);
3557
401
                goto skip;
3558
401
            }
3559
1.15k
            type = get_token(fp, token, MAXTOKEN);
3560
1.15k
        }
3561
14.2k
        while (type == GROUP || type == OBJECT) {
3562
10.2k
            if (type == GROUP) {
3563
1.38k
                type = get_token(fp, token, MAXTOKEN);
3564
1.38k
                if (type != LABEL) {
3565
201
                    print_error("Bad group name", token, type);
3566
201
                    goto skip;
3567
201
                }
3568
1.18k
                if (!compliance_lookup(token, modid))
3569
921
                    print_error("Unknown group", token, type);
3570
1.18k
                type = get_token(fp, token, MAXTOKEN);
3571
8.89k
            } else {
3572
8.89k
                type = get_token(fp, token, MAXTOKEN);
3573
8.89k
                if (type != LABEL) {
3574
254
                    print_error("Bad object name", token, type);
3575
254
                    goto skip;
3576
254
                }
3577
8.64k
                if (!compliance_lookup(token, modid))
3578
511
                    print_error("Unknown group", token, type);
3579
8.64k
                type = get_token(fp, token, MAXTOKEN);
3580
8.64k
                if (type == SYNTAX)
3581
4.29k
                    type = eat_syntax(fp, token, MAXTOKEN);
3582
8.64k
                if (type == WRSYNTAX)
3583
1.87k
                    type = eat_syntax(fp, token, MAXTOKEN);
3584
8.64k
                if (type == MINACCESS) {
3585
1.81k
                    type = get_token(fp, token, MAXTOKEN);
3586
1.81k
                    if (type != NOACCESS && type != ACCNOTIFY
3587
1.53k
                        && type != READONLY && type != WRITEONLY
3588
665
                        && type != READCREATE && type != READWRITE) {
3589
260
                        print_error("Bad MIN-ACCESS spec", token, type);
3590
260
                        goto skip;
3591
260
                    }
3592
1.55k
                    type = get_token(fp, token, MAXTOKEN);
3593
1.55k
                }
3594
8.64k
            }
3595
9.56k
            if (type != DESCRIPTION) {
3596
6.76k
                print_error("Expected DESCRIPTION", token, type);
3597
6.76k
                goto skip;
3598
6.76k
            }
3599
2.79k
            type = get_token(fp, token, MAXTOKEN);
3600
2.79k
            if (type != QUOTESTRING) {
3601
359
                print_error("Bad DESCRIPTION", token, type);
3602
359
                goto skip;
3603
359
            }
3604
2.44k
            type = get_token(fp, token, MAXTOKEN);
3605
2.44k
        }
3606
11.7k
    }
3607
17.2k
  skip:
3608
400k
    while (type != EQUALS && type != ENDOFFILE)
3609
383k
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3610
3611
17.2k
    return merge_parse_objectid(np, fp, name);
3612
11.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.66k
        print_error("Expected PRODUCT-RELEASE", token, type);
3633
1.66k
        goto skip;
3634
1.66k
    }
3635
11.2k
    type = get_token(fp, token, MAXTOKEN);
3636
11.2k
    if (type != QUOTESTRING) {
3637
100
        print_error("Expected STRING after PRODUCT-RELEASE", token, type);
3638
100
        goto skip;
3639
100
    }
3640
11.1k
    type = get_token(fp, token, MAXTOKEN);
3641
11.1k
    if (type != STATUS) {
3642
663
        print_error("Expected STATUS", token, type);
3643
663
        goto skip;
3644
663
    }
3645
10.4k
    type = get_token(fp, token, MAXTOKEN);
3646
10.4k
    if (type != CURRENT && type != OBSOLETE) {
3647
502
        print_error("STATUS should be current or obsolete", token, type);
3648
502
        goto skip;
3649
502
    }
3650
9.98k
    type = get_token(fp, token, MAXTOKEN);
3651
9.98k
    if (type != DESCRIPTION) {
3652
1.05k
        print_error("Expected DESCRIPTION", token, type);
3653
1.05k
        goto skip;
3654
1.05k
    }
3655
8.92k
    type = get_token(fp, quoted_string_buffer, sizeof(quoted_string_buffer));
3656
8.92k
    if (type != QUOTESTRING) {
3657
231
        print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3658
231
        goto skip;
3659
231
    }
3660
8.69k
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
3661
8.69k
             NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
3662
0
        np->description = strdup(quoted_string_buffer);
3663
0
    }
3664
8.69k
    type = get_token(fp, token, MAXTOKEN);
3665
8.69k
    if (type == REFERENCE) {
3666
928
        type = get_token(fp, quoted_string_buffer,
3667
928
                         sizeof(quoted_string_buffer));
3668
928
        if (type != QUOTESTRING) {
3669
706
            print_error("Bad REFERENCE", quoted_string_buffer, type);
3670
706
            goto skip;
3671
706
        }
3672
222
        np->reference = strdup(quoted_string_buffer);
3673
222
        type = get_token(fp, token, type);
3674
222
    }
3675
9.19k
    while (type == SUPPORTS) {
3676
8.23k
        int             modid;
3677
8.23k
        struct tree    *tp;
3678
3679
8.23k
        type = get_token(fp, token, MAXTOKEN);
3680
8.23k
        if (type != LABEL) {
3681
227
            print_error("Bad module name", token, type);
3682
227
            goto skip;
3683
227
        }
3684
8.01k
        modid = read_module_internal(token);
3685
8.01k
        if (modid != MODULE_LOADED_OK && modid != MODULE_ALREADY_LOADED) {
3686
556
            print_error("Module not found", token, type);
3687
556
            goto skip;
3688
556
        }
3689
7.45k
        modid = which_module(token);
3690
7.45k
        type = get_token(fp, token, MAXTOKEN);
3691
7.45k
        if (type != INCLUDES) {
3692
636
            print_error("Expected INCLUDES", token, type);
3693
636
            goto skip;
3694
636
        }
3695
6.81k
        type = get_token(fp, token, MAXTOKEN);
3696
6.81k
        if (type != LEFTBRACKET) {
3697
336
            print_error("Expected \"{\"", token, type);
3698
336
            goto skip;
3699
336
        }
3700
11.4k
        do {
3701
11.4k
            type = get_token(fp, token, MAXTOKEN);
3702
11.4k
            if (type != LABEL) {
3703
274
                print_error("Expected group name", token, type);
3704
274
                goto skip;
3705
274
            }
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.20k
        if (type != RIGHTBRACKET) {
3712
933
            print_error("Expected \"}\" after group list", token, type);
3713
933
            goto skip;
3714
933
        }
3715
5.27k
        type = get_token(fp, token, MAXTOKEN);
3716
6.58k
        while (type == VARIATION) {
3717
5.37k
            type = get_token(fp, token, MAXTOKEN);
3718
5.37k
            if (type != LABEL) {
3719
362
                print_error("Bad object name", token, type);
3720
362
                goto skip;
3721
362
            }
3722
5.01k
            tp = find_tree_node(token, modid);
3723
5.01k
            if (!tp)
3724
4.32k
                print_error("Object not found in module", token, type);
3725
5.01k
            type = get_token(fp, token, MAXTOKEN);
3726
5.01k
            if (type == SYNTAX) {
3727
1.45k
                type = eat_syntax(fp, token, MAXTOKEN);
3728
1.45k
            }
3729
5.01k
            if (type == WRSYNTAX) {
3730
196
                type = eat_syntax(fp, token, MAXTOKEN);
3731
196
            }
3732
5.01k
            if (type == ACCESS) {
3733
1.32k
                type = get_token(fp, token, MAXTOKEN);
3734
1.32k
                if (type != ACCNOTIFY && type != READONLY
3735
1.05k
                    && type != READWRITE && type != READCREATE
3736
668
                    && type != WRITEONLY && type != NOTIMPL) {
3737
405
                    print_error("Bad ACCESS", token, type);
3738
405
                    goto skip;
3739
405
                }
3740
923
                type = get_token(fp, token, MAXTOKEN);
3741
923
            }
3742
4.61k
            if (type == CREATEREQ) {
3743
857
                type = get_token(fp, token, MAXTOKEN);
3744
857
                if (type != LEFTBRACKET) {
3745
249
                    print_error("Expected \"{\"", token, type);
3746
249
                    goto skip;
3747
249
                }
3748
1.39k
                do {
3749
1.39k
                    type = get_token(fp, token, MAXTOKEN);
3750
1.39k
                    if (type != LABEL) {
3751
198
                        print_error("Bad object name in list", token,
3752
198
                                    type);
3753
198
                        goto skip;
3754
198
                    }
3755
1.19k
                    type = get_token(fp, token, MAXTOKEN);
3756
1.19k
                } while (type == COMMA);
3757
410
                if (type != RIGHTBRACKET) {
3758
210
                    print_error("Expected \"}\" after list", token, type);
3759
210
                    goto skip;
3760
210
                }
3761
200
                type = get_token(fp, token, MAXTOKEN);
3762
200
            }
3763
3.95k
            if (type == DEFVAL) {
3764
426
                int             level = 1;
3765
426
                type = get_token(fp, token, MAXTOKEN);
3766
426
                if (type != LEFTBRACKET) {
3767
194
                    print_error("Expected \"{\" after DEFVAL", token,
3768
194
                                type);
3769
194
                    goto skip;
3770
194
                }
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
232
                if (type != RIGHTBRACKET) {
3780
35
                    print_error("Missing \"}\" after DEFVAL", token, type);
3781
35
                    goto skip;
3782
35
                }
3783
197
                type = get_token(fp, token, MAXTOKEN);
3784
197
            }
3785
3.72k
            if (type != DESCRIPTION) {
3786
2.20k
                print_error("Expected DESCRIPTION", token, type);
3787
2.20k
                goto skip;
3788
2.20k
            }
3789
1.52k
            type = get_token(fp, quoted_string_buffer,
3790
1.52k
                             sizeof(quoted_string_buffer));
3791
1.52k
            if (type != QUOTESTRING) {
3792
218
                print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3793
218
                goto skip;
3794
218
            }
3795
1.30k
            type = get_token(fp, token, MAXTOKEN);
3796
1.30k
        }
3797
5.27k
    }
3798
955
    if (type != EQUALS)
3799
761
        print_error("Expected \"::=\"", token, type);
3800
12.9k
  skip:
3801
514k
    while (type != EQUALS && type != ENDOFFILE) {
3802
502k
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3803
502k
    }
3804
12.9k
    return merge_parse_objectid(np, fp, name);
3805
955
}
3806
3807
/*
3808
 * Parses a module identity macro
3809
 * Returns 0 on error.
3810
 */
3811
static void
3812
check_utc(const char *utc)
3813
6.99k
{
3814
6.99k
    int             len, year, month, day, hour, minute;
3815
3816
6.99k
    len = strlen(utc);
3817
6.99k
    if (len == 0) {
3818
222
        print_error("Timestamp has zero length", utc, QUOTESTRING);
3819
222
        return;
3820
222
    }
3821
6.77k
    if (utc[len - 1] != 'Z' && utc[len - 1] != 'z') {
3822
1.05k
        print_error("Timestamp should end with Z", utc, QUOTESTRING);
3823
1.05k
        return;
3824
1.05k
    }
3825
5.72k
    if (len == 11) {
3826
1.13k
        len = sscanf(utc, "%2d%2d%2d%2d%2dZ", &year, &month, &day, &hour,
3827
1.13k
                     &minute);
3828
1.13k
        year += 1900;
3829
4.58k
    } else if (len == 13)
3830
402
        len = sscanf(utc, "%4d%2d%2d%2d%2dZ", &year, &month, &day, &hour,
3831
402
                     &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.53k
    if (len != 5) {
3838
252
        print_error("Bad timestamp format", utc, QUOTESTRING);
3839
252
        return;
3840
252
    }
3841
1.28k
    if (month < 1 || month > 12)
3842
677
        print_error("Bad month in timestamp", utc, QUOTESTRING);
3843
1.28k
    if (day < 1 || day > 31)
3844
686
        print_error("Bad day in timestamp", utc, QUOTESTRING);
3845
1.28k
    if (hour < 0 || hour > 23)
3846
845
        print_error("Bad hour in timestamp", utc, QUOTESTRING);
3847
1.28k
    if (minute < 0 || minute > 59)
3848
448
        print_error("Bad minute in timestamp", utc, QUOTESTRING);
3849
1.28k
}
3850
3851
static struct node *
3852
parse_moduleIdentity(FILE * fp, char *name)
3853
6.63k
{
3854
6.63k
    register int    type;
3855
6.63k
    char            token[MAXTOKEN];
3856
6.63k
    char            quoted_string_buffer[MAXQUOTESTR];
3857
6.63k
    register struct node *np;
3858
3859
6.63k
    np = alloc_node(current_module);
3860
6.63k
    if (np == NULL)
3861
0
        return (NULL);
3862
6.63k
    type = get_token(fp, token, MAXTOKEN);
3863
6.63k
    if (type != LASTUPDATED) {
3864
886
        print_error("Expected LAST-UPDATED", token, type);
3865
886
        goto skip;
3866
886
    }
3867
5.74k
    type = get_token(fp, token, MAXTOKEN);
3868
5.74k
    if (type != QUOTESTRING) {
3869
226
        print_error("Need STRING for LAST-UPDATED", token, type);
3870
226
        goto skip;
3871
226
    }
3872
5.52k
    check_utc(token);
3873
5.52k
    type = get_token(fp, token, MAXTOKEN);
3874
5.52k
    if (type != ORGANIZATION) {
3875
1.93k
        print_error("Expected ORGANIZATION", token, type);
3876
1.93k
        goto skip;
3877
1.93k
    }
3878
3.58k
    type = get_token(fp, token, MAXTOKEN);
3879
3.58k
    if (type != QUOTESTRING) {
3880
429
        print_error("Bad ORGANIZATION", token, type);
3881
429
        goto skip;
3882
429
    }
3883
3.15k
    type = get_token(fp, token, MAXTOKEN);
3884
3.15k
    if (type != CONTACTINFO) {
3885
410
        print_error("Expected CONTACT-INFO", token, type);
3886
410
        goto skip;
3887
410
    }
3888
2.74k
    type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3889
2.74k
    if (type != QUOTESTRING) {
3890
264
        print_error("Bad CONTACT-INFO", quoted_string_buffer, type);
3891
264
        goto skip;
3892
264
    }
3893
2.48k
    type = get_token(fp, token, MAXTOKEN);
3894
2.48k
    if (type != DESCRIPTION) {
3895
289
        print_error("Expected DESCRIPTION", token, type);
3896
289
        goto skip;
3897
289
    }
3898
2.19k
    type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3899
2.19k
    if (type != QUOTESTRING) {
3900
315
        print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3901
315
        goto skip;
3902
315
    }
3903
1.87k
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
3904
1.87k
             NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
3905
0
        np->description = strdup(quoted_string_buffer);
3906
0
    }
3907
1.87k
    type = get_token(fp, token, MAXTOKEN);
3908
2.59k
    while (type == REVISION) {
3909
1.71k
        type = get_token(fp, token, MAXTOKEN);
3910
1.71k
        if (type != QUOTESTRING) {
3911
246
            print_error("Bad REVISION", token, type);
3912
246
            goto skip;
3913
246
        }
3914
1.47k
        check_utc(token);
3915
1.47k
        type = get_token(fp, token, MAXTOKEN);
3916
1.47k
        if (type != DESCRIPTION) {
3917
349
            print_error("Expected DESCRIPTION", token, type);
3918
349
            goto skip;
3919
349
        }
3920
1.12k
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3921
1.12k
        if (type != QUOTESTRING) {
3922
409
            print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3923
409
            goto skip;
3924
409
        }
3925
715
        type = get_token(fp, token, MAXTOKEN);
3926
715
    }
3927
873
    if (type != EQUALS)
3928
661
        print_error("Expected \"::=\"", token, type);
3929
6.63k
  skip:
3930
161k
    while (type != EQUALS && type != ENDOFFILE) {
3931
154k
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3932
154k
    }
3933
6.63k
    return merge_parse_objectid(np, fp, name);
3934
873
}
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
680
{
3945
680
    register int    type;
3946
680
    char            token[MAXTOKEN];
3947
680
    struct node    *np;
3948
680
    int             iLine = mibLine;
3949
3950
680
    np = alloc_node(current_module);
3951
680
    if (np == NULL)
3952
0
        return (NULL);
3953
680
    type = get_token(fp, token, sizeof(token));
3954
4.89k
    while (type != EQUALS && type != ENDOFFILE) {
3955
4.21k
        type = get_token(fp, token, sizeof(token));
3956
4.21k
    }
3957
680
    if (type != EQUALS) {
3958
35
        if (np)
3959
35
            free_node(np);
3960
35
        return NULL;
3961
35
    }
3962
7.23k
    while (type != BEGIN && type != ENDOFFILE) {
3963
6.58k
        type = get_token(fp, token, sizeof(token));
3964
6.58k
    }
3965
645
    if (type != BEGIN) {
3966
23
        if (np)
3967
23
            free_node(np);
3968
23
        return NULL;
3969
23
    }
3970
17.5k
    while (type != END && type != ENDOFFILE) {
3971
16.8k
        type = get_token(fp, token, sizeof(token));
3972
16.8k
    }
3973
622
    if (type != END) {
3974
29
        if (np)
3975
29
            free_node(np);
3976
29
        return NULL;
3977
29
    }
3978
3979
593
    if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
3980
593
         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
593
    return np;
3987
622
}
3988
3989
/*
3990
 * Parses a module import clause
3991
 *   loading any modules referenced
3992
 */
3993
static void
3994
parse_imports(FILE * fp)
3995
7.05k
{
3996
7.05k
    register int    type;
3997
7.05k
    char            token[MAXTOKEN];
3998
7.05k
    char            modbuf[256];
3999
339k
#define MAX_IMPORTS 512
4000
7.05k
    struct module_import *import_list;
4001
7.05k
    int             this_module;
4002
7.05k
    struct module  *mp;
4003
4004
7.05k
    int             import_count = 0;   /* Total number of imported descriptors */
4005
7.05k
    int             i = 0, old_i;       /* index of first import from each module */
4006
4007
7.05k
    import_list = malloc(MAX_IMPORTS * sizeof(*import_list));
4008
4009
7.05k
    type = get_token(fp, token, MAXTOKEN);
4010
4011
    /*
4012
     * Parse the IMPORTS clause
4013
     */
4014
398k
    while (type != SEMI && type != ENDOFFILE) {
4015
391k
        if (type == LABEL) {
4016
332k
            if (import_count == MAX_IMPORTS) {
4017
251
                print_error("Too many imported symbols", token, type);
4018
233k
                do {
4019
233k
                    type = get_token(fp, token, MAXTOKEN);
4020
233k
                } while (type != SEMI && type != ENDOFFILE);
4021
251
                goto out;
4022
251
            }
4023
332k
            import_list[import_count++].label = strdup(token);
4024
332k
        } else if (type == FROM) {
4025
3.45k
            type = get_token(fp, token, MAXTOKEN);
4026
3.45k
            if (import_count == i) {    /* All imports are handled internally */
4027
363
                type = get_token(fp, token, MAXTOKEN);
4028
363
                continue;
4029
363
            }
4030
3.09k
            this_module = which_module(token);
4031
4032
98.3k
            for (old_i = i; i < import_count; ++i)
4033
95.2k
                import_list[i].modid = this_module;
4034
4035
            /*
4036
             * Recursively read any pre-requisite modules
4037
             */
4038
3.09k
            if (read_module_internal(token) == MODULE_NOT_FOUND) {
4039
2.15k
    int found = 0;
4040
30.1k
                for (; old_i < import_count; ++old_i) {
4041
27.9k
                    found += read_import_replacements(token, &import_list[old_i]);
4042
27.9k
                }
4043
2.15k
    if (!found)
4044
1.49k
        print_module_not_found(token);
4045
2.15k
            }
4046
3.09k
        }
4047
391k
        type = get_token(fp, token, MAXTOKEN);
4048
391k
    }
4049
4050
    /* Initialize modid in case the module name was missing. */
4051
119k
    for (; i < import_count; ++i)
4052
112k
        import_list[i].modid = -1;
4053
4054
    /*
4055
     * Save the import information
4056
     *   in the global module table
4057
     */
4058
11.7k
    for (mp = module_head; mp; mp = mp->next) {
4059
11.7k
        if (mp->modid == current_module) {
4060
6.80k
            if (import_count == 0)
4061
347
                goto out;
4062
6.45k
            if (mp->imports && (mp->imports != root_imports)) {
4063
                /*
4064
                 * this can happen if all modules are in one source file. 
4065
                 */
4066
144k
                for (i = 0; i < mp->no_imports; ++i) {
4067
140k
                    DEBUGMSGTL(("parse-mibs",
4068
140k
                                "#### freeing Module %d '%s' %d\n",
4069
140k
                                mp->modid, mp->imports[i].label,
4070
140k
                                mp->imports[i].modid));
4071
140k
                    free(mp->imports[i].label);
4072
140k
                }
4073
4.19k
                free(mp->imports);
4074
4.19k
            }
4075
6.45k
            mp->imports = (struct module_import *)
4076
6.45k
                calloc(import_count, sizeof(struct module_import));
4077
6.45k
            if (mp->imports == NULL)
4078
0
                goto out;
4079
210k
            for (i = 0; i < import_count; ++i) {
4080
203k
                mp->imports[i].label = import_list[i].label;
4081
203k
                import_list[i].label = NULL;
4082
203k
                mp->imports[i].modid = import_list[i].modid;
4083
203k
                DEBUGMSGTL(("parse-mibs",
4084
203k
                            "#### adding Module %d '%s' %d\n", mp->modid,
4085
203k
                            mp->imports[i].label, mp->imports[i].modid));
4086
203k
            }
4087
6.45k
            mp->no_imports = import_count;
4088
6.45k
            goto out;
4089
6.45k
        }
4090
11.7k
    }
4091
4092
    /*
4093
     * Shouldn't get this far
4094
     */
4095
0
    print_module_not_found(module_name(current_module, modbuf));
4096
4097
7.05k
out:
4098
339k
    for (i = 0; i < import_count; ++i)
4099
332k
        free(import_list[i].label);
4100
7.05k
    free(import_list);
4101
7.05k
    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
100k
{
4126
100k
    struct module  *mp;
4127
4128
218k
    for (mp = module_head; mp; mp = mp->next)
4129
167k
        if (!label_compare(mp->name, name))
4130
48.8k
            return (mp->modid);
4131
4132
51.3k
    DEBUGMSGTL(("parse-mibs", "Module %s not found\n", name));
4133
51.3k
    return (-1);
4134
100k
}
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
10.8k
{
4142
10.8k
    struct module  *mp;
4143
4144
12.5k
    for (mp = module_head; mp; mp = mp->next)
4145
8.87k
        if (mp->modid == modid) {
4146
7.22k
            strcpy(cp, mp->name);
4147
7.22k
            return (cp);
4148
7.22k
        }
4149
4150
3.65k
    if (modid != -1) DEBUGMSGTL(("parse-mibs", "Module %d not found\n", modid));
4151
3.65k
    sprintf(cp, "#%d", modid);
4152
3.65k
    return (cp);
4153
10.8k
}
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
202k
{
4190
202k
    struct module_compatability *mcp;
4191
4192
4.44M
    for (mcp = module_map_head; mcp; mcp = mcp->next) {
4193
4.25M
        if (!label_compare(mcp->old_module, name)) {
4194
12.0k
            if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
4195
12.0k
           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
12.0k
            (void) netsnmp_read_module(mcp->new_module);
4201
12.0k
            return 1;
4202
12.0k
        }
4203
4.25M
    }
4204
190k
    return 0;
4205
202k
}
4206
4207
static int
4208
read_import_replacements(const char *old_module_name,
4209
                         struct module_import *identifier)
4210
27.9k
{
4211
27.9k
    struct module_compatability *mcp;
4212
4213
    /*
4214
     * Look for matches first
4215
     */
4216
614k
    for (mcp = module_map_head; mcp; mcp = mcp->next) {
4217
590k
        if (!label_compare(mcp->old_module, old_module_name)) {
4218
4219
82.7k
            if (                /* exact match */
4220
82.7k
                   (mcp->tag_len == 0 &&
4221
21.0k
                    (mcp->tag == NULL ||
4222
17.7k
                     !label_compare(mcp->tag, identifier->label))) ||
4223
                   /*
4224
                    * prefix match 
4225
                    */
4226
79.2k
                   (mcp->tag_len != 0 &&
4227
61.7k
                    !strncmp(mcp->tag, identifier->label, mcp->tag_len))
4228
82.7k
                ) {
4229
4230
4.02k
                if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
4231
4.02k
               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.02k
                (void) netsnmp_read_module(mcp->new_module);
4238
4.02k
                identifier->modid = which_module(mcp->new_module);
4239
4.02k
                return 1;         /* finished! */
4240
4.02k
            }
4241
82.7k
        }
4242
590k
    }
4243
4244
    /*
4245
     * If no exact match, load everything relevant
4246
     */
4247
23.9k
    return read_module_replacements(old_module_name);
4248
27.9k
}
4249
4250
static int
4251
read_from_file(struct module *mp, const char *name)
4252
25.7k
{
4253
25.7k
    const char     *oldFile = File;
4254
25.7k
    int             oldLine = mibLine;
4255
25.7k
    int             oldModule = current_module;
4256
25.7k
    FILE           *fp;
4257
25.7k
    struct node    *np;
4258
25.7k
    int             res;
4259
4260
25.7k
    if (mp->no_imports != -1) {
4261
13.0k
        DEBUGMSGTL(("parse-mibs", "Module %s already loaded\n",
4262
13.0k
                    name));
4263
13.0k
        return MODULE_ALREADY_LOADED;
4264
13.0k
    }
4265
12.7k
    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.7k
#ifdef HAVE_FLOCKFILE
4275
12.7k
    flockfile(fp);
4276
12.7k
#endif
4277
12.7k
    mp->no_imports = 0; /* Note that we've read the file */
4278
12.7k
    File = mp->file;
4279
12.7k
    mibLine = 1;
4280
12.7k
    current_module = mp->modid;
4281
    /*
4282
     * Parse the file
4283
     */
4284
12.7k
    np = parse(fp);
4285
12.7k
#ifdef HAVE_FUNLOCKFILE
4286
12.7k
    funlockfile(fp);
4287
12.7k
#endif
4288
12.7k
    fclose(fp);
4289
12.7k
    File = oldFile;
4290
12.7k
    mibLine = oldLine;
4291
12.7k
    current_module = oldModule;
4292
12.7k
    res = !np && gMibError == MODULE_SYNTAX_ERROR ?
4293
6.86k
        MODULE_SYNTAX_ERROR : MODULE_LOADED_OK;
4294
33.2k
    while (np) {
4295
20.4k
        struct node *nnp = np->next;
4296
20.4k
        free_node(np);
4297
20.4k
        np = nnp;
4298
20.4k
    }
4299
12.7k
    return res;
4300
12.7k
}
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
208k
{
4310
208k
    struct module  *mp;
4311
4312
208k
    netsnmp_init_mib_internals();
4313
4314
373k
    for (mp = module_head; mp; mp = mp->next)
4315
190k
        if (!label_compare(mp->name, name))
4316
25.7k
            return read_from_file(mp, name);
4317
4318
182k
    return MODULE_NOT_FOUND;
4319
208k
}
4320
4321
void
4322
adopt_orphans(void)
4323
3.43k
{
4324
3.43k
    struct node    *np = NULL, *onp;
4325
3.43k
    struct tree    *tp;
4326
3.43k
    int             i, adopted = 1;
4327
4328
3.43k
    if (!orphan_nodes)
4329
3.16k
        return;
4330
265
    init_node_hash(orphan_nodes);
4331
265
    orphan_nodes = NULL;
4332
4333
533
    while (adopted) {
4334
268
        adopted = 0;
4335
34.5k
        for (i = 0; i < NHASHSIZE; i++)
4336
34.3k
            if (nbuckets[i]) {
4337
6.22k
                for (np = nbuckets[i]; np != NULL; np = np->next) {
4338
3.63k
                    tp = find_tree_node(np->parent, -1);
4339
3.63k
        if (tp) {
4340
4
      do_subtree(tp, &np);
4341
4
      adopted = 1;
4342
                        /*
4343
                         * if do_subtree adopted the entire bucket, stop
4344
                         */
4345
4
                        if(NULL == nbuckets[i])
4346
3
                            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.63k
    }
4363
2.59k
            }
4364
268
    }
4365
4366
    /*
4367
     * Report on outstanding orphans
4368
     *    and link them back into the orphan list
4369
     */
4370
34.1k
    for (i = 0; i < NHASHSIZE; i++)
4371
33.9k
        if (nbuckets[i]) {
4372
2.59k
            if (orphan_nodes)
4373
2.33k
                onp = np->next = nbuckets[i];
4374
263
            else
4375
263
                onp = orphan_nodes = nbuckets[i];
4376
2.59k
            nbuckets[i] = NULL;
4377
6.22k
            while (onp) {
4378
3.62k
                char            modbuf[256];
4379
3.62k
                snmp_log(LOG_WARNING,
4380
3.62k
                         "Cannot resolve OID in %s: %s ::= { %s %ld } at line %d in %s\n",
4381
3.62k
                         module_name(onp->modid, modbuf),
4382
3.62k
                         (onp->label ? onp->label : "<no label>"),
4383
3.62k
                         (onp->parent ? onp->parent : "<no parent>"),
4384
3.62k
                         onp->subid, onp->lineno, onp->filename);
4385
3.62k
                np = onp;
4386
3.62k
                onp = onp->next;
4387
3.62k
            }
4388
2.59k
        }
4389
265
}
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
193k
{
4402
193k
    int status = 0;
4403
193k
    status = read_module_internal(name);
4404
4405
193k
    if (status == MODULE_NOT_FOUND) {
4406
178k
        if (!read_module_replacements(name))
4407
174k
            print_module_not_found(name);
4408
178k
    } else if (status == MODULE_SYNTAX_ERROR) {
4409
5.84k
        gMibError = 0;
4410
5.84k
        gLoop = 1;
4411
4412
5.84k
        strncat(gMibNames, " ", sizeof(gMibNames) - strlen(gMibNames) - 1);
4413
5.84k
        strncat(gMibNames, name, sizeof(gMibNames) - strlen(gMibNames) - 1);
4414
5.84k
    }
4415
4416
193k
    return tree_head;
4417
193k
}
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
209k
{
4427
209k
    struct tree    *tp, *next;
4428
209k
    int             i;
4429
4430
883k
    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
673k
        int             nmod = tp->number_modules;
4439
673k
        if (nmod > 0) {         /* in some module */
4440
            /*
4441
             * Remove all copies of this module ID
4442
             */
4443
671k
            int             cnt = 0, *pi1, *pi2 = tp->module_list;
4444
2.08M
            for (i = 0, pi1 = pi2; i < nmod; i++, pi2++) {
4445
1.41M
                if (*pi2 == modID)
4446
675k
                    continue;
4447
738k
                cnt++;
4448
738k
                *pi1++ = *pi2;
4449
738k
            }
4450
671k
            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
366k
                tp->number_modules = cnt;
4456
366k
                switch (cnt) {
4457
361k
                case 0:
4458
361k
                    tp->module_list[0] = -1;    /* Mark unused, */
4459
361k
        NETSNMP_FALLTHROUGH;
4460
4461
363k
                case 1:        /* save the remaining module */
4462
363k
                    if (&(tp->modid) != tp->module_list) {
4463
61.4k
                        tp->modid = tp->module_list[0];
4464
61.4k
                        free(tp->module_list);
4465
61.4k
                        tp->module_list = &(tp->modid);
4466
61.4k
                    }
4467
363k
                    break;
4468
4469
2.41k
                default:
4470
2.41k
                    break;
4471
366k
                }
4472
366k
            }                   /* if tree node is in this module */
4473
671k
        }
4474
        /*
4475
         * if tree node is in some module 
4476
         */
4477
673k
        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
673k
        if (tp->child_list)
4486
179k
            unload_module_by_ID(modID, tp->child_list);
4487
4488
4489
673k
        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
363k
            if (tp->child_list == NULL) {
4495
361k
                unlink_tree(tp);
4496
361k
                free_tree(tp);
4497
361k
            } else {
4498
2.45k
                free_partial_tree(tp, TRUE);
4499
2.45k
            }
4500
363k
        }
4501
673k
    }
4502
209k
}
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.1k
{
4540
13.1k
    struct module  *mp;
4541
13.1k
    struct module_compatability *mcp;
4542
13.1k
    struct tc      *ptc;
4543
13.1k
    unsigned int    i;
4544
4545
13.1k
    for (mcp = module_map_head; mcp; mcp = module_map_head) {
4546
12.9k
        if (mcp == module_map)
4547
12.9k
            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
30.7k
    for (mp = module_head; mp; mp = module_head) {
4556
17.5k
        struct module_import *mi = mp->imports;
4557
17.5k
        if (mi) {
4558
86.5k
            for (i = 0; i < (unsigned int)mp->no_imports; ++i) {
4559
79.1k
                SNMP_FREE((mi + i)->label);
4560
79.1k
            }
4561
7.44k
            mp->no_imports = 0;
4562
7.44k
            if (mi == root_imports)
4563
5.19k
                memset(mi, 0, sizeof(*mi));
4564
2.25k
            else
4565
2.25k
                free(mi);
4566
7.44k
        }
4567
4568
17.5k
        unload_module_by_ID(mp->modid, tree_head);
4569
17.5k
        module_head = mp->next;
4570
17.5k
        free(mp->name);
4571
17.5k
        free(mp->file);
4572
17.5k
        free(mp);
4573
17.5k
    }
4574
13.1k
    unload_module_by_ID(-1, tree_head);
4575
    /*
4576
     * tree nodes are cleared 
4577
     */
4578
4579
1.31M
    for (i = 0, ptc = tclist; i < tc_alloc; i++, ptc++) {
4580
1.29M
        if (ptc->type == 0)
4581
1.29M
            continue;
4582
5.12k
        free_enums(&ptc->enums);
4583
5.12k
        free_ranges(&ptc->ranges);
4584
5.12k
        free(ptc->descriptor);
4585
5.12k
        if (ptc->hint)
4586
41
            free(ptc->hint);
4587
5.12k
        if (ptc->description)
4588
0
            free(ptc->description);
4589
5.12k
    }
4590
13.1k
    SNMP_FREE(tclist);
4591
13.1k
    tc_alloc = 0;
4592
4593
13.1k
    memset(buckets, 0, sizeof(buckets));
4594
13.1k
    memset(nbuckets, 0, sizeof(nbuckets));
4595
13.1k
    memset(tbuckets, 0, sizeof(tbuckets));
4596
4597
52.6k
    for (i = 0; i < sizeof(root_imports) / sizeof(root_imports[0]); i++) {
4598
39.4k
        SNMP_FREE(root_imports[i].label);
4599
39.4k
    }
4600
4601
13.1k
    max_module = 0;
4602
13.1k
    current_module = 0;
4603
13.1k
    module_map_head = NULL;
4604
13.1k
    SNMP_FREE(last_err_module);
4605
4606
13.1k
    {
4607
13.1k
        struct node *np = orphan_nodes;
4608
4609
463k
        while (np) {
4610
450k
            struct node *nnp = np->next;
4611
450k
            free_node(np);
4612
450k
            np = nnp;
4613
450k
        }
4614
13.1k
        orphan_nodes = NULL;
4615
13.1k
    }
4616
13.1k
    erroneousMibs = 0;
4617
13.1k
    first_err_module = 1;
4618
13.1k
}
4619
4620
static void
4621
new_module(const char *name, const char *file)
4622
22.7k
{
4623
22.7k
    struct module  *mp;
4624
4625
406k
    for (mp = module_head; mp; mp = mp->next)
4626
387k
        if (!label_compare(mp->name, name)) {
4627
4.32k
            DEBUGMSGTL(("parse-mibs", "  Module %s already noted\n", name));
4628
            /*
4629
             * Not the same file 
4630
             */
4631
4.32k
            if (label_compare(mp->file, file)) {
4632
2.75k
                DEBUGMSGTL(("parse-mibs", "    %s is now in %s\n",
4633
2.75k
                            name, file));
4634
2.75k
                if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
4635
2.75k
               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.75k
                free(mp->file);
4645
2.75k
                mp->file = strdup(file);
4646
2.75k
            }
4647
4.32k
            return;
4648
4.32k
        }
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
108k
{
4679
108k
    int             oLine = mibLine;
4680
4681
111k
    while (list) {
4682
3.06k
        struct objgroup *gp = list;
4683
3.06k
        struct node    *np;
4684
3.06k
        list = list->next;
4685
3.06k
        np = root;
4686
168k
        while (np)
4687
165k
            if (label_compare(np->label, gp->name))
4688
165k
                np = np->next;
4689
247
            else
4690
247
                break;
4691
3.06k
        if (!np) {
4692
2.82k
      int i;
4693
2.82k
      struct module_import *mip;
4694
      /* if not local, check if it was IMPORTed */
4695
19.3k
      for (i = 0, mip = mp->imports; i < mp->no_imports; i++, mip++)
4696
16.8k
    if (strcmp(mip->label, gp->name) == 0)
4697
284
        break;
4698
2.82k
      if (i == mp->no_imports) {
4699
2.53k
    mibLine = gp->line;
4700
2.53k
    print_error(error, gp->name, QUOTESTRING);
4701
2.53k
      }
4702
2.82k
        }
4703
3.06k
        free(gp->name);
4704
3.06k
        free(gp);
4705
3.06k
    }
4706
108k
    mibLine = oLine;
4707
108k
}
4708
4709
static void free_objgroup(struct objgroup *o)
4710
152k
{
4711
167k
    while (o) {
4712
14.0k
        struct objgroup *next = o->next;
4713
4714
14.0k
        free(o->name);
4715
14.0k
        free(o);
4716
14.0k
        o = next;
4717
14.0k
    }
4718
152k
}
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.59M
{
4746
1.59M
    unsigned int    h = 2166136261u;
4747
4748
8.54M
    for (; *label; label++) {
4749
6.94M
        h ^= (unsigned char)*label;
4750
6.94M
        h *= 16777619u;
4751
6.94M
    }
4752
1.59M
    return h;
4753
1.59M
}
4754
4755
static struct label_entry *
4756
label_table_find(const struct label_table *lt, const char *label,
4757
                 unsigned int hash)
4758
1.59M
{
4759
1.59M
    struct label_entry *le;
4760
4761
1.59M
    if (!lt->size)
4762
71.4k
        return NULL;
4763
2.00M
    for (le = lt->buckets[hash & (lt->size - 1)]; le; le = le->next)
4764
1.45M
        if (le->hash == hash && strcmp(le->first->label, label) == 0)
4765
975k
            return le;
4766
547k
    return NULL;
4767
1.52M
}
4768
4769
static int
4770
label_table_grow(struct label_table *lt)
4771
37.4k
{
4772
37.4k
    size_t          new_size = lt->size ? 2 * lt->size : 64;
4773
37.4k
    struct label_entry **new_buckets;
4774
37.4k
    size_t          i;
4775
4776
37.4k
    new_buckets = calloc(new_size, sizeof(*new_buckets));
4777
37.4k
    if (!new_buckets)
4778
0
        return -1;
4779
316k
    for (i = 0; i < lt->size; i++) {
4780
278k
        struct label_entry *le, *next;
4781
4782
557k
        for (le = lt->buckets[i]; le; le = next) {
4783
278k
            struct label_entry **head =
4784
278k
                &new_buckets[le->hash & (new_size - 1)];
4785
4786
278k
            next = le->next;
4787
278k
            le->next = *head;
4788
278k
            *head = le;
4789
278k
        }
4790
278k
    }
4791
37.4k
    free(lt->buckets);
4792
37.4k
    lt->buckets = new_buckets;
4793
37.4k
    lt->size = new_size;
4794
37.4k
    return 0;
4795
37.4k
}
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
133k
{
4804
133k
    struct label_entry *le;
4805
4806
133k
    if (!np->label)
4807
0
        return NULL;
4808
133k
    le = label_table_find(lt, np->label, label_hash(np->label));
4809
133k
    if (!le)
4810
55.8k
        return NULL;
4811
77.4k
    if (le->first->subid != np->subid)
4812
4.06k
        return le->first;
4813
73.3k
    return le->other;
4814
77.4k
}
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.46M
{
4823
1.46M
    struct label_entry *le, **head;
4824
1.46M
    unsigned int    hash;
4825
4826
1.46M
    if (!np->label)
4827
0
        return;
4828
1.46M
    hash = label_hash(np->label);
4829
1.46M
    le = label_table_find(lt, np->label, hash);
4830
1.46M
    if (le) {
4831
897k
        if (!le->other && le->first->subid != np->subid)
4832
1.88k
            le->other = np;
4833
897k
        return;
4834
897k
    }
4835
563k
    if (lt->count >= lt->size && label_table_grow(lt) < 0)
4836
0
        return;
4837
563k
    le = malloc(sizeof(*le));
4838
563k
    if (!le)
4839
0
        return;
4840
563k
    le->hash = hash;
4841
563k
    le->first = np;
4842
563k
    le->other = NULL;
4843
563k
    head = &lt->buckets[hash & (lt->size - 1)];
4844
563k
    le->next = *head;
4845
563k
    *head = le;
4846
563k
    lt->count++;
4847
563k
}
4848
4849
static void
4850
label_table_clear(struct label_table *lt)
4851
48.7k
{
4852
48.7k
    size_t          i;
4853
4854
2.61M
    for (i = 0; i < lt->size; i++) {
4855
2.56M
        struct label_entry *le, *next;
4856
4857
3.12M
        for (le = lt->buckets[i]; le; le = next) {
4858
563k
            next = le->next;
4859
563k
            free(le);
4860
563k
        }
4861
2.56M
    }
4862
48.7k
    free(lt->buckets);
4863
48.7k
    lt->buckets = NULL;
4864
48.7k
    lt->size = 0;
4865
48.7k
    lt->count = 0;
4866
48.7k
}
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.7k
{
4875
#ifdef TEST
4876
    extern void     xmalloc_stats(FILE *);
4877
#endif
4878
12.7k
    char            token[MAXTOKEN];
4879
12.7k
    char            name[MAXTOKEN+1];
4880
12.7k
    int             type = LABEL;
4881
12.7k
    int             lasttype = LABEL;
4882
4883
87.0k
#define BETWEEN_MIBS          1
4884
74.4k
#define IN_MIB                2
4885
12.7k
    int             state = BETWEEN_MIBS;
4886
12.7k
    struct node    *np = NULL, *root = NULL;
4887
12.7k
    struct label_table labels = { NULL, 0, 0 };
4888
12.7k
    struct objgroup *oldgroups = objgroups, *oldobjects = objects,
4889
12.7k
                    *oldnotifs = notifs;
4890
4891
12.7k
    DEBUGMSGTL(("parse-file", "Parsing file:  %s...\n", File));
4892
4893
12.7k
    if (last_err_module)
4894
2.33k
        free(last_err_module);
4895
12.7k
    last_err_module = NULL;
4896
12.7k
    objgroups = NULL;
4897
12.7k
    objects = NULL;
4898
12.7k
    notifs = NULL;
4899
4900
329k
    while (type != ENDOFFILE) {
4901
322k
        struct node *nnp;
4902
4903
322k
        if (lasttype == CONTINUE)
4904
116k
            lasttype = type;
4905
205k
        else
4906
205k
            type = lasttype = get_token(fp, token, MAXTOKEN);
4907
4908
322k
        switch (type) {
4909
36.1k
        case END:
4910
36.1k
            if (state != IN_MIB) {
4911
63
                print_error("Error, END before start of MIB", NULL, type);
4912
63
                gMibError = MODULE_SYNTAX_ERROR;
4913
63
                goto free_mib;
4914
36.0k
            } else {
4915
36.0k
                struct module  *mp;
4916
#ifdef TEST
4917
                printf("\nNodes for Module %s:\n", name);
4918
                print_nodes(stdout, root);
4919
#endif
4920
81.8k
                for (mp = module_head; mp; mp = mp->next)
4921
81.8k
                    if (mp->modid == current_module)
4922
36.0k
                        break;
4923
36.0k
                scan_objlist(root, mp, objgroups, "Undefined OBJECT-GROUP");
4924
36.0k
                scan_objlist(root, mp, objects, "Undefined OBJECT");
4925
36.0k
                scan_objlist(root, mp, notifs, "Undefined NOTIFICATION");
4926
36.0k
                objgroups = NULL;
4927
36.0k
                objects = NULL;
4928
36.0k
                notifs = NULL;
4929
36.0k
                do_linkup(mp, root);
4930
36.0k
                np = root = NULL;
4931
36.0k
                label_table_clear(&labels);
4932
36.0k
            }
4933
36.0k
            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
36.0k
            continue;
4941
7.05k
        case IMPORTS:
4942
7.05k
            parse_imports(fp);
4943
7.05k
            continue;
4944
240
        case EXPORTS:
4945
1.28k
            while (type != SEMI && type != ENDOFFILE)
4946
1.04k
                type = get_token(fp, token, MAXTOKEN);
4947
240
            continue;
4948
215k
        case LABEL:
4949
215k
        case INTEGER:
4950
216k
        case INTEGER32:
4951
216k
        case UINTEGER32:
4952
216k
        case UNSIGNED32:
4953
217k
        case COUNTER:
4954
218k
        case COUNTER64:
4955
219k
        case GAUGE:
4956
219k
        case IPADDR:
4957
220k
        case NETADDR:
4958
220k
        case NSAPADDRESS:
4959
221k
        case OBJSYNTAX:
4960
221k
        case APPSYNTAX:
4961
222k
        case SIMPLESYNTAX:
4962
222k
        case OBJNAME:
4963
223k
        case NOTIFNAME:
4964
223k
        case KW_OPAQUE:
4965
224k
        case TIMETICKS:
4966
224k
            break;
4967
3.38k
        case ENDOFFILE:
4968
3.38k
            continue;
4969
51.4k
        default:
4970
51.4k
            strlcpy(name, token, sizeof(name));
4971
51.4k
            type = get_token(fp, token, MAXTOKEN);
4972
51.4k
            nnp = NULL;
4973
51.4k
            if (type == MACRO) {
4974
385
                nnp = parse_macro(fp, name);
4975
385
                if (nnp == NULL) {
4976
15
                    print_error("Bad parse of MACRO", NULL, type);
4977
15
                    gMibError = MODULE_SYNTAX_ERROR;
4978
15
                }
4979
385
                free_node(nnp); /* IGNORE */
4980
385
                nnp = NULL;
4981
385
            } else
4982
51.0k
                print_error(name, "is a reserved word", lasttype);
4983
51.4k
            continue;           /* see if we can parse the rest of the file */
4984
322k
        }
4985
224k
        strlcpy(name, token, sizeof(name));
4986
224k
        type = get_token(fp, token, MAXTOKEN);
4987
224k
        nnp = NULL;
4988
4989
        /*
4990
         * Handle obsolete method to assign an object identifier to a
4991
         * module
4992
         */
4993
224k
        if (lasttype == LABEL && type == LEFTBRACKET) {
4994
787k
            while (type != RIGHTBRACKET && type != ENDOFFILE)
4995
784k
                type = get_token(fp, token, MAXTOKEN);
4996
2.92k
            if (type == ENDOFFILE) {
4997
605
                print_error("Expected \"}\"", token, type);
4998
605
                gMibError = MODULE_SYNTAX_ERROR;
4999
605
                goto free_mib;
5000
605
            }
5001
2.32k
            type = get_token(fp, token, MAXTOKEN);
5002
2.32k
        }
5003
5004
223k
        switch (type) {
5005
38.2k
        case DEFINITIONS:
5006
38.2k
            if (state != BETWEEN_MIBS) {
5007
3
                print_error("Error, nested MIBS", NULL, type);
5008
3
                gMibError = MODULE_SYNTAX_ERROR;
5009
3
                goto free_mib;
5010
3
            }
5011
38.2k
            state = IN_MIB;
5012
38.2k
            current_module = which_module(name);
5013
38.2k
            free_objgroup(objgroups);
5014
38.2k
            objgroups = NULL;
5015
38.2k
            free_objgroup(objects);
5016
38.2k
            objects = NULL;
5017
38.2k
            free_objgroup(notifs);
5018
38.2k
            notifs = NULL;
5019
38.2k
            if (current_module == -1) {
5020
5.66k
                new_module(name, File);
5021
5.66k
                current_module = which_module(name);
5022
5.66k
            }
5023
38.2k
            {
5024
38.2k
                struct module  *mp;
5025
5026
84.8k
                for (mp = module_head; mp; mp = mp->next) {
5027
84.8k
                    if (mp->modid == current_module) {
5028
38.2k
                        if (mp->no_imports == -1)
5029
5.66k
                            mp->no_imports = 0;
5030
38.2k
                        break;
5031
38.2k
                    }
5032
84.8k
                }
5033
38.2k
            }
5034
38.2k
            DEBUGMSGTL(("parse-mibs", "Parsing MIB: %d %s\n",
5035
38.2k
                        current_module, name));
5036
962k
            while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE)
5037
961k
                if (type == BEGIN)
5038
37.8k
                    break;
5039
38.2k
            break;
5040
11.3k
        case OBJTYPE:
5041
11.3k
            nnp = parse_objecttype(fp, name);
5042
11.3k
            if (nnp == NULL) {
5043
683
                print_error("Bad parse of OBJECT-TYPE", NULL, type);
5044
683
                gMibError = MODULE_SYNTAX_ERROR;
5045
683
                goto free_mib;
5046
683
            }
5047
10.7k
            break;
5048
10.7k
        case OBJGROUP:
5049
4.55k
            nnp = parse_objectgroup(fp, name, OBJECTS, &objects);
5050
4.55k
            if (nnp == NULL) {
5051
164
                print_error("Bad parse of OBJECT-GROUP", NULL, type);
5052
164
                gMibError = MODULE_SYNTAX_ERROR;
5053
164
                goto free_mib;
5054
164
            }
5055
4.38k
            break;
5056
4.38k
        case NOTIFGROUP:
5057
586
            nnp = parse_objectgroup(fp, name, NOTIFICATIONS, &notifs);
5058
586
            if (nnp == NULL) {
5059
37
                print_error("Bad parse of NOTIFICATION-GROUP", NULL, type);
5060
37
                gMibError = MODULE_SYNTAX_ERROR;
5061
37
                goto free_mib;
5062
37
            }
5063
549
            break;
5064
643
        case TRAPTYPE:
5065
643
            nnp = parse_trapDefinition(fp, name);
5066
643
            if (nnp == NULL) {
5067
195
                print_error("Bad parse of TRAP-TYPE", NULL, type);
5068
195
                gMibError = MODULE_SYNTAX_ERROR;
5069
195
                goto free_mib;
5070
195
            }
5071
448
            break;
5072
8.42k
        case NOTIFTYPE:
5073
8.42k
            nnp = parse_notificationDefinition(fp, name);
5074
8.42k
            if (nnp == NULL) {
5075
124
                print_error("Bad parse of NOTIFICATION-TYPE", NULL, type);
5076
124
                gMibError = MODULE_SYNTAX_ERROR;
5077
124
                goto free_mib;
5078
124
            }
5079
8.29k
            break;
5080
17.2k
        case COMPLIANCE:
5081
17.2k
            nnp = parse_compliance(fp, name);
5082
17.2k
            if (nnp == NULL) {
5083
776
                print_error("Bad parse of MODULE-COMPLIANCE", NULL, type);
5084
776
                gMibError = MODULE_SYNTAX_ERROR;
5085
776
                goto free_mib;
5086
776
            }
5087
16.4k
            break;
5088
16.4k
        case AGENTCAP:
5089
12.9k
            nnp = parse_capabilities(fp, name);
5090
12.9k
            if (nnp == NULL) {
5091
807
                print_error("Bad parse of AGENT-CAPABILITIES", NULL, type);
5092
807
                gMibError = MODULE_SYNTAX_ERROR;
5093
807
                goto free_mib;
5094
807
            }
5095
12.1k
            break;
5096
12.1k
        case MACRO:
5097
295
            nnp = parse_macro(fp, name);
5098
295
            if (nnp == NULL) {
5099
72
                print_error("Bad parse of MACRO", NULL, type);
5100
72
                gMibError = MODULE_SYNTAX_ERROR;
5101
72
            }
5102
295
            free_node(nnp);     /* IGNORE */
5103
295
            nnp = NULL;
5104
295
            break;
5105
6.63k
        case MODULEIDENTITY:
5106
6.63k
            nnp = parse_moduleIdentity(fp, name);
5107
6.63k
            if (nnp == NULL) {
5108
415
                print_error("Bad parse of MODULE-IDENTITY", NULL, type);
5109
415
                gMibError = MODULE_SYNTAX_ERROR;
5110
415
                goto free_mib;
5111
415
            }
5112
6.22k
            break;
5113
6.22k
        case OBJIDENTITY:
5114
1.17k
            nnp = parse_objectgroup(fp, name, OBJECTS, &objects);
5115
1.17k
            if (nnp == NULL) {
5116
64
                print_error("Bad parse of OBJECT-IDENTITY", NULL, type);
5117
64
                gMibError = MODULE_SYNTAX_ERROR;
5118
64
                goto free_mib;
5119
64
            }
5120
1.11k
            break;
5121
1.11k
        case OBJECT:
5122
972
            type = get_token(fp, token, MAXTOKEN);
5123
972
            if (type != IDENTIFIER) {
5124
32
                print_error("Expected IDENTIFIER", token, type);
5125
32
                gMibError = MODULE_SYNTAX_ERROR;
5126
32
                goto free_mib;
5127
32
            }
5128
940
            type = get_token(fp, token, MAXTOKEN);
5129
940
            if (type != EQUALS) {
5130
12
                print_error("Expected \"::=\"", token, type);
5131
12
                gMibError = MODULE_SYNTAX_ERROR;
5132
12
                goto free_mib;
5133
12
            }
5134
928
            nnp = parse_objectid(fp, name);
5135
928
            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
926
            break;
5141
117k
        case EQUALS:
5142
117k
            nnp = parse_asntype(fp, name, &type, token);
5143
117k
            lasttype = CONTINUE;
5144
117k
            break;
5145
1.38k
        case ENDOFFILE:
5146
1.38k
            break;
5147
1.78k
        default:
5148
1.78k
            print_error("Bad operator", token, type);
5149
1.78k
            gMibError = MODULE_SYNTAX_ERROR;
5150
1.78k
            goto free_mib;
5151
223k
        }
5152
218k
        if (nnp) {
5153
133k
            struct node *op = label_table_find_dup(&labels, nnp);
5154
5155
133k
            if (op) {
5156
5.09k
                struct node *next_node;
5157
5158
5.09k
                snmp_log(LOG_ERR, 
5159
5.09k
                    "Duplicate Object '%s' at line %d in %s. First at line %d\n",
5160
5.09k
                    op->label, mibLine, File, op->lineno);
5161
5.09k
                erroneousMibs++;
5162
10.7k
                while (nnp) {
5163
5.68k
                    next_node = nnp->next;
5164
5.68k
                    free_node(nnp);
5165
5.68k
                    nnp = next_node;
5166
5.68k
                }
5167
128k
            } else {
5168
128k
                if (np)
5169
92.4k
                    np->next = nnp;
5170
35.7k
                else
5171
35.7k
                    np = root = nnp;
5172
128k
                label_table_add(&labels, np);
5173
1.46M
                while (np->next) {
5174
1.33M
                    np = np->next;
5175
1.33M
                    label_table_add(&labels, np);
5176
1.33M
                }
5177
128k
                if (np->type == TYPE_OTHER)
5178
119k
                    np->type = type;
5179
128k
            }
5180
133k
        }
5181
218k
    }
5182
6.95k
    DEBUGMSGTL(("parse-file", "End of file (%s)\n", File));
5183
6.95k
    label_table_clear(&labels);
5184
6.95k
    free_objgroup(objgroups);
5185
6.95k
    objgroups = oldgroups;
5186
6.95k
    free_objgroup(objects);
5187
6.95k
    objects = oldobjects;
5188
6.95k
    free_objgroup(notifs);
5189
6.95k
    notifs = oldnotifs;
5190
6.95k
    return root;
5191
5192
5.76k
free_mib:
5193
5.76k
    label_table_clear(&labels);
5194
123k
    for (; root; root = np) {
5195
117k
        np = root->next;
5196
117k
        free_node(root);
5197
117k
    }
5198
5.76k
    free_objgroup(objgroups);
5199
5.76k
    objgroups = oldgroups;
5200
5.76k
    free_objgroup(objects);
5201
5.76k
    objects = oldobjects;
5202
5.76k
    free_objgroup(notifs);
5203
5.76k
    notifs = oldnotifs;
5204
5.76k
    return NULL;
5205
12.7k
}
5206
5207
/*
5208
 * return zero if character is not a label character. 
5209
 */
5210
static int
5211
is_labelchar(int ich)
5212
23.6M
{
5213
23.6M
    netsnmp_assert(ich == EOF || (0 <= ich && ich < 256));
5214
23.6M
    if ((isalnum(ich)) || (ich == '-'))
5215
16.8M
        return 1;
5216
6.86M
    if (ich == '_' && netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
5217
11.6k
               NETSNMP_DS_LIB_MIB_PARSE_LABEL)) {
5218
1.93k
        return 1;
5219
1.93k
    }
5220
5221
6.86M
    return 0;
5222
6.86M
}
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
59.7M
{
5232
59.7M
#ifdef HAVE_FGETC_UNLOCKED
5233
59.7M
    return fgetc_unlocked(stream);
5234
#else
5235
    return getc(stream);
5236
#endif
5237
59.7M
}
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
10.7M
{
5247
10.7M
    int             ch, ch_next;
5248
10.7M
    char           *cp;
5249
10.7M
    int             hash;
5250
10.7M
    struct tok     *tp;
5251
10.7M
    int             too_long;
5252
10.7M
    enum { bdigits, xdigits, other } seenSymbols;
5253
5254
11.7M
fetch_next_token:
5255
11.7M
    cp = token;
5256
11.7M
    hash = 0;
5257
11.7M
    too_long = 0;
5258
    /*
5259
     * skip all white space 
5260
     */
5261
15.7M
    do {
5262
15.7M
        ch = netsnmp_getc(fp);
5263
15.7M
        if (ch == '\n')
5264
460k
            mibLine++;
5265
15.7M
    }
5266
15.7M
    while (isspace(ch) && ch != EOF);
5267
11.7M
    *cp++ = ch;
5268
11.7M
    *cp = '\0';
5269
11.7M
    switch (ch) {
5270
14.8k
    case EOF:
5271
14.8k
        return ENDOFFILE;
5272
222k
    case '"':
5273
222k
        return parseQuoteString(fp, token, maxtlen);
5274
137k
    case '\'':                 /* binary or hex constant */
5275
137k
        seenSymbols = bdigits;
5276
7.11M
        while ((ch = netsnmp_getc(fp)) != EOF && ch != '\'') {
5277
6.97M
            switch (seenSymbols) {
5278
105k
            case bdigits:
5279
105k
                if (ch == '0' || ch == '1')
5280
7.66k
                    break;
5281
97.4k
                seenSymbols = xdigits;
5282
97.4k
                NETSNMP_FALLTHROUGH;
5283
118k
            case xdigits:
5284
118k
                if (isxdigit(ch))
5285
22.6k
                    break;
5286
96.1k
                seenSymbols = other;
5287
96.1k
                NETSNMP_FALLTHROUGH;
5288
6.94M
            case other:
5289
6.94M
                break;
5290
6.97M
            }
5291
6.97M
            if (cp - token < maxtlen - 2)
5292
2.65M
                *cp++ = ch;
5293
6.97M
        }
5294
137k
        if (ch == '\'') {
5295
135k
            unsigned long   val = 0;
5296
135k
            char           *run = token + 1;
5297
135k
            ch = netsnmp_getc(fp);
5298
135k
            switch (ch) {
5299
32
            case EOF:
5300
32
                return ENDOFFILE;
5301
526
            case 'b':
5302
2.63k
            case 'B':
5303
2.63k
                if (seenSymbols > bdigits) {
5304
1.61k
                    *cp++ = '\'';
5305
1.61k
                    *cp = 0;
5306
1.61k
                    return LABEL;
5307
1.61k
                }
5308
2.48k
                while (run != cp)
5309
1.46k
                    val = val * 2 + *run++ - '0';
5310
1.01k
                break;
5311
23.3k
            case 'h':
5312
26.6k
            case 'H':
5313
26.6k
                if (seenSymbols > xdigits) {
5314
24.5k
                    *cp++ = '\'';
5315
24.5k
                    *cp = 0;
5316
24.5k
                    return LABEL;
5317
24.5k
                }
5318
9.47k
                while (run != cp) {
5319
7.36k
                    ch = *run++;
5320
7.36k
                    if ('0' <= ch && ch <= '9')
5321
3.10k
                        val = val * 16 + ch - '0';
5322
4.26k
                    else if ('a' <= ch && ch <= 'f')
5323
2.87k
                        val = val * 16 + ch - 'a' + 10;
5324
1.38k
                    else if ('A' <= ch && ch <= 'F')
5325
1.38k
                        val = val * 16 + ch - 'A' + 10;
5326
7.36k
                }
5327
2.10k
                break;
5328
106k
            default:
5329
106k
                *cp++ = '\'';
5330
106k
                *cp = 0;
5331
106k
                return LABEL;
5332
135k
            }
5333
3.12k
            snprintf(token, maxtlen, "%ld", val);
5334
3.12k
            return NUMBER;
5335
135k
        } else
5336
1.29k
            return LABEL;
5337
54.4k
    case '(':
5338
54.4k
        return LEFTPAREN;
5339
40.1k
    case ')':
5340
40.1k
        return RIGHTPAREN;
5341
1.41M
    case '{':
5342
1.41M
        return LEFTBRACKET;
5343
1.39M
    case '}':
5344
1.39M
        return RIGHTBRACKET;
5345
8.71k
    case '[':
5346
8.71k
        return LEFTSQBRACK;
5347
13.6k
    case ']':
5348
13.6k
        return RIGHTSQBRACK;
5349
27.7k
    case ';':
5350
27.7k
        return SEMI;
5351
38.3k
    case ',':
5352
38.3k
        return COMMA;
5353
30.2k
    case '|':
5354
30.2k
        return BAR;
5355
57.7k
    case '.':
5356
57.7k
        ch_next = netsnmp_getc(fp);
5357
57.7k
        if (ch_next == '.')
5358
39.4k
            return RANGE;
5359
18.3k
        ungetc(ch_next, fp);
5360
18.3k
        return LABEL;
5361
482k
    case ':':
5362
482k
        ch_next = netsnmp_getc(fp);
5363
482k
        if (ch_next != ':') {
5364
31.8k
            ungetc(ch_next, fp);
5365
31.8k
            return LABEL;
5366
31.8k
        }
5367
450k
        ch_next = netsnmp_getc(fp);
5368
450k
        if (ch_next != '=') {
5369
242k
            ungetc(ch_next, fp);
5370
242k
            return LABEL;
5371
242k
        }
5372
208k
        return EQUALS;
5373
1.11M
    case '-':
5374
1.11M
        ch_next = netsnmp_getc(fp);
5375
1.11M
        if (ch_next == '-') {
5376
991k
            if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
5377
991k
               NETSNMP_DS_LIB_MIB_COMMENT_TERM)) {
5378
                /*
5379
                 * Treat the rest of this line as a comment. 
5380
                 */
5381
0
                while ((ch_next != EOF) && (ch_next != '\n'))
5382
0
                    ch_next = netsnmp_getc(fp);
5383
991k
            } 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
991k
                ch = ' ';
5391
991k
                ch_next = netsnmp_getc(fp);
5392
5.51M
                while (ch_next != EOF && ch_next != '\n' &&
5393
5.22M
                       (ch != '-' || ch_next != '-')) {
5394
4.51M
                    ch = ch_next;
5395
4.51M
                    ch_next = netsnmp_getc(fp);
5396
4.51M
                }
5397
991k
            }
5398
991k
            if (ch_next == EOF)
5399
172
                return ENDOFFILE;
5400
990k
            if (ch_next == '\n')
5401
285k
                mibLine++;
5402
990k
            goto fetch_next_token;
5403
991k
        }
5404
121k
        ungetc(ch_next, fp);
5405
121k
  NETSNMP_FALLTHROUGH;
5406
6.85M
    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
6.85M
        if (!is_labelchar(ch))
5413
4.87M
            return LABEL;
5414
1.98M
        hash += tolower(ch);
5415
1.99M
      more:
5416
16.8M
        while (is_labelchar(ch_next = netsnmp_getc(fp))) {
5417
14.8M
            hash += tolower(ch_next);
5418
14.8M
            if (cp - token < maxtlen - 1)
5419
10.9M
                *cp++ = ch_next;
5420
3.89M
            else
5421
3.89M
                too_long = 1;
5422
14.8M
        }
5423
1.99M
        ungetc(ch_next, fp);
5424
1.99M
        *cp = '\0';
5425
5426
1.99M
        if (too_long)
5427
1.30k
            print_error("Warning: token too long", token, CONTINUE);
5428
6.82M
        for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
5429
5.52M
            if ((tp->hash == hash) && (!label_compare(tp->name, token)))
5430
690k
                break;
5431
5.52M
        }
5432
1.99M
        if (tp) {
5433
690k
            if (tp->token != CONTINUE)
5434
678k
                return (tp->token);
5435
11.7k
            while (isspace((ch_next = netsnmp_getc(fp))))
5436
245k
                if (ch_next == '\n')
5437
2.11k
                    mibLine++;
5438
11.7k
            if (ch_next == EOF)
5439
33
                return ENDOFFILE;
5440
11.7k
            if (isalnum(ch_next)) {
5441
6.14k
                *cp++ = ch_next;
5442
6.14k
                hash += tolower(ch_next);
5443
6.14k
                goto more;
5444
6.14k
            }
5445
11.7k
        }
5446
1.30M
        if (token[0] == '-' || isdigit((unsigned char)(token[0]))) {
5447
1.22M
            for (cp = token + 1; *cp; cp++)
5448
775k
                if (!isdigit((unsigned char)(*cp)))
5449
81.9k
                    return LABEL;
5450
446k
            return NUMBER;
5451
528k
        }
5452
778k
        return LABEL;
5453
11.7M
    }
5454
11.7M
}
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
20.2k
{
5468
20.2k
    FILE           *fp;
5469
20.2k
    char            token[MAXTOKEN], token2[MAXTOKEN];
5470
5471
    /*
5472
     * which module is this 
5473
     */
5474
20.2k
    if ((fp = fopen(tmpstr, "r")) == NULL) {
5475
0
        snmp_log_perror(tmpstr);
5476
0
        return 1;
5477
0
    }
5478
20.2k
    DEBUGMSGTL(("parse-mibs", "Checking file: %s...\n",
5479
20.2k
                tmpstr));
5480
20.2k
    mibLine = 1;
5481
20.2k
    File = tmpstr;
5482
20.2k
    if (get_token(fp, token, MAXTOKEN) != LABEL) {
5483
10.5k
      fclose(fp);
5484
10.5k
      return 1;
5485
10.5k
    }
5486
    /*
5487
     * simple test for this being a MIB 
5488
     */
5489
9.74k
    if (get_token(fp, token2, MAXTOKEN) == DEFINITIONS) {
5490
4.75k
        new_module(token, tmpstr);
5491
4.75k
        fclose(fp);
5492
4.75k
        return 0;
5493
4.99k
    } else {
5494
4.99k
        fclose(fp);
5495
4.99k
        return 1;
5496
4.99k
    }
5497
9.74k
}
5498
5499
static int elemcmp(const void *a, const void *b)
5500
27.0k
{
5501
27.0k
    const char *const *s1 = a, *const *s2 = b;
5502
5503
27.0k
    return strcmp(*s1, *s2);
5504
27.0k
}
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.49k
{
5512
3.49k
    DIR            *dir, *dir2;
5513
3.49k
    struct dirent  *file;
5514
3.49k
    char          **filenames = NULL;
5515
3.49k
    int             fname_len, i, filename_count = 0, array_size = 0;
5516
3.49k
    char           *tmpstr;
5517
5518
3.49k
    *result = NULL;
5519
5520
3.49k
    dir = opendir(dirname);
5521
3.49k
    if (!dir)
5522
132
        return -1;
5523
5524
33.6k
    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
30.3k
        fname_len = strlen(file->d_name);
5531
30.3k
        if (fname_len > 0 && file->d_name[0] != '.'
5532
23.6k
            && file->d_name[0] != '#'
5533
23.6k
            && file->d_name[fname_len-1] != '#'
5534
23.6k
            && file->d_name[fname_len-1] != '~') {
5535
23.6k
            if (asprintf(&tmpstr, "%s/%s", dirname, file->d_name) < 0)
5536
0
                continue;
5537
23.6k
            dir2 = opendir(tmpstr);
5538
23.6k
            if (dir2) {
5539
                /* file is a directory, don't read it */
5540
6.72k
                closedir(dir2);
5541
16.8k
            } else {
5542
16.8k
                if (filename_count >= array_size) {
5543
3.36k
                    char **new_filenames;
5544
5545
3.36k
                    array_size = (array_size + 16) * 2;
5546
3.36k
                    new_filenames = realloc(filenames,
5547
3.36k
                                        array_size * sizeof(filenames[0]));
5548
3.36k
                    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.36k
                    filenames = new_filenames;
5557
3.36k
                }
5558
16.8k
                filenames[filename_count++] = tmpstr;
5559
16.8k
                tmpstr = NULL;
5560
16.8k
            }
5561
23.6k
            free(tmpstr);
5562
23.6k
        }
5563
30.3k
    }
5564
3.36k
    closedir(dir);
5565
5566
3.36k
    if (filenames)
5567
3.36k
        qsort(filenames, filename_count, sizeof(filenames[0]), elemcmp);
5568
3.36k
    *result = filenames;
5569
5570
3.36k
    return filename_count;
5571
3.36k
}
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.49k
{
5582
3.49k
    const char     *oldFile = File;
5583
3.49k
    int             oldLine = mibLine;
5584
3.49k
    char          **filenames;
5585
3.49k
    int             count = 0;
5586
3.49k
    int             filename_count, i;
5587
5588
3.49k
    DEBUGMSGTL(("parse-mibs", "Scanning directory %s\n", dirname));
5589
5590
3.49k
    filename_count = scan_directory(&filenames, dirname);
5591
5592
3.49k
    if (filename_count >= 0) {
5593
20.2k
        for (i = 0; i < filename_count; i++) {
5594
16.8k
            if (add_mibfile(filenames[i], strrchr(filenames[i], '/')) == 0)
5595
2.37k
                count++;
5596
16.8k
      free(filenames[i]);
5597
16.8k
        }
5598
3.36k
        File = oldFile;
5599
3.36k
        mibLine = oldLine;
5600
3.36k
        free(filenames);
5601
3.36k
        return (count);
5602
3.36k
    }
5603
132
    else
5604
132
        DEBUGMSGTL(("parse-mibs","cannot open MIB directory %s\n", dirname));
5605
5606
132
    return (-1);
5607
3.49k
}
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.2k
{
5617
13.2k
    FILE           *fp;
5618
13.2k
    char            token[MAXTOKEN];
5619
13.2k
    const char     *oldFile = File;
5620
13.2k
    int             oldLine = mibLine;
5621
5622
13.2k
    fp = fopen(filename, "r");
5623
13.2k
    if (fp == NULL) {
5624
325
        snmp_log_perror(filename);
5625
325
        return NULL;
5626
325
    }
5627
12.9k
    mibLine = 1;
5628
12.9k
    File = filename;
5629
12.9k
    DEBUGMSGTL(("parse-mibs", "Parsing file: %s...\n", filename));
5630
12.9k
    if (get_token(fp, token, MAXTOKEN) != LABEL) {
5631
630
      snmp_log(LOG_ERR, "Failed to parse MIB file %s\n", filename);
5632
630
      fclose(fp);
5633
630
      File = oldFile;
5634
630
      mibLine = oldLine;
5635
630
      return NULL;
5636
630
    }
5637
12.3k
    fclose(fp);
5638
12.3k
    new_module(token, filename);
5639
12.3k
    (void) netsnmp_read_module(token);
5640
5641
12.3k
    File = oldFile;
5642
12.3k
    mibLine = oldLine;
5643
12.3k
    return tree_head;
5644
12.9k
}
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
222k
{
5702
222k
    register int    ch;
5703
222k
    int             count = 0;
5704
222k
    int             too_long = 0;
5705
222k
    char           *token_start = token;
5706
5707
12.0M
    for (ch = netsnmp_getc(fp); ch != EOF; ch = netsnmp_getc(fp)) {
5708
12.0M
        if (ch == '\r')
5709
5.29k
            continue;
5710
12.0M
        if (ch == '\n') {
5711
69.6k
            mibLine++;
5712
11.9M
        } else if (ch == '"') {
5713
222k
            netsnmp_assert(token - token_start < maxtlen);
5714
222k
            *token = '\0';
5715
222k
            if (too_long && netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
5716
2.22k
             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
222k
            return QUOTESTRING;
5729
222k
        }
5730
        /*
5731
         * maximum description length check.  If greater, keep parsing
5732
         * but truncate the string 
5733
         */
5734
11.8M
        if (++count < maxtlen)
5735
4.02M
            *token++ = ch;
5736
7.80M
        else
5737
7.80M
            too_long = 1;
5738
11.8M
    }
5739
5740
640
    return 0;
5741
222k
}
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.41k
{
5753
4.41k
    int             type;
5754
4.41k
    char            token[MAXTOKEN];
5755
4.41k
    char            nextIsImplied = 0;
5756
5757
4.41k
    struct index_list *mylist = NULL;
5758
4.41k
    struct index_list **mypp = &mylist;
5759
5760
4.41k
    free_indexes(retp);
5761
5762
4.41k
    type = get_token(fp, token, MAXTOKEN);
5763
5764
4.41k
    if (type != LEFTBRACKET) {
5765
23
        return NULL;
5766
23
    }
5767
5768
4.39k
    type = get_token(fp, token, MAXTOKEN);
5769
156k
    while (type != RIGHTBRACKET && type != ENDOFFILE) {
5770
151k
        if ((type == LABEL) || (type & SYNTAX_MASK)) {
5771
136k
            *mypp = calloc(1, sizeof(struct index_list));
5772
136k
            if (*mypp) {
5773
136k
                (*mypp)->ilabel = strdup(token);
5774
136k
                (*mypp)->isimplied = nextIsImplied;
5775
136k
                mypp = &(*mypp)->next;
5776
136k
                nextIsImplied = 0;
5777
136k
            }
5778
136k
        } else if (type == IMPLIED) {
5779
325
            nextIsImplied = 1;
5780
325
        }
5781
151k
        type = get_token(fp, token, MAXTOKEN);
5782
151k
    }
5783
5784
4.39k
    *retp = mylist;
5785
4.39k
    return mylist;
5786
4.41k
}
5787
5788
static struct varbind_list *
5789
getVarbinds(FILE * fp, struct varbind_list **retp)
5790
8.50k
{
5791
8.50k
    int             type;
5792
8.50k
    char            token[MAXTOKEN];
5793
5794
8.50k
    struct varbind_list *mylist = NULL;
5795
8.50k
    struct varbind_list **mypp = &mylist;
5796
5797
8.50k
    free_varbinds(retp);
5798
5799
8.50k
    type = get_token(fp, token, MAXTOKEN);
5800
5801
8.50k
    if (type != LEFTBRACKET) {
5802
30
        return NULL;
5803
30
    }
5804
5805
8.47k
    type = get_token(fp, token, MAXTOKEN);
5806
1.00M
    while (type != RIGHTBRACKET && type != ENDOFFILE) {
5807
996k
        if ((type == LABEL) || (type & SYNTAX_MASK)) {
5808
932k
            *mypp = calloc(1, sizeof(struct varbind_list));
5809
932k
            if (*mypp) {
5810
932k
                (*mypp)->vblabel = strdup(token);
5811
932k
                mypp = &(*mypp)->next;
5812
932k
            }
5813
932k
        }
5814
996k
        type = get_token(fp, token, MAXTOKEN);
5815
996k
    }
5816
5817
8.47k
    *retp = mylist;
5818
8.47k
    return mylist;
5819
8.50k
}
5820
5821
static void
5822
free_indexes(struct index_list **spp)
5823
2.33M
{
5824
2.33M
    if (spp && *spp) {
5825
4.39k
        struct index_list *pp, *npp;
5826
5827
4.39k
        pp = *spp;
5828
4.39k
        *spp = NULL;
5829
5830
141k
        while (pp) {
5831
136k
            npp = pp->next;
5832
136k
            if (pp->ilabel)
5833
136k
                free(pp->ilabel);
5834
136k
            free(pp);
5835
136k
            pp = npp;
5836
136k
        }
5837
4.39k
    }
5838
2.33M
}
5839
5840
static void
5841
free_varbinds(struct varbind_list **spp)
5842
2.34M
{
5843
2.34M
    if (spp && *spp) {
5844
8.45k
        struct varbind_list *pp, *npp;
5845
5846
8.45k
        pp = *spp;
5847
8.45k
        *spp = NULL;
5848
5849
940k
        while (pp) {
5850
932k
            npp = pp->next;
5851
932k
            if (pp->vblabel)
5852
932k
                free(pp->vblabel);
5853
932k
            free(pp);
5854
932k
            pp = npp;
5855
932k
        }
5856
8.45k
    }
5857
2.34M
}
5858
5859
static void
5860
free_ranges(struct range_list **spp)
5861
2.34M
{
5862
2.34M
    if (spp && *spp) {
5863
4.31k
        struct range_list *pp, *npp;
5864
5865
4.31k
        pp = *spp;
5866
4.31k
        *spp = NULL;
5867
5868
13.3k
        while (pp) {
5869
9.02k
            npp = pp->next;
5870
9.02k
            free(pp);
5871
9.02k
            pp = npp;
5872
9.02k
        }
5873
4.31k
    }
5874
2.34M
}
5875
5876
static void
5877
free_enums(struct enum_list **spp)
5878
2.35M
{
5879
2.35M
    if (spp && *spp) {
5880
6.15k
        struct enum_list *pp, *npp;
5881
5882
6.15k
        pp = *spp;
5883
6.15k
        *spp = NULL;
5884
5885
18.6k
        while (pp) {
5886
12.5k
            npp = pp->next;
5887
12.5k
            if (pp->label)
5888
12.5k
                free(pp->label);
5889
12.5k
            free(pp);
5890
12.5k
            pp = npp;
5891
12.5k
        }
5892
6.15k
    }
5893
2.35M
}
5894
5895
static struct enum_list *
5896
copy_enums(struct enum_list *sp)
5897
606
{
5898
606
    struct enum_list *xp = NULL, **spp = &xp;
5899
5900
1.39k
    while (sp) {
5901
786
        *spp = calloc(1, sizeof(struct enum_list));
5902
786
        if (!*spp)
5903
0
            break;
5904
786
        (*spp)->label = strdup(sp->label);
5905
786
        (*spp)->value = sp->value;
5906
786
        spp = &(*spp)->next;
5907
786
        sp = sp->next;
5908
786
    }
5909
606
    return (xp);
5910
606
}
5911
5912
static struct range_list *
5913
copy_ranges(struct range_list *sp)
5914
606
{
5915
606
    struct range_list *xp = NULL, **spp = &xp;
5916
5917
1.88k
    while (sp) {
5918
1.27k
        *spp = calloc(1, sizeof(struct range_list));
5919
1.27k
        if (!*spp)
5920
0
            break;
5921
1.27k
        (*spp)->low = sp->low;
5922
1.27k
        (*spp)->high = sp->high;
5923
1.27k
        spp = &(*spp)->next;
5924
1.27k
        sp = sp->next;
5925
1.27k
    }
5926
606
    return (xp);
5927
606
}
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
230
{
5936
230
    int             type;
5937
230
    char            token[MAXTOKEN];
5938
230
    int             bracketcount = 1;
5939
5940
230
    type = get_token(fp, token, MAXTOKEN);
5941
5942
230
    if (type != LEFTBRACKET)
5943
1
        return 0;
5944
37.5k
    while ((type != RIGHTBRACKET || bracketcount > 0) && type != ENDOFFILE) {
5945
37.3k
        type = get_token(fp, token, MAXTOKEN);
5946
37.3k
        if (type == LEFTBRACKET)
5947
33.5k
            bracketcount++;
5948
3.74k
        else if (type == RIGHTBRACKET)
5949
402
            bracketcount--;
5950
37.3k
    }
5951
5952
229
    if (type == RIGHTBRACKET)
5953
197
        return OBJID;
5954
32
    else
5955
32
        return 0;
5956
229
}
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
62.2k
{
6220
62.2k
    struct node    *nnp;
6221
    /*
6222
     * printf("merge defval --> %s\n",np->defaultValue); 
6223
     */
6224
62.2k
    nnp = parse_objectid(fp, name);
6225
62.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
59.8k
        struct node    *headp, *nextp;
6234
59.8k
        int             ncount = 0;
6235
59.8k
        nextp = headp = nnp;
6236
295k
        while (nnp->next) {
6237
235k
            nextp = nnp;
6238
235k
            ncount++;
6239
235k
            nnp = nnp->next;
6240
235k
        }
6241
6242
59.8k
        np->label = nnp->label;
6243
59.8k
        np->subid = nnp->subid;
6244
59.8k
        np->modid = nnp->modid;
6245
59.8k
        np->parent = nnp->parent;
6246
59.8k
  if (nnp->filename != NULL) {
6247
59.8k
    free(nnp->filename);
6248
59.8k
  }
6249
59.8k
        free(nnp);
6250
6251
59.8k
        if (ncount) {
6252
34.1k
            nextp->next = np;
6253
34.1k
            np = headp;
6254
34.1k
        }
6255
59.8k
    } else {
6256
2.35k
        free_node(np);
6257
2.35k
        np = NULL;
6258
2.35k
    }
6259
6260
62.2k
    return np;
6261
62.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
453k
{
6277
453k
    free_partial_tree(tp, FALSE);
6278
6279
453k
    tp->label = np->label;
6280
453k
    np->label = NULL;
6281
453k
    tp->enums = np->enums;
6282
453k
    np->enums = NULL;
6283
453k
    tp->ranges = np->ranges;
6284
453k
    np->ranges = NULL;
6285
453k
    tp->indexes = np->indexes;
6286
453k
    np->indexes = NULL;
6287
453k
    tp->augments = np->augments;
6288
453k
    np->augments = NULL;
6289
453k
    tp->varbinds = np->varbinds;
6290
453k
    np->varbinds = NULL;
6291
453k
    tp->hint = np->hint;
6292
453k
    np->hint = NULL;
6293
453k
    tp->units = np->units;
6294
453k
    np->units = NULL;
6295
453k
    tp->description = np->description;
6296
453k
    np->description = NULL;
6297
453k
    tp->reference = np->reference;
6298
453k
    np->reference = NULL;
6299
453k
    tp->defaultValue = np->defaultValue;
6300
453k
    np->defaultValue = NULL;
6301
453k
    tp->subid = np->subid;
6302
453k
    tp->tc_index = np->tc_index;
6303
453k
    tp->type = translation_table[np->type];
6304
453k
    tp->access = np->access;
6305
453k
    tp->status = np->status;
6306
6307
453k
    set_function(tp);
6308
453k
}
6309
6310
#endif /* NETSNMP_DISABLE_MIB_LOADING */