Coverage Report

Created: 2026-02-14 06:36

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.33k
#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
157k
#define SYNTAX_MASK     0x80
158
/*
159
 * types of tokens
160
 * Tokens with the SYNTAX_MASK bit set are syntax tokens 
161
 */
162
198k
#define CONTINUE    -1
163
212k
#define ENDOFFILE   0
164
116k
#define LABEL       1
165
#define SUBTREE     2
166
389
#define SYNTAX      3
167
3.35k
#define OBJID       (4 | SYNTAX_MASK)
168
3.35k
#define OCTETSTR    (5 | SYNTAX_MASK)
169
9.38k
#define INTEGER     (6 | SYNTAX_MASK)
170
9.37k
#define NETADDR     (7 | SYNTAX_MASK)
171
9.37k
#define IPADDR      (8 | SYNTAX_MASK)
172
9.40k
#define COUNTER     (9 | SYNTAX_MASK)
173
9.41k
#define GAUGE       (10 | SYNTAX_MASK)
174
9.39k
#define TIMETICKS   (11 | SYNTAX_MASK)
175
9.39k
#define KW_OPAQUE   (12 | SYNTAX_MASK)
176
3.34k
#define NUL         (13 | SYNTAX_MASK)
177
4.42k
#define SEQUENCE    14
178
6
#define OF          15          /* SEQUENCE OF */
179
98
#define OBJTYPE     16
180
94
#define ACCESS      17
181
190
#define READONLY    18
182
128
#define READWRITE   19
183
122
#define WRITEONLY   20
184
#ifdef NOACCESS
185
#undef NOACCESS                 /* agent 'NOACCESS' token */
186
#endif
187
123
#define NOACCESS    21
188
176
#define STATUS      22
189
188
#define MANDATORY   23
190
124
#define KW_OPTIONAL    24
191
130
#define OBSOLETE    25
192
/*
193
 * #define RECOMMENDED 26 
194
 */
195
#define PUNCT       27
196
11.3k
#define EQUALS      28
197
20.1k
#define NUMBER      29
198
14.0k
#define LEFTBRACKET 30
199
25.0k
#define RIGHTBRACKET 31
200
15.0k
#define LEFTPAREN   32
201
1.00k
#define RIGHTPAREN  33
202
575
#define COMMA       34
203
403
#define DESCRIPTION 35
204
673
#define QUOTESTRING 36
205
5
#define INDEX       37
206
0
#define DEFVAL      38
207
283
#define DEPRECATED  39
208
58
#define SIZE        40
209
3.38k
#define BITSTRING   (41 | SYNTAX_MASK)
210
9.38k
#define NSAPADDRESS (42 | SYNTAX_MASK)
211
9.36k
#define COUNTER64   (43 | SYNTAX_MASK)
212
3.36k
#define OBJGROUP    44
213
3.39k
#define NOTIFTYPE   45
214
1
#define AUGMENTS    46
215
3.37k
#define COMPLIANCE  47
216
101
#define READCREATE  48
217
94
#define UNITS       49
218
47
#define REFERENCE   50
219
0
#define NUM_ENTRIES 51
220
3.42k
#define MODULEIDENTITY 52
221
89
#define LASTUPDATED 53
222
52
#define ORGANIZATION 54
223
4
#define CONTACTINFO 55
224
9.36k
#define UINTEGER32 (56 | SYNTAX_MASK)
225
242
#define CURRENT     57
226
12.4k
#define DEFINITIONS 58
227
1.30k
#define END         59
228
10.5k
#define SEMI        60
229
3.38k
#define TRAPTYPE    61
230
10
#define ENTERPRISE  62
231
/*
232
 * #define DISPLAYSTR (63 | SYNTAX_MASK) 
233
 */
234
10.6k
#define BEGIN       64
235
442
#define IMPORTS     65
236
19
#define EXPORTS     66
237
4
#define ACCNOTIFY   67
238
1.05k
#define BAR         68
239
420
#define RANGE       69
240
998
#define CONVENTION  70
241
127
#define DISPLAYHINT 71
242
871
#define FROM        72
243
3.36k
#define AGENTCAP    73
244
3.98k
#define MACRO       74
245
5
#define IMPLIED     75
246
0
#define SUPPORTS    76
247
0
#define INCLUDES    77
248
0
#define VARIATION   78
249
11
#define REVISION    79
250
0
#define NOTIMPL     80
251
70
#define OBJECTS     81
252
44
#define NOTIFICATIONS 82
253
28
#define MODULE      83
254
1
#define MINACCESS   84
255
25
#define PRODREL     85
256
1
#define WRSYNTAX    86
257
0
#define CREATEREQ   87
258
3.38k
#define NOTIFGROUP  88
259
9
#define MANDATORYGROUPS 89
260
39
#define GROUP     90
261
1.14k
#define OBJECT      91
262
54
#define IDENTIFIER  92
263
2.18k
#define CHOICE      93
264
1.47k
#define LEFTSQBRACK 95
265
954
#define RIGHTSQBRACK  96
266
69
#define IMPLICIT    97
267
6.03k
#define APPSYNTAX (98 | SYNTAX_MASK)
268
6.03k
#define OBJSYNTAX (99 | SYNTAX_MASK)
269
6.04k
#define SIMPLESYNTAX  (100 | SYNTAX_MASK)
270
6.04k
#define OBJNAME   (101 | SYNTAX_MASK)
271
6.04k
#define NOTIFNAME (102 | SYNTAX_MASK)
272
2
#define VARIABLES 103
273
9.36k
#define UNSIGNED32  (104 | SYNTAX_MASK)
274
9.35k
#define INTEGER32 (105 | SYNTAX_MASK)
275
3.34k
#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
314k
#define MODULE_NOT_FOUND  0
514
4.13k
#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
6.12k
#define MODULE_SYNTAX_ERROR     4
521
522
int gMibError = 0,gLoop = 0;
523
static char *gpMibErrorString;
524
char gMibNames[STRINGMAX];
525
526
357k
#define HASHSIZE        32
527
357k
#define BUCKET(x)       (x & (HASHSIZE-1))
528
529
1.64M
#define NHASHSIZE    128
530
541k
#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
958
#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
849k
{
688
849k
    int             hash = 0;
689
849k
    const char     *cp;
690
691
849k
    if (!name)
692
0
        return 0;
693
7.81M
    for (cp = name; *cp; cp++)
694
6.96M
        hash += tolower((unsigned char)(*cp));
695
849k
    return (hash);
696
849k
}
697
698
void
699
netsnmp_init_mib_internals(void)
700
168k
{
701
168k
    register struct tok *tp;
702
168k
    register int    b, i;
703
168k
    int             max_modc;
704
705
168k
    if (tree_head)
706
165k
        return;
707
708
    /*
709
     * Set up hash list of pre-defined tokens
710
     */
711
3.33k
    memset(buckets, 0, sizeof(buckets));
712
310k
    for (tp = tokens; tp->name; tp++) {
713
307k
        tp->hash = name_hash(tp->name);
714
307k
        b = BUCKET(tp->hash);
715
307k
        if (buckets[b])
716
200k
            tp->next = buckets[b];      /* BUG ??? */
717
307k
        buckets[b] = tp;
718
307k
    }
719
720
    /*
721
     * Initialise other internal structures
722
     */
723
724
3.33k
    max_modc = sizeof(module_map) / sizeof(module_map[0]) - 1;
725
73.4k
    for (i = 0; i < max_modc; ++i)
726
70.0k
        module_map[i].next = &(module_map[i + 1]);
727
3.33k
    module_map[max_modc].next = NULL;
728
3.33k
    module_map_head = module_map;
729
730
3.33k
    memset(nbuckets, 0, sizeof(nbuckets));
731
3.33k
    memset(tbuckets, 0, sizeof(tbuckets));
732
3.33k
    tc_alloc = TC_INCR;
733
3.33k
    tclist = calloc(tc_alloc, sizeof(struct tc));
734
3.33k
    build_translation_table();
735
3.33k
    init_tree_roots();          /* Set up initial roots */
736
    /*
737
     * Relies on 'add_mibdir' having set up the modules 
738
     */
739
3.33k
}
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.42k
{
752
4.42k
    struct node    *np, *nextp;
753
4.42k
    int             hash;
754
755
4.42k
    memset(nbuckets, 0, sizeof(nbuckets));
756
236k
    for (np = nodes; np;) {
757
232k
        nextp = np->next;
758
232k
        hash = NBUCKET(name_hash(np->parent));
759
232k
        np->next = nbuckets[hash];
760
232k
        nbuckets[hash] = np;
761
232k
        np = nextp;
762
232k
    }
763
4.42k
}
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
174k
{
780
174k
    erroneousMibs++;
781
174k
    if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
782
174k
                                NETSNMP_DS_LIB_MIB_ERRORS))
783
0
  return;
784
174k
    DEBUGMSGTL(("parse-mibs", "\n"));
785
174k
    if (type == ENDOFFILE)
786
353
        snmp_log(LOG_ERR, "%s (EOF): At line %d in %s\n", str, mibLine,
787
353
                 File);
788
173k
    else if (token && *token)
789
173k
        snmp_log(LOG_ERR, "%s (%s): At line %d in %s\n", str, token,
790
173k
                 mibLine, File);
791
481
    else
792
481
        snmp_log(LOG_ERR, "%s: At line %d in %s\n", str, mibLine, File);
793
174k
}
794
795
static void
796
print_module_not_found(const char *cp)
797
155k
{
798
155k
    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
155k
    if (!last_err_module || strcmp(cp, last_err_module))
804
154k
        print_error("Cannot find module", cp, CONTINUE);
805
155k
    if (last_err_module)
806
149k
        free(last_err_module);
807
155k
    last_err_module = strdup(cp);
808
155k
}
809
810
static struct node *
811
alloc_node(int modid)
812
14.9k
{
813
14.9k
    struct node    *np;
814
815
14.9k
    np = calloc(1, sizeof(struct node));
816
14.9k
    if (!np)
817
0
        return NULL;
818
819
14.9k
    np->tc_index = -1;
820
14.9k
    np->modid = modid;
821
14.9k
    np->filename = strdup(File);
822
14.9k
    np->lineno = mibLine;
823
824
14.9k
    return np;
825
14.9k
}
826
827
static void
828
unlink_tbucket(struct tree *tp)
829
22.4k
{
830
22.4k
    int             hash = NBUCKET(name_hash(tp->label));
831
22.4k
    struct tree    *otp = NULL, *ntp = tbuckets[hash];
832
833
26.4k
    while (ntp && ntp != tp) {
834
3.98k
        otp = ntp;
835
3.98k
        ntp = ntp->next;
836
3.98k
    }
837
22.4k
    if (!ntp)
838
0
        snmp_log(LOG_EMERG, "Can't find %s in tbuckets\n", tp->label);
839
22.4k
    else if (otp)
840
1.98k
        otp->next = ntp->next;
841
20.4k
    else
842
20.4k
        tbuckets[hash] = tp->next;
843
22.4k
}
844
845
static void
846
unlink_tree(struct tree *tp)
847
21.3k
{
848
21.3k
    struct tree    *otp = NULL, *ntp = tp->parent;
849
850
21.3k
    if (!ntp) {                 /* this tree has no parent */
851
10.0k
        DEBUGMSGTL(("unlink_tree", "Tree node %s has no parent\n",
852
10.0k
                    tp->label));
853
11.3k
    } else {
854
11.3k
        ntp = ntp->child_list;
855
856
11.4k
        while (ntp && ntp != tp) {
857
135
            otp = ntp;
858
135
            ntp = ntp->next_peer;
859
135
        }
860
11.3k
        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.3k
        else if (otp)
864
84
            otp->next_peer = ntp->next_peer;
865
11.2k
        else
866
11.2k
            tp->parent->child_list = tp->next_peer;
867
11.3k
    }
868
869
21.3k
    if (tree_head == tp)
870
10.0k
        tree_head = tp->next_peer;
871
21.3k
}
872
873
static void
874
free_partial_tree(struct tree *tp, int keep_label)
875
34.1k
{
876
34.1k
    if (!tp)
877
0
        return;
878
879
    /*
880
     * remove the data from this tree node 
881
     */
882
34.1k
    free_enums(&tp->enums);
883
34.1k
    free_ranges(&tp->ranges);
884
34.1k
    free_indexes(&tp->indexes);
885
34.1k
    free_varbinds(&tp->varbinds);
886
34.1k
    if (!keep_label)
887
34.1k
        SNMP_FREE(tp->label);
888
34.1k
    SNMP_FREE(tp->hint);
889
34.1k
    SNMP_FREE(tp->units);
890
34.1k
    SNMP_FREE(tp->description);
891
34.1k
    SNMP_FREE(tp->reference);
892
34.1k
    SNMP_FREE(tp->augments);
893
34.1k
    SNMP_FREE(tp->defaultValue);
894
34.1k
}
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.6k
{
903
21.6k
    if (!Tree)
904
0
        return;
905
906
21.6k
    unlink_tbucket(Tree);
907
21.6k
    free_partial_tree(Tree, FALSE);
908
21.6k
    if (Tree->module_list != &Tree->modid)
909
24
        free(Tree->module_list);
910
21.6k
    free(Tree);
911
21.6k
}
912
913
static void
914
free_node(struct node *np)
915
14.5k
{
916
14.5k
    if (!np)
917
27
        return;
918
919
14.5k
    free_enums(&np->enums);
920
14.5k
    free_ranges(&np->ranges);
921
14.5k
    free_indexes(&np->indexes);
922
14.5k
    free_varbinds(&np->varbinds);
923
14.5k
    free(np->label);
924
14.5k
    free(np->hint);
925
14.5k
    free(np->units);
926
14.5k
    free(np->description);
927
14.5k
    free(np->reference);
928
14.5k
    free(np->defaultValue);
929
14.5k
    free(np->parent);
930
14.5k
    free(np->augments);
931
14.5k
    free(np->filename);
932
14.5k
    free(np);
933
14.5k
}
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.33k
{
1071
3.33k
    int             count;
1072
1073
857k
    for (count = 0; count < 256; count++) {
1074
854k
        switch (count) {
1075
3.33k
        case OBJID:
1076
3.33k
            translation_table[count] = TYPE_OBJID;
1077
3.33k
            break;
1078
3.33k
        case OCTETSTR:
1079
3.33k
            translation_table[count] = TYPE_OCTETSTR;
1080
3.33k
            break;
1081
3.33k
        case INTEGER:
1082
3.33k
            translation_table[count] = TYPE_INTEGER;
1083
3.33k
            break;
1084
3.33k
        case NETADDR:
1085
3.33k
            translation_table[count] = TYPE_NETADDR;
1086
3.33k
            break;
1087
3.33k
        case IPADDR:
1088
3.33k
            translation_table[count] = TYPE_IPADDR;
1089
3.33k
            break;
1090
3.33k
        case COUNTER:
1091
3.33k
            translation_table[count] = TYPE_COUNTER;
1092
3.33k
            break;
1093
3.33k
        case GAUGE:
1094
3.33k
            translation_table[count] = TYPE_GAUGE;
1095
3.33k
            break;
1096
3.33k
        case TIMETICKS:
1097
3.33k
            translation_table[count] = TYPE_TIMETICKS;
1098
3.33k
            break;
1099
3.33k
        case KW_OPAQUE:
1100
3.33k
            translation_table[count] = TYPE_OPAQUE;
1101
3.33k
            break;
1102
3.33k
        case NUL:
1103
3.33k
            translation_table[count] = TYPE_NULL;
1104
3.33k
            break;
1105
3.33k
        case COUNTER64:
1106
3.33k
            translation_table[count] = TYPE_COUNTER64;
1107
3.33k
            break;
1108
3.33k
        case BITSTRING:
1109
3.33k
            translation_table[count] = TYPE_BITSTRING;
1110
3.33k
            break;
1111
3.33k
        case NSAPADDRESS:
1112
3.33k
            translation_table[count] = TYPE_NSAPADDRESS;
1113
3.33k
            break;
1114
3.33k
        case INTEGER32:
1115
3.33k
            translation_table[count] = TYPE_INTEGER32;
1116
3.33k
            break;
1117
3.33k
        case UINTEGER32:
1118
3.33k
            translation_table[count] = TYPE_UINTEGER;
1119
3.33k
            break;
1120
3.33k
        case UNSIGNED32:
1121
3.33k
            translation_table[count] = TYPE_UNSIGNED32;
1122
3.33k
            break;
1123
3.33k
        case TRAPTYPE:
1124
3.33k
            translation_table[count] = TYPE_TRAPTYPE;
1125
3.33k
            break;
1126
3.33k
        case NOTIFTYPE:
1127
3.33k
            translation_table[count] = TYPE_NOTIFTYPE;
1128
3.33k
            break;
1129
3.33k
        case NOTIFGROUP:
1130
3.33k
            translation_table[count] = TYPE_NOTIFGROUP;
1131
3.33k
            break;
1132
3.33k
        case OBJGROUP:
1133
3.33k
            translation_table[count] = TYPE_OBJGROUP;
1134
3.33k
            break;
1135
3.33k
        case MODULEIDENTITY:
1136
3.33k
            translation_table[count] = TYPE_MODID;
1137
3.33k
            break;
1138
3.33k
        case OBJIDENTITY:
1139
3.33k
            translation_table[count] = TYPE_OBJIDENTITY;
1140
3.33k
            break;
1141
3.33k
        case AGENTCAP:
1142
3.33k
            translation_table[count] = TYPE_AGENTCAP;
1143
3.33k
            break;
1144
3.33k
        case COMPLIANCE:
1145
3.33k
            translation_table[count] = TYPE_MODCOMP;
1146
3.33k
            break;
1147
774k
        default:
1148
774k
            translation_table[count] = TYPE_OTHER;
1149
774k
            break;
1150
854k
        }
1151
854k
    }
1152
3.33k
}
1153
1154
static void
1155
init_tree_roots(void)
1156
3.33k
{
1157
3.33k
    struct tree    *tp, *lasttp;
1158
3.33k
    int             base_modid;
1159
3.33k
    int             hash;
1160
1161
3.33k
    base_modid = which_module("SNMPv2-SMI");
1162
3.33k
    if (base_modid == -1)
1163
3.33k
        base_modid = which_module("RFC1155-SMI");
1164
3.33k
    if (base_modid == -1)
1165
3.33k
        base_modid = which_module("RFC1213-MIB");
1166
1167
    /*
1168
     * build root node 
1169
     */
1170
3.33k
    tp = calloc(1, sizeof(struct tree));
1171
3.33k
    if (tp == NULL)
1172
0
        return;
1173
3.33k
    tp->label = strdup("joint-iso-ccitt");
1174
3.33k
    tp->modid = base_modid;
1175
3.33k
    tp->number_modules = 1;
1176
3.33k
    tp->module_list = &(tp->modid);
1177
3.33k
    tp->subid = 2;
1178
3.33k
    tp->tc_index = -1;
1179
3.33k
    set_function(tp);           /* from mib.c */
1180
3.33k
    hash = NBUCKET(name_hash(tp->label));
1181
3.33k
    tp->next = tbuckets[hash];
1182
3.33k
    tbuckets[hash] = tp;
1183
3.33k
    lasttp = tp;
1184
3.33k
    root_imports[0].label = strdup(tp->label);
1185
3.33k
    root_imports[0].modid = base_modid;
1186
1187
    /*
1188
     * build root node 
1189
     */
1190
3.33k
    tp = calloc(1, sizeof(struct tree));
1191
3.33k
    if (tp == NULL)
1192
0
        return;
1193
3.33k
    tp->next_peer = lasttp;
1194
3.33k
    tp->label = strdup("ccitt");
1195
3.33k
    tp->modid = base_modid;
1196
3.33k
    tp->number_modules = 1;
1197
3.33k
    tp->module_list = &(tp->modid);
1198
3.33k
    tp->subid = 0;
1199
3.33k
    tp->tc_index = -1;
1200
3.33k
    set_function(tp);           /* from mib.c */
1201
3.33k
    hash = NBUCKET(name_hash(tp->label));
1202
3.33k
    tp->next = tbuckets[hash];
1203
3.33k
    tbuckets[hash] = tp;
1204
3.33k
    lasttp = tp;
1205
3.33k
    root_imports[1].label = strdup(tp->label);
1206
3.33k
    root_imports[1].modid = base_modid;
1207
1208
    /*
1209
     * build root node 
1210
     */
1211
3.33k
    tp = calloc(1, sizeof(struct tree));
1212
3.33k
    if (tp == NULL)
1213
0
        return;
1214
3.33k
    tp->next_peer = lasttp;
1215
3.33k
    tp->label = strdup("iso");
1216
3.33k
    tp->modid = base_modid;
1217
3.33k
    tp->number_modules = 1;
1218
3.33k
    tp->module_list = &(tp->modid);
1219
3.33k
    tp->subid = 1;
1220
3.33k
    tp->tc_index = -1;
1221
3.33k
    set_function(tp);           /* from mib.c */
1222
3.33k
    hash = NBUCKET(name_hash(tp->label));
1223
3.33k
    tp->next = tbuckets[hash];
1224
3.33k
    tbuckets[hash] = tp;
1225
3.33k
    lasttp = tp;
1226
3.33k
    root_imports[2].label = strdup(tp->label);
1227
3.33k
    root_imports[2].modid = base_modid;
1228
1229
3.33k
    tree_head = tp;
1230
3.33k
}
1231
1232
#ifdef STRICT_MIB_PARSEING
1233
#define label_compare strcasecmp
1234
#else
1235
3.70M
#define label_compare strcmp
1236
#endif
1237
1238
1239
struct tree    *
1240
find_tree_node(const char *name, int modid)
1241
233k
{
1242
233k
    struct tree    *tp, *headtp;
1243
233k
    int             count, *int_p;
1244
1245
233k
    if (!name || !*name)
1246
0
        return (NULL);
1247
1248
233k
    headtp = tbuckets[NBUCKET(name_hash(name))];
1249
251k
    for (tp = headtp; tp; tp = tp->next) {
1250
21.3k
        if (tp->label && !label_compare(tp->label, name)) {
1251
1252
3.42k
            if (modid == -1)    /* Any module */
1253
3.42k
                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
21.3k
    }
1261
1262
230k
    return (NULL);
1263
233k
}
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
745
{
1385
745
    struct tree    *child1, *child2, *previous;
1386
1387
2.12k
    for (child1 = tp1->child_list; child1;) {
1388
1389
1.38k
        for (child2 = tp2->child_list, previous = NULL;
1390
2.05k
             child2; previous = child2, child2 = child2->next_peer) {
1391
1392
1.39k
            if (child1->subid == child2->subid) {
1393
                /*
1394
                 * Found 'matching' children,
1395
                 *  so merge them
1396
                 */
1397
827
                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
827
                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
827
                } else if (!label_compare(child1->label, child2->label)) {
1425
108
                    if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
1426
108
             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
108
                    continue;
1433
719
                } else {
1434
                    /*
1435
                     * Two copies of the same node.
1436
                     * 'child2' adopts the children of 'child1'
1437
                     */
1438
1439
719
                    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
719
                        child2->child_list = child1->child_list;
1444
719
                    for (previous = child1->child_list;
1445
1.62k
                         previous; previous = previous->next_peer)
1446
902
                        previous->parent = child2;
1447
719
                    child1->child_list = NULL;
1448
1449
719
                    previous = child1;  /* Finished with 'child1' */
1450
719
                    child1 = child1->next_peer;
1451
719
                    free_tree(previous);
1452
719
                    goto next;
1453
719
                }
1454
827
            }
1455
1.39k
        }
1456
        /*
1457
         * If no match, move 'child1' to 'tp2' child_list
1458
         */
1459
664
        if (child1) {
1460
664
            previous = child1;
1461
664
            child1 = child1->next_peer;
1462
664
            previous->parent = tp2;
1463
664
            previous->next_peer = tp2->child_list;
1464
664
            tp2->child_list = previous;
1465
664
        }
1466
1.38k
      next:;
1467
1.38k
    }
1468
745
}
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.6k
{
1478
18.6k
    struct tree    *tp, *anon_tp = NULL;
1479
18.6k
    struct tree    *xroot = root;
1480
18.6k
    struct node    *np, **headp;
1481
18.6k
    struct node    *oldnp = NULL, *child_list = NULL, *childp = NULL;
1482
18.6k
    int             hash;
1483
18.6k
    int            *int_p;
1484
1485
29.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
10.3k
        xroot = xroot->next_peer;
1491
10.3k
    }
