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 netsnmp_assert(!"registration != duplicate"); /* always false */ 00536 return MIB_DUPLICATE_REGISTRATION; 00537 } 00538 00539 if (prev) { 00540 prev->children = new_sub; 00541 new_sub->children = next; 00542 netsnmp_subtree_change_prev(new_sub, prev->prev); 00543 netsnmp_subtree_change_next(new_sub, prev->next); 00544 } else { 00545 new_sub->children = next; 00546 netsnmp_subtree_change_prev(new_sub, next->prev); 00547 netsnmp_subtree_change_next(new_sub, next->next); 00548 00549 for (next = new_sub->next; next != NULL;next = next->children){ 00550 netsnmp_subtree_change_prev(next, new_sub); 00551 } 00552 00553 for (prev = new_sub->prev; prev != NULL;prev = prev->children){ 00554 netsnmp_subtree_change_next(prev, new_sub); 00555 } 00556 } 00557 break; 00558 00559 case 1: 00560 /* New subtree contains the existing one. */ 00561 new2 = netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len); 00562 res = netsnmp_subtree_load(new_sub, context_name); 00563 if (res != MIB_REGISTERED_OK) { 00564 netsnmp_subtree_free(new2); 00565 return res; 00566 } 00567 return netsnmp_subtree_load(new2, context_name); 00568 } 00569 } 00570 return 0; 00571 } 00572 00573 /* 00574 * Note: reginfo will be freed on failures 00575 */ 00576 int 00577 netsnmp_register_mib(const char *moduleName, 00578 struct variable *var, 00579 size_t varsize, 00580 size_t numvars, 00581 oid * mibloc, 00582 size_t mibloclen, 00583 int priority, 00584 int range_subid, 00585 oid range_ubound, 00586 netsnmp_session * ss, 00587 const char *context, 00588 int timeout, 00589 int flags, 00590 netsnmp_handler_registration *reginfo, 00591 int perform_callback) 00592 { 00593 netsnmp_subtree *subtree, *sub2; 00594 int res, i; 00595 struct register_parameters reg_parms; 00596 int old_lookup_cache_val = netsnmp_get_lookup_cache_size(); 00597 00598 if (moduleName == NULL || 00599 mibloc == NULL) { 00600 /* Shouldn't happen ??? */ 00601 netsnmp_handler_registration_free(reginfo); 00602 return MIB_REGISTRATION_FAILED; 00603 } 00604 subtree = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree)); 00605 if (subtree == NULL) { 00606 netsnmp_handler_registration_free(reginfo); 00607 return MIB_REGISTRATION_FAILED; 00608 } 00609 00610 DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName)); 00611 DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid, 00612 range_ubound)); 00613 DEBUGMSG(("register_mib", " with context \"%s\"\n", 00614 SNMP_STRORNULL(context))); 00615 00616 /* 00617 * verify that the passed context is equal to the context 00618 * in the reginfo. 00619 * (which begs the question, why do we have both? It appears that the 00620 * reginfo item didn't appear til 5.2) 00621 */ 00622 if( ((NULL == context) && (NULL != reginfo->contextName)) || 00623 ((NULL != context) && (NULL == reginfo->contextName)) || 00624 ( ((NULL != context) && (NULL != reginfo->contextName)) && 00625 (0 != strcmp(context, reginfo->contextName))) ) { 00626 snmp_log(LOG_WARNING,"context passed during registration does not " 00627 "equal the reginfo contextName! ('%s' != '%s')\n", 00628 context, reginfo->contextName); 00629 netsnmp_assert(!"register context == reginfo->contextName"); /* always false */ 00630 } 00631 00632 /* Create the new subtree node being registered. */ 00633 00634 subtree->reginfo = reginfo; 00635 subtree->name_a = snmp_duplicate_objid(mibloc, mibloclen); 00636 subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen); 00637 subtree->end_a = snmp_duplicate_objid(mibloc, mibloclen); 00638 subtree->label_a = strdup(moduleName); 00639 if (subtree->name_a == NULL || subtree->start_a == NULL || 00640 subtree->end_a == NULL || subtree->label_a == NULL) { 00641 netsnmp_subtree_free(subtree); /* also frees reginfo */ 00642 return MIB_REGISTRATION_FAILED; 00643 } 00644 subtree->namelen = (u_char)mibloclen; 00645 subtree->start_len = (u_char)mibloclen; 00646 subtree->end_len = (u_char)mibloclen; 00647 subtree->end_a[mibloclen - 1]++; 00648 00649 if (var != NULL) { 00650 subtree->variables = (struct variable *)malloc(varsize*numvars); 00651 if (subtree->variables == NULL) { 00652 netsnmp_subtree_free(subtree); /* also frees reginfo */ 00653 return MIB_REGISTRATION_FAILED; 00654 } 00655 memcpy(subtree->variables, var, numvars*varsize); 00656 subtree->variables_len = numvars; 00657 subtree->variables_width = varsize; 00658 } 00659 subtree->priority = priority; 00660 subtree->timeout = timeout; 00661 subtree->range_subid = range_subid; 00662 subtree->range_ubound = range_ubound; 00663 subtree->session = ss; 00664 subtree->flags = (u_char)flags; /* used to identify instance oids */ 00665 subtree->flags |= SUBTREE_ATTACHED; 00666 subtree->global_cacheid = reginfo->global_cacheid; 00667 00668 netsnmp_set_lookup_cache_size(0); 00669 res = netsnmp_subtree_load(subtree, context); 00670 00671 /* If registering a range, use the first subtree as a template for the 00672 rest of the range. */ 00673 00674 if (res == MIB_REGISTERED_OK && range_subid != 0) { 00675 for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) { 00676 sub2 = netsnmp_subtree_deepcopy(subtree); 00677 00678 if (sub2 == NULL) { 00679 unregister_mib_context(mibloc, mibloclen, priority, 00680 range_subid, range_ubound, context); 00681 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00682 invalidate_lookup_cache(context); 00683 return MIB_REGISTRATION_FAILED; 00684 } 00685 00686 sub2->name_a[range_subid - 1] = i; 00687 sub2->start_a[range_subid - 1] = i; 00688 sub2->end_a[range_subid - 1] = i; /* XXX - ???? */ 00689 if (range_subid == (int)mibloclen) 00690 ++sub2->end_a[range_subid - 1]; 00691 res = netsnmp_subtree_load(sub2, context); 00692 sub2->flags |= SUBTREE_ATTACHED; 00693 if (res != MIB_REGISTERED_OK) { 00694 unregister_mib_context(mibloc, mibloclen, priority, 00695 range_subid, range_ubound, context); 00696 netsnmp_subtree_free(sub2); 00697 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00698 invalidate_lookup_cache(context); 00699 return res; 00700 } 00701 } 00702 } else if (res == MIB_DUPLICATE_REGISTRATION || 00703 res == MIB_REGISTRATION_FAILED) { 00704 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00705 invalidate_lookup_cache(context); 00706 netsnmp_subtree_free(subtree); 00707 return res; 00708 } 00709 00710 /* 00711 * mark the MIB as detached, if there's no master agent present as of now 00712 */ 00713 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 00714 NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) { 00715 extern struct snmp_session *main_session; 00716 if (main_session == NULL) { 00717 register_mib_detach_node(subtree); 00718 } 00719 } 00720 00721 if (res == MIB_REGISTERED_OK && perform_callback) { 00722 memset(®_parms, 0x0, sizeof(reg_parms)); 00723 reg_parms.name = mibloc; 00724 reg_parms.namelen = mibloclen; 00725 reg_parms.priority = priority; 00726 reg_parms.range_subid = range_subid; 00727 reg_parms.range_ubound = range_ubound; 00728 reg_parms.timeout = timeout; 00729 reg_parms.flags = (u_char) flags; 00730 reg_parms.contextName = context; 00731 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00732 SNMPD_CALLBACK_REGISTER_OID, ®_parms); 00733 } 00734 00735 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00736 invalidate_lookup_cache(context); 00737 return res; 00738 } 00739 00740 /* 00741 * Reattach a particular node. 00742 */ 00743 00744 static void 00745 register_mib_reattach_node(netsnmp_subtree *s) 00746 { 00747 if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) { 00748 struct register_parameters reg_parms; 00749 /* 00750 * only do registrations that are not the top level nodes 00751 */ 00752 memset(®_parms, 0x0, sizeof(reg_parms)); 00753 00754 /* 00755 * XXX: do this better 00756 */ 00757 reg_parms.name = s->name_a; 00758 reg_parms.namelen = s->namelen; 00759 reg_parms.priority = s->priority; 00760 reg_parms.range_subid = s->range_subid; 00761 reg_parms.range_ubound = s->range_ubound; 00762 reg_parms.timeout = s->timeout; 00763 reg_parms.flags = s->flags; 00764 if ((NULL != s->reginfo) && (NULL != s->reginfo->contextName)) 00765 reg_parms.contextName = s->reginfo->contextName; 00766 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00767 SNMPD_CALLBACK_REGISTER_OID, ®_parms); 00768 s->flags |= SUBTREE_ATTACHED; 00769 } 00770 } 00771 00772 /* 00773 * Call callbacks to reattach all our nodes. 00774 */ 00775 00776 void 00777 register_mib_reattach(void) 00778 { 00779 netsnmp_subtree *s, *t; 00780 subtree_context_cache *ptr; 00781 00782 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 00783 for (s = ptr->first_subtree; s != NULL; s = s->next) { 00784 register_mib_reattach_node(s); 00785 for (t = s->children; t != NULL; t = t->children) { 00786 register_mib_reattach_node(t); 00787 } 00788 } 00789 } 00790 } 00791 00792 /* 00793 * Mark a node as detached. 00794 */ 00795 00796 static void 00797 register_mib_detach_node(netsnmp_subtree *s) 00798 { 00799 if (s != NULL) { 00800 s->flags = s->flags & ~SUBTREE_ATTACHED; 00801 } 00802 } 00803 00804 /* 00805 * Mark all our registered OIDs as detached. This is only really 00806 * useful for subagent protocols, when a connection is lost or 00807 * something. 00808 */ 00809 00810 void 00811 register_mib_detach(void) 00812 { 00813 netsnmp_subtree *s, *t; 00814 subtree_context_cache *ptr; 00815 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 00816 for (s = ptr->first_subtree; s != NULL; s = s->next) { 00817 register_mib_detach_node(s); 00818 for (t = s->children; t != NULL; t = t->children) { 00819 register_mib_detach_node(t); 00820 } 00821 } 00822 } 00823 } 00824 00825 int 00826 register_mib_context(const char *moduleName, 00827 struct variable *var, 00828 size_t varsize, 00829 size_t numvars, 00830 oid * mibloc, 00831 size_t mibloclen, 00832 int priority, 00833 int range_subid, 00834 oid range_ubound, 00835 netsnmp_session * ss, 00836 const char *context, int timeout, int flags) 00837 { 00838 return netsnmp_register_old_api(moduleName, var, varsize, numvars, 00839 mibloc, mibloclen, priority, 00840 range_subid, range_ubound, ss, context, 00841 timeout, flags); 00842 } 00843 00844 int 00845 register_mib_range(const char *moduleName, 00846 struct variable *var, 00847 size_t varsize, 00848 size_t numvars, 00849 oid * mibloc, 00850 size_t mibloclen, 00851 int priority, 00852 int range_subid, oid range_ubound, netsnmp_session * ss) 00853 { 00854 return register_mib_context(moduleName, var, varsize, numvars, 00855 mibloc, mibloclen, priority, 00856 range_subid, range_ubound, ss, "", -1, 0); 00857 } 00858 00859 int 00860 register_mib_priority(const char *moduleName, 00861 struct variable *var, 00862 size_t varsize, 00863 size_t numvars, 00864 oid * mibloc, size_t mibloclen, int priority) 00865 { 00866 return register_mib_range(moduleName, var, varsize, numvars, 00867 mibloc, mibloclen, priority, 0, 0, NULL); 00868 } 00869 00870 int 00871 register_mib(const char *moduleName, 00872 struct variable *var, 00873 size_t varsize, 00874 size_t numvars, oid * mibloc, size_t mibloclen) 00875 { 00876 return register_mib_priority(moduleName, var, varsize, numvars, 00877 mibloc, mibloclen, DEFAULT_MIB_PRIORITY); 00878 } 00879 00880 void 00881 netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev, const char *context) 00882 { 00883 netsnmp_subtree *ptr; 00884 00885 DEBUGMSGTL(("register_mib", "unload(")); 00886 if (sub != NULL) { 00887 DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len)); 00888 } else { 00889 DEBUGMSG(("register_mib", "[NIL]")); 00890 } 00891 DEBUGMSG(("register_mib", ", ")); 00892 if (prev != NULL) { 00893 DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len)); 00894 } else { 00895 DEBUGMSG(("register_mib", "[NIL]")); 00896 } 00897 DEBUGMSG(("register_mib", ")\n")); 00898 00899 if (prev != NULL) { /* non-leading entries are easy */ 00900 prev->children = sub->children; 00901 invalidate_lookup_cache(context); 00902 return; 00903 } 00904 /* 00905 * otherwise, we need to amend our neighbours as well 00906 */ 00907 00908 if (sub->children == NULL) { /* just remove this node completely */ 00909 for (ptr = sub->prev; ptr; ptr = ptr->children) { 00910 netsnmp_subtree_change_next(ptr, sub->next); 00911 } 00912 for (ptr = sub->next; ptr; ptr = ptr->children) { 00913 netsnmp_subtree_change_prev(ptr, sub->prev); 00914 } 00915 00916 if (sub->prev == NULL) { 00917 netsnmp_subtree_replace_first(sub->next, context); 00918 } 00919 00920 } else { 00921 for (ptr = sub->prev; ptr; ptr = ptr->children) 00922 netsnmp_subtree_change_next(ptr, sub->children); 00923 for (ptr = sub->next; ptr; ptr = ptr->children) 00924 netsnmp_subtree_change_prev(ptr, sub->children); 00925 00926 if (sub->prev == NULL) { 00927 netsnmp_subtree_replace_first(sub->children, context); 00928 } 00929 } 00930 invalidate_lookup_cache(context); 00931 } 00932 00962 int 00963 unregister_mib_context(oid * name, size_t len, int priority, 00964 int range_subid, oid range_ubound, 00965 const char *context) 00966 { 00967 netsnmp_subtree *list, *myptr; 00968 netsnmp_subtree *prev, *child, *next; /* loop through children */ 00969 struct register_parameters reg_parms; 00970 int old_lookup_cache_val = netsnmp_get_lookup_cache_size(); 00971 netsnmp_set_lookup_cache_size(0); 00972 00973 DEBUGMSGTL(("register_mib", "unregistering ")); 00974 DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound)); 00975 DEBUGMSG(("register_mib", "\n")); 00976 00977 list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context), 00978 context); 00979 if (list == NULL) { 00980 return MIB_NO_SUCH_REGISTRATION; 00981 } 00982 00983 for (child = list, prev = NULL; child != NULL; 00984 prev = child, child = child->children) { 00985 if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 && 00986 child->priority == priority) { 00987 break; /* found it */ 00988 } 00989 } 00990 00991 if (child == NULL) { 00992 return MIB_NO_SUCH_REGISTRATION; 00993 } 00994 00995 netsnmp_subtree_unload(child, prev, context); 00996 myptr = child; /* remember this for later */ 00997 00998 /* 00999 * Now handle any occurances in the following subtrees, 01000 * as a result of splitting this range. Due to the 01001 * nature of the way such splits work, the first 01002 * subtree 'slice' that doesn't refer to the given 01003 * name marks the end of the original region. 01004 * 01005 * This should also serve to register ranges. 01006 */ 01007 01008 for (list = myptr->next; list != NULL; list = next) { 01009 next = list->next; /* list gets freed sometimes; cache next */ 01010 for (child = list, prev = NULL; child != NULL; 01011 prev = child, child = child->children) { 01012 if ((netsnmp_oid_equals(child->name_a, child->namelen, 01013 name, len) == 0) && 01014 (child->priority == priority)) { 01015 netsnmp_subtree_unload(child, prev, context); 01016 netsnmp_subtree_free(child); 01017 break; 01018 } 01019 } 01020 if (child == NULL) /* Didn't find the given name */ 01021 break; 01022 } 01023 01024 memset(®_parms, 0x0, sizeof(reg_parms)); 01025 reg_parms.name = name; 01026 reg_parms.namelen = len; 01027 reg_parms.priority = priority; 01028 reg_parms.range_subid = range_subid; 01029 reg_parms.range_ubound = range_ubound; 01030 reg_parms.flags = 0x00; /* this is okay I think */ 01031 reg_parms.contextName = context; 01032 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01033 SNMPD_CALLBACK_UNREGISTER_OID, ®_parms); 01034 01035 netsnmp_subtree_free(myptr); 01036 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 01037 invalidate_lookup_cache(context); 01038 return MIB_UNREGISTERED_OK; 01039 } 01040 01041 int 01042 netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority, 01043 int var_subid, oid range_ubound, 01044 const char *context) 01045 { 01046 netsnmp_subtree *list, *myptr, *futureptr; 01047 netsnmp_subtree *prev, *child; /* loop through children */ 01048 struct register_parameters reg_parms; 01049 oid range_lbound = name[var_subid - 1]; 01050 01051 DEBUGMSGTL(("register_mib", "unregistering ")); 01052 DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound)); 01053 DEBUGMSG(("register_mib", "\n")); 01054 01055 for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) { 01056 list = netsnmp_subtree_find(name, len, 01057 netsnmp_subtree_find_first(context), context); 01058 01059 if (list == NULL) { 01060 continue; 01061 } 01062 01063 for (child = list, prev = NULL; child != NULL; 01064 prev = child, child = child->children) { 01065 01066 if (netsnmp_oid_equals(child->name_a, child->namelen, 01067 name, len) == 0 && 01068 (child->priority == priority)) { 01069 break; /* found it */ 01070 } 01071 } 01072 01073 if (child == NULL) { 01074 continue; 01075 } 01076 01077 netsnmp_subtree_unload(child, prev, context); 01078 myptr = child; /* remember this for later */ 01079 01080 for (list = myptr->next; list != NULL; list = futureptr) { 01081 /* remember the next spot in the list in case we free this node */ 01082 futureptr = list->next; 01083 01084 /* check each child */ 01085 for (child = list, prev = NULL; child != NULL; 01086 prev = child, child = child->children) { 01087 01088 if (netsnmp_oid_equals(child->name_a, child->namelen, 01089 name, len) == 0 && 01090 (child->priority == priority)) { 01091 netsnmp_subtree_unload(child, prev, context); 01092 netsnmp_subtree_free(child); 01093 break; 01094 } 01095 } 01096 01097 /* XXX: wjh: not sure why we're bailing here */ 01098 if (child == NULL) { /* Didn't find the given name */ 01099 break; 01100 } 01101 } 01102 netsnmp_subtree_free(myptr); 01103 } 01104 01105 name[var_subid - 1] = range_lbound; 01106 memset(®_parms, 0x0, sizeof(reg_parms)); 01107 reg_parms.name = name; 01108 reg_parms.namelen = len; 01109 reg_parms.priority = priority; 01110 reg_parms.range_subid = var_subid; 01111 reg_parms.range_ubound = range_ubound; 01112 reg_parms.flags = 0x00; /* this is okay I think */ 01113 reg_parms.contextName = context; 01114 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01115 SNMPD_CALLBACK_UNREGISTER_OID, ®_parms); 01116 01117 return 0; 01118 } 01119 01120 int 01121 unregister_mib_range(oid * name, size_t len, int priority, 01122 int range_subid, oid range_ubound) 01123 { 01124 return unregister_mib_context(name, len, priority, range_subid, 01125 range_ubound, ""); 01126 } 01127 01128 int 01129 unregister_mib_priority(oid * name, size_t len, int priority) 01130 { 01131 return unregister_mib_range(name, len, priority, 0, 0); 01132 } 01133 01134 int 01135 unregister_mib(oid * name, size_t len) 01136 { 01137 return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY); 01138 } 01139 01140 void 01141 unregister_mibs_by_session(netsnmp_session * ss) 01142 { 01143 netsnmp_subtree *list, *list2; 01144 netsnmp_subtree *child, *prev, *next_child; 01145 struct register_parameters rp; 01146 subtree_context_cache *contextptr; 01147 01148 DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n", 01149 ss, (ss && ss->contextName) ? ss->contextName : "[NIL]")); 01150 01151 for (contextptr = get_top_context_cache(); contextptr != NULL; 01152 contextptr = contextptr->next) { 01153 for (list = contextptr->first_subtree; list != NULL; list = list2) { 01154 list2 = list->next; 01155 01156 for (child = list, prev = NULL; child != NULL; child = next_child){ 01157 next_child = child->children; 01158 01159 if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && 01160 child->session == ss) || 01161 (!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session && 01162 child->session->subsession == ss)) { 01163 01164 memset(&rp,0x0,sizeof(rp)); 01165 rp.name = child->name_a; 01166 child->name_a = NULL; 01167 rp.namelen = child->namelen; 01168 rp.priority = child->priority; 01169 rp.range_subid = child->range_subid; 01170 rp.range_ubound = child->range_ubound; 01171 rp.timeout = child->timeout; 01172 rp.flags = child->flags; 01173 if ((NULL != child->reginfo) && 01174 (NULL != child->reginfo->contextName)) 01175 rp.contextName = child->reginfo->contextName; 01176 01177 if (child->reginfo != NULL) { 01178 /* 01179 * Don't let's free the session pointer just yet! 01180 */ 01181 child->reginfo->handler->myvoid = NULL; 01182 netsnmp_handler_registration_free(child->reginfo); 01183 child->reginfo = NULL; 01184 } 01185 01186 netsnmp_subtree_unload(child, prev, contextptr->context_name); 01187 netsnmp_subtree_free(child); 01188 01189 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01190 SNMPD_CALLBACK_UNREGISTER_OID, &rp); 01191 SNMP_FREE(rp.name); 01192 } else { 01193 prev = child; 01194 } 01195 } 01196 } 01197 netsnmp_subtree_join(contextptr->first_subtree); 01198 } 01199 } 01200 01201 /* 01202 * in_a_view: determines if a given snmp_pdu is allowed to see a 01203 * given name/namelen OID pointer 01204 * name IN - name of var, OUT - name matched 01205 * nameLen IN -number of sub-ids in name, OUT - subid-is in matched name 01206 * pi IN - relevant auth info re PDU 01207 * cvp IN - relevant auth info re mib module 01208 */ 01209 01210 int 01211 in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type) 01212 { 01213 struct view_parameters view_parms; 01214 01215 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 01216 /* Enable bypassing of view-based access control */ 01217 return VACM_SUCCESS; 01218 } 01219 01220 /* 01221 * check for v1 and counter64s, since snmpv1 doesn't support it 01222 */ 01223 #ifndef NETSNMP_DISABLE_SNMPV1 01224 if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) { 01225 return VACM_NOTINVIEW; 01226 } 01227 #endif 01228 01229 view_parms.pdu = pdu; 01230 view_parms.name = name; 01231 if (namelen != NULL) { 01232 view_parms.namelen = *namelen; 01233 } else { 01234 view_parms.namelen = 0; 01235 } 01236 view_parms.errorcode = 0; 01237 view_parms.check_subtree = 0; 01238 01239 switch (pdu->version) { 01240 #ifndef NETSNMP_DISABLE_SNMPV1 01241 case SNMP_VERSION_1: 01242 #endif 01243 #ifndef NETSNMP_DISABLE_SNMPV2C 01244 case SNMP_VERSION_2c: 01245 #endif 01246 case SNMP_VERSION_3: 01247 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01248 SNMPD_CALLBACK_ACM_CHECK, &view_parms); 01249 return view_parms.errorcode; 01250 } 01251 return VACM_NOSECNAME; 01252 } 01253 01254 /* 01255 * check_acces: determines if a given snmp_pdu is ever going to be 01256 * allowed to do anynthing or if it's not going to ever be 01257 * authenticated. 01258 */ 01259 int 01260 check_access(netsnmp_pdu *pdu) 01261 { /* IN - pdu being checked */ 01262 struct view_parameters view_parms; 01263 view_parms.pdu = pdu; 01264 view_parms.name = 0; 01265 view_parms.namelen = 0; 01266 view_parms.errorcode = 0; 01267 view_parms.check_subtree = 0; 01268 01269 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 01270 /* Enable bypassing of view-based access control */ 01271 return 0; 01272 } 01273 01274 switch (pdu->version) { 01275 #ifndef NETSNMP_DISABLE_SNMPV1 01276 case SNMP_VERSION_1: 01277 #endif 01278 #ifndef NETSNMP_DISABLE_SNMPV2C 01279 case SNMP_VERSION_2c: 01280 #endif 01281 case SNMP_VERSION_3: 01282 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01283 SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms); 01284 return view_parms.errorcode; 01285 } 01286 return 1; 01287 } 01288 01296 int 01297 netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen) 01298 { /* IN - pdu being checked */ 01299 struct view_parameters view_parms; 01300 view_parms.pdu = pdu; 01301 view_parms.name = name; 01302 view_parms.namelen = namelen; 01303 view_parms.errorcode = 0; 01304 view_parms.check_subtree = 1; 01305 01306 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 01307 /* Enable bypassing of view-based access control */ 01308 return 0; 01309 } 01310 01311 switch (pdu->version) { 01312 #ifndef NETSNMP_DISABLE_SNMPV1 01313 case SNMP_VERSION_1: 01314 #endif 01315 #ifndef NETSNMP_DISABLE_SNMPV2C 01316 case SNMP_VERSION_2c: 01317 #endif 01318 case SNMP_VERSION_3: 01319 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01320 SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms); 01321 return view_parms.errorcode; 01322 } 01323 return 1; 01324 } 01325 01326 #define SUBTREE_DEFAULT_CACHE_SIZE 8 01327 #define SUBTREE_MAX_CACHE_SIZE 32 01328 int lookup_cache_size = 0; /*enabled later after registrations are loaded */ 01329 01330 typedef struct lookup_cache_s { 01331 netsnmp_subtree *next; 01332 netsnmp_subtree *previous; 01333 } lookup_cache; 01334 01335 typedef struct lookup_cache_context_s { 01336 char *context; 01337 struct lookup_cache_context_s *next; 01338 int thecachecount; 01339 int currentpos; 01340 lookup_cache cache[SUBTREE_MAX_CACHE_SIZE]; 01341 } lookup_cache_context; 01342 01343 static lookup_cache_context *thecontextcache = NULL; 01344 01356 void 01357 netsnmp_set_lookup_cache_size(int newsize) { 01358 if (newsize < 0) 01359 lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE; 01360 else if (newsize < SUBTREE_MAX_CACHE_SIZE) 01361 lookup_cache_size = newsize; 01362 else 01363 lookup_cache_size = SUBTREE_MAX_CACHE_SIZE; 01364 } 01365 01369 int 01370 netsnmp_get_lookup_cache_size(void) { 01371 return lookup_cache_size; 01372 } 01373 01374 NETSNMP_STATIC_INLINE lookup_cache_context * 01375 get_context_lookup_cache(const char *context) { 01376 lookup_cache_context *ptr; 01377 if (!context) 01378 context = ""; 01379 01380 for(ptr = thecontextcache; ptr; ptr = ptr->next) { 01381 if (strcmp(ptr->context, context) == 0) 01382 break; 01383 } 01384 if (!ptr) { 01385 if (netsnmp_subtree_find_first(context)) { 01386 ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context); 01387 ptr->next = thecontextcache; 01388 ptr->context = strdup(context); 01389 thecontextcache = ptr; 01390 } else { 01391 return NULL; 01392 } 01393 } 01394 return ptr; 01395 } 01396 01397 NETSNMP_STATIC_INLINE void 01398 lookup_cache_add(const char *context, 01399 netsnmp_subtree *next, netsnmp_subtree *previous) { 01400 lookup_cache_context *cptr; 01401 01402 if ((cptr = get_context_lookup_cache(context)) == NULL) 01403 return; 01404 01405 if (cptr->thecachecount < lookup_cache_size) 01406 cptr->thecachecount++; 01407 01408 cptr->cache[cptr->currentpos].next = next; 01409 cptr->cache[cptr->currentpos].previous = previous; 01410 01411 if (++cptr->currentpos >= lookup_cache_size) 01412 cptr->currentpos = 0; 01413 } 01414 01415 NETSNMP_STATIC_INLINE void 01416 lookup_cache_replace(lookup_cache *ptr, 01417 netsnmp_subtree *next, netsnmp_subtree *previous) { 01418 01419 ptr->next = next; 01420 ptr->previous = previous; 01421 } 01422 01423 NETSNMP_STATIC_INLINE lookup_cache * 01424 lookup_cache_find(const char *context, oid *name, size_t name_len, 01425 int *retcmp) { 01426 lookup_cache_context *cptr; 01427 lookup_cache *ret = NULL; 01428 int cmp; 01429 int i; 01430 01431 if ((cptr = get_context_lookup_cache(context)) == NULL) 01432 return NULL; 01433 01434 for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) { 01435 if (cptr->cache[i].previous->start_a) 01436 cmp = snmp_oid_compare(name, name_len, 01437 cptr->cache[i].previous->start_a, 01438 cptr->cache[i].previous->start_len); 01439 else 01440 cmp = 1; 01441 if (cmp >= 0) { 01442 *retcmp = cmp; 01443 ret = &(cptr->cache[i]); 01444 } 01445 } 01446 return ret; 01447 } 01448 01449 NETSNMP_STATIC_INLINE void 01450 invalidate_lookup_cache(const char *context) { 01451 lookup_cache_context *cptr; 01452 if ((cptr = get_context_lookup_cache(context)) != NULL) { 01453 cptr->thecachecount = 0; 01454 cptr->currentpos = 0; 01455 } 01456 } 01457 01458 netsnmp_subtree * 01459 netsnmp_subtree_find_prev(oid *name, size_t len, netsnmp_subtree *subtree, 01460 const char *context_name) 01461 { 01462 lookup_cache *lookup_cache = NULL; 01463 netsnmp_subtree *myptr = NULL, *previous = NULL; 01464 int cmp = 1; 01465 size_t ll_off = 0; 01466 01467 if (subtree) { 01468 myptr = subtree; 01469 } else { 01470 /* look through everything */ 01471 if (lookup_cache_size) { 01472 lookup_cache = lookup_cache_find(context_name, name, len, &cmp); 01473 if (lookup_cache) { 01474 myptr = lookup_cache->next; 01475 previous = lookup_cache->previous; 01476 } 01477 if (!myptr) 01478 myptr = netsnmp_subtree_find_first(context_name); 01479 } else { 01480 myptr = netsnmp_subtree_find_first(context_name); 01481 } 01482 } 01483 01484 /* 01485 * this optimization causes a segfault on sf cf alpha-linux1. 01486 * ifdef out until someone figures out why and fixes it. xxx-rks 20051117 01487 */ 01488 #ifndef __alpha 01489 #define WTEST_OPTIMIZATION 1 01490 #endif 01491 #ifdef WTEST_OPTIMIZATION 01492 DEBUGMSGTL(("wtest","oid in: ")); 01493 DEBUGMSGOID(("wtest", name, len)); 01494 DEBUGMSG(("wtest","\n")); 01495 #endif 01496 for (; myptr != NULL; previous = myptr, myptr = myptr->next) { 01497 #ifdef WTEST_OPTIMIZATION 01498 /* Compare the incoming oid with the linked list. If we have 01499 results of previous compares, its faster to make sure the 01500 length we differed in the last check is greater than the 01501 length between this pointer and the last then we don't need 01502 to actually perform a comparison */ 01503 DEBUGMSGTL(("wtest","oid cmp: ")); 01504 DEBUGMSGOID(("wtest", myptr->start_a, myptr->start_len)); 01505 DEBUGMSG(("wtest"," --- off = %d, in off = %d test = %d\n", 01506 myptr->oid_off, ll_off, 01507 !(ll_off && myptr->oid_off && 01508 myptr->oid_off > ll_off))); 01509 if (!(ll_off && myptr->oid_off && myptr->oid_off > ll_off) && 01510 netsnmp_oid_compare_ll(name, len, 01511 myptr->start_a, myptr->start_len, 01512 &ll_off) < 0) { 01513 #else 01514 if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) { 01515 #endif 01516 if (lookup_cache_size && previous && cmp) { 01517 if (lookup_cache) { 01518 lookup_cache_replace(lookup_cache, myptr, previous); 01519 } else { 01520 lookup_cache_add(context_name, myptr, previous); 01521 } 01522 } 01523 return previous; 01524 } 01525 } 01526 return previous; 01527 } 01528 01529 netsnmp_subtree * 01530 netsnmp_subtree_find_next(oid *name, size_t len, 01531 netsnmp_subtree *subtree, const char *context_name) 01532 { 01533 netsnmp_subtree *myptr = NULL; 01534 01535 myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name); 01536 01537 if (myptr != NULL) { 01538 myptr = myptr->next; 01539 while (myptr != NULL && (myptr->variables == NULL || 01540 myptr->variables_len == 0)) { 01541 myptr = myptr->next; 01542 } 01543 return myptr; 01544 } else if (subtree != NULL && snmp_oid_compare(name, len, 01545 subtree->start_a, subtree->start_len) < 0) { 01546 return subtree; 01547 } else { 01548 return NULL; 01549 } 01550 } 01551 01552 netsnmp_subtree * 01553 netsnmp_subtree_find(oid *name, size_t len, netsnmp_subtree *subtree, 01554 const char *context_name) 01555 { 01556 netsnmp_subtree *myptr; 01557 01558 myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name); 01559 if (myptr && myptr->end_a && 01560 snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) { 01561 return myptr; 01562 } 01563 01564 return NULL; 01565 } 01566 01567 netsnmp_session * 01568 get_session_for_oid(oid *name, size_t len, const char *context_name) 01569 { 01570 netsnmp_subtree *myptr; 01571 01572 myptr = netsnmp_subtree_find_prev(name, len, 01573 netsnmp_subtree_find_first(context_name), 01574 context_name); 01575 01576 while (myptr && myptr->variables == NULL) { 01577 myptr = myptr->next; 01578 } 01579 01580 if (myptr == NULL) { 01581 return NULL; 01582 } else { 01583 return myptr->session; 01584 } 01585 } 01586 01587 void 01588 setup_tree(void) 01589 { 01590 oid ccitt[1] = { 0 }; 01591 oid iso[1] = { 1 }; 01592 oid joint_ccitt_iso[1] = { 2 }; 01593 01594 #ifdef USING_AGENTX_SUBAGENT_MODULE 01595 int role = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 01596 NETSNMP_DS_AGENT_ROLE); 01597 01598 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 01599 MASTER_AGENT); 01600 #endif 01601 01602 /* 01603 * we need to have the oid's in the heap, that we can *free* it for every case, 01604 * thats the purpose of the duplicate_objid's 01605 */ 01606 netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1); 01607 netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1); 01608 netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1); 01609 01610 #ifdef USING_AGENTX_SUBAGENT_MODULE 01611 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 01612 role); 01613 #endif 01614 } 01615 01616 int 01617 remove_tree_entry (oid *name, size_t len) { 01618 01619 netsnmp_subtree *sub = NULL; 01620 01621 if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) { 01622 return MIB_NO_SUCH_REGISTRATION; 01623 } 01624 01625 return unregister_mib_context(name, len, sub->priority, 01626 sub->range_subid, sub->range_ubound, ""); 01627 01628 } 01629 01630 01631 void 01632 shutdown_tree(void) { 01633 oid ccitt[1] = { 0 }; 01634 oid iso[1] = { 1 }; 01635 oid joint_ccitt_iso[1] = { 2 }; 01636 01637 DEBUGMSGTL(("agent_registry", "shut down tree\n")); 01638 01639 remove_tree_entry(joint_ccitt_iso, 1); 01640 remove_tree_entry(iso, 1); 01641 remove_tree_entry(ccitt, 1); 01642 01643 } 01644 01645 void 01646 clear_subtree (netsnmp_subtree *sub) { 01647 01648 netsnmp_subtree *nxt; 01649 01650 if (sub == NULL) 01651 return; 01652 01653 for(nxt = sub; nxt;) { 01654 if (nxt->children != NULL) { 01655 clear_subtree(nxt->children); 01656 } 01657 sub = nxt; 01658 nxt = nxt->next; 01659 netsnmp_subtree_free(sub); 01660 } 01661 01662 } 01663 01664 void 01665 clear_lookup_cache(void) { 01666 01667 lookup_cache_context *ptr = NULL, *next = NULL; 01668 01669 ptr = thecontextcache; 01670 while (ptr) { 01671 next = ptr->next; 01672 SNMP_FREE(ptr->context); 01673 SNMP_FREE(ptr); 01674 ptr = next; 01675 } 01676 thecontextcache = NULL; /* !!! */ 01677 } 01678 01679 void 01680 clear_context(void) { 01681 01682 subtree_context_cache *ptr = NULL, *next = NULL; 01683 01684 DEBUGMSGTL(("agent_registry", "clear context\n")); 01685 01686 ptr = get_top_context_cache(); 01687 while (ptr) { 01688 next = ptr->next; 01689 01690 if (ptr->first_subtree) { 01691 clear_subtree(ptr->first_subtree); 01692 } 01693 01694 SNMP_FREE(ptr->context_name); 01695 SNMP_FREE(ptr); 01696 01697 ptr = next; 01698 } 01699 context_subtrees = NULL; /* !!! */ 01700 clear_lookup_cache(); 01701 } 01702 01703 extern void dump_idx_registry(void); 01704 void 01705 dump_registry(void) 01706 { 01707 struct variable *vp = NULL; 01708 netsnmp_subtree *myptr, *myptr2; 01709 u_char *s = NULL, *e = NULL, *v = NULL; 01710 size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0; 01711 int i = 0; 01712 01713 if ((s = (u_char *) calloc(sl, 1)) != NULL && 01714 (e = (u_char *) calloc(sl, 1)) != NULL && 01715 (v = (u_char *) calloc(sl, 1)) != NULL) { 01716 01717 subtree_context_cache *ptr; 01718 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 01719 printf("Subtrees for Context: %s\n", ptr->context_name); 01720 for (myptr = ptr->first_subtree; myptr != NULL; 01721 myptr = myptr->next) { 01722 sl_o = el_o = vl_o = 0; 01723 01724 if (!sprint_realloc_objid(&s, &sl, &sl_o, 1, 01725 myptr->start_a, 01726 myptr->start_len)) { 01727 break; 01728 } 01729 if (!sprint_realloc_objid(&e, &el, &el_o, 1, 01730 myptr->end_a, 01731 myptr->end_len)) { 01732 break; 01733 } 01734 01735 if (myptr->variables) { 01736 printf("%02x ( %s - %s ) [", myptr->flags, s, e); 01737 for (i = 0, vp = myptr->variables; 01738 i < myptr->variables_len; i++) { 01739 vl_o = 0; 01740 if (!sprint_realloc_objid 01741 (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) { 01742 break; 01743 } 01744 printf("%s, ", v); 01745 vp = (struct variable *) ((char *) vp + 01746 myptr->variables_width); 01747 } 01748 printf("]\n"); 01749 } else { 01750 printf("%02x %s - %s \n", myptr->flags, s, e); 01751 } 01752 for (myptr2 = myptr; myptr2 != NULL; 01753 myptr2 = myptr2->children) { 01754 if (myptr2->label_a && myptr2->label_a[0]) { 01755 if (strcmp(myptr2->label_a, "old_api") == 0) { 01756 struct variable *vp = 01757 myptr2->reginfo->handler->myvoid; 01758 01759 sprint_realloc_objid(&s, &sl, &sl_o, 1, 01760 vp->name, vp->namelen); 01761 printf("\t%s[%s] %p var %s\n", myptr2->label_a, 01762 myptr2->reginfo->handlerName ? myptr2-> 01763 reginfo->handlerName : "no-name", 01764 myptr2->reginfo, s); 01765 } else { 01766 printf("\t%s %s %p\n", myptr2->label_a, 01767 myptr2->reginfo->handlerName ? myptr2-> 01768 reginfo-> 01769 handlerName : "no-handler-name", 01770 myptr2->reginfo); 01771 } 01772 } 01773 } 01774 } 01775 } 01776 } 01777 01778 if (s != NULL) { 01779 SNMP_FREE(s); 01780 } 01781 if (e != NULL) { 01782 SNMP_FREE(e); 01783 } 01784 if (v != NULL) { 01785 SNMP_FREE(v); 01786 } 01787 01788 dump_idx_registry(); 01789 } 01790 01791 int external_signal_scheduled[NUM_EXTERNAL_SIGS]; 01792 void (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int); 01793 01794 #ifndef WIN32 01795 01796 /* 01797 * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines 01798 * below for every single that might be handled by register_signal(). 01799 */ 01800 01801 RETSIGTYPE 01802 agent_SIGCHLD_handler(int sig) 01803 { 01804 external_signal_scheduled[SIGCHLD]++; 01805 #ifndef HAVE_SIGACTION 01806 /* 01807 * signal() sucks. It *might* have SysV semantics, which means that 01808 * * a signal handler is reset once it gets called. Ensure that it 01809 * * remains active. 01810 */ 01811 signal(SIGCHLD, agent_SIGCHLD_handler); 01812 #endif 01813 } 01814 01815 int 01816 register_signal(int sig, void (*func) (int)) 01817 { 01818 01819 switch (sig) { 01820 #if defined(SIGCHLD) 01821 case SIGCHLD: 01822 #ifdef HAVE_SIGACTION 01823 { 01824 static struct sigaction act; 01825 act.sa_handler = agent_SIGCHLD_handler; 01826 sigemptyset(&act.sa_mask); 01827 act.sa_flags = 0; 01828 sigaction(SIGCHLD, &act, NULL); 01829 } 01830 #else 01831 signal(SIGCHLD, agent_SIGCHLD_handler); 01832 #endif 01833 break; 01834 #endif 01835 default: 01836 snmp_log(LOG_CRIT, 01837 "register_signal: signal %d cannot be handled\n", sig); 01838 return SIG_REGISTRATION_FAILED; 01839 } 01840 01841 external_signal_handler[sig] = func; 01842 external_signal_scheduled[sig] = 0; 01843 01844 DEBUGMSGTL(("register_signal", "registered signal %d\n", sig)); 01845 return SIG_REGISTERED_OK; 01846 } 01847 01848 int 01849 unregister_signal(int sig) 01850 { 01851 signal(sig, SIG_DFL); 01852 DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig)); 01853 return SIG_UNREGISTERED_OK; 01854 } 01855 01856 #endif /* !WIN32 */ 01857