net-snmp 5.7
|
00001 /* 00002 * parse.c 00003 * 00004 */ 00005 /* Portions of this file are subject to the following copyrights. See 00006 * the Net-SNMP's COPYING file for more details and other copyrights 00007 * that may apply: 00008 */ 00009 /****************************************************************** 00010 Copyright 1989, 1991, 1992 by Carnegie Mellon University 00011 00012 All Rights Reserved 00013 00014 Permission to use, copy, modify, and distribute this software and its 00015 documentation for any purpose and without fee is hereby granted, 00016 provided that the above copyright notice appear in all copies and that 00017 both that copyright notice and this permission notice appear in 00018 supporting documentation, and that the name of CMU not be 00019 used in advertising or publicity pertaining to distribution of the 00020 software without specific, written prior permission. 00021 00022 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 00023 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 00024 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 00025 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 00026 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 00027 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 00028 SOFTWARE. 00029 ******************************************************************/ 00030 /* 00031 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. 00032 * Use is subject to license terms specified in the COPYING file 00033 * distributed with the Net-SNMP package. 00034 */ 00035 #include <net-snmp/net-snmp-config.h> 00036 #include <net-snmp/net-snmp-features.h> 00037 00038 #ifndef NETSNMP_DISABLE_MIB_LOADING 00039 00040 #if HAVE_LIMITS_H 00041 #include <limits.h> 00042 #endif 00043 #include <stdio.h> 00044 #if HAVE_STDLIB_H 00045 #include <stdlib.h> 00046 #endif 00047 #if HAVE_STRING_H 00048 #include <string.h> 00049 #else 00050 #include <strings.h> 00051 #endif 00052 #include <ctype.h> 00053 #include <sys/types.h> 00054 #if HAVE_SYS_STAT_H 00055 #include <sys/stat.h> 00056 #endif 00057 00058 /* 00059 * Wow. This is ugly. -- Wes 00060 */ 00061 #if HAVE_DIRENT_H 00062 # include <dirent.h> 00063 # define NAMLEN(dirent) strlen((dirent)->d_name) 00064 #else 00065 # define dirent direct 00066 # define NAMLEN(dirent) (dirent)->d_namlen 00067 # if HAVE_SYS_NDIR_H 00068 # include <sys/ndir.h> 00069 # endif 00070 # if HAVE_SYS_DIR_H 00071 # include <sys/dir.h> 00072 # endif 00073 # if HAVE_NDIR_H 00074 # include <ndir.h> 00075 # endif 00076 #endif 00077 #if TIME_WITH_SYS_TIME 00078 # include <sys/time.h> 00079 # include <time.h> 00080 #else 00081 # if HAVE_SYS_TIME_H 00082 # include <sys/time.h> 00083 # else 00084 # include <time.h> 00085 # endif 00086 #endif 00087 #if HAVE_NETINET_IN_H 00088 #include <netinet/in.h> 00089 #endif 00090 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) 00091 #include <regex.h> 00092 #endif 00093 #if HAVE_UNISTD_H 00094 #include <unistd.h> 00095 #endif 00096 #if HAVE_DMALLOC_H 00097 #include <dmalloc.h> 00098 #endif 00099 00100 #include <errno.h> 00101 00102 #include <net-snmp/types.h> 00103 #include <net-snmp/output_api.h> 00104 #include <net-snmp/config_api.h> 00105 #include <net-snmp/utilities.h> 00106 00107 #include <net-snmp/library/parse.h> 00108 #include <net-snmp/library/mib.h> 00109 #include <net-snmp/library/snmp_api.h> 00110 #include <net-snmp/library/tools.h> 00111 00112 netsnmp_feature_child_of(find_module, mib_api) 00113 netsnmp_feature_child_of(get_tc_description, mib_api) 00114 00115 /* 00116 * A linked list of nodes. 00117 */ 00118 struct node { 00119 struct node *next; 00120 char *label; /* This node's (unique) textual name */ 00121 u_long subid; /* This node's integer subidentifier */ 00122 int modid; /* The module containing this node */ 00123 char *parent; /* The parent's textual name */ 00124 int tc_index; /* index into tclist (-1 if NA) */ 00125 int type; /* The type of object this represents */ 00126 int access; 00127 int status; 00128 struct enum_list *enums; /* (optional) list of enumerated integers */ 00129 struct range_list *ranges; 00130 struct index_list *indexes; 00131 char *augments; 00132 struct varbind_list *varbinds; 00133 char *hint; 00134 char *units; 00135 char *description; /* description (a quoted string) */ 00136 char *reference; /* references (a quoted string) */ 00137 char *defaultValue; 00138 char *filename; 00139 int lineno; 00140 }; 00141 00142 /* 00143 * This is one element of an object identifier with either an integer 00144 * subidentifier, or a textual string label, or both. 00145 * The subid is -1 if not present, and label is NULL if not present. 00146 */ 00147 struct subid_s { 00148 int subid; 00149 int modid; 00150 char *label; 00151 }; 00152 00153 #define MAXTC 4096 00154 struct tc { /* textual conventions */ 00155 int type; 00156 int modid; 00157 char *descriptor; 00158 char *hint; 00159 struct enum_list *enums; 00160 struct range_list *ranges; 00161 char *description; 00162 } tclist[MAXTC]; 00163 00164 int mibLine = 0; 00165 const char *File = "(none)"; 00166 static int anonymous = 0; 00167 00168 struct objgroup { 00169 char *name; 00170 int line; 00171 struct objgroup *next; 00172 } *objgroups = NULL, *objects = NULL, *notifs = NULL; 00173 00174 #define SYNTAX_MASK 0x80 00175 /* 00176 * types of tokens 00177 * Tokens wiht the SYNTAX_MASK bit set are syntax tokens 00178 */ 00179 #define CONTINUE -1 00180 #define ENDOFFILE 0 00181 #define LABEL 1 00182 #define SUBTREE 2 00183 #define SYNTAX 3 00184 #define OBJID (4 | SYNTAX_MASK) 00185 #define OCTETSTR (5 | SYNTAX_MASK) 00186 #define INTEGER (6 | SYNTAX_MASK) 00187 #define NETADDR (7 | SYNTAX_MASK) 00188 #define IPADDR (8 | SYNTAX_MASK) 00189 #define COUNTER (9 | SYNTAX_MASK) 00190 #define GAUGE (10 | SYNTAX_MASK) 00191 #define TIMETICKS (11 | SYNTAX_MASK) 00192 #define KW_OPAQUE (12 | SYNTAX_MASK) 00193 #define NUL (13 | SYNTAX_MASK) 00194 #define SEQUENCE 14 00195 #define OF 15 /* SEQUENCE OF */ 00196 #define OBJTYPE 16 00197 #define ACCESS 17 00198 #define READONLY 18 00199 #define READWRITE 19 00200 #define WRITEONLY 20 00201 #ifdef NOACCESS 00202 #undef NOACCESS /* agent 'NOACCESS' token */ 00203 #endif 00204 #define NOACCESS 21 00205 #define STATUS 22 00206 #define MANDATORY 23 00207 #define KW_OPTIONAL 24 00208 #define OBSOLETE 25 00209 /* 00210 * #define RECOMMENDED 26 00211 */ 00212 #define PUNCT 27 00213 #define EQUALS 28 00214 #define NUMBER 29 00215 #define LEFTBRACKET 30 00216 #define RIGHTBRACKET 31 00217 #define LEFTPAREN 32 00218 #define RIGHTPAREN 33 00219 #define COMMA 34 00220 #define DESCRIPTION 35 00221 #define QUOTESTRING 36 00222 #define INDEX 37 00223 #define DEFVAL 38 00224 #define DEPRECATED 39 00225 #define SIZE 40 00226 #define BITSTRING (41 | SYNTAX_MASK) 00227 #define NSAPADDRESS (42 | SYNTAX_MASK) 00228 #define COUNTER64 (43 | SYNTAX_MASK) 00229 #define OBJGROUP 44 00230 #define NOTIFTYPE 45 00231 #define AUGMENTS 46 00232 #define COMPLIANCE 47 00233 #define READCREATE 48 00234 #define UNITS 49 00235 #define REFERENCE 50 00236 #define NUM_ENTRIES 51 00237 #define MODULEIDENTITY 52 00238 #define LASTUPDATED 53 00239 #define ORGANIZATION 54 00240 #define CONTACTINFO 55 00241 #define UINTEGER32 (56 | SYNTAX_MASK) 00242 #define CURRENT 57 00243 #define DEFINITIONS 58 00244 #define END 59 00245 #define SEMI 60 00246 #define TRAPTYPE 61 00247 #define ENTERPRISE 62 00248 /* 00249 * #define DISPLAYSTR (63 | SYNTAX_MASK) 00250 */ 00251 #define BEGIN 64 00252 #define IMPORTS 65 00253 #define EXPORTS 66 00254 #define ACCNOTIFY 67 00255 #define BAR 68 00256 #define RANGE 69 00257 #define CONVENTION 70 00258 #define DISPLAYHINT 71 00259 #define FROM 72 00260 #define AGENTCAP 73 00261 #define MACRO 74 00262 #define IMPLIED 75 00263 #define SUPPORTS 76 00264 #define INCLUDES 77 00265 #define VARIATION 78 00266 #define REVISION 79 00267 #define NOTIMPL 80 00268 #define OBJECTS 81 00269 #define NOTIFICATIONS 82 00270 #define MODULE 83 00271 #define MINACCESS 84 00272 #define PRODREL 85 00273 #define WRSYNTAX 86 00274 #define CREATEREQ 87 00275 #define NOTIFGROUP 88 00276 #define MANDATORYGROUPS 89 00277 #define GROUP 90 00278 #define OBJECT 91 00279 #define IDENTIFIER 92 00280 #define CHOICE 93 00281 #define LEFTSQBRACK 95 00282 #define RIGHTSQBRACK 96 00283 #define IMPLICIT 97 00284 #define APPSYNTAX (98 | SYNTAX_MASK) 00285 #define OBJSYNTAX (99 | SYNTAX_MASK) 00286 #define SIMPLESYNTAX (100 | SYNTAX_MASK) 00287 #define OBJNAME (101 | SYNTAX_MASK) 00288 #define NOTIFNAME (102 | SYNTAX_MASK) 00289 #define VARIABLES 103 00290 #define UNSIGNED32 (104 | SYNTAX_MASK) 00291 #define INTEGER32 (105 | SYNTAX_MASK) 00292 #define OBJIDENTITY 106 00293 /* 00294 * Beware of reaching SYNTAX_MASK (0x80) 00295 */ 00296 00297 struct tok { 00298 const char *name; /* token name */ 00299 int len; /* length not counting nul */ 00300 int token; /* value */ 00301 int hash; /* hash of name */ 00302 struct tok *next; /* pointer to next in hash table */ 00303 }; 00304 00305 00306 static struct tok tokens[] = { 00307 {"obsolete", sizeof("obsolete") - 1, OBSOLETE} 00308 , 00309 {"Opaque", sizeof("Opaque") - 1, KW_OPAQUE} 00310 , 00311 {"optional", sizeof("optional") - 1, KW_OPTIONAL} 00312 , 00313 {"LAST-UPDATED", sizeof("LAST-UPDATED") - 1, LASTUPDATED} 00314 , 00315 {"ORGANIZATION", sizeof("ORGANIZATION") - 1, ORGANIZATION} 00316 , 00317 {"CONTACT-INFO", sizeof("CONTACT-INFO") - 1, CONTACTINFO} 00318 , 00319 {"MODULE-IDENTITY", sizeof("MODULE-IDENTITY") - 1, MODULEIDENTITY} 00320 , 00321 {"MODULE-COMPLIANCE", sizeof("MODULE-COMPLIANCE") - 1, COMPLIANCE} 00322 , 00323 {"DEFINITIONS", sizeof("DEFINITIONS") - 1, DEFINITIONS} 00324 , 00325 {"END", sizeof("END") - 1, END} 00326 , 00327 {"AUGMENTS", sizeof("AUGMENTS") - 1, AUGMENTS} 00328 , 00329 {"not-accessible", sizeof("not-accessible") - 1, NOACCESS} 00330 , 00331 {"write-only", sizeof("write-only") - 1, WRITEONLY} 00332 , 00333 {"NsapAddress", sizeof("NsapAddress") - 1, NSAPADDRESS} 00334 , 00335 {"UNITS", sizeof("Units") - 1, UNITS} 00336 , 00337 {"REFERENCE", sizeof("REFERENCE") - 1, REFERENCE} 00338 , 00339 {"NUM-ENTRIES", sizeof("NUM-ENTRIES") - 1, NUM_ENTRIES} 00340 , 00341 {"BITSTRING", sizeof("BITSTRING") - 1, BITSTRING} 00342 , 00343 {"BIT", sizeof("BIT") - 1, CONTINUE} 00344 , 00345 {"BITS", sizeof("BITS") - 1, BITSTRING} 00346 , 00347 {"Counter64", sizeof("Counter64") - 1, COUNTER64} 00348 , 00349 {"TimeTicks", sizeof("TimeTicks") - 1, TIMETICKS} 00350 , 00351 {"NOTIFICATION-TYPE", sizeof("NOTIFICATION-TYPE") - 1, NOTIFTYPE} 00352 , 00353 {"OBJECT-GROUP", sizeof("OBJECT-GROUP") - 1, OBJGROUP} 00354 , 00355 {"OBJECT-IDENTITY", sizeof("OBJECT-IDENTITY") - 1, OBJIDENTITY} 00356 , 00357 {"IDENTIFIER", sizeof("IDENTIFIER") - 1, IDENTIFIER} 00358 , 00359 {"OBJECT", sizeof("OBJECT") - 1, OBJECT} 00360 , 00361 {"NetworkAddress", sizeof("NetworkAddress") - 1, NETADDR} 00362 , 00363 {"Gauge", sizeof("Gauge") - 1, GAUGE} 00364 , 00365 {"Gauge32", sizeof("Gauge32") - 1, GAUGE} 00366 , 00367 {"Unsigned32", sizeof("Unsigned32") - 1, UNSIGNED32} 00368 , 00369 {"read-write", sizeof("read-write") - 1, READWRITE} 00370 , 00371 {"read-create", sizeof("read-create") - 1, READCREATE} 00372 , 00373 {"OCTETSTRING", sizeof("OCTETSTRING") - 1, OCTETSTR} 00374 , 00375 {"OCTET", sizeof("OCTET") - 1, CONTINUE} 00376 , 00377 {"OF", sizeof("OF") - 1, OF} 00378 , 00379 {"SEQUENCE", sizeof("SEQUENCE") - 1, SEQUENCE} 00380 , 00381 {"NULL", sizeof("NULL") - 1, NUL} 00382 , 00383 {"IpAddress", sizeof("IpAddress") - 1, IPADDR} 00384 , 00385 {"UInteger32", sizeof("UInteger32") - 1, UINTEGER32} 00386 , 00387 {"INTEGER", sizeof("INTEGER") - 1, INTEGER} 00388 , 00389 {"Integer32", sizeof("Integer32") - 1, INTEGER32} 00390 , 00391 {"Counter", sizeof("Counter") - 1, COUNTER} 00392 , 00393 {"Counter32", sizeof("Counter32") - 1, COUNTER} 00394 , 00395 {"read-only", sizeof("read-only") - 1, READONLY} 00396 , 00397 {"DESCRIPTION", sizeof("DESCRIPTION") - 1, DESCRIPTION} 00398 , 00399 {"INDEX", sizeof("INDEX") - 1, INDEX} 00400 , 00401 {"DEFVAL", sizeof("DEFVAL") - 1, DEFVAL} 00402 , 00403 {"deprecated", sizeof("deprecated") - 1, DEPRECATED} 00404 , 00405 {"SIZE", sizeof("SIZE") - 1, SIZE} 00406 , 00407 {"MAX-ACCESS", sizeof("MAX-ACCESS") - 1, ACCESS} 00408 , 00409 {"ACCESS", sizeof("ACCESS") - 1, ACCESS} 00410 , 00411 {"mandatory", sizeof("mandatory") - 1, MANDATORY} 00412 , 00413 {"current", sizeof("current") - 1, CURRENT} 00414 , 00415 {"STATUS", sizeof("STATUS") - 1, STATUS} 00416 , 00417 {"SYNTAX", sizeof("SYNTAX") - 1, SYNTAX} 00418 , 00419 {"OBJECT-TYPE", sizeof("OBJECT-TYPE") - 1, OBJTYPE} 00420 , 00421 {"TRAP-TYPE", sizeof("TRAP-TYPE") - 1, TRAPTYPE} 00422 , 00423 {"ENTERPRISE", sizeof("ENTERPRISE") - 1, ENTERPRISE} 00424 , 00425 {"BEGIN", sizeof("BEGIN") - 1, BEGIN} 00426 , 00427 {"IMPORTS", sizeof("IMPORTS") - 1, IMPORTS} 00428 , 00429 {"EXPORTS", sizeof("EXPORTS") - 1, EXPORTS} 00430 , 00431 {"accessible-for-notify", sizeof("accessible-for-notify") - 1, 00432 ACCNOTIFY} 00433 , 00434 {"TEXTUAL-CONVENTION", sizeof("TEXTUAL-CONVENTION") - 1, CONVENTION} 00435 , 00436 {"NOTIFICATION-GROUP", sizeof("NOTIFICATION-GROUP") - 1, NOTIFGROUP} 00437 , 00438 {"DISPLAY-HINT", sizeof("DISPLAY-HINT") - 1, DISPLAYHINT} 00439 , 00440 {"FROM", sizeof("FROM") - 1, FROM} 00441 , 00442 {"AGENT-CAPABILITIES", sizeof("AGENT-CAPABILITIES") - 1, AGENTCAP} 00443 , 00444 {"MACRO", sizeof("MACRO") - 1, MACRO} 00445 , 00446 {"IMPLIED", sizeof("IMPLIED") - 1, IMPLIED} 00447 , 00448 {"SUPPORTS", sizeof("SUPPORTS") - 1, SUPPORTS} 00449 , 00450 {"INCLUDES", sizeof("INCLUDES") - 1, INCLUDES} 00451 , 00452 {"VARIATION", sizeof("VARIATION") - 1, VARIATION} 00453 , 00454 {"REVISION", sizeof("REVISION") - 1, REVISION} 00455 , 00456 {"not-implemented", sizeof("not-implemented") - 1, NOTIMPL} 00457 , 00458 {"OBJECTS", sizeof("OBJECTS") - 1, OBJECTS} 00459 , 00460 {"NOTIFICATIONS", sizeof("NOTIFICATIONS") - 1, NOTIFICATIONS} 00461 , 00462 {"MODULE", sizeof("MODULE") - 1, MODULE} 00463 , 00464 {"MIN-ACCESS", sizeof("MIN-ACCESS") - 1, MINACCESS} 00465 , 00466 {"PRODUCT-RELEASE", sizeof("PRODUCT-RELEASE") - 1, PRODREL} 00467 , 00468 {"WRITE-SYNTAX", sizeof("WRITE-SYNTAX") - 1, WRSYNTAX} 00469 , 00470 {"CREATION-REQUIRES", sizeof("CREATION-REQUIRES") - 1, CREATEREQ} 00471 , 00472 {"MANDATORY-GROUPS", sizeof("MANDATORY-GROUPS") - 1, MANDATORYGROUPS} 00473 , 00474 {"GROUP", sizeof("GROUP") - 1, GROUP} 00475 , 00476 {"CHOICE", sizeof("CHOICE") - 1, CHOICE} 00477 , 00478 {"IMPLICIT", sizeof("IMPLICIT") - 1, IMPLICIT} 00479 , 00480 {"ObjectSyntax", sizeof("ObjectSyntax") - 1, OBJSYNTAX} 00481 , 00482 {"SimpleSyntax", sizeof("SimpleSyntax") - 1, SIMPLESYNTAX} 00483 , 00484 {"ApplicationSyntax", sizeof("ApplicationSyntax") - 1, APPSYNTAX} 00485 , 00486 {"ObjectName", sizeof("ObjectName") - 1, OBJNAME} 00487 , 00488 {"NotificationName", sizeof("NotificationName") - 1, NOTIFNAME} 00489 , 00490 {"VARIABLES", sizeof("VARIABLES") - 1, VARIABLES} 00491 , 00492 {NULL} 00493 }; 00494 00495 static struct module_compatability *module_map_head; 00496 static struct module_compatability module_map[] = { 00497 {"RFC1065-SMI", "RFC1155-SMI", NULL, 0}, 00498 {"RFC1066-MIB", "RFC1156-MIB", NULL, 0}, 00499 /* 00500 * 'mib' -> 'mib-2' 00501 */ 00502 {"RFC1156-MIB", "RFC1158-MIB", NULL, 0}, 00503 /* 00504 * 'snmpEnableAuthTraps' -> 'snmpEnableAuthenTraps' 00505 */ 00506 {"RFC1158-MIB", "RFC1213-MIB", NULL, 0}, 00507 /* 00508 * 'nullOID' -> 'zeroDotZero' 00509 */ 00510 {"RFC1155-SMI", "SNMPv2-SMI", NULL, 0}, 00511 {"RFC1213-MIB", "SNMPv2-SMI", "mib-2", 0}, 00512 {"RFC1213-MIB", "SNMPv2-MIB", "sys", 3}, 00513 {"RFC1213-MIB", "IF-MIB", "if", 2}, 00514 {"RFC1213-MIB", "IP-MIB", "ip", 2}, 00515 {"RFC1213-MIB", "IP-MIB", "icmp", 4}, 00516 {"RFC1213-MIB", "TCP-MIB", "tcp", 3}, 00517 {"RFC1213-MIB", "UDP-MIB", "udp", 3}, 00518 {"RFC1213-MIB", "SNMPv2-SMI", "transmission", 0}, 00519 {"RFC1213-MIB", "SNMPv2-MIB", "snmp", 4}, 00520 {"RFC1231-MIB", "TOKENRING-MIB", NULL, 0}, 00521 {"RFC1271-MIB", "RMON-MIB", NULL, 0}, 00522 {"RFC1286-MIB", "SOURCE-ROUTING-MIB", "dot1dSr", 7}, 00523 {"RFC1286-MIB", "BRIDGE-MIB", NULL, 0}, 00524 {"RFC1315-MIB", "FRAME-RELAY-DTE-MIB", NULL, 0}, 00525 {"RFC1316-MIB", "CHARACTER-MIB", NULL, 0}, 00526 {"RFC1406-MIB", "DS1-MIB", NULL, 0}, 00527 {"RFC-1213", "RFC1213-MIB", NULL, 0}, 00528 }; 00529 00530 #define MODULE_NOT_FOUND 0 00531 #define MODULE_LOADED_OK 1 00532 #define MODULE_ALREADY_LOADED 2 00533 /* 00534 * #define MODULE_LOAD_FAILED 3 00535 */ 00536 #define MODULE_LOAD_FAILED MODULE_NOT_FOUND 00537 #define MODULE_SYNTAX_ERROR 4 00538 00539 int gMibError = 0,gLoop = 0; 00540 char *gpMibErrorString = NULL; 00541 char gMibNames[STRINGMAX]; 00542 00543 #define HASHSIZE 32 00544 #define BUCKET(x) (x & (HASHSIZE-1)) 00545 00546 #define NHASHSIZE 128 00547 #define NBUCKET(x) (x & (NHASHSIZE-1)) 00548 00549 static struct tok *buckets[HASHSIZE]; 00550 00551 static struct node *nbuckets[NHASHSIZE]; 00552 static struct tree *tbuckets[NHASHSIZE]; 00553 static struct module *module_head = NULL; 00554 00555 static struct node *orphan_nodes = NULL; 00556 NETSNMP_IMPORT struct tree *tree_head; 00557 struct tree *tree_head = NULL; 00558 00559 #define NUMBER_OF_ROOT_NODES 3 00560 static struct module_import root_imports[NUMBER_OF_ROOT_NODES]; 00561 00562 static int current_module = 0; 00563 static int max_module = 0; 00564 static int first_err_module = 1; 00565 static char *last_err_module = NULL; /* no repeats on "Cannot find module..." */ 00566 00567 static void tree_from_node(struct tree *tp, struct node *np); 00568 static void do_subtree(struct tree *, struct node **); 00569 static void do_linkup(struct module *, struct node *); 00570 static void dump_module_list(void); 00571 static int get_token(FILE *, char *, int); 00572 static int parseQuoteString(FILE *, char *, int); 00573 static int tossObjectIdentifier(FILE *); 00574 static int name_hash(const char *); 00575 static void init_node_hash(struct node *); 00576 static void print_error(const char *, const char *, int); 00577 static void free_tree(struct tree *); 00578 static void free_partial_tree(struct tree *, int); 00579 static void free_node(struct node *); 00580 static void build_translation_table(void); 00581 static void init_tree_roots(void); 00582 static void merge_anon_children(struct tree *, struct tree *); 00583 static void unlink_tbucket(struct tree *); 00584 static void unlink_tree(struct tree *); 00585 static int getoid(FILE *, struct subid_s *, int); 00586 static struct node *parse_objectid(FILE *, char *); 00587 static int get_tc(const char *, int, int *, struct enum_list **, 00588 struct range_list **, char **); 00589 static int get_tc_index(const char *, int); 00590 static struct enum_list *parse_enumlist(FILE *, struct enum_list **); 00591 static struct range_list *parse_ranges(FILE * fp, struct range_list **); 00592 static struct node *parse_asntype(FILE *, char *, int *, char *); 00593 static struct node *parse_objecttype(FILE *, char *); 00594 static struct node *parse_objectgroup(FILE *, char *, int, 00595 struct objgroup **); 00596 static struct node *parse_notificationDefinition(FILE *, char *); 00597 static struct node *parse_trapDefinition(FILE *, char *); 00598 static struct node *parse_compliance(FILE *, char *); 00599 static struct node *parse_capabilities(FILE *, char *); 00600 static struct node *parse_moduleIdentity(FILE *, char *); 00601 static struct node *parse_macro(FILE *, char *); 00602 static void parse_imports(FILE *); 00603 static struct node *parse(FILE *, struct node *); 00604 00605 static int read_module_internal(const char *); 00606 static int read_module_replacements(const char *); 00607 static int read_import_replacements(const char *, 00608 struct module_import *); 00609 00610 static void new_module(const char *, const char *); 00611 00612 static struct node *merge_parse_objectid(struct node *, FILE *, char *); 00613 static struct index_list *getIndexes(FILE * fp, struct index_list **); 00614 static struct varbind_list *getVarbinds(FILE * fp, struct varbind_list **); 00615 static void free_indexes(struct index_list **); 00616 static void free_varbinds(struct varbind_list **); 00617 static void free_ranges(struct range_list **); 00618 static void free_enums(struct enum_list **); 00619 static struct range_list *copy_ranges(struct range_list *); 00620 static struct enum_list *copy_enums(struct enum_list *); 00621 00622 static u_int compute_match(const char *search_base, const char *key); 00623 00624 void 00625 snmp_mib_toggle_options_usage(const char *lead, FILE * outf) 00626 { 00627 fprintf(outf, "%su: %sallow the use of underlines in MIB symbols\n", 00628 lead, ((netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00629 NETSNMP_DS_LIB_MIB_PARSE_LABEL)) ? 00630 "dis" : "")); 00631 fprintf(outf, "%sc: %sallow the use of \"--\" to terminate comments\n", 00632 lead, ((netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00633 NETSNMP_DS_LIB_MIB_COMMENT_TERM)) ? 00634 "" : "dis")); 00635 00636 fprintf(outf, "%sd: %ssave the DESCRIPTIONs of the MIB objects\n", 00637 lead, ((netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00638 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) ? 00639 "do not " : "")); 00640 00641 fprintf(outf, "%se: disable errors when MIB symbols conflict\n", lead); 00642 00643 fprintf(outf, "%sw: enable warnings when MIB symbols conflict\n", lead); 00644 00645 fprintf(outf, "%sW: enable detailed warnings when MIB symbols conflict\n", 00646 lead); 00647 00648 fprintf(outf, "%sR: replace MIB symbols from latest module\n", lead); 00649 } 00650 00651 char * 00652 snmp_mib_toggle_options(char *options) 00653 { 00654 if (options) { 00655 while (*options) { 00656 switch (*options) { 00657 case 'u': 00658 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_PARSE_LABEL, 00659 !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00660 NETSNMP_DS_LIB_MIB_PARSE_LABEL)); 00661 break; 00662 00663 case 'c': 00664 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, 00665 NETSNMP_DS_LIB_MIB_COMMENT_TERM); 00666 break; 00667 00668 case 'e': 00669 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, 00670 NETSNMP_DS_LIB_MIB_ERRORS); 00671 break; 00672 00673 case 'w': 00674 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 00675 NETSNMP_DS_LIB_MIB_WARNINGS, 1); 00676 break; 00677 00678 case 'W': 00679 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 00680 NETSNMP_DS_LIB_MIB_WARNINGS, 2); 00681 break; 00682 00683 case 'd': 00684 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, 00685 NETSNMP_DS_LIB_SAVE_MIB_DESCRS); 00686 break; 00687 00688 case 'R': 00689 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, 00690 NETSNMP_DS_LIB_MIB_REPLACE); 00691 break; 00692 00693 default: 00694 /* 00695 * return at the unknown option 00696 */ 00697 return options; 00698 } 00699 options++; 00700 } 00701 } 00702 return NULL; 00703 } 00704 00705 static int 00706 name_hash(const char *name) 00707 { 00708 int hash = 0; 00709 const char *cp; 00710 00711 if (!name) 00712 return 0; 00713 for (cp = name; *cp; cp++) 00714 hash += tolower((unsigned char)(*cp)); 00715 return (hash); 00716 } 00717 00718 void 00719 netsnmp_init_mib_internals(void) 00720 { 00721 register struct tok *tp; 00722 register int b, i; 00723 int max_modc; 00724 00725 if (tree_head) 00726 return; 00727 00728 /* 00729 * Set up hash list of pre-defined tokens 00730 */ 00731 memset(buckets, 0, sizeof(buckets)); 00732 for (tp = tokens; tp->name; tp++) { 00733 tp->hash = name_hash(tp->name); 00734 b = BUCKET(tp->hash); 00735 if (buckets[b]) 00736 tp->next = buckets[b]; /* BUG ??? */ 00737 buckets[b] = tp; 00738 } 00739 00740 /* 00741 * Initialise other internal structures 00742 */ 00743 00744 max_modc = sizeof(module_map) / sizeof(module_map[0]) - 1; 00745 for (i = 0; i < max_modc; ++i) 00746 module_map[i].next = &(module_map[i + 1]); 00747 module_map[max_modc].next = NULL; 00748 module_map_head = module_map; 00749 00750 memset(nbuckets, 0, sizeof(nbuckets)); 00751 memset(tbuckets, 0, sizeof(tbuckets)); 00752 memset(tclist, 0, MAXTC * sizeof(struct tc)); 00753 build_translation_table(); 00754 init_tree_roots(); /* Set up initial roots */ 00755 /* 00756 * Relies on 'add_mibdir' having set up the modules 00757 */ 00758 } 00759 00760 #ifndef NETSNMP_NO_LEGACY_DEFINITIONS 00761 void 00762 init_mib_internals(void) 00763 { 00764 netsnmp_init_mib_internals(); 00765 } 00766 #endif 00767 00768 static void 00769 init_node_hash(struct node *nodes) 00770 { 00771 struct node *np, *nextp; 00772 int hash; 00773 00774 memset(nbuckets, 0, sizeof(nbuckets)); 00775 for (np = nodes; np;) { 00776 nextp = np->next; 00777 hash = NBUCKET(name_hash(np->parent)); 00778 np->next = nbuckets[hash]; 00779 nbuckets[hash] = np; 00780 np = nextp; 00781 } 00782 } 00783 00784 static int erroneousMibs = 0; 00785 00786 netsnmp_feature_child_of(parse_get_error_count, netsnmp_unused) 00787 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_GET_ERROR_COUNT 00788 int 00789 get_mib_parse_error_count(void) 00790 { 00791 return erroneousMibs; 00792 } 00793 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_GET_ERROR_COUNT */ 00794 00795 00796 static void 00797 print_error(const char *str, const char *token, int type) 00798 { 00799 erroneousMibs++; 00800 DEBUGMSGTL(("parse-mibs", "\n")); 00801 if (type == ENDOFFILE) 00802 snmp_log(LOG_ERR, "%s (EOF): At line %d in %s\n", str, mibLine, 00803 File); 00804 else if (token && *token) 00805 snmp_log(LOG_ERR, "%s (%s): At line %d in %s\n", str, token, 00806 mibLine, File); 00807 else 00808 snmp_log(LOG_ERR, "%s: At line %d in %s\n", str, mibLine, File); 00809 } 00810 00811 static void 00812 print_module_not_found(const char *cp) 00813 { 00814 if (first_err_module) { 00815 snmp_log(LOG_ERR, "MIB search path: %s\n", 00816 netsnmp_get_mib_directory()); 00817 first_err_module = 0; 00818 } 00819 if (!last_err_module || strcmp(cp, last_err_module)) 00820 print_error("Cannot find module", cp, CONTINUE); 00821 if (last_err_module) 00822 free(last_err_module); 00823 last_err_module = strdup(cp); 00824 } 00825 00826 static struct node * 00827 alloc_node(int modid) 00828 { 00829 struct node *np; 00830 np = (struct node *) calloc(1, sizeof(struct node)); 00831 if (np) { 00832 np->tc_index = -1; 00833 np->modid = modid; 00834 np->filename = strdup(File); 00835 np->lineno = mibLine; 00836 } 00837 return np; 00838 } 00839 00840 static void 00841 unlink_tbucket(struct tree *tp) 00842 { 00843 int hash = NBUCKET(name_hash(tp->label)); 00844 struct tree *otp = NULL, *ntp = tbuckets[hash]; 00845 00846 while (ntp && ntp != tp) { 00847 otp = ntp; 00848 ntp = ntp->next; 00849 } 00850 if (!ntp) 00851 snmp_log(LOG_EMERG, "Can't find %s in tbuckets\n", tp->label); 00852 else if (otp) 00853 otp->next = ntp->next; 00854 else 00855 tbuckets[hash] = tp->next; 00856 } 00857 00858 static void 00859 unlink_tree(struct tree *tp) 00860 { 00861 struct tree *otp = NULL, *ntp = tp->parent; 00862 00863 if (!ntp) { /* this tree has no parent */ 00864 DEBUGMSGTL(("unlink_tree", "Tree node %s has no parent\n", 00865 tp->label)); 00866 } else { 00867 ntp = ntp->child_list; 00868 00869 while (ntp && ntp != tp) { 00870 otp = ntp; 00871 ntp = ntp->next_peer; 00872 } 00873 if (!ntp) 00874 snmp_log(LOG_EMERG, "Can't find %s in %s's children\n", 00875 tp->label, tp->parent->label); 00876 else if (otp) 00877 otp->next_peer = ntp->next_peer; 00878 else 00879 tp->parent->child_list = tp->next_peer; 00880 } 00881 00882 if (tree_head == tp) 00883 tree_head = tp->next_peer; 00884 } 00885 00886 static void 00887 free_partial_tree(struct tree *tp, int keep_label) 00888 { 00889 if (!tp) 00890 return; 00891 00892 /* 00893 * remove the data from this tree node 00894 */ 00895 free_enums(&tp->enums); 00896 free_ranges(&tp->ranges); 00897 free_indexes(&tp->indexes); 00898 free_varbinds(&tp->varbinds); 00899 if (!keep_label) 00900 SNMP_FREE(tp->label); 00901 SNMP_FREE(tp->hint); 00902 SNMP_FREE(tp->units); 00903 SNMP_FREE(tp->description); 00904 SNMP_FREE(tp->reference); 00905 SNMP_FREE(tp->augments); 00906 SNMP_FREE(tp->defaultValue); 00907 } 00908 00909 /* 00910 * free a tree node. Note: the node must already have been unlinked 00911 * from the tree when calling this routine 00912 */ 00913 static void 00914 free_tree(struct tree *Tree) 00915 { 00916 if (!Tree) 00917 return; 00918 00919 unlink_tbucket(Tree); 00920 free_partial_tree(Tree, FALSE); 00921 if (Tree->number_modules > 1) 00922 free((char *) Tree->module_list); 00923 free((char *) Tree); 00924 } 00925 00926 static void 00927 free_node(struct node *np) 00928 { 00929 if (!np) 00930 return; 00931 00932 free_enums(&np->enums); 00933 free_ranges(&np->ranges); 00934 free_indexes(&np->indexes); 00935 free_varbinds(&np->varbinds); 00936 if (np->label) 00937 free(np->label); 00938 if (np->hint) 00939 free(np->hint); 00940 if (np->units) 00941 free(np->units); 00942 if (np->description) 00943 free(np->description); 00944 if (np->reference) 00945 free(np->reference); 00946 if (np->defaultValue) 00947 free(np->defaultValue); 00948 if (np->parent) 00949 free(np->parent); 00950 if (np->augments) 00951 free(np->augments); 00952 if (np->filename) 00953 free(np->filename); 00954 free((char *) np); 00955 } 00956 00957 static void 00958 print_range_value(FILE * fp, int type, struct range_list * rp) 00959 { 00960 switch (type) { 00961 case TYPE_INTEGER: 00962 case TYPE_INTEGER32: 00963 if (rp->low == rp->high) 00964 fprintf(fp, "%d", rp->low); 00965 else 00966 fprintf(fp, "%d..%d", rp->low, rp->high); 00967 break; 00968 case TYPE_UNSIGNED32: 00969 case TYPE_OCTETSTR: 00970 case TYPE_GAUGE: 00971 case TYPE_UINTEGER: 00972 if (rp->low == rp->high) 00973 fprintf(fp, "%u", (unsigned)rp->low); 00974 else 00975 fprintf(fp, "%u..%u", (unsigned)rp->low, (unsigned)rp->high); 00976 break; 00977 default: 00978 /* No other range types allowed */ 00979 break; 00980 } 00981 } 00982 00983 #ifdef TEST 00984 static void 00985 print_nodes(FILE * fp, struct node *root) 00986 { 00987 struct enum_list *ep; 00988 struct index_list *ip; 00989 struct varbind_list *vp; 00990 struct node *np; 00991 00992 for (np = root; np; np = np->next) { 00993 fprintf(fp, "%s ::= { %s %ld } (%d)\n", np->label, np->parent, 00994 np->subid, np->type); 00995 if (np->tc_index >= 0) 00996 fprintf(fp, " TC = %s\n", tclist[np->tc_index].descriptor); 00997 if (np->enums) { 00998 fprintf(fp, " Enums: \n"); 00999 for (ep = np->enums; ep; ep = ep->next) { 01000 fprintf(fp, " %s(%d)\n", ep->label, ep->value); 01001 } 01002 } 01003 if (np->ranges) { 01004 struct range_list *rp; 01005 fprintf(fp, " Ranges: "); 01006 for (rp = np->ranges; rp; rp = rp->next) { 01007 fprintf(fp, "\n "); 01008 print_range_value(fp, np->type, rp); 01009 } 01010 fprintf(fp, "\n"); 01011 } 01012 if (np->indexes) { 01013 fprintf(fp, " Indexes: \n"); 01014 for (ip = np->indexes; ip; ip = ip->next) { 01015 fprintf(fp, " %s\n", ip->ilabel); 01016 } 01017 } 01018 if (np->augments) 01019 fprintf(fp, " Augments: %s\n", np->augments); 01020 if (np->varbinds) { 01021 fprintf(fp, " Varbinds: \n"); 01022 for (vp = np->varbinds; vp; vp = vp->next) { 01023 fprintf(fp, " %s\n", vp->vblabel); 01024 } 01025 } 01026 if (np->hint) 01027 fprintf(fp, " Hint: %s\n", np->hint); 01028 if (np->units) 01029 fprintf(fp, " Units: %s\n", np->units); 01030 if (np->defaultValue) 01031 fprintf(fp, " DefaultValue: %s\n", np->defaultValue); 01032 } 01033 } 01034 #endif 01035 01036 void 01037 print_subtree(FILE * f, struct tree *tree, int count) 01038 { 01039 struct tree *tp; 01040 int i; 01041 char modbuf[256]; 01042 01043 for (i = 0; i < count; i++) 01044 fprintf(f, " "); 01045 fprintf(f, "Children of %s(%ld):\n", tree->label, tree->subid); 01046 count++; 01047 for (tp = tree->child_list; tp; tp = tp->next_peer) { 01048 for (i = 0; i < count; i++) 01049 fprintf(f, " "); 01050 fprintf(f, "%s:%s(%ld) type=%d", 01051 module_name(tp->module_list[0], modbuf), 01052 tp->label, tp->subid, tp->type); 01053 if (tp->tc_index != -1) 01054 fprintf(f, " tc=%d", tp->tc_index); 01055 if (tp->hint) 01056 fprintf(f, " hint=%s", tp->hint); 01057 if (tp->units) 01058 fprintf(f, " units=%s", tp->units); 01059 if (tp->number_modules > 1) { 01060 fprintf(f, " modules:"); 01061 for (i = 1; i < tp->number_modules; i++) 01062 fprintf(f, " %s", module_name(tp->module_list[i], modbuf)); 01063 } 01064 fprintf(f, "\n"); 01065 } 01066 for (tp = tree->child_list; tp; tp = tp->next_peer) { 01067 if (tp->child_list) 01068 print_subtree(f, tp, count); 01069 } 01070 } 01071 01072 void 01073 print_ascii_dump_tree(FILE * f, struct tree *tree, int count) 01074 { 01075 struct tree *tp; 01076 01077 count++; 01078 for (tp = tree->child_list; tp; tp = tp->next_peer) { 01079 fprintf(f, "%s OBJECT IDENTIFIER ::= { %s %ld }\n", tp->label, 01080 tree->label, tp->subid); 01081 } 01082 for (tp = tree->child_list; tp; tp = tp->next_peer) { 01083 if (tp->child_list) 01084 print_ascii_dump_tree(f, tp, count); 01085 } 01086 } 01087 01088 static int translation_table[256]; 01089 01090 static void 01091 build_translation_table(void) 01092 { 01093 int count; 01094 01095 for (count = 0; count < 256; count++) { 01096 switch (count) { 01097 case OBJID: 01098 translation_table[count] = TYPE_OBJID; 01099 break; 01100 case OCTETSTR: 01101 translation_table[count] = TYPE_OCTETSTR; 01102 break; 01103 case INTEGER: 01104 translation_table[count] = TYPE_INTEGER; 01105 break; 01106 case NETADDR: 01107 translation_table[count] = TYPE_NETADDR; 01108 break; 01109 case IPADDR: 01110 translation_table[count] = TYPE_IPADDR; 01111 break; 01112 case COUNTER: 01113 translation_table[count] = TYPE_COUNTER; 01114 break; 01115 case GAUGE: 01116 translation_table[count] = TYPE_GAUGE; 01117 break; 01118 case TIMETICKS: 01119 translation_table[count] = TYPE_TIMETICKS; 01120 break; 01121 case KW_OPAQUE: 01122 translation_table[count] = TYPE_OPAQUE; 01123 break; 01124 case NUL: 01125 translation_table[count] = TYPE_NULL; 01126 break; 01127 case COUNTER64: 01128 translation_table[count] = TYPE_COUNTER64; 01129 break; 01130 case BITSTRING: 01131 translation_table[count] = TYPE_BITSTRING; 01132 break; 01133 case NSAPADDRESS: 01134 translation_table[count] = TYPE_NSAPADDRESS; 01135 break; 01136 case INTEGER32: 01137 translation_table[count] = TYPE_INTEGER32; 01138 break; 01139 case UINTEGER32: 01140 translation_table[count] = TYPE_UINTEGER; 01141 break; 01142 case UNSIGNED32: 01143 translation_table[count] = TYPE_UNSIGNED32; 01144 break; 01145 case TRAPTYPE: 01146 translation_table[count] = TYPE_TRAPTYPE; 01147 break; 01148 case NOTIFTYPE: 01149 translation_table[count] = TYPE_NOTIFTYPE; 01150 break; 01151 case NOTIFGROUP: 01152 translation_table[count] = TYPE_NOTIFGROUP; 01153 break; 01154 case OBJGROUP: 01155 translation_table[count] = TYPE_OBJGROUP; 01156 break; 01157 case MODULEIDENTITY: 01158 translation_table[count] = TYPE_MODID; 01159 break; 01160 case OBJIDENTITY: 01161 translation_table[count] = TYPE_OBJIDENTITY; 01162 break; 01163 case AGENTCAP: 01164 translation_table[count] = TYPE_AGENTCAP; 01165 break; 01166 case COMPLIANCE: 01167 translation_table[count] = TYPE_MODCOMP; 01168 break; 01169 default: 01170 translation_table[count] = TYPE_OTHER; 01171 break; 01172 } 01173 } 01174 } 01175 01176 static void 01177 init_tree_roots(void) 01178 { 01179 struct tree *tp, *lasttp; 01180 int base_modid; 01181 int hash; 01182 01183 base_modid = which_module("SNMPv2-SMI"); 01184 if (base_modid == -1) 01185 base_modid = which_module("RFC1155-SMI"); 01186 if (base_modid == -1) 01187 base_modid = which_module("RFC1213-MIB"); 01188 01189 /* 01190 * build root node 01191 */ 01192 tp = (struct tree *) calloc(1, sizeof(struct tree)); 01193 if (tp == NULL) 01194 return; 01195 tp->label = strdup("joint-iso-ccitt"); 01196 tp->modid = base_modid; 01197 tp->number_modules = 1; 01198 tp->module_list = &(tp->modid); 01199 tp->subid = 2; 01200 tp->tc_index = -1; 01201 set_function(tp); /* from mib.c */ 01202 hash = NBUCKET(name_hash(tp->label)); 01203 tp->next = tbuckets[hash]; 01204 tbuckets[hash] = tp; 01205 lasttp = tp; 01206 root_imports[0].label = strdup(tp->label); 01207 root_imports[0].modid = base_modid; 01208 01209 /* 01210 * build root node 01211 */ 01212 tp = (struct tree *) calloc(1, sizeof(struct tree)); 01213 if (tp == NULL) 01214 return; 01215 tp->next_peer = lasttp; 01216 tp->label = strdup("ccitt"); 01217 tp->modid = base_modid; 01218 tp->number_modules = 1; 01219 tp->module_list = &(tp->modid); 01220 tp->subid = 0; 01221 tp->tc_index = -1; 01222 set_function(tp); /* from mib.c */ 01223 hash = NBUCKET(name_hash(tp->label)); 01224 tp->next = tbuckets[hash]; 01225 tbuckets[hash] = tp; 01226 lasttp = tp; 01227 root_imports[1].label = strdup(tp->label); 01228 root_imports[1].modid = base_modid; 01229 01230 /* 01231 * build root node 01232 */ 01233 tp = (struct tree *) calloc(1, sizeof(struct tree)); 01234 if (tp == NULL) 01235 return; 01236 tp->next_peer = lasttp; 01237 tp->label = strdup("iso"); 01238 tp->modid = base_modid; 01239 tp->number_modules = 1; 01240 tp->module_list = &(tp->modid); 01241 tp->subid = 1; 01242 tp->tc_index = -1; 01243 set_function(tp); /* from mib.c */ 01244 hash = NBUCKET(name_hash(tp->label)); 01245 tp->next = tbuckets[hash]; 01246 tbuckets[hash] = tp; 01247 lasttp = tp; 01248 root_imports[2].label = strdup(tp->label); 01249 root_imports[2].modid = base_modid; 01250 01251 tree_head = tp; 01252 } 01253 01254 #ifdef STRICT_MIB_PARSEING 01255 #define label_compare strcasecmp 01256 #else 01257 #define label_compare strcmp 01258 #endif 01259 01260 01261 struct tree * 01262 find_tree_node(const char *name, int modid) 01263 { 01264 struct tree *tp, *headtp; 01265 int count, *int_p; 01266 01267 if (!name || !*name) 01268 return (NULL); 01269 01270 headtp = tbuckets[NBUCKET(name_hash(name))]; 01271 for (tp = headtp; tp; tp = tp->next) { 01272 if (tp->label && !label_compare(tp->label, name)) { 01273 01274 if (modid == -1) /* Any module */ 01275 return (tp); 01276 01277 for (int_p = tp->module_list, count = 0; 01278 count < tp->number_modules; ++count, ++int_p) 01279 if (*int_p == modid) 01280 return (tp); 01281 } 01282 } 01283 01284 return (NULL); 01285 } 01286 01287 /* 01288 * computes a value which represents how close name1 is to name2. 01289 * * high scores mean a worse match. 01290 * * (yes, the algorithm sucks!) 01291 */ 01292 #define MAX_BAD 0xffffff 01293 01294 static u_int 01295 compute_match(const char *search_base, const char *key) 01296 { 01297 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) 01298 int rc; 01299 regex_t parsetree; 01300 regmatch_t pmatch; 01301 rc = regcomp(&parsetree, key, REG_ICASE | REG_EXTENDED); 01302 if (rc == 0) 01303 rc = regexec(&parsetree, search_base, 1, &pmatch, 0); 01304 regfree(&parsetree); 01305 if (rc == 0) { 01306 /* 01307 * found 01308 */ 01309 return pmatch.rm_so; 01310 } 01311 #else /* use our own wildcard matcher */ 01312 /* 01313 * first find the longest matching substring (ick) 01314 */ 01315 char *first = NULL, *result = NULL, *entry; 01316 const char *position; 01317 char *newkey = strdup(key); 01318 char *st; 01319 01320 01321 entry = strtok_r(newkey, "*", &st); 01322 position = search_base; 01323 while (entry) { 01324 result = strcasestr(position, entry); 01325 01326 if (result == NULL) { 01327 free(newkey); 01328 return MAX_BAD; 01329 } 01330 01331 if (first == NULL) 01332 first = result; 01333 01334 position = result + strlen(entry); 01335 entry = strtok_r(NULL, "*", &st); 01336 } 01337 free(newkey); 01338 if (result) 01339 return (first - search_base); 01340 #endif 01341 01342 /* 01343 * not found 01344 */ 01345 return MAX_BAD; 01346 } 01347 01348 /* 01349 * Find the tree node that best matches the pattern string. 01350 * Use the "reported" flag such that only one match 01351 * is attempted for every node. 01352 * 01353 * Warning! This function may recurse. 01354 * 01355 * Caller _must_ invoke clear_tree_flags before first call 01356 * to this function. This function may be called multiple times 01357 * to ensure that the entire tree is traversed. 01358 */ 01359 01360 struct tree * 01361 find_best_tree_node(const char *pattrn, struct tree *tree_top, 01362 u_int * match) 01363 { 01364 struct tree *tp, *best_so_far = NULL, *retptr; 01365 u_int old_match = MAX_BAD, new_match = MAX_BAD; 01366 01367 if (!pattrn || !*pattrn) 01368 return (NULL); 01369 01370 if (!tree_top) 01371 tree_top = get_tree_head(); 01372 01373 for (tp = tree_top; tp; tp = tp->next_peer) { 01374 if (!tp->reported && tp->label) 01375 new_match = compute_match(tp->label, pattrn); 01376 tp->reported = 1; 01377 01378 if (new_match < old_match) { 01379 best_so_far = tp; 01380 old_match = new_match; 01381 } 01382 if (new_match == 0) 01383 break; /* this is the best result we can get */ 01384 if (tp->child_list) { 01385 retptr = 01386 find_best_tree_node(pattrn, tp->child_list, &new_match); 01387 if (new_match < old_match) { 01388 best_so_far = retptr; 01389 old_match = new_match; 01390 } 01391 if (new_match == 0) 01392 break; /* this is the best result we can get */ 01393 } 01394 } 01395 if (match) 01396 *match = old_match; 01397 return (best_so_far); 01398 } 01399 01400 01401 static void 01402 merge_anon_children(struct tree *tp1, struct tree *tp2) 01403 /* 01404 * NB: tp1 is the 'anonymous' node 01405 */ 01406 { 01407 struct tree *child1, *child2, *previous; 01408 01409 for (child1 = tp1->child_list; child1;) { 01410 01411 for (child2 = tp2->child_list, previous = NULL; 01412 child2; previous = child2, child2 = child2->next_peer) { 01413 01414 if (child1->subid == child2->subid) { 01415 /* 01416 * Found 'matching' children, 01417 * so merge them 01418 */ 01419 if (!strncmp(child1->label, ANON, ANON_LEN)) { 01420 merge_anon_children(child1, child2); 01421 01422 child1->child_list = NULL; 01423 previous = child1; /* Finished with 'child1' */ 01424 child1 = child1->next_peer; 01425 free_tree(previous); 01426 goto next; 01427 } 01428 01429 else if (!strncmp(child2->label, ANON, ANON_LEN)) { 01430 merge_anon_children(child2, child1); 01431 01432 if (previous) 01433 previous->next_peer = child2->next_peer; 01434 else 01435 tp2->child_list = child2->next_peer; 01436 free_tree(child2); 01437 01438 previous = child1; /* Move 'child1' to 'tp2' */ 01439 child1 = child1->next_peer; 01440 previous->next_peer = tp2->child_list; 01441 tp2->child_list = previous; 01442 for (previous = tp2->child_list; 01443 previous; previous = previous->next_peer) 01444 previous->parent = tp2; 01445 goto next; 01446 } else if (!label_compare(child1->label, child2->label)) { 01447 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 01448 NETSNMP_DS_LIB_MIB_WARNINGS)) { 01449 snmp_log(LOG_WARNING, 01450 "Warning: %s.%ld is both %s and %s (%s)\n", 01451 tp2->label, child1->subid, child1->label, 01452 child2->label, File); 01453 } 01454 continue; 01455 } else { 01456 /* 01457 * Two copies of the same node. 01458 * 'child2' adopts the children of 'child1' 01459 */ 01460 01461 if (child2->child_list) { 01462 for (previous = child2->child_list; previous->next_peer; previous = previous->next_peer); /* Find the end of the list */ 01463 previous->next_peer = child1->child_list; 01464 } else 01465 child2->child_list = child1->child_list; 01466 for (previous = child1->child_list; 01467 previous; previous = previous->next_peer) 01468 previous->parent = child2; 01469 child1->child_list = NULL; 01470 01471 previous = child1; /* Finished with 'child1' */ 01472 child1 = child1->next_peer; 01473 free_tree(previous); 01474 goto next; 01475 } 01476 } 01477 } 01478 /* 01479 * If no match, move 'child1' to 'tp2' child_list 01480 */ 01481 if (child1) { 01482 previous = child1; 01483 child1 = child1->next_peer; 01484 previous->parent = tp2; 01485 previous->next_peer = tp2->child_list; 01486 tp2->child_list = previous; 01487 } 01488 next:; 01489 } 01490 } 01491 01492 01493 /* 01494 * Find all the children of root in the list of nodes. Link them into the 01495 * tree and out of the nodes list. 01496 */ 01497 static void 01498 do_subtree(struct tree *root, struct node **nodes) 01499 { 01500 struct tree *tp, *anon_tp = NULL; 01501 struct tree *xroot = root; 01502 struct node *np, **headp; 01503 struct node *oldnp = NULL, *child_list = NULL, *childp = NULL; 01504 int hash; 01505 int *int_p; 01506 01507 while (xroot->next_peer && xroot->next_peer->subid == root->subid) { 01508 #if 0 01509 printf("xroot: %s.%s => %s\n", xroot->parent->label, xroot->label, 01510 xroot->next_peer->label); 01511 #endif 01512 xroot = xroot->next_peer; 01513 } 01514 01515 tp = root; 01516 headp = &nbuckets[NBUCKET(name_hash(tp->label))]; 01517 /* 01518 * Search each of the nodes for one whose parent is root, and 01519 * move each into a separate list. 01520 */ 01521 for (np = *headp; np; np = np->next) { 01522 if (!label_compare(tp->label, np->parent)) { 01523 /* 01524 * take this node out of the node list 01525 */ 01526 if (oldnp == NULL) { 01527 *headp = np->next; /* fix root of node list */ 01528 } else { 01529 oldnp->next = np->next; /* link around this node */ 01530 } 01531 if (child_list) 01532 childp->next = np; 01533 else 01534 child_list = np; 01535 childp = np; 01536 } else { 01537 oldnp = np; 01538 } 01539 01540 } 01541 if (childp) 01542 childp->next = NULL; 01543 /* 01544 * Take each element in the child list and place it into the tree. 01545 */ 01546 for (np = child_list; np; np = np->next) { 01547 struct tree *otp = NULL; 01548 struct tree *xxroot = xroot; 01549 anon_tp = NULL; 01550 tp = xroot->child_list; 01551 01552 if (np->subid == -1) { 01553 /* 01554 * name ::= { parent } 01555 */ 01556 np->subid = xroot->subid; 01557 tp = xroot; 01558 xxroot = xroot->parent; 01559 } 01560 01561 while (tp) { 01562 if (tp->subid == np->subid) 01563 break; 01564 else { 01565 otp = tp; 01566 tp = tp->next_peer; 01567 } 01568 } 01569 if (tp) { 01570 if (!label_compare(tp->label, np->label)) { 01571 /* 01572 * Update list of modules 01573 */ 01574 int_p = 01575 (int *) malloc((tp->number_modules + 1) * sizeof(int)); 01576 if (int_p == NULL) 01577 return; 01578 memcpy(int_p, tp->module_list, 01579 tp->number_modules * sizeof(int)); 01580 int_p[tp->number_modules] = np->modid; 01581 if (tp->number_modules > 1) 01582 free((char *) tp->module_list); 01583 ++tp->number_modules; 01584 tp->module_list = int_p; 01585 01586 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01587 NETSNMP_DS_LIB_MIB_REPLACE)) { 01588 /* 01589 * Replace from node 01590 */ 01591 tree_from_node(tp, np); 01592 } 01593 /* 01594 * Handle children 01595 */ 01596 do_subtree(tp, nodes); 01597 continue; 01598 } 01599 if (!strncmp(np->label, ANON, ANON_LEN) || 01600 !strncmp(tp->label, ANON, ANON_LEN)) { 01601 anon_tp = tp; /* Need to merge these two trees later */ 01602 } else if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 01603 NETSNMP_DS_LIB_MIB_WARNINGS)) { 01604 snmp_log(LOG_WARNING, 01605 "Warning: %s.%ld is both %s and %s (%s)\n", 01606 root->label, np->subid, tp->label, np->label, 01607 File); 01608 } 01609 } 01610 01611 tp = (struct tree *) calloc(1, sizeof(struct tree)); 01612 if (tp == NULL) 01613 return; 01614 tp->parent = xxroot; 01615 tp->modid = np->modid; 01616 tp->number_modules = 1; 01617 tp->module_list = &(tp->modid); 01618 tree_from_node(tp, np); 01619 tp->next_peer = otp ? otp->next_peer : xxroot->child_list; 01620 if (otp) 01621 otp->next_peer = tp; 01622 else 01623 xxroot->child_list = tp; 01624 hash = NBUCKET(name_hash(tp->label)); 01625 tp->next = tbuckets[hash]; 01626 tbuckets[hash] = tp; 01627 do_subtree(tp, nodes); 01628 01629 if (anon_tp) { 01630 if (!strncmp(tp->label, ANON, ANON_LEN)) { 01631 /* 01632 * The new node is anonymous, 01633 * so merge it with the existing one. 01634 */ 01635 merge_anon_children(tp, anon_tp); 01636 01637 /* 01638 * unlink and destroy tp 01639 */ 01640 unlink_tree(tp); 01641 free_tree(tp); 01642 } else if (!strncmp(anon_tp->label, ANON, ANON_LEN)) { 01643 struct tree *ntp; 01644 /* 01645 * The old node was anonymous, 01646 * so merge it with the existing one, 01647 * and fill in the full information. 01648 */ 01649 merge_anon_children(anon_tp, tp); 01650 01651 /* 01652 * unlink anon_tp from the hash 01653 */ 01654 unlink_tbucket(anon_tp); 01655 01656 /* 01657 * get rid of old contents of anon_tp 01658 */ 01659 free_partial_tree(anon_tp, FALSE); 01660 01661 /* 01662 * put in the current information 01663 */ 01664 anon_tp->label = tp->label; 01665 anon_tp->child_list = tp->child_list; 01666 anon_tp->modid = tp->modid; 01667 anon_tp->tc_index = tp->tc_index; 01668 anon_tp->type = tp->type; 01669 anon_tp->enums = tp->enums; 01670 anon_tp->indexes = tp->indexes; 01671 anon_tp->augments = tp->augments; 01672 anon_tp->varbinds = tp->varbinds; 01673 anon_tp->ranges = tp->ranges; 01674 anon_tp->hint = tp->hint; 01675 anon_tp->units = tp->units; 01676 anon_tp->description = tp->description; 01677 anon_tp->reference = tp->reference; 01678 anon_tp->defaultValue = tp->defaultValue; 01679 anon_tp->parent = tp->parent; 01680 01681 set_function(anon_tp); 01682 01683 /* 01684 * update parent pointer in moved children 01685 */ 01686 ntp = anon_tp->child_list; 01687 while (ntp) { 01688 ntp->parent = anon_tp; 01689 ntp = ntp->next_peer; 01690 } 01691 01692 /* 01693 * hash in anon_tp in its new place 01694 */ 01695 hash = NBUCKET(name_hash(anon_tp->label)); 01696 anon_tp->next = tbuckets[hash]; 01697 tbuckets[hash] = anon_tp; 01698 01699 /* 01700 * unlink and destroy tp 01701 */ 01702 unlink_tbucket(tp); 01703 unlink_tree(tp); 01704 free(tp); 01705 } else { 01706 /* 01707 * Uh? One of these two should have been anonymous! 01708 */ 01709 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 01710 NETSNMP_DS_LIB_MIB_WARNINGS)) { 01711 snmp_log(LOG_WARNING, 01712 "Warning: expected anonymous node (either %s or %s) in %s\n", 01713 tp->label, anon_tp->label, File); 01714 } 01715 } 01716 anon_tp = NULL; 01717 } 01718 } 01719 /* 01720 * free all nodes that were copied into tree 01721 */ 01722 oldnp = NULL; 01723 for (np = child_list; np; np = np->next) { 01724 if (oldnp) 01725 free_node(oldnp); 01726 oldnp = np; 01727 } 01728 if (oldnp) 01729 free_node(oldnp); 01730 } 01731 01732 static void 01733 do_linkup(struct module *mp, struct node *np) 01734 { 01735 struct module_import *mip; 01736 struct node *onp, *oldp, *newp; 01737 struct tree *tp; 01738 int i, more; 01739 /* 01740 * All modules implicitly import 01741 * the roots of the tree 01742 */ 01743 if (snmp_get_do_debugging() > 1) 01744 dump_module_list(); 01745 DEBUGMSGTL(("parse-mibs", "Processing IMPORTS for module %d %s\n", 01746 mp->modid, mp->name)); 01747 if (mp->no_imports == 0) { 01748 mp->no_imports = NUMBER_OF_ROOT_NODES; 01749 mp->imports = root_imports; 01750 } 01751 01752 /* 01753 * Build the tree 01754 */ 01755 init_node_hash(np); 01756 for (i = 0, mip = mp->imports; i < mp->no_imports; ++i, ++mip) { 01757 char modbuf[256]; 01758 DEBUGMSGTL(("parse-mibs", " Processing import: %s\n", 01759 mip->label)); 01760 if (get_tc_index(mip->label, mip->modid) != -1) 01761 continue; 01762 tp = find_tree_node(mip->label, mip->modid); 01763 if (!tp) { 01764 snmp_log(LOG_WARNING, 01765 "Did not find '%s' in module %s (%s)\n", 01766 mip->label, module_name(mip->modid, modbuf), 01767 File); 01768 continue; 01769 } 01770 do_subtree(tp, &np); 01771 } 01772 01773 /* 01774 * If any nodes left over, 01775 * check that they're not the result of a "fully qualified" 01776 * name, and then add them to the list of orphans 01777 */ 01778 01779 if (!np) 01780 return; 01781 for (tp = tree_head; tp; tp = tp->next_peer) 01782 do_subtree(tp, &np); 01783 if (!np) 01784 return; 01785 01786 /* 01787 * quietly move all internal references to the orphan list 01788 */ 01789 oldp = orphan_nodes; 01790 do { 01791 for (i = 0; i < NHASHSIZE; i++) 01792 for (onp = nbuckets[i]; onp; onp = onp->next) { 01793 struct node *op = NULL; 01794 int hash = NBUCKET(name_hash(onp->label)); 01795 np = nbuckets[hash]; 01796 while (np) { 01797 if (label_compare(onp->label, np->parent)) { 01798 op = np; 01799 np = np->next; 01800 } else { 01801 if (op) 01802 op->next = np->next; 01803 else 01804 nbuckets[hash] = np->next; 01805 np->next = orphan_nodes; 01806 orphan_nodes = np; 01807 op = NULL; 01808 np = nbuckets[hash]; 01809 } 01810 } 01811 } 01812 newp = orphan_nodes; 01813 more = 0; 01814 for (onp = orphan_nodes; onp != oldp; onp = onp->next) { 01815 struct node *op = NULL; 01816 int hash = NBUCKET(name_hash(onp->label)); 01817 np = nbuckets[hash]; 01818 while (np) { 01819 if (label_compare(onp->label, np->parent)) { 01820 op = np; 01821 np = np->next; 01822 } else { 01823 if (op) 01824 op->next = np->next; 01825 else 01826 nbuckets[hash] = np->next; 01827 np->next = orphan_nodes; 01828 orphan_nodes = np; 01829 op = NULL; 01830 np = nbuckets[hash]; 01831 more = 1; 01832 } 01833 } 01834 } 01835 oldp = newp; 01836 } while (more); 01837 01838 /* 01839 * complain about left over nodes 01840 */ 01841 for (np = orphan_nodes; np && np->next; np = np->next); /* find the end of the orphan list */ 01842 for (i = 0; i < NHASHSIZE; i++) 01843 if (nbuckets[i]) { 01844 if (orphan_nodes) 01845 onp = np->next = nbuckets[i]; 01846 else 01847 onp = orphan_nodes = nbuckets[i]; 01848 nbuckets[i] = NULL; 01849 while (onp) { 01850 snmp_log(LOG_WARNING, 01851 "Unlinked OID in %s: %s ::= { %s %ld }\n", 01852 (mp->name ? mp->name : "<no module>"), 01853 (onp->label ? onp->label : "<no label>"), 01854 (onp->parent ? onp->parent : "<no parent>"), 01855 onp->subid); 01856 snmp_log(LOG_WARNING, 01857 "Undefined identifier: %s near line %d of %s\n", 01858 (onp->parent ? onp->parent : "<no parent>"), 01859 onp->lineno, onp->filename); 01860 np = onp; 01861 onp = onp->next; 01862 } 01863 } 01864 return; 01865 } 01866 01867 01868 /* 01869 * Takes a list of the form: 01870 * { iso org(3) dod(6) 1 } 01871 * and creates several nodes, one for each parent-child pair. 01872 * Returns 0 on error. 01873 */ 01874 static int 01875 getoid(FILE * fp, struct subid_s *id, /* an array of subids */ 01876 int length) 01877 { /* the length of the array */ 01878 register int count; 01879 int type; 01880 char token[MAXTOKEN]; 01881 01882 if ((type = get_token(fp, token, MAXTOKEN)) != LEFTBRACKET) { 01883 print_error("Expected \"{\"", token, type); 01884 return 0; 01885 } 01886 type = get_token(fp, token, MAXTOKEN); 01887 for (count = 0; count < length; count++, id++) { 01888 id->label = NULL; 01889 id->modid = current_module; 01890 id->subid = -1; 01891 if (type == RIGHTBRACKET) 01892 return count; 01893 if (type == LABEL) { 01894 /* 01895 * this entry has a label 01896 */ 01897 id->label = strdup(token); 01898 type = get_token(fp, token, MAXTOKEN); 01899 if (type == LEFTPAREN) { 01900 type = get_token(fp, token, MAXTOKEN); 01901 if (type == NUMBER) { 01902 id->subid = strtoul(token, NULL, 10); 01903 if ((type = 01904 get_token(fp, token, MAXTOKEN)) != RIGHTPAREN) { 01905 print_error("Expected a closing parenthesis", 01906 token, type); 01907 return 0; 01908 } 01909 } else { 01910 print_error("Expected a number", token, type); 01911 return 0; 01912 } 01913 } else { 01914 continue; 01915 } 01916 } else if (type == NUMBER) { 01917 /* 01918 * this entry has just an integer sub-identifier 01919 */ 01920 id->subid = strtoul(token, NULL, 10); 01921 } else { 01922 print_error("Expected label or number", token, type); 01923 return 0; 01924 } 01925 type = get_token(fp, token, MAXTOKEN); 01926 } 01927 print_error("Too long OID", token, type); 01928 return 0; 01929 } 01930 01931 /* 01932 * Parse a sequence of object subidentifiers for the given name. 01933 * The "label OBJECT IDENTIFIER ::=" portion has already been parsed. 01934 * 01935 * The majority of cases take this form : 01936 * label OBJECT IDENTIFIER ::= { parent 2 } 01937 * where a parent label and a child subidentifier number are specified. 01938 * 01939 * Variations on the theme include cases where a number appears with 01940 * the parent, or intermediate subidentifiers are specified by label, 01941 * by number, or both. 01942 * 01943 * Here are some representative samples : 01944 * internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 } 01945 * mgmt OBJECT IDENTIFIER ::= { internet 2 } 01946 * rptrInfoHealth OBJECT IDENTIFIER ::= { snmpDot3RptrMgt 0 4 } 01947 * 01948 * Here is a very rare form : 01949 * iso OBJECT IDENTIFIER ::= { 1 } 01950 * 01951 * Returns NULL on error. When this happens, memory may be leaked. 01952 */ 01953 static struct node * 01954 parse_objectid(FILE * fp, char *name) 01955 { 01956 register int count; 01957 register struct subid_s *op, *nop; 01958 int length; 01959 struct subid_s loid[32]; 01960 struct node *np, *root = NULL, *oldnp = NULL; 01961 struct tree *tp; 01962 01963 if ((length = getoid(fp, loid, 32)) == 0) { 01964 print_error("Bad object identifier", NULL, CONTINUE); 01965 return NULL; 01966 } 01967 01968 /* 01969 * Handle numeric-only object identifiers, 01970 * by labelling the first sub-identifier 01971 */ 01972 op = loid; 01973 if (!op->label) { 01974 if (length == 1) { 01975 print_error("Attempt to define a root oid", name, OBJECT); 01976 return NULL; 01977 } 01978 for (tp = tree_head; tp; tp = tp->next_peer) 01979 if ((int) tp->subid == op->subid) { 01980 op->label = strdup(tp->label); 01981 break; 01982 } 01983 } 01984 01985 /* 01986 * Handle "label OBJECT-IDENTIFIER ::= { subid }" 01987 */ 01988 if (length == 1) { 01989 op = loid; 01990 np = alloc_node(op->modid); 01991 if (np == NULL) 01992 return (NULL); 01993 np->subid = op->subid; 01994 np->label = strdup(name); 01995 np->parent = op->label; 01996 return np; 01997 } 01998 01999 /* 02000 * For each parent-child subid pair in the subid array, 02001 * create a node and link it into the node list. 02002 */ 02003 for (count = 0, op = loid, nop = loid + 1; count < (length - 1); 02004 count++, op++, nop++) { 02005 /* 02006 * every node must have parent's name and child's name or number 02007 */ 02008 /* 02009 * XX the next statement is always true -- does it matter ?? 02010 */ 02011 if (op->label && (nop->label || (nop->subid != -1))) { 02012 np = alloc_node(nop->modid); 02013 if (np == NULL) 02014 return (NULL); 02015 if (root == NULL) 02016 root = np; 02017 02018 np->parent = strdup(op->label); 02019 if (count == (length - 2)) { 02020 /* 02021 * The name for this node is the label for this entry 02022 */ 02023 np->label = strdup(name); 02024 } else { 02025 if (!nop->label) { 02026 nop->label = (char *) malloc(20 + ANON_LEN); 02027 if (nop->label == NULL) 02028 return (NULL); 02029 sprintf(nop->label, "%s%d", ANON, anonymous++); 02030 } 02031 np->label = strdup(nop->label); 02032 } 02033 if (nop->subid != -1) 02034 np->subid = nop->subid; 02035 else 02036 print_error("Warning: This entry is pretty silly", 02037 np->label, CONTINUE); 02038 02039 /* 02040 * set up next entry 02041 */ 02042 if (oldnp) 02043 oldnp->next = np; 02044 oldnp = np; 02045 } /* end if(op->label... */ 02046 } 02047 02048 /* 02049 * free the loid array 02050 */ 02051 for (count = 0, op = loid; count < length; count++, op++) { 02052 if (op->label) 02053 free(op->label); 02054 } 02055 02056 return root; 02057 } 02058 02059 static int 02060 get_tc(const char *descriptor, 02061 int modid, 02062 int *tc_index, 02063 struct enum_list **ep, struct range_list **rp, char **hint) 02064 { 02065 int i; 02066 struct tc *tcp; 02067 02068 i = get_tc_index(descriptor, modid); 02069 if (tc_index) 02070 *tc_index = i; 02071 if (i != -1) { 02072 tcp = &tclist[i]; 02073 if (ep) { 02074 free_enums(ep); 02075 *ep = copy_enums(tcp->enums); 02076 } 02077 if (rp) { 02078 free_ranges(rp); 02079 *rp = copy_ranges(tcp->ranges); 02080 } 02081 if (hint) { 02082 if (*hint) 02083 free(*hint); 02084 *hint = (tcp->hint ? strdup(tcp->hint) : NULL); 02085 } 02086 return tcp->type; 02087 } 02088 return LABEL; 02089 } 02090 02091 /* 02092 * return index into tclist of given TC descriptor 02093 * return -1 if not found 02094 */ 02095 static int 02096 get_tc_index(const char *descriptor, int modid) 02097 { 02098 int i; 02099 struct tc *tcp; 02100 struct module *mp; 02101 struct module_import *mip; 02102 02103 /* 02104 * Check that the descriptor isn't imported 02105 * by searching the import list 02106 */ 02107 02108 for (mp = module_head; mp; mp = mp->next) 02109 if (mp->modid == modid) 02110 break; 02111 if (mp) 02112 for (i = 0, mip = mp->imports; i < mp->no_imports; ++i, ++mip) { 02113 if (!label_compare(mip->label, descriptor)) { 02114 /* 02115 * Found it - so amend the module ID 02116 */ 02117 modid = mip->modid; 02118 break; 02119 } 02120 } 02121 02122 02123 for (i = 0, tcp = tclist; i < MAXTC; i++, tcp++) { 02124 if (tcp->type == 0) 02125 break; 02126 if (!label_compare(descriptor, tcp->descriptor) && 02127 ((modid == tcp->modid) || (modid == -1))) { 02128 return i; 02129 } 02130 } 02131 return -1; 02132 } 02133 02134 /* 02135 * translate integer tc_index to string identifier from tclist 02136 * * 02137 * * Returns pointer to string in table (should not be modified) or NULL 02138 */ 02139 const char * 02140 get_tc_descriptor(int tc_index) 02141 { 02142 if (tc_index < 0 || tc_index >= MAXTC) 02143 return NULL; 02144 return (tclist[tc_index].descriptor); 02145 } 02146 02147 #ifndef NETSNMP_FEATURE_REMOVE_GET_TC_DESCRIPTION 02148 /* used in the perl module */ 02149 const char * 02150 get_tc_description(int tc_index) 02151 { 02152 if (tc_index < 0 || tc_index >= MAXTC) 02153 return NULL; 02154 return (tclist[tc_index].description); 02155 } 02156 #endif /* NETSNMP_FEATURE_REMOVE_GET_TC_DESCRIPTION */ 02157 02158 02159 /* 02160 * Parses an enumeration list of the form: 02161 * { label(value) label(value) ... } 02162 * The initial { has already been parsed. 02163 * Returns NULL on error. 02164 */ 02165 02166 static struct enum_list * 02167 parse_enumlist(FILE * fp, struct enum_list **retp) 02168 { 02169 register int type; 02170 char token[MAXTOKEN]; 02171 struct enum_list *ep = NULL, **epp = &ep; 02172 02173 free_enums(retp); 02174 02175 while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE) { 02176 if (type == RIGHTBRACKET) 02177 break; 02178 /* some enums use "deprecated" to indicate a no longer value label */ 02179 /* (EG: IP-MIB's IpAddressStatusTC) */ 02180 if (type == LABEL || type == DEPRECATED) { 02181 /* 02182 * this is an enumerated label 02183 */ 02184 *epp = 02185 (struct enum_list *) calloc(1, sizeof(struct enum_list)); 02186 if (*epp == NULL) 02187 return (NULL); 02188 /* 02189 * a reasonable approximation for the length 02190 */ 02191 (*epp)->label = strdup(token); 02192 type = get_token(fp, token, MAXTOKEN); 02193 if (type != LEFTPAREN) { 02194 print_error("Expected \"(\"", token, type); 02195 return NULL; 02196 } 02197 type = get_token(fp, token, MAXTOKEN); 02198 if (type != NUMBER) { 02199 print_error("Expected integer", token, type); 02200 return NULL; 02201 } 02202 (*epp)->value = strtol(token, NULL, 10); 02203 type = get_token(fp, token, MAXTOKEN); 02204 if (type != RIGHTPAREN) { 02205 print_error("Expected \")\"", token, type); 02206 return NULL; 02207 } 02208 epp = &(*epp)->next; 02209 } 02210 } 02211 if (type == ENDOFFILE) { 02212 print_error("Expected \"}\"", token, type); 02213 return NULL; 02214 } 02215 *retp = ep; 02216 return ep; 02217 } 02218 02219 static struct range_list * 02220 parse_ranges(FILE * fp, struct range_list **retp) 02221 { 02222 int low, high; 02223 char nexttoken[MAXTOKEN]; 02224 int nexttype; 02225 struct range_list *rp = NULL, **rpp = &rp; 02226 int size = 0, taken = 1; 02227 02228 free_ranges(retp); 02229 02230 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02231 if (nexttype == SIZE) { 02232 size = 1; 02233 taken = 0; 02234 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02235 if (nexttype != LEFTPAREN) 02236 print_error("Expected \"(\" after SIZE", nexttoken, nexttype); 02237 } 02238 02239 do { 02240 if (!taken) 02241 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02242 else 02243 taken = 0; 02244 high = low = strtoul(nexttoken, NULL, 10); 02245 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02246 if (nexttype == RANGE) { 02247 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02248 errno = 0; 02249 high = strtoul(nexttoken, NULL, 10); 02250 if ( errno == ERANGE ) { 02251 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 02252 NETSNMP_DS_LIB_MIB_WARNINGS)) 02253 snmp_log(LOG_WARNING, 02254 "Warning: Upper bound not handled correctly (%s != %d): At line %d in %s\n", 02255 nexttoken, high, mibLine, File); 02256 } 02257 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02258 } 02259 *rpp = (struct range_list *) calloc(1, sizeof(struct range_list)); 02260 if (*rpp == NULL) 02261 break; 02262 (*rpp)->low = low; 02263 (*rpp)->high = high; 02264 rpp = &(*rpp)->next; 02265 02266 } while (nexttype == BAR); 02267 if (size) { 02268 if (nexttype != RIGHTPAREN) 02269 print_error("Expected \")\" after SIZE", nexttoken, nexttype); 02270 nexttype = get_token(fp, nexttoken, nexttype); 02271 } 02272 if (nexttype != RIGHTPAREN) 02273 print_error("Expected \")\"", nexttoken, nexttype); 02274 02275 *retp = rp; 02276 return rp; 02277 } 02278 02279 /* 02280 * Parses an asn type. Structures are ignored by this parser. 02281 * Returns NULL on error. 02282 */ 02283 static struct node * 02284 parse_asntype(FILE * fp, char *name, int *ntype, char *ntoken) 02285 { 02286 int type, i; 02287 char token[MAXTOKEN]; 02288 char quoted_string_buffer[MAXQUOTESTR]; 02289 char *hint = NULL; 02290 char *descr = NULL; 02291 struct tc *tcp; 02292 int level; 02293 02294 type = get_token(fp, token, MAXTOKEN); 02295 if (type == SEQUENCE || type == CHOICE) { 02296 level = 0; 02297 while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE) { 02298 if (type == LEFTBRACKET) { 02299 level++; 02300 } else if (type == RIGHTBRACKET && --level == 0) { 02301 *ntype = get_token(fp, ntoken, MAXTOKEN); 02302 return NULL; 02303 } 02304 } 02305 print_error("Expected \"}\"", token, type); 02306 return NULL; 02307 } else if (type == LEFTBRACKET) { 02308 struct node *np; 02309 int ch_next = '{'; 02310 ungetc(ch_next, fp); 02311 np = parse_objectid(fp, name); 02312 if (np != NULL) { 02313 *ntype = get_token(fp, ntoken, MAXTOKEN); 02314 return np; 02315 } 02316 return NULL; 02317 } else if (type == LEFTSQBRACK) { 02318 int size = 0; 02319 do { 02320 type = get_token(fp, token, MAXTOKEN); 02321 } while (type != ENDOFFILE && type != RIGHTSQBRACK); 02322 if (type != RIGHTSQBRACK) { 02323 print_error("Expected \"]\"", token, type); 02324 return NULL; 02325 } 02326 type = get_token(fp, token, MAXTOKEN); 02327 if (type == IMPLICIT) 02328 type = get_token(fp, token, MAXTOKEN); 02329 *ntype = get_token(fp, ntoken, MAXTOKEN); 02330 if (*ntype == LEFTPAREN) { 02331 switch (type) { 02332 case OCTETSTR: 02333 *ntype = get_token(fp, ntoken, MAXTOKEN); 02334 if (*ntype != SIZE) { 02335 print_error("Expected SIZE", ntoken, *ntype); 02336 return NULL; 02337 } 02338 size = 1; 02339 *ntype = get_token(fp, ntoken, MAXTOKEN); 02340 if (*ntype != LEFTPAREN) { 02341 print_error("Expected \"(\" after SIZE", ntoken, 02342 *ntype); 02343 return NULL; 02344 } 02345 /* 02346 * fall through 02347 */ 02348 case INTEGER: 02349 *ntype = get_token(fp, ntoken, MAXTOKEN); 02350 do { 02351 if (*ntype != NUMBER) 02352 print_error("Expected NUMBER", ntoken, *ntype); 02353 *ntype = get_token(fp, ntoken, MAXTOKEN); 02354 if (*ntype == RANGE) { 02355 *ntype = get_token(fp, ntoken, MAXTOKEN); 02356 if (*ntype != NUMBER) 02357 print_error("Expected NUMBER", ntoken, *ntype); 02358 *ntype = get_token(fp, ntoken, MAXTOKEN); 02359 } 02360 } while (*ntype == BAR); 02361 if (*ntype != RIGHTPAREN) { 02362 print_error("Expected \")\"", ntoken, *ntype); 02363 return NULL; 02364 } 02365 *ntype = get_token(fp, ntoken, MAXTOKEN); 02366 if (size) { 02367 if (*ntype != RIGHTPAREN) { 02368 print_error("Expected \")\" to terminate SIZE", 02369 ntoken, *ntype); 02370 return NULL; 02371 } 02372 *ntype = get_token(fp, ntoken, MAXTOKEN); 02373 } 02374 } 02375 } 02376 return NULL; 02377 } else { 02378 if (type == CONVENTION) { 02379 while (type != SYNTAX && type != ENDOFFILE) { 02380 if (type == DISPLAYHINT) { 02381 type = get_token(fp, token, MAXTOKEN); 02382 if (type != QUOTESTRING) 02383 print_error("DISPLAY-HINT must be string", token, 02384 type); 02385 else 02386 hint = strdup(token); 02387 } else if (type == DESCRIPTION && 02388 netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 02389 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) { 02390 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 02391 if (type != QUOTESTRING) 02392 print_error("DESCRIPTION must be string", token, 02393 type); 02394 else 02395 descr = strdup(quoted_string_buffer); 02396 } else 02397 type = 02398 get_token(fp, quoted_string_buffer, MAXQUOTESTR); 02399 } 02400 type = get_token(fp, token, MAXTOKEN); 02401 if (type == OBJECT) { 02402 type = get_token(fp, token, MAXTOKEN); 02403 if (type != IDENTIFIER) { 02404 print_error("Expected IDENTIFIER", token, type); 02405 SNMP_FREE(hint); 02406 return NULL; 02407 } 02408 type = OBJID; 02409 } 02410 } else if (type == OBJECT) { 02411 type = get_token(fp, token, MAXTOKEN); 02412 if (type != IDENTIFIER) { 02413 print_error("Expected IDENTIFIER", token, type); 02414 return NULL; 02415 } 02416 type = OBJID; 02417 } 02418 02419 if (type == LABEL) { 02420 type = get_tc(token, current_module, NULL, NULL, NULL, NULL); 02421 } 02422 02423 /* 02424 * textual convention 02425 */ 02426 for (i = 0; i < MAXTC; i++) { 02427 if (tclist[i].type == 0) 02428 break; 02429 } 02430 02431 if (i == MAXTC) { 02432 print_error("Too many textual conventions", token, type); 02433 SNMP_FREE(hint); 02434 return NULL; 02435 } 02436 if (!(type & SYNTAX_MASK)) { 02437 print_error("Textual convention doesn't map to real type", 02438 token, type); 02439 SNMP_FREE(hint); 02440 return NULL; 02441 } 02442 tcp = &tclist[i]; 02443 tcp->modid = current_module; 02444 tcp->descriptor = strdup(name); 02445 tcp->hint = hint; 02446 tcp->description = descr; 02447 tcp->type = type; 02448 *ntype = get_token(fp, ntoken, MAXTOKEN); 02449 if (*ntype == LEFTPAREN) { 02450 tcp->ranges = parse_ranges(fp, &tcp->ranges); 02451 *ntype = get_token(fp, ntoken, MAXTOKEN); 02452 } else if (*ntype == LEFTBRACKET) { 02453 /* 02454 * if there is an enumeration list, parse it 02455 */ 02456 tcp->enums = parse_enumlist(fp, &tcp->enums); 02457 *ntype = get_token(fp, ntoken, MAXTOKEN); 02458 } 02459 return NULL; 02460 } 02461 } 02462 02463 02464 /* 02465 * Parses an OBJECT TYPE macro. 02466 * Returns 0 on error. 02467 */ 02468 static struct node * 02469 parse_objecttype(FILE * fp, char *name) 02470 { 02471 register int type; 02472 char token[MAXTOKEN]; 02473 char nexttoken[MAXTOKEN]; 02474 char quoted_string_buffer[MAXQUOTESTR]; 02475 int nexttype, tctype; 02476 register struct node *np; 02477 02478 type = get_token(fp, token, MAXTOKEN); 02479 if (type != SYNTAX) { 02480 print_error("Bad format for OBJECT-TYPE", token, type); 02481 return NULL; 02482 } 02483 np = alloc_node(current_module); 02484 if (np == NULL) 02485 return (NULL); 02486 type = get_token(fp, token, MAXTOKEN); 02487 if (type == OBJECT) { 02488 type = get_token(fp, token, MAXTOKEN); 02489 if (type != IDENTIFIER) { 02490 print_error("Expected IDENTIFIER", token, type); 02491 free_node(np); 02492 return NULL; 02493 } 02494 type = OBJID; 02495 } 02496 if (type == LABEL) { 02497 int tmp_index; 02498 tctype = get_tc(token, current_module, &tmp_index, 02499 &np->enums, &np->ranges, &np->hint); 02500 if (tctype == LABEL && 02501 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 02502 NETSNMP_DS_LIB_MIB_WARNINGS) > 1) { 02503 print_error("Warning: No known translation for type", token, 02504 type); 02505 } 02506 type = tctype; 02507 np->tc_index = tmp_index; /* store TC for later reference */ 02508 } 02509 np->type = type; 02510 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02511 switch (type) { 02512 case SEQUENCE: 02513 if (nexttype == OF) { 02514 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02515 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02516 02517 } 02518 break; 02519 case INTEGER: 02520 case INTEGER32: 02521 case UINTEGER32: 02522 case UNSIGNED32: 02523 case COUNTER: 02524 case GAUGE: 02525 case BITSTRING: 02526 case LABEL: 02527 if (nexttype == LEFTBRACKET) { 02528 /* 02529 * if there is an enumeration list, parse it 02530 */ 02531 np->enums = parse_enumlist(fp, &np->enums); 02532 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02533 } else if (nexttype == LEFTPAREN) { 02534 /* 02535 * if there is a range list, parse it 02536 */ 02537 np->ranges = parse_ranges(fp, &np->ranges); 02538 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02539 } 02540 break; 02541 case OCTETSTR: 02542 case KW_OPAQUE: 02543 /* 02544 * parse any SIZE specification 02545 */ 02546 if (nexttype == LEFTPAREN) { 02547 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02548 if (nexttype == SIZE) { 02549 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02550 if (nexttype == LEFTPAREN) { 02551 np->ranges = parse_ranges(fp, &np->ranges); 02552 nexttype = get_token(fp, nexttoken, MAXTOKEN); /* ) */ 02553 if (nexttype == RIGHTPAREN) { 02554 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02555 break; 02556 } 02557 } 02558 } 02559 print_error("Bad SIZE syntax", token, type); 02560 free_node(np); 02561 return NULL; 02562 } 02563 break; 02564 case OBJID: 02565 case NETADDR: 02566 case IPADDR: 02567 case TIMETICKS: 02568 case NUL: 02569 case NSAPADDRESS: 02570 case COUNTER64: 02571 break; 02572 default: 02573 print_error("Bad syntax", token, type); 02574 free_node(np); 02575 return NULL; 02576 } 02577 if (nexttype == UNITS) { 02578 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 02579 if (type != QUOTESTRING) { 02580 print_error("Bad UNITS", quoted_string_buffer, type); 02581 free_node(np); 02582 return NULL; 02583 } 02584 np->units = strdup(quoted_string_buffer); 02585 nexttype = get_token(fp, nexttoken, MAXTOKEN); 02586 } 02587 if (nexttype != ACCESS) { 02588 print_error("Should be ACCESS", nexttoken, nexttype); 02589 free_node(np); 02590 return NULL; 02591 } 02592 type = get_token(fp, token, MAXTOKEN); 02593 if (type != READONLY && type != READWRITE && type != WRITEONLY 02594 && type != NOACCESS && type != READCREATE && type != ACCNOTIFY) { 02595 print_error("Bad ACCESS type", token, type); 02596 free_node(np); 02597 return NULL; 02598 } 02599 np->access = type; 02600 type = get_token(fp, token, MAXTOKEN); 02601 if (type != STATUS) { 02602 print_error("Should be STATUS", token, type); 02603 free_node(np); 02604 return NULL; 02605 } 02606 type = get_token(fp, token, MAXTOKEN); 02607 if (type != MANDATORY && type != CURRENT && type != KW_OPTIONAL && 02608 type != OBSOLETE && type != DEPRECATED) { 02609 print_error("Bad STATUS", token, type); 02610 free_node(np); 02611 return NULL; 02612 } 02613 np->status = type; 02614 /* 02615 * Optional parts of the OBJECT-TYPE macro 02616 */ 02617 type = get_token(fp, token, MAXTOKEN); 02618 while (type != EQUALS && type != ENDOFFILE) { 02619 switch (type) { 02620 case DESCRIPTION: 02621 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 02622 02623 if (type != QUOTESTRING) { 02624 print_error("Bad DESCRIPTION", quoted_string_buffer, type); 02625 free_node(np); 02626 return NULL; 02627 } 02628 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 02629 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) { 02630 np->description = strdup(quoted_string_buffer); 02631 } 02632 break; 02633 02634 case REFERENCE: 02635 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 02636 if (type != QUOTESTRING) { 02637 print_error("Bad REFERENCE", quoted_string_buffer, type); 02638 free_node(np); 02639 return NULL; 02640 } 02641 np->reference = strdup(quoted_string_buffer); 02642 break; 02643 case INDEX: 02644 if (np->augments) { 02645 print_error("Cannot have both INDEX and AUGMENTS", token, 02646 type); 02647 free_node(np); 02648 return NULL; 02649 } 02650 np->indexes = getIndexes(fp, &np->indexes); 02651 if (np->indexes == NULL) { 02652 print_error("Bad INDEX list", token, type); 02653 free_node(np); 02654 return NULL; 02655 } 02656 break; 02657 case AUGMENTS: 02658 if (np->indexes) { 02659 print_error("Cannot have both INDEX and AUGMENTS", token, 02660 type); 02661 free_node(np); 02662 return NULL; 02663 } 02664 np->indexes = getIndexes(fp, &np->indexes); 02665 if (np->indexes == NULL) { 02666 print_error("Bad AUGMENTS list", token, type); 02667 free_node(np); 02668 return NULL; 02669 } 02670 np->augments = strdup(np->indexes->ilabel); 02671 free_indexes(&np->indexes); 02672 break; 02673 case DEFVAL: 02674 /* 02675 * Mark's defVal section 02676 */ 02677 type = get_token(fp, quoted_string_buffer, MAXTOKEN); 02678 if (type != LEFTBRACKET) { 02679 print_error("Bad DEFAULTVALUE", quoted_string_buffer, 02680 type); 02681 free_node(np); 02682 return NULL; 02683 } 02684 02685 { 02686 int level = 1; 02687 char defbuf[512]; 02688 02689 defbuf[0] = 0; 02690 while (1) { 02691 type = get_token(fp, quoted_string_buffer, MAXTOKEN); 02692 if ((type == RIGHTBRACKET && --level == 0) 02693 || type == ENDOFFILE) 02694 break; 02695 else if (type == LEFTBRACKET) 02696 level++; 02697 if (type == QUOTESTRING) { 02698 if (strlen(defbuf)+2 < sizeof(defbuf)) { 02699 defbuf[ strlen(defbuf)+2 ] = 0; 02700 defbuf[ strlen(defbuf)+1 ] = '"'; 02701 defbuf[ strlen(defbuf) ] = '\\'; 02702 } 02703 defbuf[ sizeof(defbuf)-1 ] = 0; 02704 } 02705 strncat(defbuf, quoted_string_buffer, 02706 sizeof(defbuf)-strlen(defbuf)-1); 02707 defbuf[ sizeof(defbuf)-1 ] = 0; 02708 if (type == QUOTESTRING) { 02709 if (strlen(defbuf)+2 < sizeof(defbuf)) { 02710 defbuf[ strlen(defbuf)+2 ] = 0; 02711 defbuf[ strlen(defbuf)+1 ] = '"'; 02712 defbuf[ strlen(defbuf) ] = '\\'; 02713 } 02714 defbuf[ sizeof(defbuf)-1 ] = 0; 02715 } 02716 if (strlen(defbuf)+1 < sizeof(defbuf)) { 02717 defbuf[ strlen(defbuf)+1 ] = 0; 02718 defbuf[ strlen(defbuf) ] = ' '; 02719 } 02720 } 02721 02722 if (type != RIGHTBRACKET) { 02723 print_error("Bad DEFAULTVALUE", quoted_string_buffer, 02724 type); 02725 free_node(np); 02726 return NULL; 02727 } 02728 02729 defbuf[strlen(defbuf) - 1] = 0; 02730 np->defaultValue = strdup(defbuf); 02731 } 02732 02733 break; 02734 02735 case NUM_ENTRIES: 02736 if (tossObjectIdentifier(fp) != OBJID) { 02737 print_error("Bad Object Identifier", token, type); 02738 free_node(np); 02739 return NULL; 02740 } 02741 break; 02742 02743 default: 02744 print_error("Bad format of optional clauses", token, type); 02745 free_node(np); 02746 return NULL; 02747 02748 } 02749 type = get_token(fp, token, MAXTOKEN); 02750 } 02751 if (type != EQUALS) { 02752 print_error("Bad format", token, type); 02753 free_node(np); 02754 return NULL; 02755 } 02756 return merge_parse_objectid(np, fp, name); 02757 } 02758 02759 /* 02760 * Parses an OBJECT GROUP macro. 02761 * Returns 0 on error. 02762 * 02763 * Also parses object-identity, since they are similar (ignore STATUS). 02764 * - WJH 10/96 02765 */ 02766 static struct node * 02767 parse_objectgroup(FILE * fp, char *name, int what, struct objgroup **ol) 02768 { 02769 int type; 02770 char token[MAXTOKEN]; 02771 char quoted_string_buffer[MAXQUOTESTR]; 02772 struct node *np; 02773 02774 np = alloc_node(current_module); 02775 if (np == NULL) 02776 return (NULL); 02777 type = get_token(fp, token, MAXTOKEN); 02778 if (type == what) { 02779 type = get_token(fp, token, MAXTOKEN); 02780 if (type != LEFTBRACKET) { 02781 print_error("Expected \"{\"", token, type); 02782 goto skip; 02783 } 02784 do { 02785 struct objgroup *o; 02786 type = get_token(fp, token, MAXTOKEN); 02787 if (type != LABEL) { 02788 print_error("Bad identifier", token, type); 02789 goto skip; 02790 } 02791 o = (struct objgroup *) malloc(sizeof(struct objgroup)); 02792 if (!o) { 02793 print_error("Resource failure", token, type); 02794 goto skip; 02795 } 02796 o->line = mibLine; 02797 o->name = strdup(token); 02798 o->next = *ol; 02799 *ol = o; 02800 type = get_token(fp, token, MAXTOKEN); 02801 } while (type == COMMA); 02802 if (type != RIGHTBRACKET) { 02803 print_error("Expected \"}\" after list", token, type); 02804 goto skip; 02805 } 02806 type = get_token(fp, token, type); 02807 } 02808 if (type != STATUS) { 02809 print_error("Expected STATUS", token, type); 02810 goto skip; 02811 } 02812 type = get_token(fp, token, MAXTOKEN); 02813 if (type != CURRENT && type != DEPRECATED && type != OBSOLETE) { 02814 print_error("Bad STATUS value", token, type); 02815 goto skip; 02816 } 02817 type = get_token(fp, token, MAXTOKEN); 02818 if (type != DESCRIPTION) { 02819 print_error("Expected DESCRIPTION", token, type); 02820 goto skip; 02821 } 02822 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 02823 if (type != QUOTESTRING) { 02824 print_error("Bad DESCRIPTION", quoted_string_buffer, type); 02825 free_node(np); 02826 return NULL; 02827 } 02828 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 02829 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) { 02830 np->description = strdup(quoted_string_buffer); 02831 } 02832 type = get_token(fp, token, MAXTOKEN); 02833 if (type == REFERENCE) { 02834 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 02835 if (type != QUOTESTRING) { 02836 print_error("Bad REFERENCE", quoted_string_buffer, type); 02837 free_node(np); 02838 return NULL; 02839 } 02840 np->reference = strdup(quoted_string_buffer); 02841 type = get_token(fp, token, MAXTOKEN); 02842 } 02843 if (type != EQUALS) 02844 print_error("Expected \"::=\"", token, type); 02845 skip: 02846 while (type != EQUALS && type != ENDOFFILE) 02847 type = get_token(fp, token, MAXTOKEN); 02848 02849 return merge_parse_objectid(np, fp, name); 02850 } 02851 02852 /* 02853 * Parses a NOTIFICATION-TYPE macro. 02854 * Returns 0 on error. 02855 */ 02856 static struct node * 02857 parse_notificationDefinition(FILE * fp, char *name) 02858 { 02859 register int type; 02860 char token[MAXTOKEN]; 02861 char quoted_string_buffer[MAXQUOTESTR]; 02862 register struct node *np; 02863 02864 np = alloc_node(current_module); 02865 if (np == NULL) 02866 return (NULL); 02867 type = get_token(fp, token, MAXTOKEN); 02868 while (type != EQUALS && type != ENDOFFILE) { 02869 switch (type) { 02870 case DESCRIPTION: 02871 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 02872 if (type != QUOTESTRING) { 02873 print_error("Bad DESCRIPTION", quoted_string_buffer, type); 02874 free_node(np); 02875 return NULL; 02876 } 02877 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 02878 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) { 02879 np->description = strdup(quoted_string_buffer); 02880 } 02881 break; 02882 case REFERENCE: 02883 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 02884 if (type != QUOTESTRING) { 02885 print_error("Bad REFERENCE", quoted_string_buffer, type); 02886 free_node(np); 02887 return NULL; 02888 } 02889 np->reference = strdup(quoted_string_buffer); 02890 break; 02891 case OBJECTS: 02892 np->varbinds = getVarbinds(fp, &np->varbinds); 02893 if (!np->varbinds) { 02894 print_error("Bad OBJECTS list", token, type); 02895 free_node(np); 02896 return NULL; 02897 } 02898 break; 02899 default: 02900 /* 02901 * NOTHING 02902 */ 02903 break; 02904 } 02905 type = get_token(fp, token, MAXTOKEN); 02906 } 02907 return merge_parse_objectid(np, fp, name); 02908 } 02909 02910 /* 02911 * Parses a TRAP-TYPE macro. 02912 * Returns 0 on error. 02913 */ 02914 static struct node * 02915 parse_trapDefinition(FILE * fp, char *name) 02916 { 02917 register int type; 02918 char token[MAXTOKEN]; 02919 char quoted_string_buffer[MAXQUOTESTR]; 02920 register struct node *np; 02921 02922 np = alloc_node(current_module); 02923 if (np == NULL) 02924 return (NULL); 02925 type = get_token(fp, token, MAXTOKEN); 02926 while (type != EQUALS && type != ENDOFFILE) { 02927 switch (type) { 02928 case DESCRIPTION: 02929 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 02930 if (type != QUOTESTRING) { 02931 print_error("Bad DESCRIPTION", quoted_string_buffer, type); 02932 free_node(np); 02933 return NULL; 02934 } 02935 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 02936 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) { 02937 np->description = strdup(quoted_string_buffer); 02938 } 02939 break; 02940 case REFERENCE: 02941 /* I'm not sure REFERENCEs are legal in smiv1 traps??? */ 02942 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 02943 if (type != QUOTESTRING) { 02944 print_error("Bad REFERENCE", quoted_string_buffer, type); 02945 free_node(np); 02946 return NULL; 02947 } 02948 np->reference = strdup(quoted_string_buffer); 02949 break; 02950 case ENTERPRISE: 02951 type = get_token(fp, token, MAXTOKEN); 02952 if (type == LEFTBRACKET) { 02953 type = get_token(fp, token, MAXTOKEN); 02954 if (type != LABEL) { 02955 print_error("Bad Trap Format", token, type); 02956 free_node(np); 02957 return NULL; 02958 } 02959 np->parent = strdup(token); 02960 /* 02961 * Get right bracket 02962 */ 02963 type = get_token(fp, token, MAXTOKEN); 02964 } else if (type == LABEL) { 02965 np->parent = strdup(token); 02966 } else { 02967 free_node(np); 02968 return NULL; 02969 } 02970 break; 02971 case VARIABLES: 02972 np->varbinds = getVarbinds(fp, &np->varbinds); 02973 if (!np->varbinds) { 02974 print_error("Bad VARIABLES list", token, type); 02975 free_node(np); 02976 return NULL; 02977 } 02978 break; 02979 default: 02980 /* 02981 * NOTHING 02982 */ 02983 break; 02984 } 02985 type = get_token(fp, token, MAXTOKEN); 02986 } 02987 type = get_token(fp, token, MAXTOKEN); 02988 02989 np->label = strdup(name); 02990 02991 if (type != NUMBER) { 02992 print_error("Expected a Number", token, type); 02993 free_node(np); 02994 return NULL; 02995 } 02996 np->subid = strtoul(token, NULL, 10); 02997 np->next = alloc_node(current_module); 02998 if (np->next == NULL) { 02999 free_node(np); 03000 return (NULL); 03001 } 03002 03003 /* Catch the syntax error */ 03004 if (np->parent == NULL) { 03005 free_node(np->next); 03006 free_node(np); 03007 gMibError = MODULE_SYNTAX_ERROR; 03008 return (NULL); 03009 } 03010 03011 np->next->parent = np->parent; 03012 np->parent = (char *) malloc(strlen(np->parent) + 2); 03013 if (np->parent == NULL) { 03014 free_node(np->next); 03015 free_node(np); 03016 return (NULL); 03017 } 03018 strcpy(np->parent, np->next->parent); 03019 strcat(np->parent, "#"); 03020 np->next->label = strdup(np->parent); 03021 return np; 03022 } 03023 03024 03025 /* 03026 * Parses a compliance macro 03027 * Returns 0 on error. 03028 */ 03029 static int 03030 eat_syntax(FILE * fp, char *token, int maxtoken) 03031 { 03032 int type, nexttype; 03033 struct node *np = alloc_node(current_module); 03034 char nexttoken[MAXTOKEN]; 03035 03036 if (!np) 03037 return 0; 03038 03039 type = get_token(fp, token, maxtoken); 03040 nexttype = get_token(fp, nexttoken, MAXTOKEN); 03041 switch (type) { 03042 case INTEGER: 03043 case INTEGER32: 03044 case UINTEGER32: 03045 case UNSIGNED32: 03046 case COUNTER: 03047 case GAUGE: 03048 case BITSTRING: 03049 case LABEL: 03050 if (nexttype == LEFTBRACKET) { 03051 /* 03052 * if there is an enumeration list, parse it 03053 */ 03054 np->enums = parse_enumlist(fp, &np->enums); 03055 nexttype = get_token(fp, nexttoken, MAXTOKEN); 03056 } else if (nexttype == LEFTPAREN) { 03057 /* 03058 * if there is a range list, parse it 03059 */ 03060 np->ranges = parse_ranges(fp, &np->ranges); 03061 nexttype = get_token(fp, nexttoken, MAXTOKEN); 03062 } 03063 break; 03064 case OCTETSTR: 03065 case KW_OPAQUE: 03066 /* 03067 * parse any SIZE specification 03068 */ 03069 if (nexttype == LEFTPAREN) { 03070 nexttype = get_token(fp, nexttoken, MAXTOKEN); 03071 if (nexttype == SIZE) { 03072 nexttype = get_token(fp, nexttoken, MAXTOKEN); 03073 if (nexttype == LEFTPAREN) { 03074 np->ranges = parse_ranges(fp, &np->ranges); 03075 nexttype = get_token(fp, nexttoken, MAXTOKEN); /* ) */ 03076 if (nexttype == RIGHTPAREN) { 03077 nexttype = get_token(fp, nexttoken, MAXTOKEN); 03078 break; 03079 } 03080 } 03081 } 03082 print_error("Bad SIZE syntax", token, type); 03083 free_node(np); 03084 return nexttype; 03085 } 03086 break; 03087 case OBJID: 03088 case NETADDR: 03089 case IPADDR: 03090 case TIMETICKS: 03091 case NUL: 03092 case NSAPADDRESS: 03093 case COUNTER64: 03094 break; 03095 default: 03096 print_error("Bad syntax", token, type); 03097 free_node(np); 03098 return nexttype; 03099 } 03100 free_node(np); 03101 return nexttype; 03102 } 03103 03104 static int 03105 compliance_lookup(const char *name, int modid) 03106 { 03107 if (modid == -1) { 03108 struct objgroup *op = 03109 (struct objgroup *) malloc(sizeof(struct objgroup)); 03110 if (!op) 03111 return 0; 03112 op->next = objgroups; 03113 op->name = strdup(name); 03114 op->line = mibLine; 03115 objgroups = op; 03116 return 1; 03117 } else 03118 return find_tree_node(name, modid) != NULL; 03119 } 03120 03121 static struct node * 03122 parse_compliance(FILE * fp, char *name) 03123 { 03124 int type; 03125 char token[MAXTOKEN]; 03126 char quoted_string_buffer[MAXQUOTESTR]; 03127 struct node *np; 03128 03129 np = alloc_node(current_module); 03130 if (np == NULL) 03131 return (NULL); 03132 type = get_token(fp, token, MAXTOKEN); 03133 if (type != STATUS) { 03134 print_error("Expected STATUS", token, type); 03135 goto skip; 03136 } 03137 type = get_token(fp, token, MAXTOKEN); 03138 if (type != CURRENT && type != DEPRECATED && type != OBSOLETE) { 03139 print_error("Bad STATUS", token, type); 03140 goto skip; 03141 } 03142 type = get_token(fp, token, MAXTOKEN); 03143 if (type != DESCRIPTION) { 03144 print_error("Expected DESCRIPTION", token, type); 03145 goto skip; 03146 } 03147 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 03148 if (type != QUOTESTRING) { 03149 print_error("Bad DESCRIPTION", quoted_string_buffer, type); 03150 goto skip; 03151 } 03152 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 03153 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) 03154 np->description = strdup(quoted_string_buffer); 03155 type = get_token(fp, token, MAXTOKEN); 03156 if (type == REFERENCE) { 03157 type = get_token(fp, quoted_string_buffer, MAXTOKEN); 03158 if (type != QUOTESTRING) { 03159 print_error("Bad REFERENCE", quoted_string_buffer, type); 03160 goto skip; 03161 } 03162 np->reference = strdup(quoted_string_buffer); 03163 type = get_token(fp, token, MAXTOKEN); 03164 } 03165 if (type != MODULE) { 03166 print_error("Expected MODULE", token, type); 03167 goto skip; 03168 } 03169 while (type == MODULE) { 03170 int modid = -1; 03171 char modname[MAXTOKEN]; 03172 type = get_token(fp, token, MAXTOKEN); 03173 if (type == LABEL 03174 && strcmp(token, module_name(current_module, modname))) { 03175 modid = read_module_internal(token); 03176 if (modid != MODULE_LOADED_OK 03177 && modid != MODULE_ALREADY_LOADED) { 03178 print_error("Unknown module", token, type); 03179 goto skip; 03180 } 03181 modid = which_module(token); 03182 type = get_token(fp, token, MAXTOKEN); 03183 } 03184 if (type == MANDATORYGROUPS) { 03185 type = get_token(fp, token, MAXTOKEN); 03186 if (type != LEFTBRACKET) { 03187 print_error("Expected \"{\"", token, type); 03188 goto skip; 03189 } 03190 do { 03191 type = get_token(fp, token, MAXTOKEN); 03192 if (type != LABEL) { 03193 print_error("Bad group name", token, type); 03194 goto skip; 03195 } 03196 if (!compliance_lookup(token, modid)) 03197 print_error("Unknown group", token, type); 03198 type = get_token(fp, token, MAXTOKEN); 03199 } while (type == COMMA); 03200 if (type != RIGHTBRACKET) { 03201 print_error("Expected \"}\"", token, type); 03202 goto skip; 03203 } 03204 type = get_token(fp, token, MAXTOKEN); 03205 } 03206 while (type == GROUP || type == OBJECT) { 03207 if (type == GROUP) { 03208 type = get_token(fp, token, MAXTOKEN); 03209 if (type != LABEL) { 03210 print_error("Bad group name", token, type); 03211 goto skip; 03212 } 03213 if (!compliance_lookup(token, modid)) 03214 print_error("Unknown group", token, type); 03215 type = get_token(fp, token, MAXTOKEN); 03216 } else { 03217 type = get_token(fp, token, MAXTOKEN); 03218 if (type != LABEL) { 03219 print_error("Bad object name", token, type); 03220 goto skip; 03221 } 03222 if (!compliance_lookup(token, modid)) 03223 print_error("Unknown group", token, type); 03224 type = get_token(fp, token, MAXTOKEN); 03225 if (type == SYNTAX) 03226 type = eat_syntax(fp, token, MAXTOKEN); 03227 if (type == WRSYNTAX) 03228 type = eat_syntax(fp, token, MAXTOKEN); 03229 if (type == MINACCESS) { 03230 type = get_token(fp, token, MAXTOKEN); 03231 if (type != NOACCESS && type != ACCNOTIFY 03232 && type != READONLY && type != WRITEONLY 03233 && type != READCREATE && type != READWRITE) { 03234 print_error("Bad MIN-ACCESS spec", token, type); 03235 goto skip; 03236 } 03237 type = get_token(fp, token, MAXTOKEN); 03238 } 03239 } 03240 if (type != DESCRIPTION) { 03241 print_error("Expected DESCRIPTION", token, type); 03242 goto skip; 03243 } 03244 type = get_token(fp, token, MAXTOKEN); 03245 if (type != QUOTESTRING) { 03246 print_error("Bad DESCRIPTION", token, type); 03247 goto skip; 03248 } 03249 type = get_token(fp, token, MAXTOKEN); 03250 } 03251 } 03252 skip: 03253 while (type != EQUALS && type != ENDOFFILE) 03254 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 03255 03256 return merge_parse_objectid(np, fp, name); 03257 } 03258 03259 03260 /* 03261 * Parses a capabilities macro 03262 * Returns 0 on error. 03263 */ 03264 static struct node * 03265 parse_capabilities(FILE * fp, char *name) 03266 { 03267 int type; 03268 char token[MAXTOKEN]; 03269 char quoted_string_buffer[MAXQUOTESTR]; 03270 struct node *np; 03271 03272 np = alloc_node(current_module); 03273 if (np == NULL) 03274 return (NULL); 03275 type = get_token(fp, token, MAXTOKEN); 03276 if (type != PRODREL) { 03277 print_error("Expected PRODUCT-RELEASE", token, type); 03278 goto skip; 03279 } 03280 type = get_token(fp, token, MAXTOKEN); 03281 if (type != QUOTESTRING) { 03282 print_error("Expected STRING after PRODUCT-RELEASE", token, type); 03283 goto skip; 03284 } 03285 type = get_token(fp, token, MAXTOKEN); 03286 if (type != STATUS) { 03287 print_error("Expected STATUS", token, type); 03288 goto skip; 03289 } 03290 type = get_token(fp, token, MAXTOKEN); 03291 if (type != CURRENT && type != OBSOLETE) { 03292 print_error("STATUS should be current or obsolete", token, type); 03293 goto skip; 03294 } 03295 type = get_token(fp, token, MAXTOKEN); 03296 if (type != DESCRIPTION) { 03297 print_error("Expected DESCRIPTION", token, type); 03298 goto skip; 03299 } 03300 type = get_token(fp, quoted_string_buffer, MAXTOKEN); 03301 if (type != QUOTESTRING) { 03302 print_error("Bad DESCRIPTION", quoted_string_buffer, type); 03303 goto skip; 03304 } 03305 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 03306 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) { 03307 np->description = strdup(quoted_string_buffer); 03308 } 03309 type = get_token(fp, token, MAXTOKEN); 03310 if (type == REFERENCE) { 03311 type = get_token(fp, quoted_string_buffer, MAXTOKEN); 03312 if (type != QUOTESTRING) { 03313 print_error("Bad REFERENCE", quoted_string_buffer, type); 03314 goto skip; 03315 } 03316 np->reference = strdup(quoted_string_buffer); 03317 type = get_token(fp, token, type); 03318 } 03319 while (type == SUPPORTS) { 03320 int modid; 03321 struct tree *tp; 03322 03323 type = get_token(fp, token, MAXTOKEN); 03324 if (type != LABEL) { 03325 print_error("Bad module name", token, type); 03326 goto skip; 03327 } 03328 modid = read_module_internal(token); 03329 if (modid != MODULE_LOADED_OK && modid != MODULE_ALREADY_LOADED) { 03330 print_error("Module not found", token, type); 03331 goto skip; 03332 } 03333 modid = which_module(token); 03334 type = get_token(fp, token, MAXTOKEN); 03335 if (type != INCLUDES) { 03336 print_error("Expected INCLUDES", token, type); 03337 goto skip; 03338 } 03339 type = get_token(fp, token, MAXTOKEN); 03340 if (type != LEFTBRACKET) { 03341 print_error("Expected \"{\"", token, type); 03342 goto skip; 03343 } 03344 do { 03345 type = get_token(fp, token, MAXTOKEN); 03346 if (type != LABEL) { 03347 print_error("Expected group name", token, type); 03348 goto skip; 03349 } 03350 tp = find_tree_node(token, modid); 03351 if (!tp) 03352 print_error("Group not found in module", token, type); 03353 type = get_token(fp, token, MAXTOKEN); 03354 } while (type == COMMA); 03355 if (type != RIGHTBRACKET) { 03356 print_error("Expected \"}\" after group list", token, type); 03357 goto skip; 03358 } 03359 type = get_token(fp, token, MAXTOKEN); 03360 while (type == VARIATION) { 03361 type = get_token(fp, token, MAXTOKEN); 03362 if (type != LABEL) { 03363 print_error("Bad object name", token, type); 03364 goto skip; 03365 } 03366 tp = find_tree_node(token, modid); 03367 if (!tp) 03368 print_error("Object not found in module", token, type); 03369 type = get_token(fp, token, MAXTOKEN); 03370 if (type == SYNTAX) { 03371 type = eat_syntax(fp, token, MAXTOKEN); 03372 } 03373 if (type == WRSYNTAX) { 03374 type = eat_syntax(fp, token, MAXTOKEN); 03375 } 03376 if (type == ACCESS) { 03377 type = get_token(fp, token, MAXTOKEN); 03378 if (type != ACCNOTIFY && type != READONLY 03379 && type != READWRITE && type != READCREATE 03380 && type != WRITEONLY && type != NOTIMPL) { 03381 print_error("Bad ACCESS", token, type); 03382 goto skip; 03383 } 03384 type = get_token(fp, token, MAXTOKEN); 03385 } 03386 if (type == CREATEREQ) { 03387 type = get_token(fp, token, MAXTOKEN); 03388 if (type != LEFTBRACKET) { 03389 print_error("Expected \"{\"", token, type); 03390 goto skip; 03391 } 03392 do { 03393 type = get_token(fp, token, MAXTOKEN); 03394 if (type != LABEL) { 03395 print_error("Bad object name in list", token, 03396 type); 03397 goto skip; 03398 } 03399 type = get_token(fp, token, MAXTOKEN); 03400 } while (type == COMMA); 03401 if (type != RIGHTBRACKET) { 03402 print_error("Expected \"}\" after list", token, type); 03403 goto skip; 03404 } 03405 type = get_token(fp, token, MAXTOKEN); 03406 } 03407 if (type == DEFVAL) { 03408 int level = 1; 03409 type = get_token(fp, token, MAXTOKEN); 03410 if (type != LEFTBRACKET) { 03411 print_error("Expected \"{\" after DEFVAL", token, 03412 type); 03413 goto skip; 03414 } 03415 do { 03416 type = get_token(fp, token, MAXTOKEN); 03417 if (type == LEFTBRACKET) 03418 level++; 03419 else if (type == RIGHTBRACKET) 03420 level--; 03421 } while (type != RIGHTBRACKET && type != ENDOFFILE 03422 && level != 0); 03423 if (type != RIGHTBRACKET) { 03424 print_error("Missing \"}\" after DEFVAL", token, type); 03425 goto skip; 03426 } 03427 type = get_token(fp, token, MAXTOKEN); 03428 } 03429 if (type != DESCRIPTION) { 03430 print_error("Expected DESCRIPTION", token, type); 03431 goto skip; 03432 } 03433 type = get_token(fp, quoted_string_buffer, MAXTOKEN); 03434 if (type != QUOTESTRING) { 03435 print_error("Bad DESCRIPTION", quoted_string_buffer, type); 03436 goto skip; 03437 } 03438 type = get_token(fp, token, MAXTOKEN); 03439 } 03440 } 03441 if (type != EQUALS) 03442 print_error("Expected \"::=\"", token, type); 03443 skip: 03444 while (type != EQUALS && type != ENDOFFILE) { 03445 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 03446 } 03447 return merge_parse_objectid(np, fp, name); 03448 } 03449 03450 /* 03451 * Parses a module identity macro 03452 * Returns 0 on error. 03453 */ 03454 static void 03455 check_utc(const char *utc) 03456 { 03457 int len, year, month, day, hour, minute; 03458 03459 len = strlen(utc); 03460 if (utc[len - 1] != 'Z' && utc[len - 1] != 'z') { 03461 print_error("Timestamp should end with Z", utc, QUOTESTRING); 03462 return; 03463 } 03464 if (len == 11) { 03465 len = 03466 sscanf(utc, "%2d%2d%2d%2d%2dZ", &year, &month, &day, &hour, 03467 &minute); 03468 year += 1900; 03469 } else if (len == 13) 03470 len = 03471 sscanf(utc, "%4d%2d%2d%2d%2dZ", &year, &month, &day, &hour, 03472 &minute); 03473 else { 03474 print_error("Bad timestamp format (11 or 13 characters)", 03475 utc, QUOTESTRING); 03476 return; 03477 } 03478 if (len != 5) { 03479 print_error("Bad timestamp format", utc, QUOTESTRING); 03480 return; 03481 } 03482 if (month < 1 || month > 12) 03483 print_error("Bad month in timestamp", utc, QUOTESTRING); 03484 if (day < 1 || day > 31) 03485 print_error("Bad day in timestamp", utc, QUOTESTRING); 03486 if (hour < 0 || hour > 23) 03487 print_error("Bad hour in timestamp", utc, QUOTESTRING); 03488 if (minute < 0 || minute > 59) 03489 print_error("Bad minute in timestamp", utc, QUOTESTRING); 03490 } 03491 03492 static struct node * 03493 parse_moduleIdentity(FILE * fp, char *name) 03494 { 03495 register int type; 03496 char token[MAXTOKEN]; 03497 char quoted_string_buffer[MAXQUOTESTR]; 03498 register struct node *np; 03499 03500 np = alloc_node(current_module); 03501 if (np == NULL) 03502 return (NULL); 03503 type = get_token(fp, token, MAXTOKEN); 03504 if (type != LASTUPDATED) { 03505 print_error("Expected LAST-UPDATED", token, type); 03506 goto skip; 03507 } 03508 type = get_token(fp, token, MAXTOKEN); 03509 if (type != QUOTESTRING) { 03510 print_error("Need STRING for LAST-UPDATED", token, type); 03511 goto skip; 03512 } 03513 check_utc(token); 03514 type = get_token(fp, token, MAXTOKEN); 03515 if (type != ORGANIZATION) { 03516 print_error("Expected ORGANIZATION", token, type); 03517 goto skip; 03518 } 03519 type = get_token(fp, token, MAXTOKEN); 03520 if (type != QUOTESTRING) { 03521 print_error("Bad ORGANIZATION", token, type); 03522 goto skip; 03523 } 03524 type = get_token(fp, token, MAXTOKEN); 03525 if (type != CONTACTINFO) { 03526 print_error("Expected CONTACT-INFO", token, type); 03527 goto skip; 03528 } 03529 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 03530 if (type != QUOTESTRING) { 03531 print_error("Bad CONTACT-INFO", quoted_string_buffer, type); 03532 goto skip; 03533 } 03534 type = get_token(fp, token, MAXTOKEN); 03535 if (type != DESCRIPTION) { 03536 print_error("Expected DESCRIPTION", token, type); 03537 goto skip; 03538 } 03539 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 03540 if (type != QUOTESTRING) { 03541 print_error("Bad DESCRIPTION", quoted_string_buffer, type); 03542 goto skip; 03543 } 03544 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 03545 NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) { 03546 np->description = strdup(quoted_string_buffer); 03547 } 03548 type = get_token(fp, token, MAXTOKEN); 03549 while (type == REVISION) { 03550 type = get_token(fp, token, MAXTOKEN); 03551 if (type != QUOTESTRING) { 03552 print_error("Bad REVISION", token, type); 03553 goto skip; 03554 } 03555 check_utc(token); 03556 type = get_token(fp, token, MAXTOKEN); 03557 if (type != DESCRIPTION) { 03558 print_error("Expected DESCRIPTION", token, type); 03559 goto skip; 03560 } 03561 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 03562 if (type != QUOTESTRING) { 03563 print_error("Bad DESCRIPTION", quoted_string_buffer, type); 03564 goto skip; 03565 } 03566 type = get_token(fp, token, MAXTOKEN); 03567 } 03568 if (type != EQUALS) 03569 print_error("Expected \"::=\"", token, type); 03570 skip: 03571 while (type != EQUALS && type != ENDOFFILE) { 03572 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR); 03573 } 03574 return merge_parse_objectid(np, fp, name); 03575 } 03576 03577 03578 /* 03579 * Parses a MACRO definition 03580 * Expect BEGIN, discard everything to end. 03581 * Returns 0 on error. 03582 */ 03583 static struct node * 03584 parse_macro(FILE * fp, char *name) 03585 { 03586 register int type; 03587 char token[MAXTOKEN]; 03588 struct node *np; 03589 int iLine = mibLine; 03590 03591 np = alloc_node(current_module); 03592 if (np == NULL) 03593 return (NULL); 03594 type = get_token(fp, token, sizeof(token)); 03595 while (type != EQUALS && type != ENDOFFILE) { 03596 type = get_token(fp, token, sizeof(token)); 03597 } 03598 if (type != EQUALS) { 03599 if (np) 03600 free_node(np); 03601 return NULL; 03602 } 03603 while (type != BEGIN && type != ENDOFFILE) { 03604 type = get_token(fp, token, sizeof(token)); 03605 } 03606 if (type != BEGIN) { 03607 if (np) 03608 free_node(np); 03609 return NULL; 03610 } 03611 while (type != END && type != ENDOFFILE) { 03612 type = get_token(fp, token, sizeof(token)); 03613 } 03614 if (type != END) { 03615 if (np) 03616 free_node(np); 03617 return NULL; 03618 } 03619 03620 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 03621 NETSNMP_DS_LIB_MIB_WARNINGS)) { 03622 snmp_log(LOG_WARNING, 03623 "%s MACRO (lines %d..%d parsed and ignored).\n", name, 03624 iLine, mibLine); 03625 } 03626 03627 return np; 03628 } 03629 03630 /* 03631 * Parses a module import clause 03632 * loading any modules referenced 03633 */ 03634 static void 03635 parse_imports(FILE * fp) 03636 { 03637 register int type; 03638 char token[MAXTOKEN]; 03639 char modbuf[256]; 03640 #define MAX_IMPORTS 256 03641 struct module_import import_list[MAX_IMPORTS]; 03642 int this_module; 03643 struct module *mp; 03644 03645 int import_count = 0; /* Total number of imported descriptors */ 03646 int i = 0, old_i; /* index of first import from each module */ 03647 03648 type = get_token(fp, token, MAXTOKEN); 03649 03650 /* 03651 * Parse the IMPORTS clause 03652 */ 03653 while (type != SEMI && type != ENDOFFILE) { 03654 if (type == LABEL) { 03655 if (import_count == MAX_IMPORTS) { 03656 print_error("Too many imported symbols", token, type); 03657 do { 03658 type = get_token(fp, token, MAXTOKEN); 03659 } while (type != SEMI && type != ENDOFFILE); 03660 return; 03661 } 03662 import_list[import_count++].label = strdup(token); 03663 } else if (type == FROM) { 03664 type = get_token(fp, token, MAXTOKEN); 03665 if (import_count == i) { /* All imports are handled internally */ 03666 type = get_token(fp, token, MAXTOKEN); 03667 continue; 03668 } 03669 this_module = which_module(token); 03670 03671 for (old_i = i; i < import_count; ++i) 03672 import_list[i].modid = this_module; 03673 03674 /* 03675 * Recursively read any pre-requisite modules 03676 */ 03677 if (read_module_internal(token) == MODULE_NOT_FOUND) { 03678 int found = 0; 03679 for (; old_i < import_count; ++old_i) { 03680 found += read_import_replacements(token, &import_list[old_i]); 03681 } 03682 if (!found) 03683 print_module_not_found(token); 03684 } 03685 } 03686 type = get_token(fp, token, MAXTOKEN); 03687 } 03688 03689 /* 03690 * Save the import information 03691 * in the global module table 03692 */ 03693 for (mp = module_head; mp; mp = mp->next) 03694 if (mp->modid == current_module) { 03695 if (import_count == 0) 03696 return; 03697 if (mp->imports && (mp->imports != root_imports)) { 03698 /* 03699 * this can happen if all modules are in one source file. 03700 */ 03701 for (i = 0; i < mp->no_imports; ++i) { 03702 DEBUGMSGTL(("parse-mibs", 03703 "#### freeing Module %d '%s' %d\n", 03704 mp->modid, mp->imports[i].label, 03705 mp->imports[i].modid)); 03706 free((char *) mp->imports[i].label); 03707 } 03708 free((char *) mp->imports); 03709 } 03710 mp->imports = (struct module_import *) 03711 calloc(import_count, sizeof(struct module_import)); 03712 if (mp->imports == NULL) 03713 return; 03714 for (i = 0; i < import_count; ++i) { 03715 mp->imports[i].label = import_list[i].label; 03716 mp->imports[i].modid = import_list[i].modid; 03717 DEBUGMSGTL(("parse-mibs", 03718 "#### adding Module %d '%s' %d\n", mp->modid, 03719 mp->imports[i].label, mp->imports[i].modid)); 03720 } 03721 mp->no_imports = import_count; 03722 return; 03723 } 03724 03725 /* 03726 * Shouldn't get this far 03727 */ 03728 print_module_not_found(module_name(current_module, modbuf)); 03729 return; 03730 } 03731 03732 03733 03734 /* 03735 * MIB module handling routines 03736 */ 03737 03738 static void 03739 dump_module_list(void) 03740 { 03741 struct module *mp = module_head; 03742 03743 DEBUGMSGTL(("parse-mibs", "Module list:\n")); 03744 while (mp) { 03745 DEBUGMSGTL(("parse-mibs", " %s %d %s %d\n", mp->name, mp->modid, 03746 mp->file, mp->no_imports)); 03747 mp = mp->next; 03748 } 03749 } 03750 03751 int 03752 which_module(const char *name) 03753 { 03754 struct module *mp; 03755 03756 for (mp = module_head; mp; mp = mp->next) 03757 if (!label_compare(mp->name, name)) 03758 return (mp->modid); 03759 03760 DEBUGMSGTL(("parse-mibs", "Module %s not found\n", name)); 03761 return (-1); 03762 } 03763 03764 /* 03765 * module_name - copy module name to user buffer, return ptr to same. 03766 */ 03767 char * 03768 module_name(int modid, char *cp) 03769 { 03770 struct module *mp; 03771 03772 for (mp = module_head; mp; mp = mp->next) 03773 if (mp->modid == modid) { 03774 strcpy(cp, mp->name); 03775 return (cp); 03776 } 03777 03778 if (modid != -1) DEBUGMSGTL(("parse-mibs", "Module %d not found\n", modid)); 03779 sprintf(cp, "#%d", modid); 03780 return (cp); 03781 } 03782 03783 /* 03784 * Backwards compatability 03785 * Read newer modules that replace the one specified:- 03786 * either all of them (read_module_replacements), 03787 * or those relating to a specified identifier (read_import_replacements) 03788 * plus an interface to add new replacement requirements 03789 */ 03790 netsnmp_feature_child_of(parse_add_module_replacement, netsnmp_unused) 03791 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_ADD_MODULE_REPLACEMENT 03792 void 03793 add_module_replacement(const char *old_module, 03794 const char *new_module_name, 03795 const char *tag, int len) 03796 { 03797 struct module_compatability *mcp; 03798 03799 mcp = (struct module_compatability *) 03800 calloc(1, sizeof(struct module_compatability)); 03801 if (mcp == NULL) 03802 return; 03803 03804 mcp->old_module = strdup(old_module); 03805 mcp->new_module = strdup(new_module_name); 03806 if (tag) 03807 mcp->tag = strdup(tag); 03808 mcp->tag_len = len; 03809 03810 mcp->next = module_map_head; 03811 module_map_head = mcp; 03812 } 03813 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_ADD_MODULE_REPLACEMENT */ 03814 03815 static int 03816 read_module_replacements(const char *name) 03817 { 03818 struct module_compatability *mcp; 03819 03820 for (mcp = module_map_head; mcp; mcp = mcp->next) { 03821 if (!label_compare(mcp->old_module, name)) { 03822 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 03823 NETSNMP_DS_LIB_MIB_WARNINGS)) { 03824 snmp_log(LOG_WARNING, 03825 "Loading replacement module %s for %s (%s)\n", 03826 mcp->new_module, name, File); 03827 } 03828 (void) netsnmp_read_module(mcp->new_module); 03829 return 1; 03830 } 03831 } 03832 return 0; 03833 } 03834 03835 static int 03836 read_import_replacements(const char *old_module_name, 03837 struct module_import *identifier) 03838 { 03839 struct module_compatability *mcp; 03840 03841 /* 03842 * Look for matches first 03843 */ 03844 for (mcp = module_map_head; mcp; mcp = mcp->next) { 03845 if (!label_compare(mcp->old_module, old_module_name)) { 03846 03847 if ( /* exact match */ 03848 (mcp->tag_len == 0 && 03849 (mcp->tag == NULL || 03850 !label_compare(mcp->tag, identifier->label))) || 03851 /* 03852 * prefix match 03853 */ 03854 (mcp->tag_len != 0 && 03855 !strncmp(mcp->tag, identifier->label, mcp->tag_len)) 03856 ) { 03857 03858 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 03859 NETSNMP_DS_LIB_MIB_WARNINGS)) { 03860 snmp_log(LOG_WARNING, 03861 "Importing %s from replacement module %s instead of %s (%s)\n", 03862 identifier->label, mcp->new_module, 03863 old_module_name, File); 03864 } 03865 (void) netsnmp_read_module(mcp->new_module); 03866 identifier->modid = which_module(mcp->new_module); 03867 return 1; /* finished! */ 03868 } 03869 } 03870 } 03871 03872 /* 03873 * If no exact match, load everything relevant 03874 */ 03875 return read_module_replacements(old_module_name); 03876 } 03877 03878 03879 /* 03880 * Read in the named module 03881 * Returns the root of the whole tree 03882 * (by analogy with 'read_mib') 03883 */ 03884 static int 03885 read_module_internal(const char *name) 03886 { 03887 struct module *mp; 03888 FILE *fp; 03889 struct node *np; 03890 03891 netsnmp_init_mib_internals(); 03892 03893 for (mp = module_head; mp; mp = mp->next) 03894 if (!label_compare(mp->name, name)) { 03895 const char *oldFile = File; 03896 int oldLine = mibLine; 03897 int oldModule = current_module; 03898 03899 if (mp->no_imports != -1) { 03900 DEBUGMSGTL(("parse-mibs", "Module %s already loaded\n", 03901 name)); 03902 return MODULE_ALREADY_LOADED; 03903 } 03904 if ((fp = fopen(mp->file, "r")) == NULL) { 03905 snmp_log_perror(mp->file); 03906 return MODULE_LOAD_FAILED; 03907 } 03908 mp->no_imports = 0; /* Note that we've read the file */ 03909 File = mp->file; 03910 mibLine = 1; 03911 current_module = mp->modid; 03912 /* 03913 * Parse the file 03914 */ 03915 np = parse(fp, NULL); 03916 fclose(fp); 03917 File = oldFile; 03918 mibLine = oldLine; 03919 current_module = oldModule; 03920 if (np != NULL) 03921 return MODULE_LOADED_OK; 03922 else if (gMibError == MODULE_SYNTAX_ERROR) 03923 return MODULE_SYNTAX_ERROR; 03924 } 03925 03926 return MODULE_NOT_FOUND; 03927 } 03928 03929 void 03930 adopt_orphans(void) 03931 { 03932 struct node *np, *onp; 03933 struct tree *tp; 03934 int i, adopted = 1; 03935 03936 if (!orphan_nodes) 03937 return; 03938 init_node_hash(orphan_nodes); 03939 orphan_nodes = NULL; 03940 03941 while (adopted) { 03942 adopted = 0; 03943 for (i = 0; i < NHASHSIZE; i++) 03944 if (nbuckets[i]) { 03945 for (np = nbuckets[i]; np != NULL; np = np->next) { 03946 tp = find_tree_node(np->parent, -1); 03947 if (tp) { 03948 do_subtree(tp, &np); 03949 adopted = 1; 03950 /* 03951 * if do_subtree adopted the entire bucket, stop 03952 */ 03953 if(NULL == nbuckets[i]) 03954 break; 03955 03956 /* 03957 * do_subtree may modify nbuckets, and if np 03958 * was adopted, np->next probably isn't an orphan 03959 * anymore. if np is still in the bucket (do_subtree 03960 * didn't adopt it) keep on plugging. otherwise 03961 * start over, at the top of the bucket. 03962 */ 03963 for(onp = nbuckets[i]; onp; onp = onp->next) 03964 if(onp == np) 03965 break; 03966 if(NULL == onp) { /* not in the list */ 03967 np = nbuckets[i]; /* start over */ 03968 } 03969 } 03970 } 03971 } 03972 } 03973 03974 /* 03975 * Report on outstanding orphans 03976 * and link them back into the orphan list 03977 */ 03978 for (i = 0; i < NHASHSIZE; i++) 03979 if (nbuckets[i]) { 03980 if (orphan_nodes) 03981 onp = np->next = nbuckets[i]; 03982 else 03983 onp = orphan_nodes = nbuckets[i]; 03984 nbuckets[i] = NULL; 03985 while (onp) { 03986 char modbuf[256]; 03987 snmp_log(LOG_WARNING, 03988 "Cannot adopt OID in %s: %s ::= { %s %ld }\n", 03989 module_name(onp->modid, modbuf), 03990 (onp->label ? onp->label : "<no label>"), 03991 (onp->parent ? onp->parent : "<no parent>"), 03992 onp->subid); 03993 03994 np = onp; 03995 onp = onp->next; 03996 } 03997 } 03998 } 03999 04000 #ifndef NETSNMP_NO_LEGACY_DEFINITIONS 04001 struct tree * 04002 read_module(const char *name) 04003 { 04004 return netsnmp_read_module(name); 04005 } 04006 #endif 04007 04008 struct tree * 04009 netsnmp_read_module(const char *name) 04010 { 04011 int status = 0; 04012 status = read_module_internal(name); 04013 04014 if (status == MODULE_NOT_FOUND) { 04015 if (!read_module_replacements(name)) 04016 print_module_not_found(name); 04017 } else if (status == MODULE_SYNTAX_ERROR) { 04018 gMibError = 0; 04019 gLoop = 1; 04020 04021 strncat(gMibNames, " ", sizeof(gMibNames) - strlen(gMibNames) - 1); 04022 strncat(gMibNames, name, sizeof(gMibNames) - strlen(gMibNames) - 1); 04023 } 04024 04025 return tree_head; 04026 } 04027 04028 /* 04029 * Prototype definition 04030 */ 04031 void unload_module_by_ID(int modID, struct tree *tree_top); 04032 04033 void 04034 unload_module_by_ID(int modID, struct tree *tree_top) 04035 { 04036 struct tree *tp, *next; 04037 int i; 04038 04039 for (tp = tree_top; tp; tp = next) { 04040 /* 04041 * Essentially, this is equivalent to the code fragment: 04042 * if (tp->modID == modID) 04043 * tp->number_modules--; 04044 * but handles one tree node being part of several modules, 04045 * and possible multiple copies of the same module ID. 04046 */ 04047 int nmod = tp->number_modules; 04048 if (nmod > 0) { /* in some module */ 04049 /* 04050 * Remove all copies of this module ID 04051 */ 04052 int cnt = 0, *pi1, *pi2 = tp->module_list; 04053 for (i = 0, pi1 = pi2; i < nmod; i++, pi2++) { 04054 if (*pi2 == modID) 04055 continue; 04056 cnt++; 04057 *pi1++ = *pi2; 04058 } 04059 if (nmod != cnt) { /* in this module */ 04060 /* 04061 * if ( (nmod - cnt) > 1) 04062 * printf("Dup modid %d, %d times, '%s'\n", tp->modid, (nmod-cnt), tp->label); fflush(stdout); ?* XXDEBUG 04063 */ 04064 tp->number_modules = cnt; 04065 switch (cnt) { 04066 case 0: 04067 tp->module_list[0] = -1; /* Mark unused, and FALL THROUGH */ 04068 04069 case 1: /* save the remaining module */ 04070 if (&(tp->modid) != tp->module_list) { 04071 tp->modid = tp->module_list[0]; 04072 free(tp->module_list); 04073 tp->module_list = &(tp->modid); 04074 } 04075 break; 04076 04077 default: 04078 break; 04079 } 04080 } /* if tree node is in this module */ 04081 } 04082 /* 04083 * if tree node is in some module 04084 */ 04085 next = tp->next_peer; 04086 04087 04088 /* 04089 * OK - that's dealt with *this* node. 04090 * Now let's look at the children. 04091 * (Isn't recursion wonderful!) 04092 */ 04093 if (tp->child_list) 04094 unload_module_by_ID(modID, tp->child_list); 04095 04096 04097 if (tp->number_modules == 0) { 04098 /* 04099 * This node isn't needed any more (except perhaps 04100 * for the sake of the children) 04101 */ 04102 if (tp->child_list == NULL) { 04103 unlink_tree(tp); 04104 free_tree(tp); 04105 } else { 04106 free_partial_tree(tp, TRUE); 04107 } 04108 } 04109 } 04110 } 04111 04112 #ifndef NETSNMP_NO_LEGACY_DEFINITIONS 04113 int 04114 unload_module(const char *name) 04115 { 04116 return netsnmp_unload_module(name); 04117 } 04118 #endif 04119 04120 int 04121 netsnmp_unload_module(const char *name) 04122 { 04123 struct module *mp; 04124 int modID = -1; 04125 04126 for (mp = module_head; mp; mp = mp->next) 04127 if (!label_compare(mp->name, name)) { 04128 modID = mp->modid; 04129 break; 04130 } 04131 04132 if (modID == -1) { 04133 DEBUGMSGTL(("unload-mib", "Module %s not found to unload\n", 04134 name)); 04135 return MODULE_NOT_FOUND; 04136 } 04137 unload_module_by_ID(modID, tree_head); 04138 mp->no_imports = -1; /* mark as unloaded */ 04139 return MODULE_LOADED_OK; /* Well, you know what I mean! */ 04140 } 04141 04142 /* 04143 * Clear module map, tree nodes, textual convention table. 04144 */ 04145 void 04146 unload_all_mibs(void) 04147 { 04148 struct module *mp; 04149 struct module_compatability *mcp; 04150 struct tc *ptc; 04151 unsigned int i; 04152 04153 for (mcp = module_map_head; mcp; mcp = module_map_head) { 04154 if (mcp == module_map) 04155 break; 04156 module_map_head = mcp->next; 04157 if (mcp->tag) free(NETSNMP_REMOVE_CONST(char *, mcp->tag)); 04158 free(NETSNMP_REMOVE_CONST(char *, mcp->old_module)); 04159 free(NETSNMP_REMOVE_CONST(char *, mcp->new_module)); 04160 free(mcp); 04161 } 04162 04163 for (mp = module_head; mp; mp = module_head) { 04164 struct module_import *mi = mp->imports; 04165 if (mi) { 04166 for (i = 0; i < (unsigned int)mp->no_imports; ++i) { 04167 SNMP_FREE((mi + i)->label); 04168 } 04169 mp->no_imports = 0; 04170 if (mi == root_imports) 04171 memset(mi, 0, sizeof(*mi)); 04172 else 04173 free(mi); 04174 } 04175 04176 unload_module_by_ID(mp->modid, tree_head); 04177 module_head = mp->next; 04178 free(mp->name); 04179 free(mp->file); 04180 free(mp); 04181 } 04182 unload_module_by_ID(-1, tree_head); 04183 /* 04184 * tree nodes are cleared 04185 */ 04186 04187 for (i = 0, ptc = tclist; i < MAXTC; i++, ptc++) { 04188 if (ptc->type == 0) 04189 continue; 04190 free_enums(&ptc->enums); 04191 free_ranges(&ptc->ranges); 04192 free(ptc->descriptor); 04193 if (ptc->hint) 04194 free(ptc->hint); 04195 } 04196 memset(tclist, 0, MAXTC * sizeof(struct tc)); 04197 04198 memset(buckets, 0, sizeof(buckets)); 04199 memset(nbuckets, 0, sizeof(nbuckets)); 04200 memset(tbuckets, 0, sizeof(tbuckets)); 04201 04202 for (i = 0; i < sizeof(root_imports) / sizeof(root_imports[0]); i++) { 04203 SNMP_FREE(root_imports[i].label); 04204 } 04205 04206 max_module = 0; 04207 current_module = 0; 04208 module_map_head = NULL; 04209 SNMP_FREE(last_err_module); 04210 } 04211 04212 static void 04213 new_module(const char *name, const char *file) 04214 { 04215 struct module *mp; 04216 04217 for (mp = module_head; mp; mp = mp->next) 04218 if (!label_compare(mp->name, name)) { 04219 DEBUGMSGTL(("parse-mibs", " Module %s already noted\n", name)); 04220 /* 04221 * Not the same file 04222 */ 04223 if (label_compare(mp->file, file)) { 04224 DEBUGMSGTL(("parse-mibs", " %s is now in %s\n", 04225 name, file)); 04226 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 04227 NETSNMP_DS_LIB_MIB_WARNINGS)) { 04228 snmp_log(LOG_WARNING, 04229 "Warning: Module %s was in %s now is %s\n", 04230 name, mp->file, file); 04231 } 04232 04233 /* 04234 * Use the new one in preference 04235 */ 04236 free(mp->file); 04237 mp->file = strdup(file); 04238 } 04239 return; 04240 } 04241 04242 /* 04243 * Add this module to the list 04244 */ 04245 DEBUGMSGTL(("parse-mibs", " Module %d %s is in %s\n", max_module, 04246 name, file)); 04247 mp = (struct module *) calloc(1, sizeof(struct module)); 04248 if (mp == NULL) 04249 return; 04250 mp->name = strdup(name); 04251 mp->file = strdup(file); 04252 mp->imports = NULL; 04253 mp->no_imports = -1; /* Not yet loaded */ 04254 mp->modid = max_module; 04255 ++max_module; 04256 04257 mp->next = module_head; /* Or add to the *end* of the list? */ 04258 module_head = mp; 04259 } 04260 04261 04262 static void 04263 scan_objlist(struct node *root, struct module *mp, struct objgroup *list, const char *error) 04264 { 04265 int oLine = mibLine; 04266 04267 while (list) { 04268 struct objgroup *gp = list; 04269 struct node *np; 04270 list = list->next; 04271 np = root; 04272 while (np) 04273 if (label_compare(np->label, gp->name)) 04274 np = np->next; 04275 else 04276 break; 04277 if (!np) { 04278 int i; 04279 struct module_import *mip; 04280 /* if not local, check if it was IMPORTed */ 04281 for (i = 0, mip = mp->imports; i < mp->no_imports; i++, mip++) 04282 if (strcmp(mip->label, gp->name) == 0) 04283 break; 04284 if (i == mp->no_imports) { 04285 mibLine = gp->line; 04286 print_error(error, gp->name, QUOTESTRING); 04287 } 04288 } 04289 free(gp->name); 04290 free(gp); 04291 } 04292 mibLine = oLine; 04293 } 04294 04295 /* 04296 * Parses a mib file and returns a linked list of nodes found in the file. 04297 * Returns NULL on error. 04298 */ 04299 static struct node * 04300 parse(FILE * fp, struct node *root) 04301 { 04302 #ifdef TEST 04303 extern void xmalloc_stats(FILE *); 04304 #endif 04305 char token[MAXTOKEN]; 04306 char name[MAXTOKEN+1]; 04307 int type = LABEL; 04308 int lasttype = LABEL; 04309 04310 #define BETWEEN_MIBS 1 04311 #define IN_MIB 2 04312 int state = BETWEEN_MIBS; 04313 struct node *np, *nnp; 04314 struct objgroup *oldgroups = NULL, *oldobjects = NULL, *oldnotifs = 04315 NULL; 04316 04317 DEBUGMSGTL(("parse-file", "Parsing file: %s...\n", File)); 04318 04319 if (last_err_module) 04320 free(last_err_module); 04321 last_err_module = NULL; 04322 04323 np = root; 04324 if (np != NULL) { 04325 /* 04326 * now find end of chain 04327 */ 04328 while (np->next) 04329 np = np->next; 04330 } 04331 04332 while (type != ENDOFFILE) { 04333 if (lasttype == CONTINUE) 04334 lasttype = type; 04335 else 04336 type = lasttype = get_token(fp, token, MAXTOKEN); 04337 04338 switch (type) { 04339 case END: 04340 if (state != IN_MIB) { 04341 print_error("Error, END before start of MIB", NULL, type); 04342 return NULL; 04343 } else { 04344 struct module *mp; 04345 #ifdef TEST 04346 printf("\nNodes for Module %s:\n", name); 04347 print_nodes(stdout, root); 04348 #endif 04349 for (mp = module_head; mp; mp = mp->next) 04350 if (mp->modid == current_module) 04351 break; 04352 scan_objlist(root, mp, objgroups, "Undefined OBJECT-GROUP"); 04353 scan_objlist(root, mp, objects, "Undefined OBJECT"); 04354 scan_objlist(root, mp, notifs, "Undefined NOTIFICATION"); 04355 objgroups = oldgroups; 04356 objects = oldobjects; 04357 notifs = oldnotifs; 04358 do_linkup(mp, root); 04359 np = root = NULL; 04360 } 04361 state = BETWEEN_MIBS; 04362 #ifdef TEST 04363 if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 04364 NETSNMP_DS_LIB_MIB_WARNINGS)) { 04365 /* xmalloc_stats(stderr); */ 04366 } 04367 #endif 04368 continue; 04369 case IMPORTS: 04370 parse_imports(fp); 04371 continue; 04372 case EXPORTS: 04373 while (type != SEMI && type != ENDOFFILE) 04374 type = get_token(fp, token, MAXTOKEN); 04375 continue; 04376 case LABEL: 04377 case INTEGER: 04378 case INTEGER32: 04379 case UINTEGER32: 04380 case UNSIGNED32: 04381 case COUNTER: 04382 case COUNTER64: 04383 case GAUGE: 04384 case IPADDR: 04385 case NETADDR: 04386 case NSAPADDRESS: 04387 case OBJSYNTAX: 04388 case APPSYNTAX: 04389 case SIMPLESYNTAX: 04390 case OBJNAME: 04391 case NOTIFNAME: 04392 case KW_OPAQUE: 04393 case TIMETICKS: 04394 break; 04395 case ENDOFFILE: 04396 continue; 04397 default: 04398 strncpy(name, token, sizeof(name)); 04399 name[sizeof(name)-1] = '\0'; 04400 type = get_token(fp, token, MAXTOKEN); 04401 nnp = NULL; 04402 if (type == MACRO) { 04403 nnp = parse_macro(fp, name); 04404 if (nnp == NULL) { 04405 print_error("Bad parse of MACRO", NULL, type); 04406 /* 04407 * return NULL; 04408 */ 04409 } 04410 free_node(nnp); /* IGNORE */ 04411 nnp = NULL; 04412 } else 04413 print_error(name, "is a reserved word", lasttype); 04414 continue; /* see if we can parse the rest of the file */ 04415 } 04416 strncpy(name, token, sizeof(name)); 04417 name[sizeof(name)-1] = '\0'; 04418 type = get_token(fp, token, MAXTOKEN); 04419 nnp = NULL; 04420 04421 /* 04422 * Handle obsolete method to assign an object identifier to a 04423 * module 04424 */ 04425 if (lasttype == LABEL && type == LEFTBRACKET) { 04426 while (type != RIGHTBRACKET && type != ENDOFFILE) 04427 type = get_token(fp, token, MAXTOKEN); 04428 if (type == ENDOFFILE) { 04429 print_error("Expected \"}\"", token, type); 04430 return NULL; 04431 } 04432 type = get_token(fp, token, MAXTOKEN); 04433 } 04434 04435 switch (type) { 04436 case DEFINITIONS: 04437 if (state != BETWEEN_MIBS) { 04438 print_error("Error, nested MIBS", NULL, type); 04439 return NULL; 04440 } 04441 state = IN_MIB; 04442 current_module = which_module(name); 04443 oldgroups = objgroups; 04444 objgroups = NULL; 04445 oldobjects = objects; 04446 objects = NULL; 04447 oldnotifs = notifs; 04448 notifs = NULL; 04449 if (current_module == -1) { 04450 new_module(name, File); 04451 current_module = which_module(name); 04452 } 04453 DEBUGMSGTL(("parse-mibs", "Parsing MIB: %d %s\n", 04454 current_module, name)); 04455 while ((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE) 04456 if (type == BEGIN) 04457 break; 04458 break; 04459 case OBJTYPE: 04460 nnp = parse_objecttype(fp, name); 04461 if (nnp == NULL) { 04462 print_error("Bad parse of OBJECT-TYPE", NULL, type); 04463 return NULL; 04464 } 04465 break; 04466 case OBJGROUP: 04467 nnp = parse_objectgroup(fp, name, OBJECTS, &objects); 04468 if (nnp == NULL) { 04469 print_error("Bad parse of OBJECT-GROUP", NULL, type); 04470 return NULL; 04471 } 04472 break; 04473 case NOTIFGROUP: 04474 nnp = parse_objectgroup(fp, name, NOTIFICATIONS, ¬ifs); 04475 if (nnp == NULL) { 04476 print_error("Bad parse of NOTIFICATION-GROUP", NULL, type); 04477 return NULL; 04478 } 04479 break; 04480 case TRAPTYPE: 04481 nnp = parse_trapDefinition(fp, name); 04482 if (nnp == NULL) { 04483 print_error("Bad parse of TRAP-TYPE", NULL, type); 04484 return NULL; 04485 } 04486 break; 04487 case NOTIFTYPE: 04488 nnp = parse_notificationDefinition(fp, name); 04489 if (nnp == NULL) { 04490 print_error("Bad parse of NOTIFICATION-TYPE", NULL, type); 04491 return NULL; 04492 } 04493 break; 04494 case COMPLIANCE: 04495 nnp = parse_compliance(fp, name); 04496 if (nnp == NULL) { 04497 print_error("Bad parse of MODULE-COMPLIANCE", NULL, type); 04498 return NULL; 04499 } 04500 break; 04501 case AGENTCAP: 04502 nnp = parse_capabilities(fp, name); 04503 if (nnp == NULL) { 04504 print_error("Bad parse of AGENT-CAPABILITIES", NULL, type); 04505 return NULL; 04506 } 04507 break; 04508 case MACRO: 04509 nnp = parse_macro(fp, name); 04510 if (nnp == NULL) { 04511 print_error("Bad parse of MACRO", NULL, type); 04512 /* 04513 * return NULL; 04514 */ 04515 } 04516 free_node(nnp); /* IGNORE */ 04517 nnp = NULL; 04518 break; 04519 case MODULEIDENTITY: 04520 nnp = parse_moduleIdentity(fp, name); 04521 if (nnp == NULL) { 04522 print_error("Bad parse of MODULE-IDENTITY", NULL, type); 04523 return NULL; 04524 } 04525 break; 04526 case OBJIDENTITY: 04527 nnp = parse_objectgroup(fp, name, OBJECTS, &objects); 04528 if (nnp == NULL) { 04529 print_error("Bad parse of OBJECT-IDENTITY", NULL, type); 04530 return NULL; 04531 } 04532 break; 04533 case OBJECT: 04534 type = get_token(fp, token, MAXTOKEN); 04535 if (type != IDENTIFIER) { 04536 print_error("Expected IDENTIFIER", token, type); 04537 return NULL; 04538 } 04539 type = get_token(fp, token, MAXTOKEN); 04540 if (type != EQUALS) { 04541 print_error("Expected \"::=\"", token, type); 04542 return NULL; 04543 } 04544 nnp = parse_objectid(fp, name); 04545 if (nnp == NULL) { 04546 print_error("Bad parse of OBJECT IDENTIFIER", NULL, type); 04547 return NULL; 04548 } 04549 break; 04550 case EQUALS: 04551 nnp = parse_asntype(fp, name, &type, token); 04552 lasttype = CONTINUE; 04553 break; 04554 case ENDOFFILE: 04555 break; 04556 default: 04557 print_error("Bad operator", token, type); 04558 return NULL; 04559 } 04560 if (nnp) { 04561 if (np) 04562 np->next = nnp; 04563 else 04564 np = root = nnp; 04565 while (np->next) 04566 np = np->next; 04567 if (np->type == TYPE_OTHER) 04568 np->type = type; 04569 } 04570 } 04571 DEBUGMSGTL(("parse-file", "End of file (%s)\n", File)); 04572 return root; 04573 } 04574 04575 /* 04576 * return zero if character is not a label character. 04577 */ 04578 static int 04579 is_labelchar(int ich) 04580 { 04581 if ((isalnum(ich)) || (ich == '-')) 04582 return 1; 04583 if (ich == '_' && netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 04584 NETSNMP_DS_LIB_MIB_PARSE_LABEL)) { 04585 return 1; 04586 } 04587 04588 return 0; 04589 } 04590 04591 /* 04592 * Parses a token from the file. The type of the token parsed is returned, 04593 * and the text is placed in the string pointed to by token. 04594 * Warning: this method may recurse. 04595 */ 04596 static int 04597 get_token(FILE * fp, char *token, int maxtlen) 04598 { 04599 register int ch, ch_next; 04600 register char *cp = token; 04601 register int hash = 0; 04602 register struct tok *tp; 04603 int too_long = 0; 04604 enum { bdigits, xdigits, other } seenSymbols; 04605 04606 /* 04607 * skip all white space 04608 */ 04609 do { 04610 ch = getc(fp); 04611 if (ch == '\n') 04612 mibLine++; 04613 } 04614 while (isspace(ch) && ch != EOF); 04615 *cp++ = ch; 04616 *cp = '\0'; 04617 switch (ch) { 04618 case EOF: 04619 return ENDOFFILE; 04620 case '"': 04621 return parseQuoteString(fp, token, maxtlen); 04622 case '\'': /* binary or hex constant */ 04623 seenSymbols = bdigits; 04624 while ((ch = getc(fp)) != EOF && ch != '\'') { 04625 switch (seenSymbols) { 04626 case bdigits: 04627 if (ch == '0' || ch == '1') 04628 break; 04629 seenSymbols = xdigits; 04630 case xdigits: 04631 if (isxdigit(ch)) 04632 break; 04633 seenSymbols = other; 04634 case other: 04635 break; 04636 } 04637 if (cp - token < maxtlen - 2) 04638 *cp++ = ch; 04639 } 04640 if (ch == '\'') { 04641 unsigned long val = 0; 04642 char *run = token + 1; 04643 ch = getc(fp); 04644 switch (ch) { 04645 case EOF: 04646 return ENDOFFILE; 04647 case 'b': 04648 case 'B': 04649 if (seenSymbols > bdigits) { 04650 *cp++ = '\''; 04651 *cp = 0; 04652 return LABEL; 04653 } 04654 while (run != cp) 04655 val = val * 2 + *run++ - '0'; 04656 break; 04657 case 'h': 04658 case 'H': 04659 if (seenSymbols > xdigits) { 04660 *cp++ = '\''; 04661 *cp = 0; 04662 return LABEL; 04663 } 04664 while (run != cp) { 04665 ch = *run++; 04666 if ('0' <= ch && ch <= '9') 04667 val = val * 16 + ch - '0'; 04668 else if ('a' <= ch && ch <= 'f') 04669 val = val * 16 + ch - 'a' + 10; 04670 else if ('A' <= ch && ch <= 'F') 04671 val = val * 16 + ch - 'A' + 10; 04672 } 04673 break; 04674 default: 04675 *cp++ = '\''; 04676 *cp = 0; 04677 return LABEL; 04678 } 04679 sprintf(token, "%ld", val); 04680 return NUMBER; 04681 } else 04682 return LABEL; 04683 case '(': 04684 return LEFTPAREN; 04685 case ')': 04686 return RIGHTPAREN; 04687 case '{': 04688 return LEFTBRACKET; 04689 case '}': 04690 return RIGHTBRACKET; 04691 case '[': 04692 return LEFTSQBRACK; 04693 case ']': 04694 return RIGHTSQBRACK; 04695 case ';': 04696 return SEMI; 04697 case ',': 04698 return COMMA; 04699 case '|': 04700 return BAR; 04701 case '.': 04702 ch_next = getc(fp); 04703 if (ch_next == '.') 04704 return RANGE; 04705 ungetc(ch_next, fp); 04706 return LABEL; 04707 case ':': 04708 ch_next = getc(fp); 04709 if (ch_next != ':') { 04710 ungetc(ch_next, fp); 04711 return LABEL; 04712 } 04713 ch_next = getc(fp); 04714 if (ch_next != '=') { 04715 ungetc(ch_next, fp); 04716 return LABEL; 04717 } 04718 return EQUALS; 04719 case '-': 04720 ch_next = getc(fp); 04721 if (ch_next == '-') { 04722 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 04723 NETSNMP_DS_LIB_MIB_COMMENT_TERM)) { 04724 /* 04725 * Treat the rest of this line as a comment. 04726 */ 04727 while ((ch_next != EOF) && (ch_next != '\n')) 04728 ch_next = getc(fp); 04729 } else { 04730 /* 04731 * Treat the rest of the line or until another '--' as a comment 04732 */ 04733 /* 04734 * (this is the "technically" correct way to parse comments) 04735 */ 04736 ch = ' '; 04737 ch_next = getc(fp); 04738 while (ch_next != EOF && ch_next != '\n' && 04739 (ch != '-' || ch_next != '-')) { 04740 ch = ch_next; 04741 ch_next = getc(fp); 04742 } 04743 } 04744 if (ch_next == EOF) 04745 return ENDOFFILE; 04746 if (ch_next == '\n') 04747 mibLine++; 04748 return get_token(fp, token, maxtlen); 04749 } 04750 ungetc(ch_next, fp); 04751 default: 04752 /* 04753 * Accumulate characters until end of token is found. Then attempt to 04754 * match this token as a reserved word. If a match is found, return the 04755 * type. Else it is a label. 04756 */ 04757 if (!is_labelchar(ch)) 04758 return LABEL; 04759 hash += tolower(ch); 04760 more: 04761 while (is_labelchar(ch_next = getc(fp))) { 04762 hash += tolower(ch_next); 04763 if (cp - token < maxtlen - 1) 04764 *cp++ = ch_next; 04765 else 04766 too_long = 1; 04767 } 04768 ungetc(ch_next, fp); 04769 *cp = '\0'; 04770 04771 if (too_long) 04772 print_error("Warning: token too long", token, CONTINUE); 04773 for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) { 04774 if ((tp->hash == hash) && (!label_compare(tp->name, token))) 04775 break; 04776 } 04777 if (tp) { 04778 if (tp->token != CONTINUE) 04779 return (tp->token); 04780 while (isspace((ch_next = getc(fp)))) 04781 if (ch_next == '\n') 04782 mibLine++; 04783 if (ch_next == EOF) 04784 return ENDOFFILE; 04785 if (isalnum(ch_next)) { 04786 *cp++ = ch_next; 04787 hash += tolower(ch_next); 04788 goto more; 04789 } 04790 } 04791 if (token[0] == '-' || isdigit((unsigned char)(token[0]))) { 04792 for (cp = token + 1; *cp; cp++) 04793 if (!isdigit((unsigned char)(*cp))) 04794 return LABEL; 04795 return NUMBER; 04796 } 04797 return LABEL; 04798 } 04799 } 04800 04801 netsnmp_feature_child_of(parse_get_token, netsnmp_unused) 04802 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_GET_TOKEN 04803 int 04804 snmp_get_token(FILE * fp, char *token, int maxtlen) 04805 { 04806 return get_token(fp, token, maxtlen); 04807 } 04808 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_GET_TOKEN */ 04809 04810 int 04811 add_mibfile(const char* tmpstr, const char* d_name, FILE *ip ) 04812 { 04813 FILE *fp; 04814 char token[MAXTOKEN], token2[MAXTOKEN]; 04815 04816 /* 04817 * which module is this 04818 */ 04819 if ((fp = fopen(tmpstr, "r")) == NULL) { 04820 snmp_log_perror(tmpstr); 04821 return 1; 04822 } 04823 DEBUGMSGTL(("parse-mibs", "Checking file: %s...\n", 04824 tmpstr)); 04825 mibLine = 1; 04826 File = tmpstr; 04827 get_token(fp, token, MAXTOKEN); 04828 /* 04829 * simple test for this being a MIB 04830 */ 04831 if (get_token(fp, token2, MAXTOKEN) == DEFINITIONS) { 04832 new_module(token, tmpstr); 04833 if (ip) 04834 fprintf(ip, "%s %s\n", token, d_name); 04835 fclose(fp); 04836 return 0; 04837 } else { 04838 fclose(fp); 04839 return 1; 04840 } 04841 } 04842 04843 /* For Win32 platforms, the directory does not maintain a last modification 04844 * date that we can compare with the modification date of the .index file. 04845 * Therefore there is no way to know whether any .index file is valid. 04846 * This is the reason for the #if !(defined(WIN32) || defined(cygwin)) 04847 * in the add_mibdir function 04848 */ 04849 int 04850 add_mibdir(const char *dirname) 04851 { 04852 FILE *ip; 04853 DIR *dir, *dir2; 04854 const char *oldFile = File; 04855 struct dirent *file; 04856 char tmpstr[300]; 04857 int count = 0; 04858 int fname_len = 0; 04859 #if !(defined(WIN32) || defined(cygwin)) 04860 char *token; 04861 char space; 04862 char newline; 04863 struct stat dir_stat, idx_stat; 04864 char tmpstr1[300]; 04865 #endif 04866 04867 DEBUGMSGTL(("parse-mibs", "Scanning directory %s\n", dirname)); 04868 #if !(defined(WIN32) || defined(cygwin)) 04869 token = netsnmp_mibindex_lookup( dirname ); 04870 if (token && stat(token, &idx_stat) == 0 && stat(dirname, &dir_stat) == 0) { 04871 if (dir_stat.st_mtime < idx_stat.st_mtime) { 04872 DEBUGMSGTL(("parse-mibs", "The index is good\n")); 04873 if ((ip = fopen(token, "r")) != NULL) { 04874 fgets(tmpstr, sizeof(tmpstr), ip); /* Skip dir line */ 04875 while (fscanf(ip, "%127s%c%299s%c", token, &space, tmpstr, 04876 &newline) == 4) { 04877 04878 /* 04879 * If an overflow of the token or tmpstr buffers has been 04880 * found log a message and break out of the while loop, 04881 * thus the rest of the file tokens will be ignored. 04882 */ 04883 if (space != ' ' || newline != '\n') { 04884 snmp_log(LOG_ERR, 04885 "add_mibdir: strings scanned in from %s/%s " \ 04886 "are too large. count = %d\n ", dirname, 04887 ".index", count); 04888 break; 04889 } 04890 04891 snprintf(tmpstr1, sizeof(tmpstr1), "%s/%s", dirname, tmpstr); 04892 tmpstr1[ sizeof(tmpstr1)-1 ] = 0; 04893 new_module(token, tmpstr1); 04894 count++; 04895 } 04896 fclose(ip); 04897 return count; 04898 } else 04899 DEBUGMSGTL(("parse-mibs", "Can't read index\n")); 04900 } else 04901 DEBUGMSGTL(("parse-mibs", "Index outdated\n")); 04902 } else 04903 DEBUGMSGTL(("parse-mibs", "No index\n")); 04904 #endif 04905 04906 if ((dir = opendir(dirname))) { 04907 ip = netsnmp_mibindex_new( dirname ); 04908 while ((file = readdir(dir))) { 04909 /* 04910 * Only parse file names that don't begin with a '.' 04911 * Also skip files ending in '~', or starting/ending 04912 * with '#' which are typically editor backup files. 04913 */ 04914 if (file->d_name != NULL) { 04915 fname_len = strlen( file->d_name ); 04916 if (fname_len > 0 && file->d_name[0] != '.' 04917 && file->d_name[0] != '#' 04918 && file->d_name[fname_len-1] != '#' 04919 && file->d_name[fname_len-1] != '~') { 04920 snprintf(tmpstr, sizeof(tmpstr), "%s/%s", dirname, file->d_name); 04921 tmpstr[ sizeof(tmpstr)-1 ] = 0; 04922 if ((dir2 = opendir(tmpstr))) { 04923 /* 04924 * file is a directory, don't read it 04925 */ 04926 closedir(dir2); 04927 } else { 04928 if ( !add_mibfile( tmpstr, file->d_name, ip )) 04929 count++; 04930 } 04931 } 04932 } 04933 } 04934 File = oldFile; 04935 closedir(dir); 04936 if (ip) 04937 fclose(ip); 04938 return (count); 04939 } 04940 else 04941 DEBUGMSGTL(("parse-mibs","cannot open MIB directory %s\n", dirname)); 04942 04943 return (-1); 04944 } 04945 04946 04947 /* 04948 * Returns the root of the whole tree 04949 * (for backwards compatability) 04950 */ 04951 struct tree * 04952 read_mib(const char *filename) 04953 { 04954 FILE *fp; 04955 char token[MAXTOKEN]; 04956 04957 fp = fopen(filename, "r"); 04958 if (fp == NULL) { 04959 snmp_log_perror(filename); 04960 return NULL; 04961 } 04962 mibLine = 1; 04963 File = filename; 04964 DEBUGMSGTL(("parse-mibs", "Parsing file: %s...\n", filename)); 04965 get_token(fp, token, MAXTOKEN); 04966 fclose(fp); 04967 new_module(token, filename); 04968 (void) netsnmp_read_module(token); 04969 04970 return tree_head; 04971 } 04972 04973 04974 struct tree * 04975 read_all_mibs(void) 04976 { 04977 struct module *mp; 04978 04979 for (mp = module_head; mp; mp = mp->next) 04980 if (mp->no_imports == -1) 04981 netsnmp_read_module(mp->name); 04982 adopt_orphans(); 04983 04984 /* If entered the syntax error loop in "read_module()" */ 04985 if (gLoop == 1) { 04986 gLoop = 0; 04987 if (gpMibErrorString != NULL) { 04988 SNMP_FREE(gpMibErrorString); 04989 } 04990 gpMibErrorString = (char *) calloc(1, MAXQUOTESTR); 04991 if (gpMibErrorString == NULL) { 04992 snmp_log(LOG_CRIT, "failed to allocated memory for gpMibErrorString\n"); 04993 } else { 04994 snprintf(gpMibErrorString, sizeof(gpMibErrorString)-1, "Error in parsing MIB module(s): %s ! Unable to load corresponding MIB(s)", gMibNames); 04995 } 04996 } 04997 04998 /* Caller's responsibility to free this memory */ 04999 tree_head->parseErrorString = gpMibErrorString; 05000 05001 return tree_head; 05002 } 05003 05004 05005 #ifdef TEST 05006 int main(int argc, char *argv[]) 05007 { 05008 int i; 05009 struct tree *tp; 05010 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_WARNINGS, 2); 05011 05012 netsnmp_init_mib(); 05013 05014 if (argc == 1) 05015 (void) read_all_mibs(); 05016 else 05017 for (i = 1; i < argc; i++) 05018 read_mib(argv[i]); 05019 05020 for (tp = tree_head; tp; tp = tp->next_peer) 05021 print_subtree(stdout, tp, 0); 05022 free_tree(tree_head); 05023 05024 return 0; 05025 } 05026 #endif /* TEST */ 05027 05028 static int 05029 parseQuoteString(FILE * fp, char *token, int maxtlen) 05030 { 05031 register int ch; 05032 int count = 0; 05033 int too_long = 0; 05034 char *token_start = token; 05035 05036 for (ch = getc(fp); ch != EOF; ch = getc(fp)) { 05037 if (ch == '\r') 05038 continue; 05039 if (ch == '\n') { 05040 mibLine++; 05041 } else if (ch == '"') { 05042 *token = '\0'; 05043 if (too_long && netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 05044 NETSNMP_DS_LIB_MIB_WARNINGS) > 1) { 05045 /* 05046 * show short form for brevity sake 05047 */ 05048 char ch_save = *(token_start + 50); 05049 *(token_start + 50) = '\0'; 05050 print_error("Warning: string too long", 05051 token_start, QUOTESTRING); 05052 *(token_start + 50) = ch_save; 05053 } 05054 return QUOTESTRING; 05055 } 05056 /* 05057 * maximum description length check. If greater, keep parsing 05058 * but truncate the string 05059 */ 05060 if (++count < maxtlen) 05061 *token++ = ch; 05062 else 05063 too_long = 1; 05064 } 05065 05066 return 0; 05067 } 05068 05069 /* 05070 * struct index_list * 05071 * getIndexes(FILE *fp): 05072 * This routine parses a string like { blah blah blah } and returns a 05073 * list of the strings enclosed within it. 05074 * 05075 */ 05076 static struct index_list * 05077 getIndexes(FILE * fp, struct index_list **retp) 05078 { 05079 int type; 05080 char token[MAXTOKEN]; 05081 char nextIsImplied = 0; 05082 05083 struct index_list *mylist = NULL; 05084 struct index_list **mypp = &mylist; 05085 05086 free_indexes(retp); 05087 05088 type = get_token(fp, token, MAXTOKEN); 05089 05090 if (type != LEFTBRACKET) { 05091 return NULL; 05092 } 05093 05094 type = get_token(fp, token, MAXTOKEN); 05095 while (type != RIGHTBRACKET && type != ENDOFFILE) { 05096 if ((type == LABEL) || (type & SYNTAX_MASK)) { 05097 *mypp = 05098 (struct index_list *) calloc(1, sizeof(struct index_list)); 05099 if (*mypp) { 05100 (*mypp)->ilabel = strdup(token); 05101 (*mypp)->isimplied = nextIsImplied; 05102 mypp = &(*mypp)->next; 05103 nextIsImplied = 0; 05104 } 05105 } else if (type == IMPLIED) { 05106 nextIsImplied = 1; 05107 } 05108 type = get_token(fp, token, MAXTOKEN); 05109 } 05110 05111 *retp = mylist; 05112 return mylist; 05113 } 05114 05115 static struct varbind_list * 05116 getVarbinds(FILE * fp, struct varbind_list **retp) 05117 { 05118 int type; 05119 char token[MAXTOKEN]; 05120 05121 struct varbind_list *mylist = NULL; 05122 struct varbind_list **mypp = &mylist; 05123 05124 free_varbinds(retp); 05125 05126 type = get_token(fp, token, MAXTOKEN); 05127 05128 if (type != LEFTBRACKET) { 05129 return NULL; 05130 } 05131 05132 type = get_token(fp, token, MAXTOKEN); 05133 while (type != RIGHTBRACKET && type != ENDOFFILE) { 05134 if ((type == LABEL) || (type & SYNTAX_MASK)) { 05135 *mypp = 05136 (struct varbind_list *) calloc(1, 05137 sizeof(struct 05138 varbind_list)); 05139 if (*mypp) { 05140 (*mypp)->vblabel = strdup(token); 05141 mypp = &(*mypp)->next; 05142 } 05143 } 05144 type = get_token(fp, token, MAXTOKEN); 05145 } 05146 05147 *retp = mylist; 05148 return mylist; 05149 } 05150 05151 static void 05152 free_indexes(struct index_list **spp) 05153 { 05154 if (spp && *spp) { 05155 struct index_list *pp, *npp; 05156 05157 pp = *spp; 05158 *spp = NULL; 05159 05160 while (pp) { 05161 npp = pp->next; 05162 if (pp->ilabel) 05163 free(pp->ilabel); 05164 free(pp); 05165 pp = npp; 05166 } 05167 } 05168 } 05169 05170 static void 05171 free_varbinds(struct varbind_list **spp) 05172 { 05173 if (spp && *spp) { 05174 struct varbind_list *pp, *npp; 05175 05176 pp = *spp; 05177 *spp = NULL; 05178 05179 while (pp) { 05180 npp = pp->next; 05181 if (pp->vblabel) 05182 free(pp->vblabel); 05183 free(pp); 05184 pp = npp; 05185 } 05186 } 05187 } 05188 05189 static void 05190 free_ranges(struct range_list **spp) 05191 { 05192 if (spp && *spp) { 05193 struct range_list *pp, *npp; 05194 05195 pp = *spp; 05196 *spp = NULL; 05197 05198 while (pp) { 05199 npp = pp->next; 05200 free(pp); 05201 pp = npp; 05202 } 05203 } 05204 } 05205 05206 static void 05207 free_enums(struct enum_list **spp) 05208 { 05209 if (spp && *spp) { 05210 struct enum_list *pp, *npp; 05211 05212 pp = *spp; 05213 *spp = NULL; 05214 05215 while (pp) { 05216 npp = pp->next; 05217 if (pp->label) 05218 free(pp->label); 05219 free(pp); 05220 pp = npp; 05221 } 05222 } 05223 } 05224 05225 static struct enum_list * 05226 copy_enums(struct enum_list *sp) 05227 { 05228 struct enum_list *xp = NULL, **spp = &xp; 05229 05230 while (sp) { 05231 *spp = (struct enum_list *) calloc(1, sizeof(struct enum_list)); 05232 if (!*spp) 05233 break; 05234 (*spp)->label = strdup(sp->label); 05235 (*spp)->value = sp->value; 05236 spp = &(*spp)->next; 05237 sp = sp->next; 05238 } 05239 return (xp); 05240 } 05241 05242 static struct range_list * 05243 copy_ranges(struct range_list *sp) 05244 { 05245 struct range_list *xp = NULL, **spp = &xp; 05246 05247 while (sp) { 05248 *spp = (struct range_list *) calloc(1, sizeof(struct range_list)); 05249 if (!*spp) 05250 break; 05251 (*spp)->low = sp->low; 05252 (*spp)->high = sp->high; 05253 spp = &(*spp)->next; 05254 sp = sp->next; 05255 } 05256 return (xp); 05257 } 05258 05259 /* 05260 * This routine parses a string like { blah blah blah } and returns OBJID if 05261 * it is well formed, and NULL if not. 05262 */ 05263 static int 05264 tossObjectIdentifier(FILE * fp) 05265 { 05266 int type; 05267 char token[MAXTOKEN]; 05268 int bracketcount = 1; 05269 05270 type = get_token(fp, token, MAXTOKEN); 05271 05272 if (type != LEFTBRACKET) 05273 return 0; 05274 while ((type != RIGHTBRACKET || bracketcount > 0) && type != ENDOFFILE) { 05275 type = get_token(fp, token, MAXTOKEN); 05276 if (type == LEFTBRACKET) 05277 bracketcount++; 05278 else if (type == RIGHTBRACKET) 05279 bracketcount--; 05280 } 05281 05282 if (type == RIGHTBRACKET) 05283 return OBJID; 05284 else 05285 return 0; 05286 } 05287 05288 /* Find node in any MIB module 05289 Used by Perl modules */ 05290 struct tree * 05291 find_node(const char *name, struct tree *subtree) 05292 { /* Unused */ 05293 return (find_tree_node(name, -1)); 05294 } 05295 05296 netsnmp_feature_child_of(parse_find_node2, netsnmp_unused) 05297 #ifndef NETSNMP_FEATURE_REMOVE_PARSE_FIND_NODE2 05298 struct tree * 05299 find_node2(const char *name, const char *module) 05300 { 05301 int modid = -1; 05302 if (module) { 05303 modid = which_module(module); 05304 } 05305 if (modid == -1) 05306 { 05307 return (NULL); 05308 } 05309 return (find_tree_node(name, modid)); 05310 } 05311 #endif /* NETSNMP_FEATURE_REMOVE_PARSE_FIND_NODE2 */ 05312 05313 #ifndef NETSNMP_FEATURE_REMOVE_FIND_MODULE 05314 /* Used in the perl module */ 05315 struct module * 05316 find_module(int mid) 05317 { 05318 struct module *mp; 05319 05320 for (mp = module_head; mp != NULL; mp = mp->next) { 05321 if (mp->modid == mid) 05322 break; 05323 } 05324 return mp; 05325 } 05326 #endif /* NETSNMP_FEATURE_REMOVE_FIND_MODULE */ 05327 05328 05329 static char leave_indent[256]; 05330 static int leave_was_simple; 05331 05332 static void 05333 print_mib_leaves(FILE * f, struct tree *tp, int width) 05334 { 05335 struct tree *ntp; 05336 char *ip = leave_indent + strlen(leave_indent) - 1; 05337 char last_ipch = *ip; 05338 05339 *ip = '+'; 05340 if (tp->type == TYPE_OTHER || tp->type > TYPE_SIMPLE_LAST) { 05341 fprintf(f, "%s--%s(%ld)\n", leave_indent, tp->label, tp->subid); 05342 if (tp->indexes) { 05343 struct index_list *xp = tp->indexes; 05344 int first = 1, cpos = 0, len, cmax = 05345 width - strlen(leave_indent) - 12; 05346 *ip = last_ipch; 05347 fprintf(f, "%s | Index: ", leave_indent); 05348 while (xp) { 05349 if (first) 05350 first = 0; 05351 else 05352 fprintf(f, ", "); 05353 cpos += (len = strlen(xp->ilabel) + 2); 05354 if (cpos > cmax) { 05355 fprintf(f, "\n"); 05356 fprintf(f, "%s | ", leave_indent); 05357 cpos = len; 05358 } 05359 fprintf(f, "%s", xp->ilabel); 05360 xp = xp->next; 05361 } 05362 fprintf(f, "\n"); 05363 *ip = '+'; 05364 } 05365 } else { 05366 const char *acc, *typ; 05367 int size = 0; 05368 switch (tp->access) { 05369 case MIB_ACCESS_NOACCESS: 05370 acc = "----"; 05371 break; 05372 case MIB_ACCESS_READONLY: 05373 acc = "-R--"; 05374 break; 05375 case MIB_ACCESS_WRITEONLY: 05376 acc = "--W-"; 05377 break; 05378 case MIB_ACCESS_READWRITE: 05379 acc = "-RW-"; 05380 break; 05381 case MIB_ACCESS_NOTIFY: 05382 acc = "---N"; 05383 break; 05384 case MIB_ACCESS_CREATE: 05385 acc = "CR--"; 05386 break; 05387 default: 05388 acc = " "; 05389 break; 05390 } 05391 switch (tp->type) { 05392 case TYPE_OBJID: 05393 typ = "ObjID "; 05394 break; 05395 case TYPE_OCTETSTR: 05396 typ = "String "; 05397 size = 1; 05398 break; 05399 case TYPE_INTEGER: 05400 if (tp->enums) 05401 typ = "EnumVal "; 05402 else 05403 typ = "INTEGER "; 05404 break; 05405 case TYPE_NETADDR: 05406 typ = "NetAddr "; 05407 break; 05408 case TYPE_IPADDR: 05409 typ = "IpAddr "; 05410 break; 05411 case TYPE_COUNTER: 05412 typ = "Counter "; 05413 break; 05414 case TYPE_GAUGE: 05415 typ = "Gauge "; 05416 break; 05417 case TYPE_TIMETICKS: 05418 typ = "TimeTicks"; 05419 break; 05420 case TYPE_OPAQUE: 05421 typ = "Opaque "; 05422 size = 1; 05423 break; 05424 case TYPE_NULL: 05425 typ = "Null "; 05426 break; 05427 case TYPE_COUNTER64: 05428 typ = "Counter64"; 05429 break; 05430 case TYPE_BITSTRING: 05431 typ = "BitString"; 05432 break; 05433 case TYPE_NSAPADDRESS: 05434 typ = "NsapAddr "; 05435 break; 05436 case TYPE_UNSIGNED32: 05437 typ = "Unsigned "; 05438 break; 05439 case TYPE_UINTEGER: 05440 typ = "UInteger "; 05441 break; 05442 case TYPE_INTEGER32: 05443 typ = "Integer32"; 05444 break; 05445 default: 05446 typ = " "; 05447 break; 05448 } 05449 fprintf(f, "%s-- %s %s %s(%ld)\n", leave_indent, acc, typ, 05450 tp->label, tp->subid); 05451 *ip = last_ipch; 05452 if (tp->tc_index >= 0) 05453 fprintf(f, "%s Textual Convention: %s\n", leave_indent, 05454 tclist[tp->tc_index].descriptor); 05455 if (tp->enums) { 05456 struct enum_list *ep = tp->enums; 05457 int cpos = 0, cmax = 05458 width - strlen(leave_indent) - 16; 05459 fprintf(f, "%s Values: ", leave_indent); 05460 while (ep) { 05461 char buf[80]; 05462 int bufw; 05463 if (ep != tp->enums) 05464 fprintf(f, ", "); 05465 snprintf(buf, sizeof(buf), "%s(%d)", ep->label, ep->value); 05466 buf[ sizeof(buf)-1 ] = 0; 05467 cpos += (bufw = strlen(buf) + 2); 05468 if (cpos >= cmax) { 05469 fprintf(f, "\n%s ", leave_indent); 05470 cpos = bufw; 05471 } 05472 fprintf(f, "%s", buf); 05473 ep = ep->next; 05474 } 05475 fprintf(f, "\n"); 05476 } 05477 if (tp->ranges) { 05478 struct range_list *rp = tp->ranges; 05479 if (size) 05480 fprintf(f, "%s Size: ", leave_indent); 05481 else 05482 fprintf(f, "%s Range: ", leave_indent); 05483 while (rp) { 05484 if (rp != tp->ranges) 05485 fprintf(f, " | "); 05486 print_range_value(f, tp->type, rp); 05487 rp = rp->next; 05488 } 05489 fprintf(f, "\n"); 05490 } 05491 } 05492 *ip = last_ipch; 05493 strcat(leave_indent, " |"); 05494 leave_was_simple = tp->type != TYPE_OTHER; 05495 05496 { 05497 int i, j, count = 0; 05498 struct leave { 05499 oid id; 05500 struct tree *tp; 05501 } *leaves, *lp; 05502 05503 for (ntp = tp->child_list; ntp; ntp = ntp->next_peer) 05504 count++; 05505 if (count) { 05506 leaves = (struct leave *) calloc(count, sizeof(struct leave)); 05507 if (!leaves) 05508 return; 05509 for (ntp = tp->child_list, count = 0; ntp; 05510 ntp = ntp->next_peer) { 05511 for (i = 0, lp = leaves; i < count; i++, lp++) 05512 if (lp->id >= ntp->subid) 05513 break; 05514 for (j = count; j > i; j--) 05515 leaves[j] = leaves[j - 1]; 05516 lp->id = ntp->subid; 05517 lp->tp = ntp; 05518 count++; 05519 } 05520 for (i = 1, lp = leaves; i <= count; i++, lp++) { 05521 if (!leave_was_simple || lp->tp->type == 0) 05522 fprintf(f, "%s\n", leave_indent); 05523 if (i == count) 05524 ip[3] = ' '; 05525 print_mib_leaves(f, lp->tp, width); 05526 } 05527 free(leaves); 05528 leave_was_simple = 0; 05529 } 05530 } 05531 ip[1] = 0; 05532 } 05533 05534 void 05535 print_mib_tree(FILE * f, struct tree *tp, int width) 05536 { 05537 leave_indent[0] = ' '; 05538 leave_indent[1] = 0; 05539 leave_was_simple = 1; 05540 print_mib_leaves(f, tp, width); 05541 } 05542 05543 05544 /* 05545 * Merge the parsed object identifier with the existing node. 05546 * If there is a problem with the identifier, release the existing node. 05547 */ 05548 static struct node * 05549 merge_parse_objectid(struct node *np, FILE * fp, char *name) 05550 { 05551 struct node *nnp; 05552 /* 05553 * printf("merge defval --> %s\n",np->defaultValue); 05554 */ 05555 nnp = parse_objectid(fp, name); 05556 if (nnp) { 05557 05558 /* 05559 * apply last OID sub-identifier data to the information 05560 */ 05561 /* 05562 * already collected for this node. 05563 */ 05564 struct node *headp, *nextp; 05565 int ncount = 0; 05566 nextp = headp = nnp; 05567 while (nnp->next) { 05568 nextp = nnp; 05569 ncount++; 05570 nnp = nnp->next; 05571 } 05572 05573 np->label = nnp->label; 05574 np->subid = nnp->subid; 05575 np->modid = nnp->modid; 05576 np->parent = nnp->parent; 05577 if (nnp->filename != NULL) { 05578 free(nnp->filename); 05579 } 05580 free(nnp); 05581 05582 if (ncount) { 05583 nextp->next = np; 05584 np = headp; 05585 } 05586 } else { 05587 free_node(np); 05588 np = NULL; 05589 } 05590 05591 return np; 05592 } 05593 05594 /* 05595 * transfer data to tree from node 05596 * 05597 * move pointers for alloc'd data from np to tp. 05598 * this prevents them from being freed when np is released. 05599 * parent member is not moved. 05600 * 05601 * CAUTION: nodes may be repeats of existing tree nodes. 05602 * This can happen especially when resolving IMPORT clauses. 05603 * 05604 */ 05605 static void 05606 tree_from_node(struct tree *tp, struct node *np) 05607 { 05608 free_partial_tree(tp, FALSE); 05609 05610 tp->label = np->label; 05611 np->label = NULL; 05612 tp->enums = np->enums; 05613 np->enums = NULL; 05614 tp->ranges = np->ranges; 05615 np->ranges = NULL; 05616 tp->indexes = np->indexes; 05617 np->indexes = NULL; 05618 tp->augments = np->augments; 05619 np->augments = NULL; 05620 tp->varbinds = np->varbinds; 05621 np->varbinds = NULL; 05622 tp->hint = np->hint; 05623 np->hint = NULL; 05624 tp->units = np->units; 05625 np->units = NULL; 05626 tp->description = np->description; 05627 np->description = NULL; 05628 tp->reference = np->reference; 05629 np->reference = NULL; 05630 tp->defaultValue = np->defaultValue; 05631 np->defaultValue = NULL; 05632 tp->subid = np->subid; 05633 tp->tc_index = np->tc_index; 05634 tp->type = translation_table[np->type]; 05635 tp->access = np->access; 05636 tp->status = np->status; 05637 05638 set_function(tp); 05639 } 05640 05641 #endif /* NETSNMP_DISABLE_MIB_LOADING */