1492
1493
18.6k
    tp = root;
1494
18.6k
    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
36.0k
    for (np = *headp; np; np = np->next) {
1500
17.4k
        if (!label_compare(tp->label, np->parent)) {
1501
            /*
1502
             * take this node out of the node list 
1503
             */
1504
13.0k
            if (oldnp == NULL) {
1505
12.0k
                *headp = np->next;      /* fix root of node list */
1506
12.0k
            } else {
1507
1.02k
                oldnp->next = np->next; /* link around this node */
1508
1.02k
            }
1509
13.0k
            if (child_list)
1510
3.01k
                childp->next = np;
1511
10.0k
            else
1512
10.0k
                child_list = np;
1513
13.0k
            childp = np;
1514
13.0k
        } else {
1515
4.38k
            oldnp = np;
1516
4.38k
        }
1517
1518
17.4k
    }
1519
18.6k
    if (childp)
1520
10.0k
        childp->next = NULL;
1521
    /*
1522
     * Take each element in the child list and place it into the tree.
1523
     */
1524
31.6k
    for (np = child_list; np; np = np->next) {
1525
13.0k
        struct tree    *otp = NULL;
1526
13.0k
        struct tree    *xxroot = xroot;
1527
13.0k
        anon_tp = NULL;
1528
13.0k
        tp = xroot->child_list;
1529
1530
13.0k
        if (np->subid == -1) {
1531
            /*
1532
             * name ::= { parent } 
1533
             */
1534
32
            np->subid = xroot->subid;
1535
32
            tp = xroot;
1536
32
            xxroot = xroot->parent;
1537
32
        }
1538
1539
14.5k
        while (tp) {
1540
7.27k
            if (tp->subid == np->subid)
1541
5.76k
                break;
1542
1.51k
            else {
1543
1.51k
                otp = tp;
1544
1.51k
                tp = tp->next_peer;
1545
1.51k
            }
1546
7.27k
        }
1547
13.0k
        if (tp) {
1548
5.76k
            if (!label_compare(tp->label, np->label)) {
1549
                /*
1550
                 * Update list of modules 
1551
                 */
1552
964
                int_p = malloc((tp->number_modules + 1) * sizeof(int));
1553
964
                if (int_p == NULL)
1554
0
                    return;
1555
964
                memcpy(int_p, tp->module_list,
1556
964
                       tp->number_modules * sizeof(int));
1557
964
                int_p[tp->number_modules] = np->modid;
1558
964
                if (tp->module_list != &tp->modid)
1559
374
                    free(tp->module_list);
1560
964
                ++tp->number_modules;
1561
964
                tp->module_list = int_p;
1562
1563
964
                if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
1564
964
             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
964
                do_subtree(tp, nodes);
1574
964
                continue;
1575
964
            }
1576
4.80k
            if (!strncmp(np->label, ANON, ANON_LEN) ||
1577
4.47k
                !strncmp(tp->label, ANON, ANON_LEN)) {
1578
745
                anon_tp = tp;   /* Need to merge these two trees later */
1579
4.06k
            } else if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
1580
4.06k
            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
4.80k
        }
1587
1588
12.0k
        tp = calloc(1, sizeof(struct tree));
1589
12.0k
        if (tp == NULL)
1590
0
            return;
1591
12.0k
        tp->parent = xxroot;
1592
12.0k
        tp->modid = np->modid;
1593
12.0k
        tp->number_modules = 1;
1594
12.0k
        tp->module_list = &(tp->modid);
1595
12.0k
        tree_from_node(tp, np);
1596
12.0k
        if (!otp && !xxroot) {
1597
3
          free(tp);
1598
3
          return;
1599
3
        }
1600
12.0k
        tp->next_peer = otp ? otp->next_peer : xxroot->child_list;
1601
12.0k
        if (otp)
1602
831
            otp->next_peer = tp;
1603
11.2k
        else
1604
11.2k
            xxroot->child_list = tp;
1605
12.0k
        hash = NBUCKET(name_hash(tp->label));
1606
12.0k
        tp->next = tbuckets[hash];
1607
12.0k
        tbuckets[hash] = tp;
1608
12.0k
        do_subtree(tp, nodes);
1609
1610
12.0k
        if (anon_tp) {
1611
745
            if (!strncmp(tp->label, ANON, ANON_LEN)) {
1612
                /*
1613
                 * The new node is anonymous,
1614
                 *  so merge it with the existing one.
1615
                 */
1616
333
                merge_anon_children(tp, anon_tp);
1617
1618
                /*
1619
                 * unlink and destroy tp 
1620
                 */
1621
333
                unlink_tree(tp);
1622
333
                free_tree(tp);
1623
412
            } else if (!strncmp(anon_tp->label, ANON, ANON_LEN)) {
1624
412
                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
412
                merge_anon_children(anon_tp, tp);
1631
1632
                /*
1633
                 * unlink anon_tp from the hash 
1634
                 */
1635
412
                unlink_tbucket(anon_tp);
1636
1637
                /*
1638
                 * get rid of old contents of anon_tp 
1639
                 */
1640
412
                free_partial_tree(anon_tp, FALSE);
1641
1642
                /*
1643
                 * put in the current information 
1644
                 */
1645
412
                anon_tp->label = tp->label;
1646
412
                anon_tp->child_list = tp->child_list;
1647
412
                anon_tp->modid = tp->modid;
1648
412
                anon_tp->tc_index = tp->tc_index;
1649
412
                anon_tp->type = tp->type;
1650
412
                anon_tp->enums = tp->enums;
1651
412
                anon_tp->indexes = tp->indexes;
1652
412
                anon_tp->augments = tp->augments;
1653
412
                anon_tp->varbinds = tp->varbinds;
1654
412
                anon_tp->ranges = tp->ranges;
1655
412
                anon_tp->hint = tp->hint;
1656
412
                anon_tp->units = tp->units;
1657
412
                anon_tp->description = tp->description;
1658
412
                anon_tp->reference = tp->reference;
1659
412
                anon_tp->defaultValue = tp->defaultValue;
1660
412
                anon_tp->parent = tp->parent;
1661
1662
412
                set_function(anon_tp);
1663
1664
                /*
1665
                 * update parent pointer in moved children 
1666
                 */
1667
412
                ntp = anon_tp->child_list;
1668
1.07k
                while (ntp) {
1669
664
                    ntp->parent = anon_tp;
1670
664
                    ntp = ntp->next_peer;
1671
664
                }
1672
1673
                /*
1674
                 * hash in anon_tp in its new place 
1675
                 */
1676
412
                hash = NBUCKET(name_hash(anon_tp->label));
1677
412
                anon_tp->next = tbuckets[hash];
1678
412
                tbuckets[hash] = anon_tp;
1679
1680
                /*
1681
                 * unlink and destroy tp 
1682
                 */
1683
412
                unlink_tbucket(tp);
1684
412
                unlink_tree(tp);
1685
412
                free(tp);
1686
412
            } 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
745
            anon_tp = NULL;
1698
745
        }
1699
12.0k
    }
1700
    /*
1701
     * free all nodes that were copied into tree 
1702
     */
1703
18.6k
    oldnp = NULL;
1704
31.6k
    for (np = child_list; np; np = np->next) {
1705
13.0k
        if (oldnp)
1706
3.01k
            free_node(oldnp);
1707
13.0k
        oldnp = np;
1708
13.0k
    }
1709
18.6k
    if (oldnp)
1710
10.0k
        free_node(oldnp);
1711
18.6k
}
1712
1713
static void
1714
do_linkup(struct module *mp, struct node *np)
1715
1.09k
{
1716
1.09k
    struct module_import *mip;
1717
1.09k
    struct node    *onp, *oldp, *newp;
1718
1.09k
    struct tree    *tp;
1719
1.09k
    int             i, more;
1720
    /*
1721
     * All modules implicitly import
1722
     *   the roots of the tree
1723
     */
1724
1.09k
    if (snmp_get_do_debugging() > 1)
1725
0
        dump_module_list();
1726
1.09k
    DEBUGMSGTL(("parse-mibs", "Processing IMPORTS for module %d %s\n",
1727
1.09k
                mp->modid, mp->name));
1728
1.09k
    if (mp->no_imports == 0) {
1729
958
        mp->no_imports = NUMBER_OF_ROOT_NODES;
1730
958
        mp->imports = root_imports;
1731
958
    }
1732
1733
    /*
1734
     * Build the tree
1735
     */
1736
1.09k
    init_node_hash(np);
1737
4.64k
    for (i = 0, mip = mp->imports; i < mp->no_imports; ++i, ++mip) {
1738
3.55k
        char            modbuf[256];
1739
3.55k
        DEBUGMSGTL(("parse-mibs", "  Processing import: %s\n",
1740
3.55k
                    mip->label));
1741
3.55k
        if (get_tc_index(mip->label, mip->modid) != -1)
1742
0
            continue;
1743
3.55k
        tp = find_tree_node(mip->label, mip->modid);
1744
3.55k
        if (!tp) {
1745
415
      if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_ERRORS))
1746
415
                snmp_log(LOG_WARNING,
1747
415
                         "Did not find '%s' in module %s (%s)\n",
1748
415
                         mip->label, module_name(mip->modid, modbuf),
1749
415
                         File);
1750
415
            continue;
1751
415
        }
1752
3.13k
        do_subtree(tp, &np);
1753
3.13k
    }
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.09k
    if (!np)
1762
367
        return;
1763
2.92k
    for (tp = tree_head; tp; tp = tp->next_peer)
1764
2.19k
        do_subtree(tp, &np);
1765
731
    if (!np)
1766
0
        return;
1767
1768
    /*
1769
     * quietly move all internal references to the orphan list 
1770
     */
1771
731
    oldp = orphan_nodes;
1772
953
    do {
1773
122k
        for (i = 0; i < NHASHSIZE; i++)
1774
130k
            for (onp = nbuckets[i]; onp; onp = onp->next) {
1775
8.98k
                struct node    *op = NULL;
1776
8.98k
                int             hash = NBUCKET(name_hash(onp->label));
1777
8.98k
                np = nbuckets[hash];
1778
13.2k
                while (np) {
1779
4.24k
                    if (label_compare(onp->label, np->parent)) {
1780
1.96k
                        op = np;
1781
1.96k
                        np = np->next;
1782
2.27k
                    } else {
1783
2.27k
                        if (op)
1784
206
                            op->next = np->next;
1785
2.06k
                        else
1786
2.06k
                            nbuckets[hash] = np->next;
1787
2.27k
      DEBUGMSGTL(("parse-mibs", "Moving %s to orphanage", np->label));
1788
2.27k
                        np->next = orphan_nodes;
1789
2.27k
                        orphan_nodes = np;
1790
2.27k
                        op = NULL;
1791
2.27k
                        np = nbuckets[hash];
1792
2.27k
                    }
1793
4.24k
                }
1794
8.98k
            }
1795
953
        newp = orphan_nodes;
1796
953
        more = 0;
1797
4.25k
        for (onp = orphan_nodes; onp != oldp; onp = onp->next) {
1798
3.30k
            struct node    *op = NULL;
1799
3.30k
            int             hash = NBUCKET(name_hash(onp->label));
1800
3.30k
            np = nbuckets[hash];
1801
4.67k
            while (np) {
1802
1.37k
                if (label_compare(onp->label, np->parent)) {
1803
342
                    op = np;
1804
342
                    np = np->next;
1805
1.03k
                } else {
1806
1.03k
                    if (op)
1807
34
                        op->next = np->next;
1808
996
                    else
1809
996
                        nbuckets[hash] = np->next;
1810
1.03k
                    np->next = orphan_nodes;
1811
1.03k
                    orphan_nodes = np;
1812
1.03k
                    op = NULL;
1813
1.03k
                    np = nbuckets[hash];
1814
1.03k
                    more = 1;
1815
1.03k
                }
1816
1.37k
            }
1817
3.30k
        }
1818
953
        oldp = newp;
1819
953
    } while (more);
