Coverage Report

Created: 2025-10-10 07:10

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