|
net-snmp
5.4.1
|
00001 /* 00002 * agent_registry.c 00003 */ 00004 /* Portions of this file are subject to the following copyright(s). See 00005 * the Net-SNMP's COPYING file for more details and other copyrights 00006 * that may apply: 00007 */ 00008 /* 00009 * Portions of this file are copyrighted by: 00010 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. 00011 * Use is subject to license terms specified in the COPYING file 00012 * distributed with the Net-SNMP package. 00013 */ 00020 #define IN_SNMP_VARS_C 00021 00022 #include <net-snmp/net-snmp-config.h> 00023 #include <signal.h> 00024 #if HAVE_STRING_H 00025 #include <string.h> 00026 #endif 00027 #if HAVE_STDLIB_H 00028 #include <stdlib.h> 00029 #endif 00030 #include <sys/types.h> 00031 #include <stdio.h> 00032 #include <fcntl.h> 00033 #if HAVE_WINSOCK_H 00034 #include <winsock.h> 00035 #endif 00036 #if TIME_WITH_SYS_TIME 00037 # ifdef WIN32 00038 # include <sys/timeb.h> 00039 # else 00040 # include <sys/time.h> 00041 # endif 00042 # include <time.h> 00043 #else 00044 # if HAVE_SYS_TIME_H 00045 # include <sys/time.h> 00046 # else 00047 # include <time.h> 00048 # endif 00049 #endif 00050 #if HAVE_NETINET_IN_H 00051 #include <netinet/in.h> 00052 #endif 00053 00054 #include <net-snmp/net-snmp-includes.h> 00055 #include <net-snmp/agent/net-snmp-agent-includes.h> 00056 #include <net-snmp/agent/agent_callbacks.h> 00057 00058 #include "snmpd.h" 00059 #include "mibgroup/struct.h" 00060 #include <net-snmp/agent/old_api.h> 00061 #include <net-snmp/agent/null.h> 00062 #include <net-snmp/agent/table.h> 00063 #include <net-snmp/agent/table_iterator.h> 00064 #include <net-snmp/agent/agent_registry.h> 00065 #include "mib_module_includes.h" 00066 00067 #ifdef USING_AGENTX_SUBAGENT_MODULE 00068 #include "agentx/subagent.h" 00069 #include "agentx/client.h" 00070 #endif 00071 00072 static void register_mib_detach_node(netsnmp_subtree *s); 00073 NETSNMP_STATIC_INLINE void invalidate_lookup_cache(const char *context); 00074 void netsnmp_set_lookup_cache_size(int newsize); 00075 int netsnmp_get_lookup_cache_size(void); 00076 00077 subtree_context_cache *context_subtrees = NULL; 00078 00079 void 00080 netsnmp_subtree_free(netsnmp_subtree *a) 00081 { 00082 if (a != NULL) { 00083 if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen, 00084 a->start_a, a->start_len) == 0) { 00085 SNMP_FREE(a->variables); 00086 } 00087 SNMP_FREE(a->name_a); 00088 a->namelen = 0; 00089 SNMP_FREE(a->start_a); 00090 a->start_len = 0; 00091 SNMP_FREE(a->end_a); 00092 a->end_len = 0; 00093 SNMP_FREE(a->label_a); 00094 netsnmp_handler_registration_free(a->reginfo); 00095 a->reginfo = NULL; 00096 SNMP_FREE(a); 00097 } 00098 } 00099 00100 netsnmp_subtree * 00101 netsnmp_subtree_deepcopy(netsnmp_subtree *a) 00102 { 00103 netsnmp_subtree *b = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree)); 00104 00105 if (b != NULL) { 00106 memcpy(b, a, sizeof(netsnmp_subtree)); 00107 b->name_a = snmp_duplicate_objid(a->name_a, a->namelen); 00108 b->start_a = snmp_duplicate_objid(a->start_a, a->start_len); 00109 b->end_a = snmp_duplicate_objid(a->end_a, a->end_len); 00110 b->label_a = strdup(a->label_a); 00111 00112 if (b->name_a == NULL || b->start_a == NULL || 00113 b->end_a == NULL || b->label_a == NULL) { 00114 netsnmp_subtree_free(b); 00115 return NULL; 00116 } 00117 00118 if (a->variables != NULL) { 00119 b->variables = (struct variable *)malloc(a->variables_len * 00120 a->variables_width); 00121 if (b->variables != NULL) { 00122 memcpy(b->variables, a->variables,a->variables_len*a->variables_width); 00123 } else { 00124 netsnmp_subtree_free(b); 00125 return NULL; 00126 } 00127 } 00128 00129 if (a->reginfo != NULL) { 00130 b->reginfo = netsnmp_handler_registration_dup(a->reginfo); 00131 if (b->reginfo == NULL) { 00132 netsnmp_subtree_free(b); 00133 return NULL; 00134 } 00135 } 00136 } 00137 return b; 00138 } 00139 00140 subtree_context_cache * 00141 get_top_context_cache(void) 00142 { 00143 return context_subtrees; 00144 } 00145 00146 netsnmp_subtree * 00147 netsnmp_subtree_find_first(const char *context_name) 00148 { 00149 subtree_context_cache *ptr; 00150 00151 if (!context_name) { 00152 context_name = ""; 00153 } 00154 00155 DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n", 00156 context_name)); 00157 for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) { 00158 if (ptr->context_name != NULL && 00159 strcmp(ptr->context_name, context_name) == 0) { 00160 DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name)); 00161 return ptr->first_subtree; 00162 } 00163 } 00164 DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n", 00165 context_name)); 00166 return NULL; 00167 } 00168 00169 netsnmp_subtree * 00170 add_subtree(netsnmp_subtree *new_tree, const char *context_name) 00171 { 00172 subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache); 00173 00174 if (!context_name) { 00175 context_name = ""; 00176 } 00177 00178 if (!ptr) { 00179 return NULL; 00180 } 00181 00182 DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n", 00183 context_name)); 00184 00185 ptr->next = context_subtrees; 00186 ptr->first_subtree = new_tree; 00187 ptr->context_name = strdup(context_name); 00188 context_subtrees = ptr; 00189 00190 return ptr->first_subtree; 00191 } 00192 00193 netsnmp_subtree * 00194 netsnmp_subtree_replace_first(netsnmp_subtree *new_tree, 00195 const char *context_name) 00196 { 00197 subtree_context_cache *ptr; 00198 if (!context_name) { 00199 context_name = ""; 00200 } 00201 for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) { 00202 if (ptr->context_name != NULL && 00203 strcmp(ptr->context_name, context_name) == 0) { 00204 ptr->first_subtree = new_tree; 00205 return ptr->first_subtree; 00206 } 00207 } 00208 return add_subtree(new_tree, context_name); 00209 } 00210 00211 NETSNMP_INLINE void 00212 netsnmp_subtree_change_next(netsnmp_subtree *ptr, netsnmp_subtree *thenext) 00213 { 00214 ptr->next = thenext; 00215 if (thenext) 00216 netsnmp_oid_compare_ll(ptr->start_a, 00217 ptr->start_len, 00218 thenext->start_a, 00219 thenext->start_len, 00220 &thenext->oid_off); 00221 } 00222 00223 NETSNMP_INLINE void 00224 netsnmp_subtree_change_prev(netsnmp_subtree *ptr, netsnmp_subtree *theprev) 00225 { 00226 ptr->prev = theprev; 00227 if (theprev) 00228 netsnmp_oid_compare_ll(theprev->start_a, 00229 theprev->start_len, 00230 ptr->start_a, 00231 ptr->start_len, 00232 &ptr->oid_off); 00233 } 00234 00235 int 00236 netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp) 00237 { 00238 return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen); 00239 } 00240 00241 void 00242 netsnmp_subtree_join(netsnmp_subtree *root) 00243 { 00244 netsnmp_subtree *s, *tmp, *c, *d; 00245 00246 while (root != NULL) { 00247 s = root->next; 00248 while (s != NULL && root->reginfo == s->reginfo) { 00249 tmp = s->next; 00250 DEBUGMSGTL(("subtree", "root start ")); 00251 DEBUGMSGOID(("subtree", root->start_a, root->start_len)); 00252 DEBUGMSG(("subtree", " (original end ")); 00253 DEBUGMSGOID(("subtree", root->end_a, root->end_len)); 00254 DEBUGMSG(("subtree", ")\n")); 00255 DEBUGMSGTL(("subtree", " JOINING to ")); 00256 DEBUGMSGOID(("subtree", s->start_a, s->start_len)); 00257 00258 SNMP_FREE(root->end_a); 00259 root->end_a = s->end_a; 00260 root->end_len = s->end_len; 00261 s->end_a = NULL; 00262 00263 for (c = root; c != NULL; c = c->children) { 00264 netsnmp_subtree_change_next(c, s->next); 00265 } 00266 for (c = s; c != NULL; c = c->children) { 00267 netsnmp_subtree_change_prev(c, root); 00268 } 00269 DEBUGMSG(("subtree", " so new end ")); 00270 DEBUGMSGOID(("subtree", root->end_a, root->end_len)); 00271 DEBUGMSG(("subtree", "\n")); 00272 /* 00273 * Probably need to free children too? 00274 */ 00275 for (c = s->children; c != NULL; c = d) { 00276 d = c->children; 00277 netsnmp_subtree_free(c); 00278 } 00279 netsnmp_subtree_free(s); 00280 s = tmp; 00281 } 00282 root = root->next; 00283 } 00284 } 00285 00286 00287 /* 00288 * Split the subtree into two at the specified point, 00289 * returning the new (second) subtree 00290 */ 00291 netsnmp_subtree * 00292 netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len) 00293 { 00294 struct variable *vp = NULL; 00295 netsnmp_subtree *new_sub, *ptr; 00296 int i = 0, rc = 0, rc2 = 0; 00297 size_t common_len = 0; 00298 char *cp; 00299 oid *tmp_a, *tmp_b; 00300 00301 if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) { 00302 /* Split comes after the end of this subtree */ 00303 return NULL; 00304 } 00305 00306 new_sub = netsnmp_subtree_deepcopy(current); 00307 if (new_sub == NULL) { 00308 return NULL; 00309 } 00310 00311 /* Set up the point of division. */ 00312 tmp_a = snmp_duplicate_objid(name, name_len); 00313 if (tmp_a == NULL) { 00314 netsnmp_subtree_free(new_sub); 00315 return NULL; 00316 } 00317 tmp_b = snmp_duplicate_objid(name, name_len); 00318 if (tmp_b == NULL) { 00319 netsnmp_subtree_free(new_sub); 00320 SNMP_FREE(tmp_a); 00321 return NULL; 00322 } 00323 00324 if (current->end_a != NULL) { 00325 SNMP_FREE(current->end_a); 00326 } 00327 current->end_a = tmp_a; 00328 current->end_len = name_len; 00329 if (new_sub->start_a != NULL) { 00330 SNMP_FREE(new_sub->start_a); 00331 } 00332 new_sub->start_a = tmp_b; 00333 new_sub->start_len = name_len; 00334 00335 /* Split the variables between the two new subtrees. */ 00336 i = current->variables_len; 00337 current->variables_len = 0; 00338 00339 for (vp = current->variables; i > 0; i--) { 00340 /* Note that the variable "name" field omits the prefix common to the 00341 whole registration, hence the strange comparison here. */ 00342 00343 rc = snmp_oid_compare(vp->name, vp->namelen, 00344 name + current->namelen, 00345 name_len - current->namelen); 00346 00347 if (name_len - current->namelen > vp->namelen) { 00348 common_len = vp->namelen; 00349 } else { 00350 common_len = name_len - current->namelen; 00351 } 00352 00353 rc2 = snmp_oid_compare(vp->name, common_len, 00354 name + current->namelen, common_len); 00355 00356 if (rc >= 0) { 00357 break; /* All following variables belong to the second subtree */ 00358 } 00359 00360 current->variables_len++; 00361 if (rc2 < 0) { 00362 new_sub->variables_len--; 00363 cp = (char *) new_sub->variables; 00364 new_sub->variables = (struct variable *)(cp + 00365 new_sub->variables_width); 00366 } 00367 vp = (struct variable *) ((char *) vp + current->variables_width); 00368 } 00369 00370 /* Delegated trees should retain their variables regardless */ 00371 if (current->variables_len > 0 && 00372 IS_DELEGATED((u_char) current->variables[0].type)) { 00373 new_sub->variables_len = 1; 00374 new_sub->variables = current->variables; 00375 } 00376 00377 /* Propogate this split down through any children */ 00378 if (current->children) { 00379 new_sub->children = netsnmp_subtree_split(current->children, 00380 name, name_len); 00381 } 00382 00383 /* Retain the correct linking of the list */ 00384 for (ptr = current; ptr != NULL; ptr = ptr->children) { 00385 netsnmp_subtree_change_next(ptr, new_sub); 00386 } 00387 for (ptr = new_sub; ptr != NULL; ptr = ptr->children) { 00388 netsnmp_subtree_change_prev(ptr, current); 00389 } 00390 for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) { 00391 netsnmp_subtree_change_prev(ptr, new_sub); 00392 } 00393 00394 return new_sub; 00395 } 00396 00397 int 00398 netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name) 00399 { 00400 netsnmp_subtree *tree1, *tree2, *new2; 00401 netsnmp_subtree *prev, *next; 00402 int res, rc = 0; 00403 00404 if (new_sub == NULL) { 00405 return MIB_REGISTERED_OK; /* Degenerate case */ 00406 } 00407 00408 if (!netsnmp_subtree_find_first(context_name)) { 00409 static int inloop = 0; 00410 if (!inloop) { 00411 oid ccitt[1] = { 0 }; 00412 oid iso[1] = { 1 }; 00413 oid joint_ccitt_iso[1] = { 2 }; 00414 inloop = 1; 00415 netsnmp_register_null_context(snmp_duplicate_objid(ccitt, 1), 1, 00416 context_name); 00417 netsnmp_register_null_context(snmp_duplicate_objid(iso, 1), 1, 00418 context_name); 00419 netsnmp_register_null_context(snmp_duplicate_objid(joint_ccitt_iso, 1), 00420 1, context_name); 00421 inloop = 0; 00422 } 00423 } 00424 00425 /* Find the subtree that contains the start of the new subtree (if 00426 any)...*/ 00427 00428 tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len, 00429 NULL, context_name); 00430 00431 /* ... and the subtree that follows the new one (NULL implies this is the 00432 final region covered). */ 00433 00434 if (tree1 == NULL) { 00435 tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len, 00436 NULL, context_name); 00437 } else { 00438 tree2 = tree1->next; 00439 } 00440 00441 /* Handle new subtrees that start in virgin territory. */ 00442 00443 if (tree1 == NULL) { 00444 new2 = NULL; 00445 /* Is there any overlap with later subtrees? */ 00446 if (tree2 && snmp_oid_compare(new_sub->end_a, new_sub->end_len, 00447 tree2->start_a, tree2->start_len) > 0) { 00448 new2 = netsnmp_subtree_split(new_sub, 00449 tree2->start_a, tree2->start_len); 00450 } 00451 00452 /* Link the new subtree (less any overlapping region) with the list of 00453 existing registrations. */ 00454 00455 if (tree2) { 00456 netsnmp_subtree_change_prev(new_sub, tree2->prev); 00457 netsnmp_subtree_change_prev(tree2, new_sub); 00458 } else { 00459 netsnmp_subtree_change_prev(new_sub, 00460 netsnmp_subtree_find_prev(new_sub->start_a, 00461 new_sub->start_len, NULL, context_name)); 00462 00463 if (new_sub->prev) { 00464 netsnmp_subtree_change_next(new_sub->prev, new_sub); 00465 } else { 00466 netsnmp_subtree_replace_first(new_sub, context_name); 00467 } 00468 00469 netsnmp_subtree_change_next(new_sub, tree2); 00470 00471 /* If there was any overlap, recurse to merge in the overlapping 00472 region (including anything that may follow the overlap). */ 00473 if (new2) { 00474 return netsnmp_subtree_load(new2, context_name); 00475 } 00476 } 00477 } else { 00478 /* If the new subtree starts *within* an existing registration 00479 (rather than at the same point as it), then split the existing 00480 subtree at this point. */ 00481 00482 if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len, 00483 tree1->start_a, tree1->start_len) != 0) { 00484 tree1 = netsnmp_subtree_split(tree1, new_sub->start_a, 00485 new_sub->start_len); 00486 } 00487 00488 if (tree1 == NULL) { 00489 return MIB_REGISTRATION_FAILED; 00490 } 00491 00492 /* Now consider the end of this existing subtree: 00493 00494 If it matches the new subtree precisely, 00495 simply merge the new one into the list of children 00496 00497 If it includes the whole of the new subtree, 00498 split it at the appropriate point, and merge again 00499 00500 If the new subtree extends beyond this existing region, 00501 split it, and recurse to merge the two parts. */ 00502 00503 rc = snmp_oid_compare(new_sub->end_a, new_sub->end_len, 00504 tree1->end_a, tree1->end_len); 00505 00506 switch (rc) { 00507 00508 case -1: 00509 /* Existing subtree contains new one. */ 00510 netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len); 00511 /* Fall Through */ 00512 00513 case 0: 00514 /* The two trees match precisely. */ 00515 00516 /* Note: This is the only point where the original registration 00517 OID ("name") is used. */ 00518 00519 prev = NULL; 00520 next = tree1; 00521 00522 while (next && next->namelen > new_sub->namelen) { 00523 prev = next; 00524 next = next->children; 00525 } 00526 00527 while (next && next->namelen == new_sub->namelen && 00528 next->priority < new_sub->priority ) { 00529 prev = next; 00530 next = next->children; 00531 } 00532 00533 if (next && (next->namelen == new_sub->namelen) && 00534 (next->priority == new_sub->priority)) { 00535 if (new_sub->namelen != 1) { /* ignore root OID dups */ 00536 size_t out_len = 0; 00537 size_t buf_len = 0; 00538 char *buf = NULL; 00539 int buf_overflow = 0; 00540 00541 netsnmp_sprint_realloc_objid((u_char **) &buf, &buf_len, &out_len, 00542 1, &buf_overflow, 00543 new_sub->start_a, 00544 new_sub->start_len); 00545 snmp_log(LOG_ERR, 00546 "duplicate registration: MIB modules %s and %s (oid %s%s).\n", 00547 next->label_a, new_sub->label_a, 00548 buf ? buf : "", 00549 buf_overflow ? " [TRUNCATED]" : ""); 00550 free(buf); 00551 } 00552 return MIB_DUPLICATE_REGISTRATION; 00553 } 00554 00555 if (prev) { 00556 prev->children = new_sub; 00557 new_sub->children = next; 00558 netsnmp_subtree_change_prev(new_sub, prev->prev); 00559 netsnmp_subtree_change_next(new_sub, prev->next); 00560 } else { 00561 new_sub->children = next; 00562 netsnmp_subtree_change_prev(new_sub, next->prev); 00563 netsnmp_subtree_change_next(new_sub, next->next); 00564 00565 for (next = new_sub->next; next != NULL;next = next->children){ 00566 netsnmp_subtree_change_prev(next, new_sub); 00567 } 00568 00569 for (prev = new_sub->prev; prev != NULL;prev = prev->children){ 00570 netsnmp_subtree_change_next(prev, new_sub); 00571 } 00572 } 00573 break; 00574 00575 case 1: 00576 /* New subtree contains the existing one. */ 00577 new2 = netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len); 00578 res = netsnmp_subtree_load(new_sub, context_name); 00579 if (res != MIB_REGISTERED_OK) { 00580 netsnmp_subtree_free(new2); 00581 return res; 00582 } 00583 return netsnmp_subtree_load(new2, context_name); 00584 } 00585 } 00586 return 0; 00587 } 00588 00589 /* 00590 * Note: reginfo will be freed on failures 00591 */ 00592 int 00593 netsnmp_register_mib(const char *moduleName, 00594 struct variable *var, 00595 size_t varsize, 00596 size_t numvars, 00597 oid * mibloc, 00598 size_t mibloclen, 00599 int priority, 00600 int range_subid, 00601 oid range_ubound, 00602 netsnmp_session * ss, 00603 const char *context, 00604 int timeout, 00605 int flags, 00606 netsnmp_handler_registration *reginfo, 00607 int perform_callback) 00608 { 00609 netsnmp_subtree *subtree, *sub2; 00610 int res, i; 00611 struct register_parameters reg_parms; 00612 int old_lookup_cache_val = netsnmp_get_lookup_cache_size(); 00613 00614 if (moduleName == NULL || 00615 mibloc == NULL) { 00616 /* Shouldn't happen ??? */ 00617 netsnmp_handler_registration_free(reginfo); 00618 return MIB_REGISTRATION_FAILED; 00619 } 00620 subtree = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree)); 00621 if (subtree == NULL) { 00622 netsnmp_handler_registration_free(reginfo); 00623 return MIB_REGISTRATION_FAILED; 00624 } 00625 00626 DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName)); 00627 DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid, 00628 range_ubound)); 00629 DEBUGMSG(("register_mib", " with context \"%s\"\n", 00630 SNMP_STRORNULL(context))); 00631 00632 /* 00633 * verify that the passed context is equal to the context 00634 * in the reginfo. 00635 * (which begs the question, why do we have both? It appears that the 00636 * reginfo item didn't appear til 5.2) 00637 */ 00638 if( ((NULL == context) && (NULL != reginfo->contextName)) || 00639 ((NULL != context) && (NULL == reginfo->contextName)) || 00640 ( ((NULL != context) && (NULL != reginfo->contextName)) && 00641 (0 != strcmp(context, reginfo->contextName))) ) { 00642 snmp_log(LOG_WARNING,"context passed during registration does not " 00643 "equal the reginfo contextName! ('%s' != '%s')\n", 00644 context, reginfo->contextName); 00645 netsnmp_assert(!"register context == reginfo->contextName"); /* always false */ 00646 } 00647 00648 /* Create the new subtree node being registered. */ 00649 00650 subtree->reginfo = reginfo; 00651 subtree->name_a = snmp_duplicate_objid(mibloc, mibloclen); 00652 subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen); 00653 subtree->end_a = snmp_duplicate_objid(mibloc, mibloclen); 00654 subtree->label_a = strdup(moduleName); 00655 if (subtree->name_a == NULL || subtree->start_a == NULL || 00656 subtree->end_a == NULL || subtree->label_a == NULL) { 00657 netsnmp_subtree_free(subtree); /* also frees reginfo */ 00658 return MIB_REGISTRATION_FAILED; 00659 } 00660 subtree->namelen = (u_char)mibloclen; 00661 subtree->start_len = (u_char)mibloclen; 00662 subtree->end_len = (u_char)mibloclen; 00663 subtree->end_a[mibloclen - 1]++; 00664 00665 if (var != NULL) { 00666 subtree->variables = (struct variable *)malloc(varsize*numvars); 00667 if (subtree->variables == NULL) { 00668 netsnmp_subtree_free(subtree); /* also frees reginfo */ 00669 return MIB_REGISTRATION_FAILED; 00670 } 00671 memcpy(subtree->variables, var, numvars*varsize); 00672 subtree->variables_len = numvars; 00673 subtree->variables_width = varsize; 00674 } 00675 subtree->priority = priority; 00676 subtree->timeout = timeout; 00677 subtree->range_subid = range_subid; 00678 subtree->range_ubound = range_ubound; 00679 subtree->session = ss; 00680 subtree->flags = (u_char)flags; /* used to identify instance oids */ 00681 subtree->flags |= SUBTREE_ATTACHED; 00682 subtree->global_cacheid = reginfo->global_cacheid; 00683 00684 netsnmp_set_lookup_cache_size(0); 00685 res = netsnmp_subtree_load(subtree, context); 00686 00687 /* If registering a range, use the first subtree as a template for the 00688 rest of the range. */ 00689 00690 if (res == MIB_REGISTERED_OK && range_subid != 0) { 00691 for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) { 00692 sub2 = netsnmp_subtree_deepcopy(subtree); 00693 00694 if (sub2 == NULL) { 00695 unregister_mib_context(mibloc, mibloclen, priority, 00696 range_subid, range_ubound, context); 00697 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00698 invalidate_lookup_cache(context); 00699 return MIB_REGISTRATION_FAILED; 00700 } 00701 00702 sub2->name_a[range_subid - 1] = i; 00703 sub2->start_a[range_subid - 1] = i; 00704 sub2->end_a[range_subid - 1] = i; /* XXX - ???? */ 00705 if (range_subid == (int)mibloclen) 00706 ++sub2->end_a[range_subid - 1]; 00707 res = netsnmp_subtree_load(sub2, context); 00708 sub2->flags |= SUBTREE_ATTACHED; 00709 if (res != MIB_REGISTERED_OK) { 00710 unregister_mib_context(mibloc, mibloclen, priority, 00711 range_subid, range_ubound, context); 00712 netsnmp_subtree_free(sub2); 00713 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00714 invalidate_lookup_cache(context); 00715 return res; 00716 } 00717 } 00718 } else if (res == MIB_DUPLICATE_REGISTRATION || 00719 res == MIB_REGISTRATION_FAILED) { 00720 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00721 invalidate_lookup_cache(context); 00722 netsnmp_subtree_free(subtree); 00723 return res; 00724 } 00725 00726 /* 00727 * mark the MIB as detached, if there's no master agent present as of now 00728 */ 00729 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 00730 NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) { 00731 extern struct snmp_session *main_session; 00732 if (main_session == NULL) { 00733 register_mib_detach_node(subtree); 00734 } 00735 } 00736 00737 if (res == MIB_REGISTERED_OK && perform_callback) { 00738 memset(®_parms, 0x0, sizeof(reg_parms)); 00739 reg_parms.name = mibloc; 00740 reg_parms.namelen = mibloclen; 00741 reg_parms.priority = priority; 00742 reg_parms.range_subid = range_subid; 00743 reg_parms.range_ubound = range_ubound; 00744 reg_parms.timeout = timeout; 00745 reg_parms.flags = (u_char) flags; 00746 reg_parms.contextName = context; 00747 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00748 SNMPD_CALLBACK_REGISTER_OID, ®_parms); 00749 } 00750 00751 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00752 invalidate_lookup_cache(context); 00753 return res; 00754 } 00755 00756 /* 00757 * Reattach a particular node. 00758 */ 00759 00760 static void 00761 register_mib_reattach_node(netsnmp_subtree *s) 00762 { 00763 if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) { 00764 struct register_parameters reg_parms; 00765 /* 00766 * only do registrations that are not the top level nodes 00767 */ 00768 memset(®_parms, 0x0, sizeof(reg_parms)); 00769 00770 /* 00771 * XXX: do this better 00772 */ 00773 reg_parms.name = s->name_a; 00774 reg_parms.namelen = s->namelen; 00775 reg_parms.priority = s->priority; 00776 reg_parms.range_subid = s->range_subid; 00777 reg_parms.range_ubound = s->range_ubound; 00778 reg_parms.timeout = s->timeout; 00779 reg_parms.flags = s->flags; 00780 if ((NULL != s->reginfo) && (NULL != s->reginfo->contextName)) 00781 reg_parms.contextName = s->reginfo->contextName; 00782 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00783 SNMPD_CALLBACK_REGISTER_OID, ®_parms); 00784 s->flags |= SUBTREE_ATTACHED; 00785 } 00786 } 00787 00788 /* 00789 * Call callbacks to reattach all our nodes. 00790 */ 00791 00792 void 00793 register_mib_reattach(void) 00794 { 00795 netsnmp_subtree *s, *t; 00796 subtree_context_cache *ptr; 00797 00798 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 00799 for (s = ptr->first_subtree; s != NULL; s = s->next) { 00800 register_mib_reattach_node(s); 00801 for (t = s->children; t != NULL; t = t->children) { 00802 register_mib_reattach_node(t); 00803 } 00804 } 00805 } 00806 } 00807 00808 /* 00809 * Mark a node as detached. 00810 */ 00811 00812 static void 00813 register_mib_detach_node(netsnmp_subtree *s) 00814 { 00815 if (s != NULL) { 00816 s->flags = s->flags & ~SUBTREE_ATTACHED; 00817 } 00818 } 00819 00820 /* 00821 * Mark all our registered OIDs as detached. This is only really 00822 * useful for subagent protocols, when a connection is lost or 00823 * something. 00824 */ 00825 00826 void 00827 register_mib_detach(void) 00828 { 00829 netsnmp_subtree *s, *t; 00830 subtree_context_cache *ptr; 00831 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 00832 for (s = ptr->first_subtree; s != NULL; s = s->next) { 00833 register_mib_detach_node(s); 00834 for (t = s->children; t != NULL; t = t->children) { 00835 register_mib_detach_node(t); 00836 } 00837 } 00838 } 00839 } 00840 00841 int 00842 register_mib_context(const char *moduleName, 00843 struct variable *var, 00844 size_t varsize, 00845 size_t numvars, 00846 oid * mibloc, 00847 size_t mibloclen, 00848 int priority, 00849 int range_subid, 00850 oid range_ubound, 00851 netsnmp_session * ss, 00852 const char *context, int timeout, int flags) 00853 { 00854 return netsnmp_register_old_api(moduleName, var, varsize, numvars, 00855 mibloc, mibloclen, priority, 00856 range_subid, range_ubound, ss, context, 00857 timeout, flags); 00858 } 00859 00860 int 00861 register_mib_range(const char *moduleName, 00862 struct variable *var, 00863 size_t varsize, 00864 size_t numvars, 00865 oid * mibloc, 00866 size_t mibloclen, 00867 int priority, 00868 int range_subid, oid range_ubound, netsnmp_session * ss) 00869 { 00870 return register_mib_context(moduleName, var, varsize, numvars, 00871 mibloc, mibloclen, priority, 00872 range_subid, range_ubound, ss, "", -1, 0); 00873 } 00874 00875 int 00876 register_mib_priority(const char *moduleName, 00877 struct variable *var, 00878 size_t varsize, 00879 size_t numvars, 00880 oid * mibloc, size_t mibloclen, int priority) 00881 { 00882 return register_mib_range(moduleName, var, varsize, numvars, 00883 mibloc, mibloclen, priority, 0, 0, NULL); 00884 } 00885 00886 int 00887 register_mib(const char *moduleName, 00888 struct variable *var, 00889 size_t varsize, 00890 size_t numvars, oid * mibloc, size_t mibloclen) 00891 { 00892 return register_mib_priority(moduleName, var, varsize, numvars, 00893 mibloc, mibloclen, DEFAULT_MIB_PRIORITY); 00894 } 00895 00896 void 00897 netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev, const char *context) 00898 { 00899 netsnmp_subtree *ptr; 00900 00901 DEBUGMSGTL(("register_mib", "unload(")); 00902 if (sub != NULL) { 00903 DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len)); 00904 } else { 00905 DEBUGMSG(("register_mib", "[NIL]")); 00906 } 00907 DEBUGMSG(("register_mib", ", ")); 00908 if (prev != NULL) { 00909 DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len)); 00910 } else { 00911 DEBUGMSG(("register_mib", "[NIL]")); 00912 } 00913 DEBUGMSG(("register_mib", ")\n")); 00914 00915 if (prev != NULL) { /* non-leading entries are easy */ 00916 prev->children = sub->children; 00917 invalidate_lookup_cache(context); 00918 return; 00919 } 00920 /* 00921 * otherwise, we need to amend our neighbours as well 00922 */ 00923 00924 if (sub->children == NULL) { /* just remove this node completely */ 00925 for (ptr = sub->prev; ptr; ptr = ptr->children) { 00926 netsnmp_subtree_change_next(ptr, sub->next); 00927 } 00928 for (ptr = sub->next; ptr; ptr = ptr->children) { 00929 netsnmp_subtree_change_prev(ptr, sub->prev); 00930 } 00931 00932 if (sub->prev == NULL) { 00933 netsnmp_subtree_replace_first(sub->next, context); 00934 } 00935 00936 } else { 00937 for (ptr = sub->prev; ptr; ptr = ptr->children) 00938 netsnmp_subtree_change_next(ptr, sub->children); 00939 for (ptr = sub->next; ptr; ptr = ptr->children) 00940 netsnmp_subtree_change_prev(ptr, sub->children); 00941 00942 if (sub->prev == NULL) { 00943 netsnmp_subtree_replace_first(sub->children, context); 00944 } 00945 } 00946 invalidate_lookup_cache(context); 00947 } 00948 00978 int 00979 unregister_mib_context(oid * name, size_t len, int priority, 00980 int range_subid, oid range_ubound, 00981 const char *context) 00982 { 00983 netsnmp_subtree *list, *myptr; 00984 netsnmp_subtree *prev, *child, *next; /* loop through children */ 00985 struct register_parameters reg_parms; 00986 int old_lookup_cache_val = netsnmp_get_lookup_cache_size(); 00987 netsnmp_set_lookup_cache_size(0); 00988 00989 DEBUGMSGTL(("register_mib", "unregistering ")); 00990 DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound)); 00991 DEBUGMSG(("register_mib", "\n")); 00992 00993 list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context), 00994 context); 00995 if (list == NULL) { 00996 return MIB_NO_SUCH_REGISTRATION; 00997 } 00998 00999 for (child = list, prev = NULL; child != NULL; 01000 prev = child, child = child->children) { 01001 if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 && 01002 child->priority == priority) { 01003 break; /* found it */ 01004 } 01005 } 01006 01007 if (child == NULL) { 01008 return MIB_NO_SUCH_REGISTRATION; 01009 } 01010 01011 netsnmp_subtree_unload(child, prev, context); 01012 myptr = child; /* remember this for later */ 01013 01014 /* 01015 * Now handle any occurances in the following subtrees, 01016 * as a result of splitting this range. Due to the 01017 * nature of the way such splits work, the first 01018 * subtree 'slice' that doesn't refer to the given 01019 * name marks the end of the original region. 01020 * 01021 * This should also serve to register ranges. 01022 */ 01023 01024 for (list = myptr->next; list != NULL; list = next) { 01025 next = list->next; /* list gets freed sometimes; cache next */ 01026 for (child = list, prev = NULL; child != NULL; 01027 prev = child, child = child->children) { 01028 if ((netsnmp_oid_equals(child->name_a, child->namelen, 01029 name, len) == 0) && 01030 (child->priority == priority)) { 01031 netsnmp_subtree_unload(child, prev, context); 01032 netsnmp_subtree_free(child); 01033 break; 01034 } 01035 } 01036 if (child == NULL) /* Didn't find the given name */ 01037 break; 01038 } 01039 01040 memset(®_parms, 0x0, sizeof(reg_parms)); 01041 reg_parms.name = name; 01042 reg_parms.namelen = len; 01043 reg_parms.priority = priority; 01044 reg_parms.range_subid = range_subid; 01045 reg_parms.range_ubound = range_ubound; 01046 reg_parms.flags = 0x00; /* this is okay I think */ 01047 reg_parms.contextName = context; 01048 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01049 SNMPD_CALLBACK_UNREGISTER_OID, ®_parms); 01050 01051 netsnmp_subtree_free(myptr); 01052 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 01053 invalidate_lookup_cache(context); 01054 return MIB_UNREGISTERED_OK; 01055 } 01056 01057 int 01058 netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority, 01059 int var_subid, oid range_ubound, 01060 const char *context) 01061 { 01062 netsnmp_subtree *list, *myptr, *futureptr; 01063 netsnmp_subtree *prev, *child; /* loop through children */ 01064 struct register_parameters reg_parms; 01065 oid range_lbound = name[var_subid - 1]; 01066 01067 DEBUGMSGTL(("register_mib", "unregistering ")); 01068 DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound)); 01069 DEBUGMSG(("register_mib", "\n")); 01070 01071 for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) { 01072 list = netsnmp_subtree_find(name, len, 01073 netsnmp_subtree_find_first(context), context); 01074 01075 if (list == NULL) { 01076 continue; 01077 } 01078 01079 for (child = list, prev = NULL; child != NULL; 01080 prev = child, child = child->children) { 01081 01082 if (netsnmp_oid_equals(child->name_a, child->namelen, 01083 name, len) == 0 && 01084 (child->priority == priority)) { 01085 break; /* found it */ 01086 } 01087 } 01088 01089 if (child == NULL) { 01090 continue; 01091 } 01092 01093 netsnmp_subtree_unload(child, prev, context); 01094 myptr = child; /* remember this for later */ 01095 01096 for (list = myptr->next; list != NULL; list = futureptr) { 01097 /* remember the next spot in the list in case we free this node */ 01098 futureptr = list->next; 01099 01100 /* check each child */ 01101 for (child = list, prev = NULL; child != NULL; 01102 prev = child, child = child->children) { 01103 01104 if (netsnmp_oid_equals(child->name_a, child->namelen, 01105 name, len) == 0 && 01106 (child->priority == priority)) { 01107 netsnmp_subtree_unload(child, prev, context); 01108 netsnmp_subtree_free(child); 01109 break; 01110 } 01111 } 01112 01113 /* XXX: wjh: not sure why we're bailing here */ 01114 if (child == NULL) { /* Didn't find the given name */ 01115 break; 01116 } 01117 } 01118 netsnmp_subtree_free(myptr); 01119 } 01120 01121 name[var_subid - 1] = range_lbound; 01122 memset(®_parms, 0x0, sizeof(reg_parms)); 01123 reg_parms.name = name; 01124 reg_parms.namelen = len; 01125 reg_parms.priority = priority; 01126 reg_parms.range_subid = var_subid; 01127 reg_parms.range_ubound = range_ubound; 01128 reg_parms.flags = 0x00; /* this is okay I think */ 01129 reg_parms.contextName = context; 01130 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01131 SNMPD_CALLBACK_UNREGISTER_OID, ®_parms); 01132 01133 return 0; 01134 } 01135 01136 int 01137 unregister_mib_range(oid * name, size_t len, int priority, 01138 int range_subid, oid range_ubound) 01139 { 01140 return unregister_mib_context(name, len, priority, range_subid, 01141 range_ubound, ""); 01142 } 01143 01144 int 01145 unregister_mib_priority(oid * name, size_t len, int priority) 01146 { 01147 return unregister_mib_range(name, len, priority, 0, 0); 01148 } 01149 01150 int 01151 unregister_mib(oid * name, size_t len) 01152 { 01153 return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY); 01154 } 01155 01156 void 01157 unregister_mibs_by_session(netsnmp_session * ss) 01158 { 01159 netsnmp_subtree *list, *list2; 01160 netsnmp_subtree *child, *prev, *next_child; 01161 struct register_parameters rp; 01162 subtree_context_cache *contextptr; 01163 01164 DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n", 01165 ss, (ss && ss->contextName) ? ss->contextName : "[NIL]")); 01166 01167 for (contextptr = get_top_context_cache(); contextptr != NULL; 01168 contextptr = contextptr->next) { 01169 for (list = contextptr->first_subtree; list != NULL; list = list2) { 01170 list2 = list->next; 01171 01172 for (child = list, prev = NULL; child != NULL; child = next_child){ 01173 next_child = child->children; 01174 01175 if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && 01176 child->session == ss) || 01177 (!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session && 01178 child->session->subsession == ss)) { 01179 01180 memset(&rp,0x0,sizeof(rp)); 01181 rp.name = child->name_a; 01182 child->name_a = NULL; 01183 rp.namelen = child->namelen; 01184 rp.priority = child->priority; 01185 rp.range_subid = child->range_subid; 01186 rp.range_ubound = child->range_ubound; 01187 rp.timeout = child->timeout; 01188 rp.flags = child->flags; 01189 if ((NULL != child->reginfo) && 01190 (NULL != child->reginfo->contextName)) 01191 rp.contextName = child->reginfo->contextName; 01192 01193 if (child->reginfo != NULL) { 01194 /* 01195 * Don't let's free the session pointer just yet! 01196 */ 01197 child->reginfo->handler->myvoid = NULL; 01198 netsnmp_handler_registration_free(child->reginfo); 01199 child->reginfo = NULL; 01200 } 01201 01202 netsnmp_subtree_unload(child, prev, contextptr->context_name); 01203 netsnmp_subtree_free(child); 01204 01205 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01206 SNMPD_CALLBACK_UNREGISTER_OID, &rp); 01207 SNMP_FREE(rp.name); 01208 } else { 01209 prev = child; 01210 } 01211 } 01212 } 01213 netsnmp_subtree_join(contextptr->first_subtree); 01214 } 01215 } 01216 01217 /* 01218 * in_a_view: determines if a given snmp_pdu is allowed to see a 01219 * given name/namelen OID pointer 01220 * name IN - name of var, OUT - name matched 01221 * nameLen IN -number of sub-ids in name, OUT - subid-is in matched name 01222 * pi IN - relevant auth info re PDU 01223 * cvp IN - relevant auth info re mib module 01224 */ 01225 01226 int 01227 in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type) 01228 { 01229 struct view_parameters view_parms; 01230 01231 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 01232 /* Enable bypassing of view-based access control */ 01233 return VACM_SUCCESS; 01234 } 01235 01236 /* 01237 * check for v1 and counter64s, since snmpv1 doesn't support it 01238 */ 01239 #ifndef NETSNMP_DISABLE_SNMPV1 01240 if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) { 01241 return VACM_NOTINVIEW; 01242 } 01243 #endif 01244 01245 view_parms.pdu = pdu; 01246 view_parms.name = name; 01247 if (namelen != NULL) { 01248 view_parms.namelen = *namelen; 01249 } else { 01250 view_parms.namelen = 0; 01251 } 01252 view_parms.errorcode = 0; 01253 view_parms.check_subtree = 0; 01254 01255 switch (pdu->version) { 01256 #ifndef NETSNMP_DISABLE_SNMPV1 01257 case SNMP_VERSION_1: 01258 #endif 01259 #ifndef NETSNMP_DISABLE_SNMPV2C 01260 case SNMP_VERSION_2c: 01261 #endif 01262 case SNMP_VERSION_3: 01263 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01264 SNMPD_CALLBACK_ACM_CHECK, &view_parms); 01265 return view_parms.errorcode; 01266 } 01267 return VACM_NOSECNAME; 01268 } 01269 01270 /* 01271 * check_acces: determines if a given snmp_pdu is ever going to be 01272 * allowed to do anynthing or if it's not going to ever be 01273 * authenticated. 01274 */ 01275 int 01276 check_access(netsnmp_pdu *pdu) 01277 { /* IN - pdu being checked */ 01278 struct view_parameters view_parms; 01279 view_parms.pdu = pdu; 01280 view_parms.name = 0; 01281 view_parms.namelen = 0; 01282 view_parms.errorcode = 0; 01283 view_parms.check_subtree = 0; 01284 01285 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 01286 /* Enable bypassing of view-based access control */ 01287 return 0; 01288 } 01289 01290 switch (pdu->version) { 01291 #ifndef NETSNMP_DISABLE_SNMPV1 01292 case SNMP_VERSION_1: 01293 #endif 01294 #ifndef NETSNMP_DISABLE_SNMPV2C 01295 case SNMP_VERSION_2c: 01296 #endif 01297 case SNMP_VERSION_3: 01298 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01299 SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms); 01300 return view_parms.errorcode; 01301 } 01302 return 1; 01303 } 01304 01312 int 01313 netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen) 01314 { /* IN - pdu being checked */ 01315 struct view_parameters view_parms; 01316 view_parms.pdu = pdu; 01317 view_parms.name = name; 01318 view_parms.namelen = namelen; 01319 view_parms.errorcode = 0; 01320 view_parms.check_subtree = 1; 01321 01322 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 01323 /* Enable bypassing of view-based access control */ 01324 return 0; 01325 } 01326 01327 switch (pdu->version) { 01328 #ifndef NETSNMP_DISABLE_SNMPV1 01329 case SNMP_VERSION_1: 01330 #endif 01331 #ifndef NETSNMP_DISABLE_SNMPV2C 01332 case SNMP_VERSION_2c: 01333 #endif 01334 case SNMP_VERSION_3: 01335 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01336 SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms); 01337 return view_parms.errorcode; 01338 } 01339 return 1; 01340 } 01341 01342 #define SUBTREE_DEFAULT_CACHE_SIZE 8 01343 #define SUBTREE_MAX_CACHE_SIZE 32 01344 int lookup_cache_size = 0; /*enabled later after registrations are loaded */ 01345 01346 typedef struct lookup_cache_s { 01347 netsnmp_subtree *next; 01348 netsnmp_subtree *previous; 01349 } lookup_cache; 01350 01351 typedef struct lookup_cache_context_s { 01352 char *context; 01353 struct lookup_cache_context_s *next; 01354 int thecachecount; 01355 int currentpos; 01356 lookup_cache cache[SUBTREE_MAX_CACHE_SIZE]; 01357 } lookup_cache_context; 01358 01359 static lookup_cache_context *thecontextcache = NULL; 01360 01372 void 01373 netsnmp_set_lookup_cache_size(int newsize) { 01374 if (newsize < 0) 01375 lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE; 01376 else if (newsize < SUBTREE_MAX_CACHE_SIZE) 01377 lookup_cache_size = newsize; 01378 else 01379 lookup_cache_size = SUBTREE_MAX_CACHE_SIZE; 01380 } 01381 01385 int 01386 netsnmp_get_lookup_cache_size(void) { 01387 return lookup_cache_size; 01388 } 01389 01390 NETSNMP_STATIC_INLINE lookup_cache_context * 01391 get_context_lookup_cache(const char *context) { 01392 lookup_cache_context *ptr; 01393 if (!context) 01394 context = ""; 01395 01396 for(ptr = thecontextcache; ptr; ptr = ptr->next) { 01397 if (strcmp(ptr->context, context) == 0) 01398 break; 01399 } 01400 if (!ptr) { 01401 if (netsnmp_subtree_find_first(context)) { 01402 ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context); 01403 ptr->next = thecontextcache; 01404 ptr->context = strdup(context); 01405 thecontextcache = ptr; 01406 } else { 01407 return NULL; 01408 } 01409 } 01410 return ptr; 01411 } 01412 01413 NETSNMP_STATIC_INLINE void 01414 lookup_cache_add(const char *context, 01415 netsnmp_subtree *next, netsnmp_subtree *previous) { 01416 lookup_cache_context *cptr; 01417 01418 if ((cptr = get_context_lookup_cache(context)) == NULL) 01419 return; 01420 01421 if (cptr->thecachecount < lookup_cache_size) 01422 cptr->thecachecount++; 01423 01424 cptr->cache[cptr->currentpos].next = next; 01425 cptr->cache[cptr->currentpos].previous = previous; 01426 01427 if (++cptr->currentpos >= lookup_cache_size) 01428 cptr->currentpos = 0; 01429 } 01430 01431 NETSNMP_STATIC_INLINE void 01432 lookup_cache_replace(lookup_cache *ptr, 01433 netsnmp_subtree *next, netsnmp_subtree *previous) { 01434 01435 ptr->next = next; 01436 ptr->previous = previous; 01437 } 01438 01439 NETSNMP_STATIC_INLINE lookup_cache * 01440 lookup_cache_find(const char *context, oid *name, size_t name_len, 01441 int *retcmp) { 01442 lookup_cache_context *cptr; 01443 lookup_cache *ret = NULL; 01444 int cmp; 01445 int i; 01446 01447 if ((cptr = get_context_lookup_cache(context)) == NULL) 01448 return NULL; 01449 01450 for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) { 01451 if (cptr->cache[i].previous->start_a) 01452 cmp = snmp_oid_compare(name, name_len, 01453 cptr->cache[i].previous->start_a, 01454 cptr->cache[i].previous->start_len); 01455 else 01456 cmp = 1; 01457 if (cmp >= 0) { 01458 *retcmp = cmp; 01459 ret = &(cptr->cache[i]); 01460 } 01461 } 01462 return ret; 01463 } 01464 01465 NETSNMP_STATIC_INLINE void 01466 invalidate_lookup_cache(const char *context) { 01467 lookup_cache_context *cptr; 01468 if ((cptr = get_context_lookup_cache(context)) != NULL) { 01469 cptr->thecachecount = 0; 01470 cptr->currentpos = 0; 01471 } 01472 } 01473 01474 netsnmp_subtree * 01475 netsnmp_subtree_find_prev(oid *name, size_t len, netsnmp_subtree *subtree, 01476 const char *context_name) 01477 { 01478 lookup_cache *lookup_cache = NULL; 01479 netsnmp_subtree *myptr = NULL, *previous = NULL; 01480 int cmp = 1; 01481 size_t ll_off = 0; 01482 01483 if (subtree) { 01484 myptr = subtree; 01485 } else { 01486 /* look through everything */ 01487 if (lookup_cache_size) { 01488 lookup_cache = lookup_cache_find(context_name, name, len, &cmp); 01489 if (lookup_cache) { 01490 myptr = lookup_cache->next; 01491 previous = lookup_cache->previous; 01492 } 01493 if (!myptr) 01494 myptr = netsnmp_subtree_find_first(context_name); 01495 } else { 01496 myptr = netsnmp_subtree_find_first(context_name); 01497 } 01498 } 01499 01500 /* 01501 * this optimization causes a segfault on sf cf alpha-linux1. 01502 * ifdef out until someone figures out why and fixes it. xxx-rks 20051117 01503 */ 01504 #ifndef __alpha 01505 #define WTEST_OPTIMIZATION 1 01506 #endif 01507 #ifdef WTEST_OPTIMIZATION 01508 DEBUGMSGTL(("wtest","oid in: ")); 01509 DEBUGMSGOID(("wtest", name, len)); 01510 DEBUGMSG(("wtest","\n")); 01511 #endif 01512 for (; myptr != NULL; previous = myptr, myptr = myptr->next) { 01513 #ifdef WTEST_OPTIMIZATION 01514 /* Compare the incoming oid with the linked list. If we have 01515 results of previous compares, its faster to make sure the 01516 length we differed in the last check is greater than the 01517 length between this pointer and the last then we don't need 01518 to actually perform a comparison */ 01519 DEBUGMSGTL(("wtest","oid cmp: ")); 01520 DEBUGMSGOID(("wtest", myptr->start_a, myptr->start_len)); 01521 DEBUGMSG(("wtest"," --- off = %d, in off = %d test = %d\n", 01522 myptr->oid_off, ll_off, 01523 !(ll_off && myptr->oid_off && 01524 myptr->oid_off > ll_off))); 01525 if (!(ll_off && myptr->oid_off && myptr->oid_off > ll_off) && 01526 netsnmp_oid_compare_ll(name, len, 01527 myptr->start_a, myptr->start_len, 01528 &ll_off) < 0) { 01529 #else 01530 if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) { 01531 #endif 01532 if (lookup_cache_size && previous && cmp) { 01533 if (lookup_cache) { 01534 lookup_cache_replace(lookup_cache, myptr, previous); 01535 } else { 01536 lookup_cache_add(context_name, myptr, previous); 01537 } 01538 } 01539 return previous; 01540 } 01541 } 01542 return previous; 01543 } 01544 01545 netsnmp_subtree * 01546 netsnmp_subtree_find_next(oid *name, size_t len, 01547 netsnmp_subtree *subtree, const char *context_name) 01548 { 01549 netsnmp_subtree *myptr = NULL; 01550 01551 myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name); 01552 01553 if (myptr != NULL) { 01554 myptr = myptr->next; 01555 while (myptr != NULL && (myptr->variables == NULL || 01556 myptr->variables_len == 0)) { 01557 myptr = myptr->next; 01558 } 01559 return myptr; 01560 } else if (subtree != NULL && snmp_oid_compare(name, len, 01561 subtree->start_a, subtree->start_len) < 0) { 01562 return subtree; 01563 } else { 01564 return NULL; 01565 } 01566 } 01567 01568 netsnmp_subtree * 01569 netsnmp_subtree_find(oid *name, size_t len, netsnmp_subtree *subtree, 01570 const char *context_name) 01571 { 01572 netsnmp_subtree *myptr; 01573 01574 myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name); 01575 if (myptr && myptr->end_a && 01576 snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) { 01577 return myptr; 01578 } 01579 01580 return NULL; 01581 } 01582 01583 netsnmp_session * 01584 get_session_for_oid(oid *name, size_t len, const char *context_name) 01585 { 01586 netsnmp_subtree *myptr; 01587 01588 myptr = netsnmp_subtree_find_prev(name, len, 01589 netsnmp_subtree_find_first(context_name), 01590 context_name); 01591 01592 while (myptr && myptr->variables == NULL) { 01593 myptr = myptr->next; 01594 } 01595 01596 if (myptr == NULL) { 01597 return NULL; 01598 } else { 01599 return myptr->session; 01600 } 01601 } 01602 01603 void 01604 setup_tree(void) 01605 { 01606 oid ccitt[1] = { 0 }; 01607 oid iso[1] = { 1 }; 01608 oid joint_ccitt_iso[1] = { 2 }; 01609 01610 #ifdef USING_AGENTX_SUBAGENT_MODULE 01611 int role = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 01612 NETSNMP_DS_AGENT_ROLE); 01613 01614 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 01615 MASTER_AGENT); 01616 #endif 01617 01618 /* 01619 * we need to have the oid's in the heap, that we can *free* it for every case, 01620 * thats the purpose of the duplicate_objid's 01621 */ 01622 netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1); 01623 netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1); 01624 netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1); 01625 01626 #ifdef USING_AGENTX_SUBAGENT_MODULE 01627 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 01628 role); 01629 #endif 01630 } 01631 01632 int 01633 remove_tree_entry (oid *name, size_t len) { 01634 01635 netsnmp_subtree *sub = NULL; 01636 01637 if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) { 01638 return MIB_NO_SUCH_REGISTRATION; 01639 } 01640 01641 return unregister_mib_context(name, len, sub->priority, 01642 sub->range_subid, sub->range_ubound, ""); 01643 01644 } 01645 01646 01647 void 01648 shutdown_tree(void) { 01649 oid ccitt[1] = { 0 }; 01650 oid iso[1] = { 1 }; 01651 oid joint_ccitt_iso[1] = { 2 }; 01652 01653 DEBUGMSGTL(("agent_registry", "shut down tree\n")); 01654 01655 remove_tree_entry(joint_ccitt_iso, 1); 01656 remove_tree_entry(iso, 1); 01657 remove_tree_entry(ccitt, 1); 01658 01659 } 01660 01661 void 01662 clear_subtree (netsnmp_subtree *sub) { 01663 01664 netsnmp_subtree *nxt; 01665 01666 if (sub == NULL) 01667 return; 01668 01669 for(nxt = sub; nxt;) { 01670 if (nxt->children != NULL) { 01671 clear_subtree(nxt->children); 01672 } 01673 sub = nxt; 01674 nxt = nxt->next; 01675 netsnmp_subtree_free(sub); 01676 } 01677 01678 } 01679 01680 void 01681 clear_lookup_cache(void) { 01682 01683 lookup_cache_context *ptr = NULL, *next = NULL; 01684 01685 ptr = thecontextcache; 01686 while (ptr) { 01687 next = ptr->next; 01688 SNMP_FREE(ptr->context); 01689 SNMP_FREE(ptr); 01690 ptr = next; 01691 } 01692 thecontextcache = NULL; /* !!! */ 01693 } 01694 01695 void 01696 clear_context(void) { 01697 01698 subtree_context_cache *ptr = NULL, *next = NULL; 01699 01700 DEBUGMSGTL(("agent_registry", "clear context\n")); 01701 01702 ptr = get_top_context_cache(); 01703 while (ptr) { 01704 next = ptr->next; 01705 01706 if (ptr->first_subtree) { 01707 clear_subtree(ptr->first_subtree); 01708 } 01709 01710 SNMP_FREE(ptr->context_name); 01711 SNMP_FREE(ptr); 01712 01713 ptr = next; 01714 } 01715 context_subtrees = NULL; /* !!! */ 01716 clear_lookup_cache(); 01717 } 01718 01719 extern void dump_idx_registry(void); 01720 void 01721 dump_registry(void) 01722 { 01723 struct variable *vp = NULL; 01724 netsnmp_subtree *myptr, *myptr2; 01725 u_char *s = NULL, *e = NULL, *v = NULL; 01726 size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0; 01727 int i = 0; 01728 01729 if ((s = (u_char *) calloc(sl, 1)) != NULL && 01730 (e = (u_char *) calloc(sl, 1)) != NULL && 01731 (v = (u_char *) calloc(sl, 1)) != NULL) { 01732 01733 subtree_context_cache *ptr; 01734 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 01735 printf("Subtrees for Context: %s\n", ptr->context_name); 01736 for (myptr = ptr->first_subtree; myptr != NULL; 01737 myptr = myptr->next) { 01738 sl_o = el_o = vl_o = 0; 01739 01740 if (!sprint_realloc_objid(&s, &sl, &sl_o, 1, 01741 myptr->start_a, 01742 myptr->start_len)) { 01743 break; 01744 } 01745 if (!sprint_realloc_objid(&e, &el, &el_o, 1, 01746 myptr->end_a, 01747 myptr->end_len)) { 01748 break; 01749 } 01750 01751 if (myptr->variables) { 01752 printf("%02x ( %s - %s ) [", myptr->flags, s, e); 01753 for (i = 0, vp = myptr->variables; 01754 i < myptr->variables_len; i++) { 01755 vl_o = 0; 01756 if (!sprint_realloc_objid 01757 (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) { 01758 break; 01759 } 01760 printf("%s, ", v); 01761 vp = (struct variable *) ((char *) vp + 01762 myptr->variables_width); 01763 } 01764 printf("]\n"); 01765 } else { 01766 printf("%02x %s - %s \n", myptr->flags, s, e); 01767 } 01768 for (myptr2 = myptr; myptr2 != NULL; 01769 myptr2 = myptr2->children) { 01770 if (myptr2->label_a && myptr2->label_a[0]) { 01771 if (strcmp(myptr2->label_a, "old_api") == 0) { 01772 struct variable *vp = 01773 myptr2->reginfo->handler->myvoid; 01774 01775 sprint_realloc_objid(&s, &sl, &sl_o, 1, 01776 vp->name, vp->namelen); 01777 printf("\t%s[%s] %p var %s\n", myptr2->label_a, 01778 myptr2->reginfo->handlerName ? myptr2-> 01779 reginfo->handlerName : "no-name", 01780 myptr2->reginfo, s); 01781 } else { 01782 printf("\t%s %s %p\n", myptr2->label_a, 01783 myptr2->reginfo->handlerName ? myptr2-> 01784 reginfo-> 01785 handlerName : "no-handler-name", 01786 myptr2->reginfo); 01787 } 01788 } 01789 } 01790 } 01791 } 01792 } 01793 01794 if (s != NULL) { 01795 SNMP_FREE(s); 01796 } 01797 if (e != NULL) { 01798 SNMP_FREE(e); 01799 } 01800 if (v != NULL) { 01801 SNMP_FREE(v); 01802 } 01803 01804 dump_idx_registry(); 01805 } 01806 01807 int external_signal_scheduled[NUM_EXTERNAL_SIGS]; 01808 void (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int); 01809 01810 #ifndef WIN32 01811 01812 /* 01813 * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines 01814 * below for every single that might be handled by register_signal(). 01815 */ 01816 01817 RETSIGTYPE 01818 agent_SIGCHLD_handler(int sig) 01819 { 01820 external_signal_scheduled[SIGCHLD]++; 01821 #ifndef HAVE_SIGACTION 01822 /* 01823 * signal() sucks. It *might* have SysV semantics, which means that 01824 * * a signal handler is reset once it gets called. Ensure that it 01825 * * remains active. 01826 */ 01827 signal(SIGCHLD, agent_SIGCHLD_handler); 01828 #endif 01829 } 01830 01831 int 01832 register_signal(int sig, void (*func) (int)) 01833 { 01834 01835 switch (sig) { 01836 #if defined(SIGCHLD) 01837 case SIGCHLD: 01838 #ifdef HAVE_SIGACTION 01839 { 01840 static struct sigaction act; 01841 act.sa_handler = agent_SIGCHLD_handler; 01842 sigemptyset(&act.sa_mask); 01843 act.sa_flags = 0; 01844 sigaction(SIGCHLD, &act, NULL); 01845 } 01846 #else 01847 signal(SIGCHLD, agent_SIGCHLD_handler); 01848 #endif 01849 break; 01850 #endif 01851 default: 01852 snmp_log(LOG_CRIT, 01853 "register_signal: signal %d cannot be handled\n", sig); 01854 return SIG_REGISTRATION_FAILED; 01855 } 01856 01857 external_signal_handler[sig] = func; 01858 external_signal_scheduled[sig] = 0; 01859 01860 DEBUGMSGTL(("register_signal", "registered signal %d\n", sig)); 01861 return SIG_REGISTERED_OK; 01862 } 01863 01864 int 01865 unregister_signal(int sig) 01866 { 01867 signal(sig, SIG_DFL); 01868 DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig)); 01869 return SIG_UNREGISTERED_OK; 01870 } 01871 01872 #endif /* !WIN32 */ 01873
1.7.6.1