1820
1821
    /*
1822
     * complain about left over nodes 
1823
     */
1824
52.8k
    for (np = orphan_nodes; np && np->next; np = np->next);     /* find the end of the orphan list */
1825
94.2k
    for (i = 0; i < NHASHSIZE; i++)
1826
93.5k
        if (nbuckets[i]) {
1827
277
            if (orphan_nodes)
1828
277
                onp = np->next = nbuckets[i];
1829
0
            else
1830
0
                onp = orphan_nodes = nbuckets[i];
1831
277
            nbuckets[i] = NULL;
1832
568
            while (onp) {
1833
291
                snmp_log(LOG_WARNING,
1834
291
                         "Cannot resolve OID in %s: %s ::= { %s %ld } at line %d in %s\n",
1835
291
                         (mp->name ? mp->name : "<no module>"),
1836
291
                         (onp->label ? onp->label : "<no label>"),
1837
291
                         (onp->parent ? onp->parent : "<no parent>"),
1838
291
                         onp->subid, onp->lineno, onp->filename);
1839
291
                np = onp;
1840
291
                onp = onp->next;
1841
291
            }
1842
277
        }
1843
731
    return;
1844
731
}
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.50k
{
1861
1.50k
    struct subid_s *id = id_arg;
1862
1.50k
    int             i, count, type;
1863
1.50k
    char            token[MAXTOKEN];
1864
1865
1.50k
    if ((type = get_token(fp, token, MAXTOKEN)) != LEFTBRACKET) {
1866
144
        print_error("Expected \"{\"", token, type);
1867
144
        return 0;
1868
144
    }
1869
1.35k
    type = get_token(fp, token, MAXTOKEN);
1870
17.8k
    for (count = 0; count < length; count++, id++) {
1871
17.8k
        id->label = NULL;
1872
17.8k
        id->modid = current_module;
1873
17.8k
        id->subid = -1;
1874
17.8k
        if (type == RIGHTBRACKET)
1875
1.27k
            return count;
1876
16.5k
        if (type == LABEL) {
1877
            /*
1878
             * this entry has a label 
1879
             */
1880
13.6k
            id->label = strdup(token);
1881
13.6k
            type = get_token(fp, token, MAXTOKEN);
1882
13.6k
            if (type == LEFTPAREN) {
1883
40
                type = get_token(fp, token, MAXTOKEN);
1884
40
                if (type == NUMBER) {
1885
20
                    id->subid = strtoul(token, NULL, 10);
1886
20
                    if ((type =
1887
20
                         get_token(fp, token, MAXTOKEN)) != RIGHTPAREN) {
1888
8
                        print_error("Expected a closing parenthesis",
1889
8
                                    token, type);
1890
8
                        goto free_labels;
1891
8
                    }
1892
20
                } else {
1893
20
                    print_error("Expected a number", token, type);
1894
20
                    goto free_labels;
1895
20
                }
1896
13.5k
            } else {
1897
13.5k
                continue;
1898
13.5k
            }
1899
13.6k
        } else if (type == NUMBER) {
1900
            /*
1901
             * this entry  has just an integer sub-identifier 
1902
             */
1903
2.90k
            id->subid = strtoul(token, NULL, 10);
1904
2.90k
        } else {
1905
56
            print_error("Expected label or number", token, type);
1906
56
            goto free_labels;
1907
56
        }
1908
2.91k
        type = get_token(fp, token, MAXTOKEN);
1909
2.91k
    }
1910
1
    print_error("Too long OID", token, type);
1911
1
    --count;
1912
1913
85
free_labels:
1914
739
    for (i = 0; i <= count; i++) {
1915
654
        free(id_arg[i].label);
1916
654
        id_arg[i].label = NULL;
1917
654
    }
1918
1919
85
    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.50k
{
1947
1.50k
    register int    count;
1948
1.50k
    register struct subid_s *op, *nop;
1949
1.50k
    int             length;
1950
1.50k
    struct subid_s  loid[32];
1951
1.50k
    struct node    *np, *root = NULL, *oldnp = NULL;
1952
1.50k
    struct tree    *tp;
1953
1954
1.50k
    if ((length = getoid(fp, loid, 32)) == 0) {
1955
232
        print_error("Bad object identifier", NULL, CONTINUE);
1956
232
        return NULL;
1957
232
    }
1958
1959
    /*
1960
     * Handle numeric-only object identifiers,
1961
     *  by labeling the first sub-identifier
1962
     */
1963
1.27k
    op = loid;
1964
1.27k
    if (!op->label) {
1965
688
        if (length == 1) {
1966
10
            print_error("Attempt to define a root oid", name, OBJECT);
1967
10
            return NULL;
1968
10
        }
1969
1.66k
        for (tp = tree_head; tp; tp = tp->next_peer)
1970
1.50k
            if ((int) tp->subid == op->subid) {
1971
526
                op->label = strdup(tp->label);
1972
526
                break;
1973
526
            }
1974
678
    }
1975
1976
    /*
1977
     * Handle  "label OBJECT-IDENTIFIER ::= { subid }"
1978
     */
1979
1.26k
    if (length == 1) {
1980
76
        op = loid;
1981
76
        np = alloc_node(op->modid);
1982
76
        if (np == NULL)
1983
0
            return (NULL);
1984
76
        np->subid = op->subid;
1985
76
        np->label = strdup(name);
1986
76
        np->parent = op->label;
1987
76
        return np;
1988
76
    }
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
15.8k
    for (count = 0, op = loid, nop = loid + 1; count < (length - 1);
1995
14.6k
         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.6k
        if (op->label && (nop->label || (nop->subid != -1))) {
2003
14.4k
            np = alloc_node(nop->modid);
2004
14.4k
            if (np == NULL)
2005
0
                goto err;
2006
14.4k
            if (root == NULL) {
2007
1.18k
                root = np;
2008
13.2k
            } else {
2009
13.2k
                netsnmp_assert(oldnp);
2010
13.2k
                oldnp->next = np;
2011
13.2k
            }
2012
14.4k
            oldnp = np;
2013
2014
14.4k
            np->parent = strdup(op->label);
2015
14.4k
            if (count == (length - 2)) {
2016
                /*
2017
                 * The name for this node is the label for this entry 
2018
                 */
2019
1.18k
                np->label = strdup(name);
2020
1.18k
                if (np->label == NULL)
2021
0
                    goto err;
2022
13.2k
            } else {
2023
13.2k
                if (!nop->label) {
2024
1.85k
                    if (asprintf(&nop->label, "%s%d", ANON, anonymous++) < 0)
2025
0
                        goto err;
2026
1.85k
                }
2027
13.2k
                np->label = strdup(nop->label);
2028
13.2k
            }
2029
14.4k
            if (nop->subid != -1)
2030
2.10k
                np->subid = nop->subid;
2031
12.3k
            else
2032
12.3k
                print_error("Warning: This entry is pretty silly",
2033
12.3k
                            np->label, CONTINUE);
2034
14.4k
        }                       /* end if(op->label... */
2035
14.6k
    }
2036
2037
1.18k
out:
2038
    /*
2039
     * free the loid array 
2040
     */
2041
17.0k
    for (count = 0, op = loid; count < length; count++, op++) {
2042
15.8k
        free(op->label);
2043
15.8k
        op->label = NULL;
2044
15.8k
    }
2045
2046
1.18k
    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.18k
}
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
575
{
2062
575
    int             i;
2063
575
    struct tc      *tcp;
2064
2065
575
    i = get_tc_index(descriptor, modid);
2066
575
    if (tc_index)
2067
33
        *tc_index = i;
2068
575
    if (i != -1) {
2069
21
        tcp = &tclist[i];
2070
21
        if (ep) {
2071
6
            free_enums(ep);
2072
6
            *ep = copy_enums(tcp->enums);
2073
6
        }
2074
21
        if (rp) {
2075
6
            free_ranges(rp);
2076
6
            *rp = copy_ranges(tcp->ranges);
2077
6
        }
2078
21
        if (hint) {
2079
6
            if (*hint)
2080
0
                free(*hint);
2081
6
            *hint = (tcp->hint ? strdup(tcp->hint) : NULL);
2082
6
        }
2083
21
        return tcp->type;
2084
21
    }
2085
554
    return LABEL;
2086
575
}
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.12k
{
2095
4.12k
    int             i;
2096
4.12k
    struct tc      *tcp;
2097
4.12k
    struct module  *mp;
2098
4.12k
    struct module_import *mip;
2099
2100
    /*
2101
     * Check that the descriptor isn't imported
2102
     *  by searching the import list
2103
     */
2104
2105
8.06k
    for (mp = module_head; mp; mp = mp->next)
2106
4.51k
        if (mp->modid == modid)
2107
575
            break;
2108
4.12k
    if (mp)
2109
1.00k
        for (i = 0, mip = mp->imports; i < mp->no_imports; ++i, ++mip) {
2110
451
            if (!label_compare(mip->label, descriptor)) {
2111
                /*
2112
                 * Found it - so amend the module ID 
2113
                 */
2114
22
                modid = mip->modid;
2115
22
                break;
2116
22
            }
2117
451
        }
2118
2119
2120
4.44k
    for (i = 0, tcp = tclist; i < tc_alloc; i++, tcp++) {
2121
4.44k
        if (tcp->type == 0)
2122
4.10k
            break;
2123
339
        if (!label_compare(descriptor, tcp->descriptor) &&
2124
25
            ((modid == tcp->modid) || (modid == -1))) {
2125
21
            return i;
2126
21
        }
2127
339
    }
2128
4.10k
    return -1;
2129
4.12k
}
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
114
{
2166
114
    register int    type;
2167
114
    char            token[MAXTOKEN];
2168
114
    struct enum_list *ep = NULL, **epp = &ep;
2169
2170
114
    free_enums(retp);
2171
2172
577
    while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE) {
2173
551
        if (type == RIGHTBRACKET)
2174
18
            break;
2175
        /* some enums use "deprecated" to indicate a no longer value label */
2176
        /* (EG: IP-MIB's IpAddressStatusTC) */
2177
533
        if (type == LABEL || type == DEPRECATED) {
2178
            /*
2179
             * this is an enumerated label 
2180
             */
2181
291
            *epp = calloc(1, sizeof(struct enum_list));
2182
291
            if (*epp == NULL)
2183
0
                return (NULL);
2184
            /*
2185
             * a reasonable approximation for the length 
2186
             */
2187
291
            (*epp)->label = strdup(token);
2188
291
            type = get_token(fp, token, MAXTOKEN);
2189
291
            if (type != LEFTPAREN) {
2190
47
                print_error("Expected \"(\"", token, type);
2191
47
                goto err;
2192
47
            }
2193
244
            type = get_token(fp, token, MAXTOKEN);
2194
244
            if (type != NUMBER) {
2195
16
                print_error("Expected integer", token, type);
2196
16
                goto err;
2197
16
            }
2198
228
            (*epp)->value = strtol(token, NULL, 10);
2199
228
            (*epp)->lineno = mibLine;
2200
228
            type = get_token(fp, token, MAXTOKEN);
2201
228
            if (type != RIGHTPAREN) {
2202
7
                print_error("Expected \")\"", token, type);
2203
7
                goto err;
2204
221
            } else {
2205
221
                struct enum_list *op = ep;
2206
455
                while (op != *epp) {
2207
277
                    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
267
                    else if ((*epp)->value == op->value) {
2215
33
                        snmp_log(LOG_ERR,
2216
33
                            "Duplicate enum value '%d' at line %d in %s. First at line %d\n",
2217
33
                            (*epp)->value, mibLine, File, op->lineno);
2218
33
                        erroneousMibs++;
2219
33
                        break;
2220
33
                    }
2221
234
                    op = op->next;
2222
234
                }
2223
221
            }
2224
221
            epp = &(*epp)->next;
2225
221
        }
2226
533
    }
2227
44
    if (type == ENDOFFILE) {
2228
26
        print_error("Expected \"}\"", token, type);
2229
26
        goto err;
2230
26
    }
2231
18
    *retp = ep;
2232
18
    return ep;
2233
2234
96
err:
2235
96
    free_enums(&ep);
2236
96
    return NULL;
2237
44
}
2238
2239
static struct range_list *
2240
parse_ranges(FILE * fp, struct range_list **retp)
2241
55
{
2242
55
    int             low, high;
2243
55
    char            nexttoken[MAXTOKEN];
2244
55
    int             nexttype;
2245
55
    struct range_list *rp = NULL, **rpp = &rp;
2246
55
    int             size = 0, taken = 1;
2247
2248
55
    free_ranges(retp);
2249
2250
55
    nexttype = get_token(fp, nexttoken, MAXTOKEN);
2251
55
    if (nexttype == SIZE) {
2252
22
        size = 1;
2253
22
        taken = 0;
2254
22
        nexttype = get_token(fp, nexttoken, MAXTOKEN);
2255
22
        if (nexttype != LEFTPAREN)
2256
11
            print_error("Expected \"(\" after SIZE", nexttoken, nexttype);
2257
22
    }
2258
2259
104
    do {
2260
104
        if (!taken)
2261
71
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2262
33
        else
2263
33
            taken = 0;
2264
104
        high = low = strtoul(nexttoken, NULL, 10);
2265
104
        nexttype = get_token(fp, nexttoken, MAXTOKEN);
2266
104
        if (nexttype == RANGE) {
2267
35
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2268
35
            errno = 0;
2269
35
            high = strtoul(nexttoken, NULL, 10);
2270
35
            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
35
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2278
35
        }
2279
104
        *rpp = (struct range_list *) calloc(1, sizeof(struct range_list));
2280
104
        if (*rpp == NULL)
2281
0
            break;
2282
104
        (*rpp)->low = low;
2283
104
        (*rpp)->high = high;
2284
104
        rpp = &(*rpp)->next;
2285
2286
104
    } while (nexttype == BAR);
2287
55
    if (size) {
2288
22
        if (nexttype != RIGHTPAREN)
2289
13
            print_error("Expected \")\" after SIZE", nexttoken, nexttype);
2290
22
        nexttype = get_token(fp, nexttoken, MAXTOKEN);
2291
22
    }
2292
55
    if (nexttype != RIGHTPAREN)
2293
38
        print_error("Expected \")\"", nexttoken, nexttype);
2294
2295
55
    *retp = rp;
2296
55
    return rp;
2297
55
}
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.21k
{
2306
2.21k
    int             type, i;
2307
2.21k
    char            token[MAXTOKEN];
2308
2.21k
    char            quoted_string_buffer[MAXQUOTESTR];
2309
2.21k
    char           *hint = NULL;
2310
2.21k
    char           *descr = NULL;
2311
2.21k
    struct tc      *tcp;
2312
2.21k
    int             level;
2313
2314
2.21k
    type = get_token(fp, token, MAXTOKEN);
2315
2.21k
    if (type == SEQUENCE || type == CHOICE) {
2316
28
        level = 0;
2317
456
        while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE) {
2318
437
            if (type == LEFTBRACKET) {
2319
93
                level++;
2320
344
            } else if (type == RIGHTBRACKET && --level == 0) {
2321
9
                *ntype = get_token(fp, ntoken, MAXTOKEN);
2322
9
                return NULL;
2323
9
            }
2324
437
        }
2325
19
        print_error("Expected \"}\"", token, type);
2326
19
        return NULL;
2327
2.18k
    } else if (type == LEFTBRACKET) {
2328
1.11k
        struct node    *np;
2329
1.11k
        int             ch_next = '{';
2330
1.11k
        ungetc(ch_next, fp);
2331
1.11k
        np = parse_objectid(fp, name);
2332
1.11k
        if (np != NULL) {
2333
1.01k
            *ntype = get_token(fp, ntoken, MAXTOKEN);
2334
1.01k
            return np;
2335
1.01k
        }
2336
94
        return NULL;
2337
1.11k
    } else if (type == LEFTSQBRACK) {
2338
75
        int             size = 0;
2339
329
        do {
2340
329
            type = get_token(fp, token, MAXTOKEN);
2341
329
        } while (type != ENDOFFILE && type != RIGHTSQBRACK);
2342
75
        if (type != RIGHTSQBRACK) {
2343
6
            print_error("Expected \"]\"", token, type);
2344
6
            return NULL;
2345
6
        }
2346
69
        type = get_token(fp, token, MAXTOKEN);
2347
69
        if (type == IMPLICIT)
2348
1
            type = get_token(fp, token, MAXTOKEN);
2349
69
        *ntype = get_token(fp, ntoken, MAXTOKEN);
2350
69
        if (*ntype == LEFTPAREN) {
2351
38
            switch (type) {
2352
3
            case OCTETSTR:
2353
3
                *ntype = get_token(fp, ntoken, MAXTOKEN);
2354
3
                if (*ntype != SIZE) {
2355
3
                    print_error("Expected SIZE", ntoken, *ntype);
2356
3
                    return NULL;
2357
3
                }
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
27
            case INTEGER:
2367
27
                *ntype = get_token(fp, ntoken, MAXTOKEN);
2368
210
                do {
2369
210
                    if (*ntype != NUMBER)
2370
207
                        print_error("Expected NUMBER", ntoken, *ntype);
2371
210
                    *ntype = get_token(fp, ntoken, MAXTOKEN);
2372
210
                    if (*ntype == RANGE) {
2373
17
                        *ntype = get_token(fp, ntoken, MAXTOKEN);
2374
17
                        if (*ntype != NUMBER)
2375
11
                            print_error("Expected NUMBER", ntoken, *ntype);
2376
17
                        *ntype = get_token(fp, ntoken, MAXTOKEN);
2377
17
                    }
2378
210
                } while (*ntype == BAR);
2379
27
                if (*ntype != RIGHTPAREN) {
2380
24
                    print_error("Expected \")\"", ntoken, *ntype);
2381
24
                    return NULL;
2382
24
                }
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
38
            }
2393
38
        }
2394
42
        return NULL;
2395
998
    } else {
2396
998
        if (type == CONVENTION) {
2397
145
            while (type != SYNTAX && type != ENDOFFILE) {
2398
127
                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
123
                } else if (type == DESCRIPTION &&
2408
4
                           netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
2409
4
                                                  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
123
                    type =
2420
123
                        get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2421
127
            }
2422
18
            type = get_token(fp, token, MAXTOKEN);
2423
18
            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
980
        } else if (type == OBJECT) {
2432
12
            type = get_token(fp, token, MAXTOKEN);
2433
12
            if (type != IDENTIFIER) {
2434
8
                print_error("Expected IDENTIFIER", token, type);
2435
8
                goto err;
2436
8
            }
2437
4
            type = OBJID;
2438
4
        }
2439
2440
990
        if (type == LABEL) {
2441
542
            type = get_tc(token, current_module, NULL, NULL, NULL, NULL);
2442
542
        }
2443
2444
        /*
2445
         * textual convention 
2446
         */
2447
990
        tcp = NULL;
2448
99.9k
        for (i = 0; i < tc_alloc; i++) {
2449
99.0k
            if (tclist[i].type == 0) {
2450
98.6k
                if (tcp == NULL)
2451
990
                    tcp = &tclist[i];
2452
98.6k
            } else if (strcmp(name, tclist[i].descriptor) == 0 &&
2453
60
                       tclist[i].modid == current_module) {
2454
56
                snmp_log(LOG_ERR,
2455
56
                         "Duplicate TEXTUAL-CONVENTION '%s' at line %d in %s. First at line %d\n",
2456
56
                         name, mibLine, File, tclist[i].lineno);
2457
56
                erroneousMibs++;
2458
56
            }
2459
99.0k
        }
2460
2461
990
        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
990
        if (!(type & SYNTAX_MASK)) {
2468
611
            print_error("Textual convention doesn't map to real type",
2469
611
                        token, type);
2470
611
            goto err;
2471
611
        }
2472
379
        tcp->modid = current_module;
2473
379
        tcp->descriptor = strdup(name);
2474
379
        tcp->hint = hint;
2475
379
        tcp->description = descr;
2476
379
        tcp->lineno = mibLine;
2477
379
        tcp->type = type;
2478
379
        *ntype = get_token(fp, ntoken, MAXTOKEN);
2479
379
        if (*ntype == LEFTPAREN) {
2480
44
            tcp->ranges = parse_ranges(fp, &tcp->ranges);
2481
44
            *ntype = get_token(fp, ntoken, MAXTOKEN);
2482
335
        } else if (*ntype == LEFTBRACKET) {
2483
            /*
2484
             * if there is an enumeration list, parse it 
2485
             */
2486
110
            tcp->enums = parse_enumlist(fp, &tcp->enums);
2487
110
            *ntype = get_token(fp, ntoken, MAXTOKEN);
2488
110
        }
2489
379
        return NULL;
2490
990
    }
