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