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