2491
2492
619
err:
2493
619
    SNMP_FREE(descr);
2494
619
    SNMP_FREE(hint);
2495
619
    return NULL;
2496
2.21k
}
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
98
{
2506
98
    register int    type;
2507
98
    char            token[MAXTOKEN];
2508
98
    char            nexttoken[MAXTOKEN];
2509
98
    char            quoted_string_buffer[MAXQUOTESTR];
2510
98
    int             nexttype, tctype;
2511
98
    register struct node *np;
2512
2513
98
    type = get_token(fp, token, MAXTOKEN);
2514
98
    if (type != SYNTAX) {
2515
4
        print_error("Bad format for OBJECT-TYPE", token, type);
2516
4
        return NULL;
2517
4
    }
2518
94
    np = alloc_node(current_module);
2519
94
    if (np == NULL)
2520
0
        return (NULL);
2521
94
    type = get_token(fp, token, MAXTOKEN);
2522
94
    if (type == OBJECT) {
2523
5
        type = get_token(fp, token, MAXTOKEN);
2524
5
        if (type != IDENTIFIER) {
2525
0
            print_error("Expected IDENTIFIER", token, type);
2526
0
            free_node(np);
2527
0
            return NULL;
2528
0
        }
2529
5
        type = OBJID;
2530
5
    }
2531
94
    if (type == LABEL) {
2532
33
        int             tmp_index;
2533
33
        tctype = get_tc(token, current_module, &tmp_index,
2534
33
                        &np->enums, &np->ranges, &np->hint);
2535
33
        if (tctype == LABEL &&
2536
27
            netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
2537
27
             NETSNMP_DS_LIB_MIB_WARNINGS) > 1) {
2538
0
            print_error("Warning: No known translation for type", token,
2539
0
                        type);
2540
0
        }
2541
33
        type = tctype;
2542
33
        np->tc_index = tmp_index;       /* store TC for later reference */
2543
33
    }
2544
94
    np->type = type;
2545
94
    nexttype = get_token(fp, nexttoken, MAXTOKEN);
2546
94
    switch (type) {
2547
6
    case SEQUENCE:
2548
6
        if (nexttype == OF) {
2549
6
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2550
6
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2551
2552
6
        }
2553
6
        break;
2554
10
    case INTEGER:
2555
11
    case INTEGER32:
2556
11
    case UINTEGER32:
2557
11
    case UNSIGNED32:
2558
44
    case COUNTER:
2559
46
    case GAUGE:
2560
46
    case BITSTRING:
2561
73
    case LABEL:
2562
73
        if (nexttype == LEFTBRACKET) {
2563
            /*
2564
             * if there is an enumeration list, parse it 
2565
             */
2566
4
            np->enums = parse_enumlist(fp, &np->enums);
2567
4
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2568
69
        } else if (nexttype == LEFTPAREN) {
2569
            /*
2570
             * if there is a range list, parse it 
2571
             */
2572
11
            np->ranges = parse_ranges(fp, &np->ranges);
2573
11
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2574
11
        }
2575
73
        break;
2576
9
    case OCTETSTR:
2577
9
    case KW_OPAQUE:
2578
        /*
2579
         * parse any SIZE specification 
2580
         */
2581
9
        if (nexttype == LEFTPAREN) {
2582
0
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
2583
0
            if (nexttype == SIZE) {
2584
0
                nexttype = get_token(fp, nexttoken, MAXTOKEN);
2585
0
                if (nexttype == LEFTPAREN) {
2586
0
                    np->ranges = parse_ranges(fp, &np->ranges);
2587
0
                    nexttype = get_token(fp, nexttoken, MAXTOKEN);      /* ) */
2588
0
                    if (nexttype == RIGHTPAREN) {
2589
0
                        nexttype = get_token(fp, nexttoken, MAXTOKEN);
2590
0
                        break;
2591
0
                    }
2592
0
                }
2593
0
            }
2594
0
            print_error("Bad SIZE syntax", token, type);
2595
0
            free_node(np);
2596
0
            return NULL;
2597
0
        }
2598
9
        break;
2599
9
    case OBJID:
2600
5
    case NETADDR:
2601
5
    case IPADDR:
2602
6
    case TIMETICKS:
2603
6
    case NUL:
2604
6
    case NSAPADDRESS:
2605
6
    case COUNTER64:
2606
6
        break;
2607
0
    default:
2608
0
        print_error("Bad syntax", token, type);
2609
0
        free_node(np);
2610
0
        return NULL;
2611
94
    }
2612
94
    if (nexttype == UNITS) {
2613
0
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2614
0
        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
0
        np->units = strdup(quoted_string_buffer);
2620
0
        nexttype = get_token(fp, nexttoken, MAXTOKEN);
2621
0
    }
2622
94
    if (nexttype != ACCESS) {
2623
0
        print_error("Should be ACCESS", nexttoken, nexttype);
2624
0
        free_node(np);
2625
0
        return NULL;
2626
0
    }
2627
94
    type = get_token(fp, token, MAXTOKEN);
2628
94
    if (type != READONLY && type != READWRITE && type != WRITEONLY
2629
27
        && 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
94
    np->access = type;
2635
94
    type = get_token(fp, token, MAXTOKEN);
2636
94
    if (type != STATUS) {
2637
0
        print_error("Should be STATUS", token, type);
2638
0
        free_node(np);
2639
0
        return NULL;
2640
0
    }
2641
94
    type = get_token(fp, token, MAXTOKEN);
2642
94
    if (type != MANDATORY && type != CURRENT && type != KW_OPTIONAL &&
2643
30
        type != OBSOLETE && type != DEPRECATED) {
2644
0
        print_error("Bad STATUS", token, type);
2645
0
        free_node(np);
2646
0
        return NULL;
2647
0
    }
2648
94
    np->status = type;
2649
    /*
2650
     * Optional parts of the OBJECT-TYPE macro
2651
     */
2652
94
    type = get_token(fp, token, MAXTOKEN);
2653
197
    while (type != EQUALS && type != ENDOFFILE) {
2654
103
        switch (type) {
2655
94
        case DESCRIPTION:
2656
94
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2657
2658
94
            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
94
            if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
2664
94
               NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
2665
0
                np->description = strdup(quoted_string_buffer);
2666
0
            }
2667
94
            break;
2668
2669
3
        case REFERENCE:
2670
3
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2671
3
            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
3
            np->reference = strdup(quoted_string_buffer);
2677
3
            break;
2678
5
        case INDEX:
2679
5
            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
5
            np->indexes = getIndexes(fp, &np->indexes);
2686
5
            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
5
            break;
2692
5
        case AUGMENTS:
2693
1
            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
1
            np->indexes = getIndexes(fp, &np->indexes);
2700
1
            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
1
            np->augments = strdup(np->indexes->ilabel);
2706
1
            free_indexes(&np->indexes);
2707
1
            break;
2708
0
        case DEFVAL:
2709
            /*
2710
             * Mark's defVal section 
2711
             */
2712
0
            type = get_token(fp, quoted_string_buffer,
2713
0
                             sizeof(quoted_string_buffer));
2714
0
            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
0
            {
2722
0
                int             level = 1;
2723
0
                char            defbuf[512];
2724
2725
0
                defbuf[0] = 0;
2726
0
                while (1) {
2727
0
                    type = get_token(fp, quoted_string_buffer,
2728
0
                                     sizeof(quoted_string_buffer));
2729
0
                    if ((type == RIGHTBRACKET && --level == 0)
2730
0
                        || type == ENDOFFILE)
2731
0
                        break;
2732
0
                    else if (type == LEFTBRACKET)
2733
0
                        level++;
2734
0
                    if (type == QUOTESTRING)
2735
0
                        strlcat(defbuf, "\\\"", sizeof(defbuf));
2736
0
                    strlcat(defbuf, quoted_string_buffer, sizeof(defbuf));
2737
0
                    if (type == QUOTESTRING)
2738
0
                        strlcat(defbuf, "\\\"", sizeof(defbuf));
2739
0
                    strlcat(defbuf, " ", sizeof(defbuf));
2740
0
                }
2741
2742
0
                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
0
                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
0
                defbuf[strlen(defbuf) - 1] = 0;
2759
0
                np->defaultValue = strdup(defbuf);
2760
0
            }
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
103
        }
2778
103
        type = get_token(fp, token, MAXTOKEN);
2779
103
    }
2780
94
    if (type != EQUALS) {
2781
0
        print_error("Bad format", token, type);
2782
0
        free_node(np);
2783
0
        return NULL;
2784
0
    }
2785
94
    return merge_parse_objectid(np, fp, name);
2786
94
}
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
77
{
2798
77
    int             type;
2799
77
    char            token[MAXTOKEN];
2800
77
    char            quoted_string_buffer[MAXQUOTESTR];
2801
77
    struct node    *np;
2802
2803
77
    np = alloc_node(current_module);
2804
77
    if (np == NULL)
2805
0
        return (NULL);
2806
77
    type = get_token(fp, token, MAXTOKEN);
2807
77
    if (type == what) {
2808
53
        type = get_token(fp, token, MAXTOKEN);
2809
53
        if (type != LEFTBRACKET) {
2810
1
            print_error("Expected \"{\"", token, type);
2811
1
            goto skip;
2812
1
        }
2813
167
        do {
2814
167
            struct objgroup *o;
2815
167
            type = get_token(fp, token, MAXTOKEN);
2816
167
            if (type != LABEL) {
2817
2
                print_error("Bad identifier", token, type);
2818
2
                goto skip;
2819
2
            }
2820
165
            o = (struct objgroup *) malloc(sizeof(struct objgroup));
2821
165
            if (!o) {
2822
0
                print_error("Resource failure", token, type);
2823
0
                goto skip;
2824
0
            }
2825
165
            o->line = mibLine;
2826
165
            o->name = strdup(token);
2827
165
            o->next = *ol;
2828
165
            *ol = o;
2829
165
            type = get_token(fp, token, MAXTOKEN);
2830
165
        } while (type == COMMA);
2831
50
        if (type != RIGHTBRACKET) {
2832
30
            print_error("Expected \"}\" after list", token, type);
2833
30
            goto skip;
2834
30
        }
2835
20
        type = get_token(fp, token, type);
2836
20
    }
2837
44
    if (type != STATUS) {
2838
27
        print_error("Expected STATUS", token, type);
2839
27
        goto skip;
2840
27
    }
2841
17
    type = get_token(fp, token, MAXTOKEN);
2842
17
    if (type != CURRENT && type != DEPRECATED && type != OBSOLETE) {
2843
0
        print_error("Bad STATUS value", token, type);
2844
0
        goto skip;
2845
0
    }
2846
17
    type = get_token(fp, token, MAXTOKEN);
2847
17
    if (type != DESCRIPTION) {
2848
0
        print_error("Expected DESCRIPTION", token, type);
2849
0
        goto skip;
2850
0
    }
2851
17
    type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2852
17
    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
17
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
2858
17
             NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
2859
0
        np->description = strdup(quoted_string_buffer);
2860
0
    }
2861
17
    type = get_token(fp, token, MAXTOKEN);
2862
17
    if (type == REFERENCE) {
2863
0
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2864
0
        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
0
        np->reference = strdup(quoted_string_buffer);
2870
0
        type = get_token(fp, token, MAXTOKEN);
2871
0
    }
2872
17
    if (type != EQUALS)
2873
0
        print_error("Expected \"::=\"", token, type);
2874
77
  skip:
2875
279
    while (type != EQUALS && type != ENDOFFILE)
2876
202
        type = get_token(fp, token, MAXTOKEN);
2877
2878
77
    return merge_parse_objectid(np, fp, name);
2879
17
}
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
59
{
2888
59
    register int    type;
2889
59
    char            token[MAXTOKEN];
2890
59
    char            quoted_string_buffer[MAXQUOTESTR];
2891
59
    register struct node *np;
2892
2893
59
    np = alloc_node(current_module);
2894
59
    if (np == NULL)
2895
0
        return (NULL);
2896
59
    type = get_token(fp, token, MAXTOKEN);
2897
278
    while (type != EQUALS && type != ENDOFFILE) {
2898
234
        switch (type) {
2899
9
        case DESCRIPTION:
2900
9
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2901
9
            if (type != QUOTESTRING) {
2902
5
                print_error("Bad DESCRIPTION", quoted_string_buffer, type);
2903
5
                goto free_node;
2904
5
            }
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
6
        case REFERENCE:
2911
6
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2912
6
            if (type != QUOTESTRING) {
2913
3
                print_error("Bad REFERENCE", quoted_string_buffer, type);
2914
3
                goto free_node;
2915
3
            }
2916
3
            free(np->reference);
2917
3
            np->reference = strdup(quoted_string_buffer);
2918
3
            break;
2919
37
        case OBJECTS:
2920
37
            np->varbinds = getVarbinds(fp, &np->varbinds);
2921
37
            if (!np->varbinds) {
2922
7
                print_error("Bad OBJECTS list", token, type);
2923
7
                goto free_node;
2924
7
            }
2925
30
            break;
2926
182
        default:
2927
            /*
2928
             * NOTHING 
2929
             */
2930
182
            break;
2931
234
        }
2932
219
        type = get_token(fp, token, MAXTOKEN);
2933
219
    }
2934
44
    return merge_parse_objectid(np, fp, name);
2935
2936
15
free_node:
2937
15
    free_node(np);
2938
15
    return NULL;
2939
59
}
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
43
{
2948
43
    register int    type;
2949
43
    char            token[MAXTOKEN];
2950
43
    char            quoted_string_buffer[MAXQUOTESTR];
2951
43
    register struct node *np;
2952
2953
43
    np = alloc_node(current_module);
2954
43
    if (np == NULL)
2955
0
        return (NULL);
2956
43
    type = get_token(fp, token, MAXTOKEN);
2957
393
    while (type != EQUALS && type != ENDOFFILE) {
2958
370
        switch (type) {
2959
8
        case DESCRIPTION:
2960
8
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2961
8
            if (type != QUOTESTRING) {
2962
6
                print_error("Bad DESCRIPTION", quoted_string_buffer, type);
2963
6
                goto free_node;
2964
6
            }
2965
2
            if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
2966
2
               NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
2967
0
                np->description = strdup(quoted_string_buffer);
2968
0
            }
2969
2
            break;
2970
11
        case REFERENCE:
2971
            /* I'm not sure REFERENCEs are legal in smiv1 traps??? */
2972
11
            type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2973
11
            if (type != QUOTESTRING) {
2974
8
                print_error("Bad REFERENCE", quoted_string_buffer, type);
2975
8
                goto free_node;
2976
8
            }
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
4
                np->parent = strdup(token);
2994
4
            } else {
2995
4
                goto free_node;
2996
4
            }
2997
5
            break;
2998
5
        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
339
        default:
3006
            /*
3007
             * NOTHING 
3008
             */
3009
339
            break;
3010
370
        }
3011
350
        type = get_token(fp, token, MAXTOKEN);
3012
350
    }
3013
23
    type = get_token(fp, token, MAXTOKEN);
3014
3015
23
    np->label = strdup(name);
