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