3016
3017
23
    if (type != NUMBER) {
3018
21
        print_error("Expected a Number", token, type);
3019
21
        goto free_node;
3020
21
    }
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
42
free_node:
3043
42
    free_node(np);
3044
42
    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
0
{
3055
0
    int             type, nexttype;
3056
0
    struct node    *np = alloc_node(current_module);
3057
0
    char            nexttoken[MAXTOKEN];
3058
3059
0
    if (!np)
3060
0
  return 0;
3061
3062
0
    type = get_token(fp, token, maxtoken);
3063
0
    nexttype = get_token(fp, nexttoken, MAXTOKEN);
3064
0
    switch (type) {
3065
0
    case INTEGER:
3066
0
    case INTEGER32:
3067
0
    case UINTEGER32:
3068
0
    case UNSIGNED32:
3069
0
    case COUNTER:
3070
0
    case GAUGE:
3071
0
    case BITSTRING:
3072
0
    case LABEL:
3073
0
        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
0
        } else if (nexttype == LEFTPAREN) {
3080
            /*
3081
             * if there is a range list, parse it 
3082
             */
3083
0
            np->ranges = parse_ranges(fp, &np->ranges);
3084
0
            nexttype = get_token(fp, nexttoken, MAXTOKEN);
3085
0
        }
3086
0
        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
0
    }
3123
0
    free_node(np);
3124
0
    return nexttype;
3125
0
}
3126
3127
static int
3128
compliance_lookup(const char *name, int modid)
3129
24
{
3130
24
    struct objgroup *op;
3131
3132
24
    if (modid != -1)
3133
0
        return find_tree_node(name, modid) != NULL;
3134
3135
24
    op = malloc(sizeof(struct objgroup));
3136
24
    if (!op)
3137
0
        return 0;
3138
3139
24
    op->next = objgroups;
3140
24
    op->name = strdup(name);
3141
24
    if (!op->name) {
3142
0
        free(op);
3143
0
        return 0;
3144
0
    }
3145
24
    op->line = mibLine;
3146
24
    objgroups = op;
3147
24
    return 1;
3148
24
}
3149
3150
static struct node *
3151
parse_compliance(FILE * fp, char *name)
3152
38
{
3153
38
    int             type;
3154
38
    char            token[MAXTOKEN];
3155
38
    char            quoted_string_buffer[MAXQUOTESTR];
3156
38
    struct node    *np;
3157
3158
38
    np = alloc_node(current_module);
3159
38
    if (np == NULL)
3160
0
        return (NULL);
3161
38
    type = get_token(fp, token, MAXTOKEN);
3162
38
    if (type != STATUS) {
3163
28
        print_error("Expected STATUS", token, type);
3164
28
        goto skip;
3165
28
    }
3166
10
    type = get_token(fp, token, MAXTOKEN);
3167
10
    if (type != CURRENT && type != DEPRECATED && type != OBSOLETE) {
3168
0
        print_error("Bad STATUS", token, type);
3169
0
        goto skip;
3170
0
    }
3171
10
    type = get_token(fp, token, MAXTOKEN);
3172
10
    if (type != DESCRIPTION) {
3173
0
        print_error("Expected DESCRIPTION", token, type);
3174
0
        goto skip;
3175
0
    }
3176
10
    type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3177
10
    if (type != QUOTESTRING) {
3178
0
        print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3179
0
        goto skip;
3180
0
    }
3181
10
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
3182
10
             NETSNMP_DS_LIB_SAVE_MIB_DESCRS))
3183
0
        np->description = strdup(quoted_string_buffer);
3184
10
    type = get_token(fp, token, MAXTOKEN);
3185
10
    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
10
    if (type != MODULE) {
3196
1
        print_error("Expected MODULE", token, type);
3197
1
        goto skip;
3198
1
    }
3199
18
    while (type == MODULE) {
3200
9
        int             modid = -1;
3201
9
        char            modname[MAXTOKEN];
3202
9
        type = get_token(fp, token, MAXTOKEN);
3203
9
        if (type == LABEL
3204
0
            && strcmp(token, module_name(current_module, modname))) {
3205
0
            modid = read_module_internal(token);
3206
0
            if (modid != MODULE_LOADED_OK
3207
0
                && modid != MODULE_ALREADY_LOADED) {
3208
0
                print_error("Unknown module", token, type);
3209
0
                goto skip;
3210
0
            }
3211
0
            modid = which_module(token);
3212
0
            type = get_token(fp, token, MAXTOKEN);
3213
0
        }
3214
9
        if (type == MANDATORYGROUPS) {
3215
8
            type = get_token(fp, token, MAXTOKEN);
3216
8
            if (type != LEFTBRACKET) {
3217
0
                print_error("Expected \"{\"", token, type);
3218
0
                goto skip;
3219
0
            }
3220
17
            do {
3221
17
                type = get_token(fp, token, MAXTOKEN);
3222
17
                if (type != LABEL) {
3223
0
                    print_error("Bad group name", token, type);
3224
0
                    goto skip;
3225
0
                }
3226
17
                if (!compliance_lookup(token, modid))
3227
0
                    print_error("Unknown group", token, type);
3228
17
                type = get_token(fp, token, MAXTOKEN);
3229
17
            } while (type == COMMA);
3230
8
            if (type != RIGHTBRACKET) {
3231
0
                print_error("Expected \"}\"", token, type);
3232
0
                goto skip;
3233
0
            }
3234
8
            type = get_token(fp, token, MAXTOKEN);
3235
8
        }
3236
16
        while (type == GROUP || type == OBJECT) {
3237
7
            if (type == GROUP) {
3238
6
                type = get_token(fp, token, MAXTOKEN);
3239
6
                if (type != LABEL) {
3240
0
                    print_error("Bad group name", token, type);
3241
0
                    goto skip;
3242
0
                }
3243
6
                if (!compliance_lookup(token, modid))
3244
0
                    print_error("Unknown group", token, type);
3245
6
                type = get_token(fp, token, MAXTOKEN);
3246
6
            } else {
3247
1
                type = get_token(fp, token, MAXTOKEN);
3248
1
                if (type != LABEL) {
3249
0
                    print_error("Bad object name", token, type);
3250
0
                    goto skip;
3251
0
                }
3252
1
                if (!compliance_lookup(token, modid))
3253
0
                    print_error("Unknown group", token, type);
3254
1
                type = get_token(fp, token, MAXTOKEN);
3255
1
                if (type == SYNTAX)
3256
0
                    type = eat_syntax(fp, token, MAXTOKEN);
3257
1
                if (type == WRSYNTAX)
3258
0
                    type = eat_syntax(fp, token, MAXTOKEN);
3259
1
                if (type == MINACCESS) {
3260
1
                    type = get_token(fp, token, MAXTOKEN);
3261
1
                    if (type != NOACCESS && type != ACCNOTIFY
3262
1
                        && 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
1
                    type = get_token(fp, token, MAXTOKEN);
3268
1
                }
3269
1
            }
3270
7
            if (type != DESCRIPTION) {
3271
0
                print_error("Expected DESCRIPTION", token, type);
3272
0
                goto skip;
3273
0
            }
3274
7
            type = get_token(fp, token, MAXTOKEN);
3275
7
            if (type != QUOTESTRING) {
3276
0
                print_error("Bad DESCRIPTION", token, type);
3277
0
                goto skip;
3278
0
            }
3279
7
            type = get_token(fp, token, MAXTOKEN);
3280
7
        }
3281
9
    }
3282
38
  skip:
3283
149
    while (type != EQUALS && type != ENDOFFILE)
3284
111
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3285
3286
38
    return merge_parse_objectid(np, fp, name);
3287
9
}
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
25
{
3297
25
    int             type;
3298
25
    char            token[MAXTOKEN];
3299
25
    char            quoted_string_buffer[MAXQUOTESTR];
3300
25
    struct node    *np;
3301
3302
25
    np = alloc_node(current_module);
3303
25
    if (np == NULL)
3304
0
        return (NULL);
3305
25
    type = get_token(fp, token, MAXTOKEN);
3306
25
    if (type != PRODREL) {
3307
25
        print_error("Expected PRODUCT-RELEASE", token, type);
3308
25
        goto skip;
3309
25
    }
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
25
  skip:
3476
146
    while (type != EQUALS && type != ENDOFFILE) {
3477
121
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3478
121
    }
3479
25
    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
60
{
3489
60
    int             len, year, month, day, hour, minute;
3490
3491
60
    len = strlen(utc);
3492
60
    if (len == 0) {
3493
2
        print_error("Timestamp has zero length", utc, QUOTESTRING);
3494
2
        return;
3495
2
    }
3496
58
    if (utc[len - 1] != 'Z' && utc[len - 1] != 'z') {
3497
9
        print_error("Timestamp should end with Z", utc, QUOTESTRING);
3498
9
        return;
3499
9
    }
3500
49
    if (len == 11) {
3501
11
        len = sscanf(utc, "%2d%2d%2d%2d%2dZ", &year, &month, &day, &hour,
3502
11
                     &minute);
3503
11
        year += 1900;
3504
38
    } else if (len == 13)
3505
32
        len = sscanf(utc, "%4d%2d%2d%2d%2dZ", &year, &month, &day, &hour,
3506
32
                     &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
43
    if (len != 5) {
3513
4
        print_error("Bad timestamp format", utc, QUOTESTRING);
3514
4
        return;
3515
4
    }
3516
39
    if (month < 1 || month > 12)
3517
18
        print_error("Bad month in timestamp", utc, QUOTESTRING);
3518
39
    if (day < 1 || day > 31)
3519
14
        print_error("Bad day in timestamp", utc, QUOTESTRING);
3520
39
    if (hour < 0 || hour > 23)
3521
15
        print_error("Bad hour in timestamp", utc, QUOTESTRING);
3522
39
    if (minute < 0 || minute > 59)
3523
14
        print_error("Bad minute in timestamp", utc, QUOTESTRING);
3524
39
}
3525
3526
static struct node *
3527
parse_moduleIdentity(FILE * fp, char *name)
3528
89
{
3529
89
    register int    type;
3530
89
    char            token[MAXTOKEN];
3531
89
    char            quoted_string_buffer[MAXQUOTESTR];
3532
89
    register struct node *np;
3533
3534
89
    np = alloc_node(current_module);
3535
89
    if (np == NULL)
3536
0
        return (NULL);
3537
89
    type = get_token(fp, token, MAXTOKEN);
3538
89
    if (type != LASTUPDATED) {
3539
32
        print_error("Expected LAST-UPDATED", token, type);
3540
32
        goto skip;
3541
32
    }
3542
57
    type = get_token(fp, token, MAXTOKEN);
3543
57
    if (type != QUOTESTRING) {
3544
5
        print_error("Need STRING for LAST-UPDATED", token, type);
3545
5
        goto skip;
3546
5
    }
3547
52
    check_utc(token);
3548
52
    type = get_token(fp, token, MAXTOKEN);
3549
52
    if (type != ORGANIZATION) {
3550
48
        print_error("Expected ORGANIZATION", token, type);
3551
48
        goto skip;
3552
48
    }
3553
4
    type = get_token(fp, token, MAXTOKEN);
3554
4
    if (type != QUOTESTRING) {
3555
0
        print_error("Bad ORGANIZATION", token, type);
3556
0
        goto skip;
3557
0
    }
3558
4
    type = get_token(fp, token, MAXTOKEN);
3559
4
    if (type != CONTACTINFO) {
3560
0
        print_error("Expected CONTACT-INFO", token, type);
3561
0
        goto skip;
3562
0
    }
3563
4
    type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3564
4
    if (type != QUOTESTRING) {
3565
0
        print_error("Bad CONTACT-INFO", quoted_string_buffer, type);
3566
0
        goto skip;
3567
0
    }
3568
4
    type = get_token(fp, token, MAXTOKEN);
3569
4
    if (type != DESCRIPTION) {
3570
1
        print_error("Expected DESCRIPTION", token, type);
3571
1
        goto skip;
3572
1
    }
3573
3
    type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3574
3
    if (type != QUOTESTRING) {
3575
0
        print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3576
0
        goto skip;
3577
0
    }
3578
3
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
3579
3
             NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
3580
0
        np->description = strdup(quoted_string_buffer);
3581
0
    }
3582
3
    type = get_token(fp, token, MAXTOKEN);
3583
11
    while (type == REVISION) {
3584
8
        type = get_token(fp, token, MAXTOKEN);
3585
8
        if (type != QUOTESTRING) {
3586
0
            print_error("Bad REVISION", token, type);
3587
0
            goto skip;
3588
0
        }
3589
8
        check_utc(token);
3590
8
        type = get_token(fp, token, MAXTOKEN);
3591
8
        if (type != DESCRIPTION) {
3592
0
            print_error("Expected DESCRIPTION", token, type);
3593
0
            goto skip;
3594
0
        }
3595
8
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3596
8
        if (type != QUOTESTRING) {
3597
0
            print_error("Bad DESCRIPTION", quoted_string_buffer, type);
3598
0
            goto skip;
3599
0
        }
3600
8
        type = get_token(fp, token, MAXTOKEN);
3601
8
    }
3602
3
    if (type != EQUALS)
3603
0
        print_error("Expected \"::=\"", token, type);
3604
89
  skip:
3605
443
    while (type != EQUALS && type != ENDOFFILE) {
3606
354
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
3607
354
    }
3608
89
    return merge_parse_objectid(np, fp, name);
3609
3
}
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
29
{
3620
29
    register int    type;
3621
29
    char            token[MAXTOKEN];
3622
29
    struct node    *np;
3623
29
    int             iLine = mibLine;
3624
3625
29
    np = alloc_node(current_module);
3626
29
    if (np == NULL)
3627
0
        return (NULL);
3628
29
    type = get_token(fp, token, sizeof(token));
3629
237
    while (type != EQUALS && type != ENDOFFILE) {
3630
208
        type = get_token(fp, token, sizeof(token));
3631
208
    }
3632
29
    if (type != EQUALS) {
3633
10
        if (np)
3634
10
            free_node(np);
3635
10
        return NULL;
3636
10
    }
3637
156
    while (type != BEGIN && type != ENDOFFILE) {
3638
137
        type = get_token(fp, token, sizeof(token));
3639
137
    }
3640
19
    if (type != BEGIN) {
3641
10
        if (np)
3642
10
            free_node(np);
3643
10
        return NULL;
3644
10
    }
3645
97
    while (type != END && type != ENDOFFILE) {
3646
88
        type = get_token(fp, token, sizeof(token));
3647
88
    }
3648
9
    if (type != END) {
3649
7
        if (np)
3650
7
            free_node(np);
3651
7
        return NULL;
3652
7
    }
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
9
}
3663
3664
/*
3665
 * Parses a module import clause
3666
 *   loading any modules referenced
3667
 */
3668
static void
3669
parse_imports(FILE * fp)
3670
442
{
3671
442
    register int    type;
3672
442
    char            token[MAXTOKEN];
3673
442
    char            modbuf[256];
3674
3.90k
#define MAX_IMPORTS 512
3675
442
    struct module_import *import_list;
3676
442
    int             this_module;
3677
442
    struct module  *mp;
3678
3679
442
    int             import_count = 0;   /* Total number of imported descriptors */
3680
442
    int             i = 0, old_i;       /* index of first import from each module */
3681
3682
442
    import_list = malloc(MAX_IMPORTS * sizeof(*import_list));
3683
3684
442
    type = get_token(fp, token, MAXTOKEN);
3685
3686
    /*
3687
     * Parse the IMPORTS clause
3688
     */
3689
4.77k
    while (type != SEMI && type != ENDOFFILE) {
3690
4.33k
        if (type == LABEL) {
3691
3.46k
            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.46k
            import_list[import_count++].label = strdup(token);
3699
3.46k
        } else if (type == FROM) {
3700
420
            type = get_token(fp, token, MAXTOKEN);
3701
420
            if (import_count == i) {    /* All imports are handled internally */
3702
17
                type = get_token(fp, token, MAXTOKEN);
3703
17
                continue;
3704
17
            }
3705
403
            this_module = which_module(token);
3706
3707
2.76k
            for (old_i = i; i < import_count; ++i)
3708
2.36k
                import_list[i].modid = this_module;
3709
3710
            /*
3711
             * Recursively read any pre-requisite modules
3712
             */
3713
403
            if (read_module_internal(token) == MODULE_NOT_FOUND) {
3714
399
    int found = 0;
3715
2.75k
                for (; old_i < import_count; ++old_i) {
3716
2.35k
                    found += read_import_replacements(token, &import_list[old_i]);
3717
2.35k
                }
3718
399
    if (!found)
3719
280
        print_module_not_found(token);
3720
399
            }
3721
403
        }
3722
4.31k
        type = get_token(fp, token, MAXTOKEN);
3723
4.31k
    }
3724
3725
    /* Initialize modid in case the module name was missing. */
3726
1.53k
    for (; i < import_count; ++i)
3727
1.09k
        import_list[i].modid = -1;
3728
3729
    /*
3730
     * Save the import information
3731
     *   in the global module table
3732
     */
3733
460
    for (mp = module_head; mp; mp = mp->next) {
3734
460
        if (mp->modid == current_module) {
3735
442
            if (import_count == 0)
3736
10
                goto out;
3737
432
            if (mp->imports && (mp->imports != root_imports)) {
3738
                /*
3739
                 * this can happen if all modules are in one source file. 
3740
                 */
3741
82
                for (i = 0; i < mp->no_imports; ++i) {
3742
62
                    DEBUGMSGTL(("parse-mibs",
3743
62
                                "#### freeing Module %d '%s' %d\n",
3744
62
                                mp->modid, mp->imports[i].label,
3745
62
                                mp->imports[i].modid));
3746
62
                    free(mp->imports[i].label);
3747
62
                }
3748
20
                free(mp->imports);
3749
20
            }
3750
432
            mp->imports = (struct module_import *)
3751
432
                calloc(import_count, sizeof(struct module_import));
3752
432
            if (mp->imports == NULL)
3753
0
                goto out;
3754
3.89k
            for (i = 0; i < import_count; ++i) {
3755
3.46k
                mp->imports[i].label = import_list[i].label;
3756
3.46k
                import_list[i].label = NULL;
3757
3.46k
                mp->imports[i].modid = import_list[i].modid;
3758
3.46k
                DEBUGMSGTL(("parse-mibs",
3759
3.46k
                            "#### adding Module %d '%s' %d\n", mp->modid,
3760
3.46k
                            mp->imports[i].label, mp->imports[i].modid));
3761
3.46k
            }
3762
432
            mp->no_imports = import_count;
3763
432
            goto out;
3764
432
        }
3765
460
    }
3766
3767
    /*
3768
     * Shouldn't get this far
3769
     */
3770
0
    print_module_not_found(module_name(current_module, modbuf));
3771
3772
442
out:
3773
3.90k
    for (i = 0; i < import_count; ++i)
3774
3.46k
        free(import_list[i].label);
3775
442
    free(import_list);
3776
442
    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.6k
{
3801
13.6k
    struct module  *mp;
3802
3803
14.7k
    for (mp = module_head; mp; mp = mp->next)
3804
3.82k
        if (!label_compare(mp->name, name))
3805
2.76k
            return (mp->modid);
3806
3807
10.9k
    DEBUGMSGTL(("parse-mibs", "Module %s not found\n", name));
3808
10.9k
    return (-1);
3809
13.6k
}
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
216k
{
3817
216k
    struct module  *mp;
3818
3819
279k
    for (mp = module_head; mp; mp = mp->next)
3820
168k
        if (mp->modid == modid) {
3821
104k
            strcpy(cp, mp->name);
3822
104k
            return (cp);
3823
104k
        }
3824
3825
111k
    if (modid != -1) DEBUGMSGTL(("parse-mibs", "Module %d not found\n", modid));
3826
111k
    sprintf(cp, "#%d", modid);
3827
111k
    return (cp);
3828
216k
}
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
157k
{
3865
157k
    struct module_compatability *mcp;
3866
3867
3.61M
    for (mcp = module_map_head; mcp; mcp = mcp->next) {
3868
3.45M
        if (!label_compare(mcp->old_module, name)) {
3869
736
            if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
3870
736
           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
736
            (void) netsnmp_read_module(mcp->new_module);
3876
736
            return 1;
3877
736
        }
3878
3.45M
    }
3879
156k
    return 0;
3880
157k
}
3881
3882
static int
3883
read_import_replacements(const char *old_module_name,
3884
                         struct module_import *identifier)
3885
2.35k
{
3886
2.35k
    struct module_compatability *mcp;
3887
3888
    /*
3889
     * Look for matches first
3890
     */
3891
51.3k
    for (mcp = module_map_head; mcp; mcp = mcp->next) {
3892
49.3k
        if (!label_compare(mcp->old_module, old_module_name)) {
3893
3894
5.76k
            if (                /* exact match */
3895
5.76k
                   (mcp->tag_len == 0 &&
3896
1.47k
                    (mcp->tag == NULL ||
3897
1.17k
                     !label_compare(mcp->tag, identifier->label))) ||
3898
                   /*
3899
                    * prefix match 
3900
                    */
3901
5.45k
                   (mcp->tag_len != 0 &&
3902
4.28k
                    !strncmp(mcp->tag, identifier->label, mcp->tag_len))
3903
5.76k
                ) {
3904
3905
326
                if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
3906
326
               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
326
                (void) netsnmp_read_module(mcp->new_module);
3913
326
                identifier->modid = which_module(mcp->new_module);
3914
326
                return 1;         /* finished! */
3915
326
            }
3916
5.76k
        }
3917
49.3k
    }
3918
3919
    /*
3920
     * If no exact match, load everything relevant
3921
     */
3922
2.02k
    return read_module_replacements(old_module_name);
3923
2.35k
}
3924
3925
static int
3926
read_from_file(struct module *mp, const char *name)
3927
2.45k
{
3928
2.45k
    const char     *oldFile = File;
3929
2.45k
    int             oldLine = mibLine;
3930
2.45k
    int             oldModule = current_module;
3931
2.45k
    FILE           *fp;
3932
2.45k
    struct node    *np;
3933
2.45k
    int             res;
3934
3935
2.45k
    if (mp->no_imports != -1) {
3936
47
        DEBUGMSGTL(("parse-mibs", "Module %s already loaded\n",
3937
47
                    name));
3938
47
        return MODULE_ALREADY_LOADED;
3939
47
    }
3940
2.40k
    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.40k
#ifdef HAVE_FLOCKFILE
3950
2.40k
    flockfile(fp);
3951
2.40k
#endif
3952
2.40k
    mp->no_imports = 0; /* Note that we've read the file */
3953
2.40k
    File = mp->file;
3954
2.40k
    mibLine = 1;
3955
2.40k
    current_module = mp->modid;
3956
    /*
3957
     * Parse the file
3958
     */
3959
2.40k
    np = parse(fp);
3960
2.40k
#ifdef HAVE_FUNLOCKFILE
3961
2.40k
    funlockfile(fp);
3962
2.40k
#endif
3963
2.40k
    fclose(fp);
3964
2.40k
    File = oldFile;
3965
2.40k
    mibLine = oldLine;
3966
2.40k
    current_module = oldModule;
3967
2.40k
    res = !np && gMibError == MODULE_SYNTAX_ERROR ?
3968
1.72k
        MODULE_SYNTAX_ERROR : MODULE_LOADED_OK;
3969
3.17k
    while (np) {
3970
774
        struct node *nnp = np->next;
3971
774
        free_node(np);
3972
774
        np = nnp;
3973
774
    }
3974
2.40k
    return res;
3975
2.40k
}
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
158k
{
3985
158k
    struct module  *mp;
3986
3987
158k
    netsnmp_init_mib_internals();
3988
3989
279k
    for (mp = module_head; mp; mp = mp->next)
3990
123k
        if (!label_compare(mp->name, name))
3991
2.45k
            return read_from_file(mp, name);
3992
3993
155k
    return MODULE_NOT_FOUND;
3994
158k
}
3995
3996
void
3997
adopt_orphans(void)
3998
3.33k
{
3999
3.33k
    struct node    *np = NULL, *onp;
4000
3.33k
    struct tree    *tp;
4001
3.33k
    int             i, adopted = 1;
4002
4003
3.33k
    if (!orphan_nodes)
4004
7
        return;
4005
3.33k
    init_node_hash(orphan_nodes);
4006
3.33k
    orphan_nodes = NULL;
4007
4008
6.85k
    while (adopted) {
4009
3.52k
        adopted = 0;
4010
454k
        for (i = 0; i < NHASHSIZE; i++)
4011
451k
            if (nbuckets[i]) {
4012
334k
                for (np = nbuckets[i]; np != NULL; np = np->next) {
4013
230k
                    tp = find_tree_node(np->parent, -1);
4014
230k
        if (tp) {
4015
287
      do_subtree(tp, &np);
4016
287
      adopted = 1;
4017
                        /*
4018
                         * if do_subtree adopted the entire bucket, stop
4019
                         */
4020
287
                        if(NULL == nbuckets[i])
4021
236
                            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
159
                        for(onp = nbuckets[i]; onp; onp = onp->next)
4031
108
                            if(onp == np)
4032
0
                                break;
4033
51
                        if(NULL == onp) { /* not in the list */
4034
51
                            np = nbuckets[i]; /* start over */
4035
51
                        }
4036
51
        }
4037
230k
    }
4038
104k
            }
4039
3.52k
    }
4040
4041
    /*
4042
     * Report on outstanding orphans
4043
     *    and link them back into the orphan list
4044
     */
4045
429k
    for (i = 0; i < NHASHSIZE; i++)
4046
426k
        if (nbuckets[i]) {
4047
98.0k
            if (orphan_nodes)
4048
94.7k
                onp = np->next = nbuckets[i];
4049
3.33k
            else
4050
3.33k
                onp = orphan_nodes = nbuckets[i];
4051
98.0k
            nbuckets[i] = NULL;
4052
313k
            while (onp) {
4053
215k
                char            modbuf[256];
4054
215k
                snmp_log(LOG_WARNING,
4055
215k
                         "Cannot resolve OID in %s: %s ::= { %s %ld } at line %d in %s\n",
4056
215k
                         module_name(onp->modid, modbuf),
4057
215k
                         (onp->label ? onp->label : "<no label>"),
4058
215k
                         (onp->parent ? onp->parent : "<no parent>"),
4059
215k
                         onp->subid, onp->lineno, onp->filename);
4060
215k
                np = onp;
4061
215k
                onp = onp->next;
4062
215k
            }
4063
98.0k
        }
4064
3.33k
}
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
157k
{
4077
157k
    int status = 0;
4078
157k
    status = read_module_internal(name);
4079
4080
157k
    if (status == MODULE_NOT_FOUND) {
4081
155k
        if (!read_module_replacements(name))
4082
155k
            print_module_not_found(name);
4083
155k
    } else if (status == MODULE_SYNTAX_ERROR) {
4084
678
        gMibError = 0;
4085
678
        gLoop = 1;
4086
4087
678
        strncat(gMibNames, " ", sizeof(gMibNames) - strlen(gMibNames) - 1);
4088
678
        strncat(gMibNames, name, sizeof(gMibNames) - strlen(gMibNames) - 1);
4089
678
    }
4090
4091
157k
    return tree_head;
4092
157k
}
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.9k
{
4102
12.9k
    struct tree    *tp, *next;
4103
12.9k
    int             i;
4104
4105
42.0k
    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
29.1k
        int             nmod = tp->number_modules;
4114
29.1k
        if (nmod > 0) {         /* in some module */
4115
            /*
4116
             * Remove all copies of this module ID
4117
             */
4118
29.0k
            int             cnt = 0, *pi1, *pi2 = tp->module_list;
4119
59.3k
            for (i = 0, pi1 = pi2; i < nmod; i++, pi2++) {
4120
30.2k
                if (*pi2 == modID)
4121
21.5k
                    continue;
4122
8.65k
                cnt++;
4123
8.65k
                *pi1++ = *pi2;
4124
8.65k
            }
4125
29.0k
            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.6k
                tp->number_modules = cnt;
4131
20.6k
                switch (cnt) {
4132
20.6k
                case 0:
4133
20.6k
                    tp->module_list[0] = -1;    /* Mark unused, */
4134
20.6k
        NETSNMP_FALLTHROUGH;
4135
4136
20.6k
                case 1:        /* save the remaining module */
4137
20.6k
                    if (&(tp->modid) != tp->module_list) {
4138
566
                        tp->modid = tp->module_list[0];
4139
566
                        free(tp->module_list);
4140
566
                        tp->module_list = &(tp->modid);
4141
566
                    }
4142
20.6k
                    break;
4143
4144
0
                default:
4145
0
                    break;
4146
20.6k
                }
4147
20.6k
            }                   /* if tree node is in this module */
4148
29.0k
        }
4149
        /*
4150
         * if tree node is in some module 
4151
         */
4152
29.1k
        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
29.1k
        if (tp->child_list)
4161
6.94k
            unload_module_by_ID(modID, tp->child_list);
4162
4163
4164
29.1k
        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.6k
            if (tp->child_list == NULL) {
4170
20.5k
                unlink_tree(tp);
4171
20.5k
                free_tree(tp);
4172
20.5k
            } else {
4173
39
                free_partial_tree(tp, TRUE);
4174
39
            }
4175
20.6k
        }
4176
29.1k
    }
4177
12.9k
}
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.33k
{
4215
3.33k
    struct module  *mp;
4216
3.33k
    struct module_compatability *mcp;
4217
3.33k
    struct tc      *ptc;
4218
3.33k
    unsigned int    i;
4219
4220
3.33k
    for (mcp = module_map_head; mcp; mcp = module_map_head) {
4221
3.33k
        if (mcp == module_map)
4222
3.33k
            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
6.01k
    for (mp = module_head; mp; mp = module_head) {
4231
2.67k
        struct module_import *mi = mp->imports;
4232
2.67k
        if (mi) {
4233
7.54k
            for (i = 0; i < (unsigned int)mp->no_imports; ++i) {
4234
6.20k
                SNMP_FREE((mi + i)->label);
4235
6.20k
            }
4236
1.34k
            mp->no_imports = 0;
4237
1.34k
            if (mi == root_imports)
4238
934
                memset(mi, 0, sizeof(*mi));
4239
412
            else
4240
412
                free(mi);
4241
1.34k
        }
4242
4243
2.67k
        unload_module_by_ID(mp->modid, tree_head);
4244
2.67k
        module_head = mp->next;
4245
2.67k
        free(mp->name);
4246
2.67k
        free(mp->file);
4247
2.67k
        free(mp);
4248
2.67k
    }
4249
3.33k
    unload_module_by_ID(-1, tree_head);
4250
    /*
4251
     * tree nodes are cleared 
4252
     */
4253
4254
337k
    for (i = 0, ptc = tclist; i < tc_alloc; i++, ptc++) {
4255
333k
        if (ptc->type == 0)
4256
333k
            continue;
4257
379
        free_enums(&ptc->enums);
4258
379
        free_ranges(&ptc->ranges);
4259
379
        free(ptc->descriptor);
4260
379
        if (ptc->hint)
4261
2
            free(ptc->hint);
4262
379
        if (ptc->description)
4263
0
            free(ptc->description);
4264
379
    }
4265
3.33k
    SNMP_FREE(tclist);
4266
3.33k
    tc_alloc = 0;
4267
4268
3.33k
    memset(buckets, 0, sizeof(buckets));
4269
3.33k
    memset(nbuckets, 0, sizeof(nbuckets));
4270
3.33k
    memset(tbuckets, 0, sizeof(tbuckets));
4271
4272
13.3k
    for (i = 0; i < sizeof(root_imports) / sizeof(root_imports[0]); i++) {
4273
10.0k
        SNMP_FREE(root_imports[i].label);
4274
10.0k
    }
4275
4276
3.33k
    max_module = 0;
4277
3.33k
    current_module = 0;
4278
3.33k
    module_map_head = NULL;
4279
3.33k
    SNMP_FREE(last_err_module);
4280
3.33k
}
4281
4282
static void
4283
new_module(const char *name, const char *file)
4284
5.07k
{
4285
5.07k
    struct module  *mp;
4286
4287
5.38k
    for (mp = module_head; mp; mp = mp->next)
4288
2.71k
        if (!label_compare(mp->name, name)) {
4289
2.39k
            DEBUGMSGTL(("parse-mibs", "  Module %s already noted\n", name));
4290
            /*
4291
             * Not the same file 
4292
             */
4293
2.39k
            if (label_compare(mp->file, file)) {
4294
2.39k
                DEBUGMSGTL(("parse-mibs", "    %s is now in %s\n",
4295
2.39k
                            name, file));
4296
2.39k
                if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
4297
2.39k
               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.39k
                free(mp->file);
4307
2.39k
                mp->file = strdup(file);
4308
2.39k
            }
4309
2.39k
            return;
4310
2.39k
        }
4311
4312
    /*
4313
     * Add this module to the list 
4314
     */
4315
2.67k
    DEBUGMSGTL(("parse-mibs", "  Module %d %s is in %s\n", max_module,
4316
2.67k
                name, file));
4317
2.67k
    mp = calloc(1, sizeof(struct module));
4318
2.67k
    if (mp == NULL)
4319
0
        return;
4320
2.67k
    mp->name = strdup(name);
4321
2.67k
    mp->file = strdup(file);
4322
2.67k
    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.67k
    mp->imports = NULL;
4329
2.67k
    mp->no_imports = -1;        /* Not yet loaded */
4330
2.67k
    mp->modid = max_module;
4331
2.67k
    ++max_module;
4332
4333
2.67k
    mp->next = module_head;     /* Or add to the *end* of the list? */
4334
2.67k
    module_head = mp;
4335
2.67k
}
4336
4337
4338
static void
4339
scan_objlist(struct node *root, struct module *mp, struct objgroup *list, const char *error)
4340
3.29k
{
4341
3.29k
    int             oLine = mibLine;
4342
4343
3.45k
    while (list) {
4344
161
        struct objgroup *gp = list;
4345
161
        struct node    *np;
4346
161
        list = list->next;
4347
161
        np = root;
4348
3.71k
        while (np)
4349
3.69k
            if (label_compare(np->label, gp->name))
4350
3.55k
                np = np->next;
4351
136
            else
4352
136
                break;
4353
161
        if (!np) {
4354
25
      int i;
4355
25
      struct module_import *mip;
4356
      /* if not local, check if it was IMPORTed */
4357
25
      for (i = 0, mip = mp->imports; i < mp->no_imports; i++, mip++)
4358
0
    if (strcmp(mip->label, gp->name) == 0)
4359
0
        break;
4360
25
      if (i == mp->no_imports) {
4361
25
    mibLine = gp->line;
4362
25
    print_error(error, gp->name, QUOTESTRING);
4363
25
      }
4364
25
        }
4365
161
        free(gp->name);
4366
161
        free(gp);
4367
161
    }
4368
3.29k
    mibLine = oLine;
4369
3.29k
}
4370
4371
static void free_objgroup(struct objgroup *o)
4372
1.95k
{
4373
1.98k
    while (o) {
4374
27
        struct objgroup *next = o->next;
4375
4376
27
        free(o->name);
4377
27
        free(o);
4378
27
        o = next;
4379
27
    }
4380
1.95k
}
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.40k
{
4389
#ifdef TEST
4390
    extern void     xmalloc_stats(FILE *);
4391
#endif
4392
2.40k
    char            token[MAXTOKEN];
4393
2.40k
    char            name[MAXTOKEN+1];
4394
2.40k
    int             type = LABEL;
4395
2.40k
    int             lasttype = LABEL;
4396
4397
6.22k
#define BETWEEN_MIBS          1
4398
3.82k
#define IN_MIB                2
4399
2.40k
    int             state = BETWEEN_MIBS;
4400
2.40k
    struct node    *np = NULL, *root = NULL;
4401
2.40k
    struct objgroup *oldgroups = NULL, *oldobjects = NULL, *oldnotifs =
4402
2.40k
        NULL;
4403
4404
2.40k
    DEBUGMSGTL(("parse-file", "Parsing file:  %s...\n", File));
4405
4406
2.40k
    if (last_err_module)
4407
2.34k
        free(last_err_module);
4408
2.40k
    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.11k
            lasttype = type;
4415
10.3k
        else
4416
10.3k
            type = lasttype = get_token(fp, token, MAXTOKEN);
4417
4418
12.4k
        switch (type) {
4419
1.10k
        case END:
4420
1.10k
            if (state != IN_MIB) {
4421
3
                print_error("Error, END before start of MIB", NULL, type);
4422
3
                gMibError = MODULE_SYNTAX_ERROR;
4423
3
                goto free_mib;
4424
1.09k
            } else {
4425
1.09k
                struct module  *mp;
4426
#ifdef TEST
4427
                printf("\nNodes for Module %s:\n", name);
4428
                print_nodes(stdout, root);
4429
#endif
4430
1.21k
                for (mp = module_head; mp; mp = mp->next)
4431
1.21k
                    if (mp->modid == current_module)
4432
1.09k
                        break;
4433
1.09k
                scan_objlist(root, mp, objgroups, "Undefined OBJECT-GROUP");
4434
1.09k
                scan_objlist(root, mp, objects, "Undefined OBJECT");
4435
1.09k
                scan_objlist(root, mp, notifs, "Undefined NOTIFICATION");
4436
1.09k
                objgroups = oldgroups;
4437
1.09k
                objects = oldobjects;
4438
1.09k
                notifs = oldnotifs;
4439
1.09k
                do_linkup(mp, root);
4440
1.09k
                np = root = NULL;
4441
1.09k
            }
4442
1.09k
            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.09k
            continue;
4450
442
        case IMPORTS:
4451
442
            parse_imports(fp);
4452
442
            continue;
4453
19
        case EXPORTS:
4454
152
            while (type != SEMI && type != ENDOFFILE)
4455
133
                type = get_token(fp, token, MAXTOKEN);
4456
19
            continue;
4457
6.00k
        case LABEL:
4458
6.00k
        case INTEGER:
4459
6.01k
        case INTEGER32:
4460
6.01k
        case UINTEGER32:
4461
6.01k
        case UNSIGNED32:
4462
6.01k
        case COUNTER:
4463
6.02k
        case COUNTER64:
4464
6.02k
        case GAUGE:
4465
6.03k
        case IPADDR:
4466
6.03k
        case NETADDR:
4467
6.03k
        case NSAPADDRESS:
4468
6.03k
        case OBJSYNTAX:
4469
6.03k
        case APPSYNTAX:
4470
6.04k
        case SIMPLESYNTAX:
4471
6.04k
        case OBJNAME:
4472
6.04k
        case NOTIFNAME:
4473
6.05k
        case KW_OPAQUE:
4474
6.05k
        case TIMETICKS:
4475
6.05k
            break;
4476
917
        case ENDOFFILE:
4477
917
            continue;
4478
3.95k
        default:
4479
3.95k
            strlcpy(name, token, sizeof(name));
4480
3.95k
            type = get_token(fp, token, MAXTOKEN);
4481
3.95k
            nnp = NULL;
4482
3.95k
            if (type == MACRO) {
4483
6
                nnp = parse_macro(fp, name);
4484
6
                if (nnp == NULL) {
4485
5
                    print_error("Bad parse of MACRO", NULL, type);
4486
5
                    gMibError = MODULE_SYNTAX_ERROR;
4487
5
                }
4488
6
                free_node(nnp); /* IGNORE */
4489
6
                nnp = NULL;
4490
6
            } else
4491
3.95k
                print_error(name, "is a reserved word", lasttype);
4492
3.95k
            continue;           /* see if we can parse the rest of the file */
4493
12.4k
        }
4494
6.05k
        strlcpy(name, token, sizeof(name));
4495
6.05k
        type = get_token(fp, token, MAXTOKEN);
4496
6.05k
        nnp = NULL;
4497
4498
        /*
4499
         * Handle obsolete method to assign an object identifier to a
4500
         * module
4501
         */
4502
6.05k
        if (lasttype == LABEL && type == LEFTBRACKET) {
4503
203
            while (type != RIGHTBRACKET && type != ENDOFFILE)
4504
183
                type = get_token(fp, token, MAXTOKEN);
4505
20
            if (type == ENDOFFILE) {
4506
12
                print_error("Expected \"}\"", token, type);
4507
12
                gMibError = MODULE_SYNTAX_ERROR;
4508
12
                goto free_mib;
4509
12
            }
4510
8
            type = get_token(fp, token, MAXTOKEN);
4511
8
        }
4512
4513
6.04k
        switch (type) {
4514
2.72k
        case DEFINITIONS:
4515
2.72k
            if (state != BETWEEN_MIBS) {
4516
3
                print_error("Error, nested MIBS", NULL, type);
4517
3
                gMibError = MODULE_SYNTAX_ERROR;
4518
3
                goto free_mib;
4519
3
            }
4520
2.72k
            state = IN_MIB;
4521
2.72k
            current_module = which_module(name);
4522
2.72k
            oldgroups = objgroups;
4523
2.72k
            objgroups = NULL;
4524
2.72k
            oldobjects = objects;
4525
2.72k
            objects = NULL;
4526
2.72k
            oldnotifs = notifs;
4527
2.72k
            notifs = NULL;
4528
2.72k
            if (current_module == -1) {
4529
223
                new_module(name, File);
4530
223
                current_module = which_module(name);
4531
223
            }
4532
2.72k
            DEBUGMSGTL(("parse-mibs", "Parsing MIB: %d %s\n",
4533
2.72k
                        current_module, name));
4534
10.5k
            while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE)
4535
10.2k
                if (type == BEGIN)
4536
2.46k
                    break;
4537
2.72k
            break;
4538
98
        case OBJTYPE:
4539
98
            nnp = parse_objecttype(fp, name);
4540
98
            if (nnp == NULL) {
4541
4
                print_error("Bad parse of OBJECT-TYPE", NULL, type);
4542
4
                gMibError = MODULE_SYNTAX_ERROR;
4543
4
                goto free_mib;
4544
4
            }
4545
94
            break;
4546
94
        case OBJGROUP:
4547
24
            nnp = parse_objectgroup(fp, name, OBJECTS, &objects);
4548
24
            if (nnp == NULL) {
4549
5
                print_error("Bad parse of OBJECT-GROUP", NULL, type);
4550
5
                gMibError = MODULE_SYNTAX_ERROR;
4551
5
                goto free_mib;
4552
5
            }
4553
19
            break;
4554
44
        case NOTIFGROUP:
4555
44
            nnp = parse_objectgroup(fp, name, NOTIFICATIONS, &notifs);
4556
44
            if (nnp == NULL) {
4557
13
                print_error("Bad parse of NOTIFICATION-GROUP", NULL, type);
4558
13
                gMibError = MODULE_SYNTAX_ERROR;
4559
13
                goto free_mib;
4560
13
            }
4561
31
            break;
4562
43
        case TRAPTYPE:
4563
43
            nnp = parse_trapDefinition(fp, name);
4564
43
            if (nnp == NULL) {
4565
42
                print_error("Bad parse of TRAP-TYPE", NULL, type);
4566
42
                gMibError = MODULE_SYNTAX_ERROR;
4567
42
                goto free_mib;
4568
42
            }
4569
1
            break;
4570
59
        case NOTIFTYPE:
4571
59
            nnp = parse_notificationDefinition(fp, name);
4572
59
            if (nnp == NULL) {
4573
40
                print_error("Bad parse of NOTIFICATION-TYPE", NULL, type);
4574
40
                gMibError = MODULE_SYNTAX_ERROR;
4575
40
                goto free_mib;
4576
40
            }
4577
19
            break;
4578
38
        case COMPLIANCE:
4579
38
            nnp = parse_compliance(fp, name);
4580
38
            if (nnp == NULL) {
4581
16
                print_error("Bad parse of MODULE-COMPLIANCE", NULL, type);
4582
16
                gMibError = MODULE_SYNTAX_ERROR;
4583
16
                goto free_mib;
4584
16
            }
4585
22
            break;
4586
25
        case AGENTCAP:
4587
25
            nnp = parse_capabilities(fp, name);
4588
25
            if (nnp == NULL) {
4589
14
                print_error("Bad parse of AGENT-CAPABILITIES", NULL, type);
4590
14
                gMibError = MODULE_SYNTAX_ERROR;
4591
14
                goto free_mib;
4592
14
            }
4593
11
            break;
4594
23
        case MACRO:
4595
23
            nnp = parse_macro(fp, name);
4596
23
            if (nnp == NULL) {
4597
22
                print_error("Bad parse of MACRO", NULL, type);
4598
22
                gMibError = MODULE_SYNTAX_ERROR;
4599
22
            }
4600
23
            free_node(nnp);     /* IGNORE */
4601
23
            nnp = NULL;
4602
23
            break;
4603
89
        case MODULEIDENTITY:
4604
89
            nnp = parse_moduleIdentity(fp, name);
4605
89
            if (nnp == NULL) {
4606
68
                print_error("Bad parse of MODULE-IDENTITY", NULL, type);
4607
68
                gMibError = MODULE_SYNTAX_ERROR;
4608
68
                goto free_mib;
4609
68
            }
4610
21
            break;
4611
21
        case OBJIDENTITY:
4612
9
            nnp = parse_objectgroup(fp, name, OBJECTS, &objects);
4613
9
            if (nnp == NULL) {
4614
6
                print_error("Bad parse of OBJECT-IDENTITY", NULL, type);
4615
6
                gMibError = MODULE_SYNTAX_ERROR;
4616
6
                goto free_mib;
4617
6
            }
4618
3
            break;
4619
37
        case OBJECT:
4620
37
            type = get_token(fp, token, MAXTOKEN);
4621
37
            if (type != IDENTIFIER) {
4622
8
                print_error("Expected IDENTIFIER", token, type);
4623
8
                gMibError = MODULE_SYNTAX_ERROR;
4624
8
                goto free_mib;
4625
8
            }
4626
29
            type = get_token(fp, token, MAXTOKEN);
4627
29
            if (type != EQUALS) {
4628
3
                print_error("Expected \"::=\"", token, type);
4629
3
                gMibError = MODULE_SYNTAX_ERROR;
4630
3
                goto free_mib;
4631
3
            }
4632
26
            nnp = parse_objectid(fp, name);
4633
26
            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
25
            break;
4639
2.21k
        case EQUALS:
4640
2.21k
            nnp = parse_asntype(fp, name, &type, token);
4641
2.21k
            lasttype = CONTINUE;
4642
2.21k
            break;
4643
206
        case ENDOFFILE:
4644
206
            break;
4645
413
        default:
4646
413
            print_error("Bad operator", token, type);
4647
413
            gMibError = MODULE_SYNTAX_ERROR;
4648
413
            goto free_mib;
4649
6.04k
        }
4650
5.40k
        if (nnp) {
4651
1.26k
            struct node *op;
4652
1.26k
            if (np)
4653
363
                np->next = nnp;
4654
899
            else
4655
899
                np = root = nnp;
4656
14.8k
            while (np->next)
4657
13.6k
                np = np->next;
4658
1.26k
            if (np->type == TYPE_OTHER)
4659
1.16k
                np->type = type;
4660
1.26k
            op = root;
4661
6.01k
            while (op != nnp) {
4662
4.74k
                if (strcmp(nnp->label, op->label) == 0 && nnp->subid != op->subid) {
4663
153
                    snmp_log(LOG_ERR, 
4664
153
                        "Duplicate Object '%s' at line %d in %s. First at line %d\n",
4665
153
                        op->label, mibLine, File, op->lineno);
4666
153
        erroneousMibs++;
4667
153
    }
4668
4.74k
                op = op->next;
4669
4.74k
            }
4670
1.26k
        }
4671
5.40k
    }
4672
1.75k
    DEBUGMSGTL(("parse-file", "End of file (%s)\n", File));
4673
1.75k
    return root;
4674
4675
651
free_mib:
4676
1.15k
    for (; root; root = np) {
4677
501
        np = root->next;
4678
501
        free_node(root);
4679
501
    }
4680
651
    free_objgroup(objgroups);
4681
651
    objgroups = NULL;
4682
651
    free_objgroup(objects);
4683
651
    objects = NULL;
4684
651
    free_objgroup(notifs);
4685
651
    notifs = NULL;
4686
651
    return NULL;
4687
2.40k
}
4688
4689
/*
4690
 * return zero if character is not a label character. 
4691
 */
4692
static int
4693
is_labelchar(int ich)
4694
548k
{
4695
548k
    netsnmp_assert(ich == EOF || (0 <= ich && ich < 256));
4696
548k
    if ((isalnum(ich)) || (ich == '-'))
4697
473k
        return 1;
4698
75.4k
    if (ich == '_' && netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
4699
291
               NETSNMP_DS_LIB_MIB_PARSE_LABEL)) {
4700
0
        return 1;
4701
0
    }
4702
4703
75.4k
    return 0;
4704
75.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
1.51M
{
4714
1.51M
#ifdef HAVE_FGETC_UNLOCKED
4715
1.51M
    return fgetc_unlocked(stream);
4716
#else
4717
    return getc(stream);
4718
#endif
4719
1.51M
}
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
99.3k
{
4729
99.3k
    int             ch, ch_next;
4730
99.3k
    char           *cp;
4731
99.3k
    int             hash;
4732
99.3k
    struct tok     *tp;
4733
99.3k
    int             too_long;
4734
99.3k
    enum { bdigits, xdigits, other } seenSymbols;
4735
4736
115k
fetch_next_token:
4737
115k
    cp = token;
4738
115k
    hash = 0;
4739
115k
    too_long = 0;
4740
    /*
4741
     * skip all white space 
4742
     */
4743
263k
    do {
4744
263k
        ch = netsnmp_getc(fp);
4745
263k
        if (ch == '\n')
4746
2.36k
            mibLine++;
4747
263k
    }
4748
263k
    while (isspace(ch) && ch != EOF);
4749
115k
    *cp++ = ch;
4750
115k
    *cp = '\0';
4751
115k
    switch (ch) {
4752
2.84k
    case EOF:
4753
2.84k
        return ENDOFFILE;
4754
562
    case '"':
4755
562
        return parseQuoteString(fp, token, maxtlen);
4756
1.84k
    case '\'':                 /* binary or hex constant */
4757
1.84k
        seenSymbols = bdigits;
4758
308k
        while ((ch = netsnmp_getc(fp)) != EOF && ch != '\'') {
4759
306k
            switch (seenSymbols) {
4760
2.81k
            case bdigits:
4761
2.81k
                if (ch == '0' || ch == '1')
4762
1.10k
                    break;
4763
1.70k
                seenSymbols = xdigits;
4764
1.70k
                NETSNMP_FALLTHROUGH;
4765
2.92k
            case xdigits:
4766
2.92k
                if (isxdigit(ch))
4767
1.28k
                    break;
4768
1.64k
                seenSymbols = other;
4769
1.64k
                NETSNMP_FALLTHROUGH;
4770
303k
            case other:
4771
303k
                break;
4772
306k
            }
4773
306k
            if (cp - token < maxtlen - 2)
4774
63.6k
                *cp++ = ch;
4775
306k
        }
4776
1.84k
        if (ch == '\'') {
4777
1.79k
            unsigned long   val = 0;
4778
1.79k
            char           *run = token + 1;
4779
1.79k
            ch = netsnmp_getc(fp);
4780
1.79k
            switch (ch) {
4781
7
            case EOF:
4782
7
                return ENDOFFILE;
4783
68
            case 'b':
4784
123
            case 'B':
4785
123
                if (seenSymbols > bdigits) {
4786
51
                    *cp++ = '\'';
4787
51
                    *cp = 0;
4788
51
                    return LABEL;
4789
51
                }
4790
716
                while (run != cp)
4791
644
                    val = val * 2 + *run++ - '0';
4792
72
                break;
4793
169
            case 'h':
4794
230
            case 'H':
4795
230
                if (seenSymbols > xdigits) {
4796
167
                    *cp++ = '\'';
4797
167
                    *cp = 0;
4798
167
                    return LABEL;
4799
167
                }
4800
869
                while (run != cp) {
4801
806
                    ch = *run++;
4802
806
                    if ('0' <= ch && ch <= '9')
4803
241
                        val = val * 16 + ch - '0';
4804
565
                    else if ('a' <= ch && ch <= 'f')
4805
236
                        val = val * 16 + ch - 'a' + 10;
4806
329
                    else if ('A' <= ch && ch <= 'F')
4807
329
                        val = val * 16 + ch - 'A' + 10;
4808
806
                }
4809
63
                break;
4810
1.43k
            default:
4811
1.43k
                *cp++ = '\'';
4812
1.43k
                *cp = 0;
4813
1.43k
                return LABEL;
4814
1.79k
            }
4815
135
            sprintf(token, "%ld", val);
4816
135
            return NUMBER;
4817
1.79k
        } else
4818
51
            return LABEL;
4819
627
    case '(':
4820
627
        return LEFTPAREN;
4821
648
    case ')':
4822
648
        return RIGHTPAREN;
4823
3.45k
    case '{':
4824
3.45k
        return LEFTBRACKET;
4825
5.00k
    case '}':
4826
5.00k
        return RIGHTBRACKET;
4827
398
    case '[':
4828
398
        return LEFTSQBRACK;
4829
556
    case ']':
4830
556
        return RIGHTSQBRACK;
4831
679
    case ';':
4832
679
        return SEMI;
4833
393
    case ',':
4834
393
        return COMMA;
4835
738
    case '|':
4836
738
        return BAR;
4837
443
    case '.':
4838
443
        ch_next = netsnmp_getc(fp);
4839
443
        if (ch_next == '.')
4840
106
            return RANGE;
4841
337
        ungetc(ch_next, fp);
4842
337
        return LABEL;
4843
5.68k
    case ':':
4844
5.68k
        ch_next = netsnmp_getc(fp);
4845
5.68k
        if (ch_next != ':') {
4846
841
            ungetc(ch_next, fp);
4847
841
            return LABEL;
4848
841
        }
4849
4.84k
        ch_next = netsnmp_getc(fp);
4850
4.84k
        if (ch_next != '=') {
4851
88
            ungetc(ch_next, fp);
4852
88
            return LABEL;
4853
88
        }
4854
4.75k
        return EQUALS;
4855
17.5k
    case '-':
4856
17.5k
        ch_next = netsnmp_getc(fp);
4857
17.5k
        if (ch_next == '-') {
4858
16.3k
            if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
4859
16.3k
               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
16.3k
            } 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
16.3k
                ch = ' ';
4873
16.3k
                ch_next = netsnmp_getc(fp);
4874
346k
                while (ch_next != EOF && ch_next != '\n' &&
4875
345k
                       (ch != '-' || ch_next != '-')) {
4876
329k
                    ch = ch_next;
4877
329k
                    ch_next = netsnmp_getc(fp);
4878
329k
                }
4879
16.3k
            }
4880
16.3k
            if (ch_next == EOF)
4881
28
                return ENDOFFILE;
4882
16.3k
            if (ch_next == '\n')
4883
180
                mibLine++;
4884
16.3k
            goto fetch_next_token;
4885
16.3k
        }
4886
1.17k
        ungetc(ch_next, fp);
4887
1.17k
  NETSNMP_FALLTHROUGH;
4888
75.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
75.4k
        if (!is_labelchar(ch))
4895
24.8k
            return LABEL;
4896
50.5k
        hash += tolower(ch);
4897
50.5k
      more:
4898
473k
        while (is_labelchar(ch_next = netsnmp_getc(fp))) {
4899
422k
            hash += tolower(ch_next);
4900
422k
            if (cp - token < maxtlen - 1)
4901
383k
                *cp++ = ch_next;
4902
39.4k
            else
4903
39.4k
                too_long = 1;
4904
422k
        }
4905
50.5k
        ungetc(ch_next, fp);
4906
50.5k
        *cp = '\0';
4907
4908
50.5k
        if (too_long)
4909
585
            print_error("Warning: token too long", token, CONTINUE);
4910
163k
        for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
4911
128k
            if ((tp->hash == hash) && (!label_compare(tp->name, token)))
4912
15.3k
                break;
4913
128k
        }
4914
50.5k
        if (tp) {
4915
15.3k
            if (tp->token != CONTINUE)
4916
15.3k
                return (tp->token);
4917
48
            while (isspace((ch_next = netsnmp_getc(fp))))
4918
43.0k
                if (ch_next == '\n')
4919
258
                    mibLine++;
4920
48
            if (ch_next == EOF)
4921
6
                return ENDOFFILE;
4922
42
            if (isalnum(ch_next)) {
4923
24
                *cp++ = ch_next;
4924
24
                hash += tolower(ch_next);
4925
24
                goto more;
4926
24
            }
4927
42
        }
4928
35.1k
        if (token[0] == '-' || isdigit((unsigned char)(token[0]))) {
4929
57.5k
            for (cp = token + 1; *cp; cp++)
4930
41.0k
                if (!isdigit((unsigned char)(*cp)))
4931
598
                    return LABEL;
4932
16.4k
            return NUMBER;
4933
17.0k
        }
4934
18.1k
        return LABEL;
4935
115k
    }
4936
115k
}
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
22.7k
{
4950
22.7k
    FILE           *fp;
4951
22.7k
    char            token[MAXTOKEN], token2[MAXTOKEN];
4952
4953
    /*
4954
     * which module is this 
4955
     */
4956
22.7k
    if ((fp = fopen(tmpstr, "r")) == NULL) {
4957
14
        snmp_log_perror(tmpstr);
4958
14
        return 1;
4959
14
    }
4960
22.7k
    DEBUGMSGTL(("parse-mibs", "Checking file: %s...\n",
4961
22.7k
                tmpstr));
4962
22.7k
    mibLine = 1;
4963
22.7k
    File = tmpstr;
4964
22.7k
    if (get_token(fp, token, MAXTOKEN) != LABEL) {
4965
13.0k
      fclose(fp);
4966
13.0k
      return 1;
4967
13.0k
    }
4968
    /*
4969
     * simple test for this being a MIB 
4970
     */
4971
9.69k
    if (get_token(fp, token2, MAXTOKEN) == DEFINITIONS) {
4972
4.84k
        new_module(token, tmpstr);
4973
4.84k
        fclose(fp);
4974
4.84k
        return 0;
4975
4.84k
    } else {
4976
4.84k
        fclose(fp);
4977
4.84k
        return 1;
4978
4.84k
    }
4979
9.69k
}
4980
4981
static int elemcmp(const void *a, const void *b)
4982
32.3k
{
4983
32.3k
    const char *const *s1 = a, *const *s2 = b;
4984
4985
32.3k
    return strcmp(*s1, *s2);
4986
32.3k
}
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.33k
{
4994
3.33k
    DIR            *dir, *dir2;
4995
3.33k
    struct dirent  *file;
4996
3.33k
    char          **filenames = NULL;
4997
3.33k
    int             fname_len, i, filename_count = 0, array_size = 0;
4998
3.33k
    char           *tmpstr;
4999
5000
3.33k
    *result = NULL;
5001
5002
3.33k
    dir = opendir(dirname);
5003
3.33k
    if (!dir)
5004
0
        return -1;
5005
5006
36.0k
    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
32.7k
        fname_len = strlen(file->d_name);
5013
32.7k
        if (fname_len > 0 && file->d_name[0] != '.'
5014
26.0k
            && file->d_name[0] != '#'
5015
26.0k
            && file->d_name[fname_len-1] != '#'
5016
26.0k
            && file->d_name[fname_len-1] != '~') {
5017
26.0k
            if (asprintf(&tmpstr, "%s/%s", dirname, file->d_name) < 0)
5018
0
                continue;
5019
26.0k
            dir2 = opendir(tmpstr);
5020
26.0k
            if (dir2) {
5021
                /* file is a directory, don't read it */
5022
6.67k
                closedir(dir2);
5023
19.3k
            } else {
5024
19.3k
                if (filename_count >= array_size) {
5025
3.33k
                    char **new_filenames;
5026
5027
3.33k
                    array_size = (array_size + 16) * 2;
5028
3.33k
                    new_filenames = realloc(filenames,
5029
3.33k
                                        array_size * sizeof(filenames[0]));
5030
3.33k
                    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.33k
                    filenames = new_filenames;
5039
3.33k
                }
5040
19.3k
                filenames[filename_count++] = tmpstr;
5041
19.3k
                tmpstr = NULL;
5042
19.3k
            }
5043
26.0k
            free(tmpstr);
5044
26.0k
        }
5045
32.7k
    }
5046
3.33k
    closedir(dir);
5047
5048
3.33k
    if (filenames)
5049
3.33k
        qsort(filenames, filename_count, sizeof(filenames[0]), elemcmp);
5050
3.33k
    *result = filenames;
5051
5052
3.33k
    return filename_count;
5053
3.33k
}
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.33k
{
5064
3.33k
    const char     *oldFile = File;
5065
3.33k
    char          **filenames;
5066
3.33k
    int             count = 0;
5067
3.33k
    int             filename_count, i;
5068
5069
3.33k
    DEBUGMSGTL(("parse-mibs", "Scanning directory %s\n", dirname));
5070
5071
3.33k
    filename_count = scan_directory(&filenames, dirname);
5072
5073
3.33k
    if (filename_count >= 0) {
5074
22.7k
        for (i = 0; i < filename_count; i++) {
5075
19.3k
            if (add_mibfile(filenames[i], strrchr(filenames[i], '/')) == 0)
5076
2.45k
                count++;
5077
19.3k
      free(filenames[i]);
5078
19.3k
        }
5079
3.33k
        File = oldFile;
5080
3.33k
        free(filenames);
5081
3.33k
        return (count);
5082
3.33k
    }
5083
0
    else
5084
0
        DEBUGMSGTL(("parse-mibs","cannot open MIB directory %s\n", dirname));
5085
5086
0
    return (-1);
5087
3.33k
}
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
562
{
5176
562
    register int    ch;
5177
562
    int             count = 0;
5178
562
    int             too_long = 0;
5179
562
    char           *token_start = token;
5180
5181
51.9k
    for (ch = netsnmp_getc(fp); ch != EOF; ch = netsnmp_getc(fp)) {
5182
51.7k
        if (ch == '\r')
5183
796
            continue;
5184
50.9k
        if (ch == '\n') {
5185
999
            mibLine++;
5186
49.9k
        } else if (ch == '"') {
5187
313
            netsnmp_assert(token - token_start < maxtlen);
5188
313
            *token = '\0';
5189
313
            if (too_long && netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
5190
4
             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
313
            return QUOTESTRING;
5203
313
        }
5204
        /*
5205
         * maximum description length check.  If greater, keep parsing
5206
         * but truncate the string 
5207
         */
5208
50.6k
        if (++count < maxtlen)
5209
47.8k
            *token++ = ch;
5210
2.73k
        else
5211
2.73k
            too_long = 1;
5212
50.6k
    }
5213
5214
249
    return 0;
5215
562
}
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
6
{
5227
6
    int             type;
5228
6
    char            token[MAXTOKEN];
5229
6
    char            nextIsImplied = 0;
5230
5231
6
    struct index_list *mylist = NULL;
5232
6
    struct index_list **mypp = &mylist;
5233
5234
6
    free_indexes(retp);
5235
5236
6
    type = get_token(fp, token, MAXTOKEN);
5237
5238
6
    if (type != LEFTBRACKET) {
5239
0
        return NULL;
5240
0
    }
5241
5242
6
    type = get_token(fp, token, MAXTOKEN);
5243
22
    while (type != RIGHTBRACKET && type != ENDOFFILE) {
5244
16
        if ((type == LABEL) || (type & SYNTAX_MASK)) {
5245
11
            *mypp = calloc(1, sizeof(struct index_list));
5246
11
            if (*mypp) {
5247
11
                (*mypp)->ilabel = strdup(token);
5248
11
                (*mypp)->isimplied = nextIsImplied;
5249
11
                mypp = &(*mypp)->next;
5250
11
                nextIsImplied = 0;
5251
11
            }
5252
11
        } else if (type == IMPLIED) {
5253
0
            nextIsImplied = 1;
5254
0
        }
5255
16
        type = get_token(fp, token, MAXTOKEN);
5256
16
    }
5257
5258
6
    *retp = mylist;
5259
6
    return mylist;
5260
6
}
5261
5262
static struct varbind_list *
5263
getVarbinds(FILE * fp, struct varbind_list **retp)
5264
39
{
5265
39
    int             type;
5266
39
    char            token[MAXTOKEN];
5267
5268
39
    struct varbind_list *mylist = NULL;
5269
39
    struct varbind_list **mypp = &mylist;
5270
5271
39
    free_varbinds(retp);
5272
5273
39
    type = get_token(fp, token, MAXTOKEN);
5274
5275
39
    if (type != LEFTBRACKET) {
5276
7
        return NULL;
5277
7
    }
5278
5279
32
    type = get_token(fp, token, MAXTOKEN);
5280
216
    while (type != RIGHTBRACKET && type != ENDOFFILE) {
5281
184
        if ((type == LABEL) || (type & SYNTAX_MASK)) {
5282
131
            *mypp = calloc(1, sizeof(struct varbind_list));
5283
131
            if (*mypp) {
5284
131
                (*mypp)->vblabel = strdup(token);
5285
131
                mypp = &(*mypp)->next;
5286
131
            }
5287
131
        }
5288
184
        type = get_token(fp, token, MAXTOKEN);
5289
184
    }
5290
5291
32
    *retp = mylist;
5292
32
    return mylist;
5293
39
}
5294
5295
static void
5296
free_indexes(struct index_list **spp)
5297
48.7k
{
5298
48.7k
    if (spp && *spp) {
5299
1
        struct index_list *pp, *npp;
5300
5301
1
        pp = *spp;
5302
1
        *spp = NULL;
5303
5304
2
        while (pp) {
5305
1
            npp = pp->next;
5306
1
            if (pp->ilabel)
5307
1
                free(pp->ilabel);
5308
1
            free(pp);
5309
1
            pp = npp;
5310
1
        }
5311
1
    }
5312
48.7k
}
5313
5314
static void
5315
free_varbinds(struct varbind_list **spp)
5316
48.7k
{
5317
48.7k
    if (spp && *spp) {
5318
31
        struct varbind_list *pp, *npp;
5319
5320
31
        pp = *spp;
5321
31
        *spp = NULL;
5322
5323
162
        while (pp) {
5324
131
            npp = pp->next;
5325
131
            if (pp->vblabel)
5326
131
                free(pp->vblabel);
5327
131
            free(pp);
5328
131
            pp = npp;
5329
131
        }
5330
31
    }
5331
48.7k
}
5332
5333
static void
5334
free_ranges(struct range_list **spp)
5335
49.1k
{
5336
49.1k
    if (spp && *spp) {
5337
44
        struct range_list *pp, *npp;
5338
5339
44
        pp = *spp;
5340
44
        *spp = NULL;
5341
5342
137
        while (pp) {
5343
93
            npp = pp->next;
5344
93
            free(pp);
5345
93
            pp = npp;
5346
93
        }
5347
44
    }
5348
49.1k
}
5349
5350
static void
5351
free_enums(struct enum_list **spp)
5352
49.2k
{
5353
49.2k
    if (spp && *spp) {
5354
99
        struct enum_list *pp, *npp;
5355
5356
99
        pp = *spp;
5357
99
        *spp = NULL;
5358
5359
366
        while (pp) {
5360
267
            npp = pp->next;
5361
267
            if (pp->label)
5362
267
                free(pp->label);
5363
267
            free(pp);
5364
267
            pp = npp;
5365
267
        }
5366
99
    }
5367
49.2k
}
5368
5369
static struct enum_list *
5370
copy_enums(struct enum_list *sp)
5371
6
{
5372
6
    struct enum_list *xp = NULL, **spp = &xp;
5373
5374
6
    while (sp) {
5375
0
        *spp = calloc(1, sizeof(struct enum_list));
5376
0
        if (!*spp)
5377
0
            break;
5378
0
        (*spp)->label = strdup(sp->label);
5379
0
        (*spp)->value = sp->value;
5380
0
        spp = &(*spp)->next;
5381
0
        sp = sp->next;
5382
0
    }
5383
6
    return (xp);
5384
6
}
5385
5386
static struct range_list *
5387
copy_ranges(struct range_list *sp)
5388
6
{
5389
6
    struct range_list *xp = NULL, **spp = &xp;
5390
5391
8
    while (sp) {
5392
2
        *spp = calloc(1, sizeof(struct range_list));
5393
2
        if (!*spp)
5394
0
            break;
5395
2
        (*spp)->low = sp->low;
5396
2
        (*spp)->high = sp->high;
5397
2
        spp = &(*spp)->next;
5398
2
        sp = sp->next;
5399
2
    }
5400
6
    return (xp);
5401
6
}
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
367
{
5695
367
    struct node    *nnp;
5696
    /*
5697
     * printf("merge defval --> %s\n",np->defaultValue); 
5698
     */
5699
367
    nnp = parse_objectid(fp, name);
5700
367
    if (nnp) {
5701
5702
        /*
5703
         * apply last OID sub-identifier data to the information 
5704
         */
5705
        /*
5706
         * already collected for this node. 
5707
         */
5708
220
        struct node    *headp, *nextp;
5709
220
        int             ncount = 0;
5710
220
        nextp = headp = nnp;
5711
506
        while (nnp->next) {
5712
286
            nextp = nnp;
5713
286
            ncount++;
5714
286
            nnp = nnp->next;
5715
286
        }
5716
5717
220
        np->label = nnp->label;
5718
220
        np->subid = nnp->subid;
5719
220
        np->modid = nnp->modid;
5720
220
        np->parent = nnp->parent;
5721
220
  if (nnp->filename != NULL) {
5722
220
    free(nnp->filename);
5723
220
  }
5724
220
        free(nnp);
5725
5726
220
        if (ncount) {
5727
73
            nextp->next = np;
5728
73
            np = headp;
5729
73
        }
5730
220
    } else {
5731
147
        free_node(np);
5732
147
        np = NULL;
5733
147
    }
5734
5735
367
    return np;
5736
367
}
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.0k
{
5752
12.0k
    free_partial_tree(tp, FALSE);
5753
5754
12.0k
    tp->label = np->label;
5755
12.0k
    np->label = NULL;
5756
12.0k
    tp->enums = np->enums;
5757
12.0k
    np->enums = NULL;
5758
12.0k
    tp->ranges = np->ranges;
5759
12.0k
    np->ranges = NULL;
5760
12.0k
    tp->indexes = np->indexes;
5761
12.0k
    np->indexes = NULL;
5762
12.0k
    tp->augments = np->augments;
5763
12.0k
    np->augments = NULL;
5764
12.0k
    tp->varbinds = np->varbinds;
5765
12.0k
    np->varbinds = NULL;
5766
12.0k
    tp->hint = np->hint;
5767
12.0k
    np->hint = NULL;
5768
12.0k
    tp->units = np->units;
5769
12.0k
    np->units = NULL;
5770
12.0k
    tp->description = np->description;
5771
12.0k
    np->description = NULL;
5772
12.0k
    tp->reference = np->reference;
5773
12.0k
    np->reference = NULL;
5774
12.0k
    tp->defaultValue = np->defaultValue;
5775
12.0k
    np->defaultValue = NULL;
5776
12.0k
    tp->subid = np->subid;
5777
12.0k
    tp->tc_index = np->tc_index;
5778
12.0k
    tp->type = translation_table[np->type];
5779
12.0k
    tp->access = np->access;
5780
12.0k
    tp->status = np->status;
5781
5782
12.0k
    set_function(tp);
5783
12.0k
}
5784
5785
#endif /* NETSNMP_DISABLE_MIB_LOADING */