net-snmp 5.7
|
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 */ 00022 #define IN_SNMP_VARS_C 00023 00024 #include <net-snmp/net-snmp-config.h> 00025 #include <net-snmp/net-snmp-features.h> 00026 00027 #include <signal.h> 00028 #if HAVE_STRING_H 00029 #include <string.h> 00030 #endif 00031 #if HAVE_STDLIB_H 00032 #include <stdlib.h> 00033 #endif 00034 #include <sys/types.h> 00035 #include <stdio.h> 00036 #include <fcntl.h> 00037 #if TIME_WITH_SYS_TIME 00038 # include <sys/time.h> 00039 # include <time.h> 00040 #else 00041 # if HAVE_SYS_TIME_H 00042 # include <sys/time.h> 00043 # else 00044 # include <time.h> 00045 # endif 00046 #endif 00047 #if HAVE_NETINET_IN_H 00048 #include <netinet/in.h> 00049 #endif 00050 00051 #include <net-snmp/net-snmp-includes.h> 00052 #include <net-snmp/library/snmp_assert.h> 00053 #include <net-snmp/agent/net-snmp-agent-includes.h> 00054 #include <net-snmp/agent/agent_callbacks.h> 00055 00056 #include "snmpd.h" 00057 #include "mibgroup/struct.h" 00058 #include <net-snmp/agent/old_api.h> 00059 #include <net-snmp/agent/null.h> 00060 #include <net-snmp/agent/table.h> 00061 #include <net-snmp/agent/table_iterator.h> 00062 #include <net-snmp/agent/agent_registry.h> 00063 #include "mib_module_includes.h" 00064 00065 #ifdef USING_AGENTX_SUBAGENT_MODULE 00066 #include "agentx/subagent.h" 00067 #include "agentx/client.h" 00068 #endif 00069 00070 netsnmp_feature_child_of(agent_registry_all, libnetsnmpagent) 00071 00072 netsnmp_feature_child_of(unregister_mib_table_row, agent_registry_all) 00073 00082 #define SUBTREE_DEFAULT_CACHE_SIZE 8 00083 00084 #define SUBTREE_MAX_CACHE_SIZE 32 00085 int lookup_cache_size = 0; /*enabled later after registrations are loaded */ 00086 00087 typedef struct lookup_cache_s { 00088 netsnmp_subtree *next; 00089 netsnmp_subtree *previous; 00090 } lookup_cache; 00091 00092 typedef struct lookup_cache_context_s { 00093 char *context; 00094 struct lookup_cache_context_s *next; 00095 int thecachecount; 00096 int currentpos; 00097 lookup_cache cache[SUBTREE_MAX_CACHE_SIZE]; 00098 } lookup_cache_context; 00099 00100 static lookup_cache_context *thecontextcache = NULL; 00101 00115 void 00116 netsnmp_set_lookup_cache_size(int newsize) { 00117 if (newsize < 0) 00118 lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE; 00119 else if (newsize < SUBTREE_MAX_CACHE_SIZE) 00120 lookup_cache_size = newsize; 00121 else 00122 lookup_cache_size = SUBTREE_MAX_CACHE_SIZE; 00123 } 00124 00130 int 00131 netsnmp_get_lookup_cache_size(void) { 00132 return lookup_cache_size; 00133 } 00134 00141 NETSNMP_STATIC_INLINE lookup_cache_context * 00142 get_context_lookup_cache(const char *context) { 00143 lookup_cache_context *ptr; 00144 if (!context) 00145 context = ""; 00146 00147 for(ptr = thecontextcache; ptr; ptr = ptr->next) { 00148 if (strcmp(ptr->context, context) == 0) 00149 break; 00150 } 00151 if (!ptr) { 00152 if (netsnmp_subtree_find_first(context)) { 00153 ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context); 00154 ptr->next = thecontextcache; 00155 ptr->context = strdup(context); 00156 thecontextcache = ptr; 00157 } else { 00158 return NULL; 00159 } 00160 } 00161 return ptr; 00162 } 00163 00172 NETSNMP_STATIC_INLINE void 00173 lookup_cache_add(const char *context, 00174 netsnmp_subtree *next, netsnmp_subtree *previous) { 00175 lookup_cache_context *cptr; 00176 00177 if ((cptr = get_context_lookup_cache(context)) == NULL) 00178 return; 00179 00180 if (cptr->thecachecount < lookup_cache_size) 00181 cptr->thecachecount++; 00182 00183 cptr->cache[cptr->currentpos].next = next; 00184 cptr->cache[cptr->currentpos].previous = previous; 00185 00186 if (++cptr->currentpos >= lookup_cache_size) 00187 cptr->currentpos = 0; 00188 } 00189 00199 NETSNMP_STATIC_INLINE void 00200 lookup_cache_replace(lookup_cache *ptr, 00201 netsnmp_subtree *next, netsnmp_subtree *previous) { 00202 00203 ptr->next = next; 00204 ptr->previous = previous; 00205 } 00206 00222 NETSNMP_STATIC_INLINE lookup_cache * 00223 lookup_cache_find(const char *context, const oid *name, size_t name_len, 00224 int *retcmp) { 00225 lookup_cache_context *cptr; 00226 lookup_cache *ret = NULL; 00227 int cmp; 00228 int i; 00229 00230 if ((cptr = get_context_lookup_cache(context)) == NULL) 00231 return NULL; 00232 00233 for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) { 00234 if (cptr->cache[i].previous->start_a) 00235 cmp = snmp_oid_compare(name, name_len, 00236 cptr->cache[i].previous->start_a, 00237 cptr->cache[i].previous->start_len); 00238 else 00239 cmp = 1; 00240 if (cmp >= 0) { 00241 *retcmp = cmp; 00242 ret = &(cptr->cache[i]); 00243 } 00244 } 00245 return ret; 00246 } 00247 00251 NETSNMP_STATIC_INLINE void 00252 invalidate_lookup_cache(const char *context) { 00253 lookup_cache_context *cptr; 00254 if ((cptr = get_context_lookup_cache(context)) != NULL) { 00255 cptr->thecachecount = 0; 00256 cptr->currentpos = 0; 00257 } 00258 } 00259 00260 void 00261 clear_lookup_cache(void) { 00262 00263 lookup_cache_context *ptr = NULL, *next = NULL; 00264 00265 ptr = thecontextcache; 00266 while (ptr) { 00267 next = ptr->next; 00268 SNMP_FREE(ptr->context); 00269 SNMP_FREE(ptr); 00270 ptr = next; 00271 } 00272 thecontextcache = NULL; /* !!! */ 00273 } 00274 00276 /* End of Lookup cache code */ 00277 00284 subtree_context_cache *context_subtrees = NULL; 00285 00292 subtree_context_cache * 00293 get_top_context_cache(void) 00294 { 00295 return context_subtrees; 00296 } 00297 00304 netsnmp_subtree * 00305 netsnmp_subtree_find_first(const char *context_name) 00306 { 00307 subtree_context_cache *ptr; 00308 00309 if (!context_name) { 00310 context_name = ""; 00311 } 00312 00313 DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n", 00314 context_name)); 00315 for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) { 00316 if (ptr->context_name != NULL && 00317 strcmp(ptr->context_name, context_name) == 0) { 00318 DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name)); 00319 return ptr->first_subtree; 00320 } 00321 } 00322 DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n", 00323 context_name)); 00324 return NULL; 00325 } 00326 00335 netsnmp_subtree * 00336 add_subtree(netsnmp_subtree *new_tree, const char *context_name) 00337 { 00338 subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache); 00339 00340 if (!context_name) { 00341 context_name = ""; 00342 } 00343 00344 if (!ptr) { 00345 return NULL; 00346 } 00347 00348 DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n", 00349 context_name)); 00350 00351 ptr->next = context_subtrees; 00352 ptr->first_subtree = new_tree; 00353 ptr->context_name = strdup(context_name); 00354 context_subtrees = ptr; 00355 00356 return ptr->first_subtree; 00357 } 00358 00359 void 00360 netsnmp_remove_subtree(netsnmp_subtree *tree) 00361 { 00362 subtree_context_cache *ptr; 00363 00364 if (!tree->prev) { 00365 for (ptr = context_subtrees; ptr; ptr = ptr->next) 00366 if (ptr->first_subtree == tree) 00367 break; 00368 netsnmp_assert(ptr); 00369 if (ptr) 00370 ptr->first_subtree = tree->next; 00371 } else 00372 tree->prev->next = tree->next; 00373 00374 if (tree->next) 00375 tree->next->prev = tree->prev; 00376 } 00377 00390 netsnmp_subtree * 00391 netsnmp_subtree_replace_first(netsnmp_subtree *new_tree, 00392 const char *context_name) 00393 { 00394 subtree_context_cache *ptr; 00395 if (!context_name) { 00396 context_name = ""; 00397 } 00398 for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) { 00399 if (ptr->context_name != NULL && 00400 strcmp(ptr->context_name, context_name) == 0) { 00401 ptr->first_subtree = new_tree; 00402 return ptr->first_subtree; 00403 } 00404 } 00405 return add_subtree(new_tree, context_name); 00406 } 00407 00408 00409 void clear_subtree (netsnmp_subtree *sub); 00410 00413 void 00414 clear_context(void) { 00415 00416 subtree_context_cache *ptr = NULL, *next = NULL; 00417 netsnmp_subtree *t, *u; 00418 00419 DEBUGMSGTL(("agent_registry", "clear context\n")); 00420 00421 ptr = get_top_context_cache(); 00422 while (ptr) { 00423 next = ptr->next; 00424 00425 for (t = ptr->first_subtree; t; t = u) { 00426 u = t->next; 00427 clear_subtree(t); 00428 } 00429 00430 free(NETSNMP_REMOVE_CONST(char*, ptr->context_name)); 00431 SNMP_FREE(ptr); 00432 00433 ptr = next; 00434 } 00435 context_subtrees = NULL; /* !!! */ 00436 clear_lookup_cache(); 00437 } 00438 00440 /* End of Context cache code */ 00441 00449 static void register_mib_detach_node(netsnmp_subtree *s); 00450 00459 void 00460 netsnmp_subtree_free(netsnmp_subtree *a) 00461 { 00462 if (a != NULL) { 00463 if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen, 00464 a->start_a, a->start_len) == 0) { 00465 SNMP_FREE(a->variables); 00466 } 00467 SNMP_FREE(a->name_a); 00468 a->namelen = 0; 00469 SNMP_FREE(a->start_a); 00470 a->start_len = 0; 00471 SNMP_FREE(a->end_a); 00472 a->end_len = 0; 00473 SNMP_FREE(a->label_a); 00474 netsnmp_handler_registration_free(a->reginfo); 00475 a->reginfo = NULL; 00476 SNMP_FREE(a); 00477 } 00478 } 00479 00488 netsnmp_subtree * 00489 netsnmp_subtree_deepcopy(netsnmp_subtree *a) 00490 { 00491 netsnmp_subtree *b = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree)); 00492 00493 if (b != NULL) { 00494 memcpy(b, a, sizeof(netsnmp_subtree)); 00495 b->name_a = snmp_duplicate_objid(a->name_a, a->namelen); 00496 b->start_a = snmp_duplicate_objid(a->start_a, a->start_len); 00497 b->end_a = snmp_duplicate_objid(a->end_a, a->end_len); 00498 b->label_a = strdup(a->label_a); 00499 00500 if (b->name_a == NULL || b->start_a == NULL || 00501 b->end_a == NULL || b->label_a == NULL) { 00502 netsnmp_subtree_free(b); 00503 return NULL; 00504 } 00505 00506 if (a->variables != NULL) { 00507 b->variables = (struct variable *)malloc(a->variables_len * 00508 a->variables_width); 00509 if (b->variables != NULL) { 00510 memcpy(b->variables, a->variables,a->variables_len*a->variables_width); 00511 } else { 00512 netsnmp_subtree_free(b); 00513 return NULL; 00514 } 00515 } 00516 00517 if (a->reginfo != NULL) { 00518 b->reginfo = netsnmp_handler_registration_dup(a->reginfo); 00519 if (b->reginfo == NULL) { 00520 netsnmp_subtree_free(b); 00521 return NULL; 00522 } 00523 } 00524 } 00525 return b; 00526 } 00527 00531 NETSNMP_INLINE void 00532 netsnmp_subtree_change_next(netsnmp_subtree *ptr, netsnmp_subtree *thenext) 00533 { 00534 ptr->next = thenext; 00535 if (thenext) 00536 netsnmp_oid_compare_ll(ptr->start_a, 00537 ptr->start_len, 00538 thenext->start_a, 00539 thenext->start_len, 00540 &thenext->oid_off); 00541 } 00542 00546 NETSNMP_INLINE void 00547 netsnmp_subtree_change_prev(netsnmp_subtree *ptr, netsnmp_subtree *theprev) 00548 { 00549 ptr->prev = theprev; 00550 if (theprev) 00551 netsnmp_oid_compare_ll(theprev->start_a, 00552 theprev->start_len, 00553 ptr->start_a, 00554 ptr->start_len, 00555 &ptr->oid_off); 00556 } 00557 00566 netsnmp_feature_child_of(netsnmp_subtree_compare,netsnmp_unused) 00567 #ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_SUBTREE_COMPARE 00568 int 00569 netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp) 00570 { 00571 return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen); 00572 } 00573 #endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_SUBTREE_COMPARE */ 00574 00581 void 00582 netsnmp_subtree_join(netsnmp_subtree *root) 00583 { 00584 netsnmp_subtree *s, *tmp, *c, *d; 00585 00586 while (root != NULL) { 00587 s = root->next; 00588 while (s != NULL && root->reginfo == s->reginfo) { 00589 tmp = s->next; 00590 DEBUGMSGTL(("subtree", "root start ")); 00591 DEBUGMSGOID(("subtree", root->start_a, root->start_len)); 00592 DEBUGMSG(("subtree", " (original end ")); 00593 DEBUGMSGOID(("subtree", root->end_a, root->end_len)); 00594 DEBUGMSG(("subtree", ")\n")); 00595 DEBUGMSGTL(("subtree", " JOINING to ")); 00596 DEBUGMSGOID(("subtree", s->start_a, s->start_len)); 00597 00598 SNMP_FREE(root->end_a); 00599 root->end_a = s->end_a; 00600 root->end_len = s->end_len; 00601 s->end_a = NULL; 00602 00603 for (c = root; c != NULL; c = c->children) { 00604 netsnmp_subtree_change_next(c, s->next); 00605 } 00606 for (c = s; c != NULL; c = c->children) { 00607 netsnmp_subtree_change_prev(c, root); 00608 } 00609 DEBUGMSG(("subtree", " so new end ")); 00610 DEBUGMSGOID(("subtree", root->end_a, root->end_len)); 00611 DEBUGMSG(("subtree", "\n")); 00612 /* 00613 * Probably need to free children too? 00614 */ 00615 for (c = s->children; c != NULL; c = d) { 00616 d = c->children; 00617 netsnmp_subtree_free(c); 00618 } 00619 netsnmp_subtree_free(s); 00620 s = tmp; 00621 } 00622 root = root->next; 00623 } 00624 } 00625 00626 00639 netsnmp_subtree * 00640 netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len) 00641 { 00642 struct variable *vp = NULL; 00643 netsnmp_subtree *new_sub, *ptr; 00644 int i = 0, rc = 0, rc2 = 0; 00645 size_t common_len = 0; 00646 char *cp; 00647 oid *tmp_a, *tmp_b; 00648 00649 if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) { 00650 /* Split comes after the end of this subtree */ 00651 return NULL; 00652 } 00653 00654 new_sub = netsnmp_subtree_deepcopy(current); 00655 if (new_sub == NULL) { 00656 return NULL; 00657 } 00658 00659 /* Set up the point of division. */ 00660 tmp_a = snmp_duplicate_objid(name, name_len); 00661 if (tmp_a == NULL) { 00662 netsnmp_subtree_free(new_sub); 00663 return NULL; 00664 } 00665 tmp_b = snmp_duplicate_objid(name, name_len); 00666 if (tmp_b == NULL) { 00667 netsnmp_subtree_free(new_sub); 00668 SNMP_FREE(tmp_a); 00669 return NULL; 00670 } 00671 00672 SNMP_FREE(current->end_a); 00673 current->end_a = tmp_a; 00674 current->end_len = name_len; 00675 if (new_sub->start_a != NULL) { 00676 SNMP_FREE(new_sub->start_a); 00677 } 00678 new_sub->start_a = tmp_b; 00679 new_sub->start_len = name_len; 00680 00681 /* Split the variables between the two new subtrees. */ 00682 i = current->variables_len; 00683 current->variables_len = 0; 00684 00685 for (vp = current->variables; i > 0; i--) { 00686 /* Note that the variable "name" field omits the prefix common to the 00687 whole registration, hence the strange comparison here. */ 00688 00689 rc = snmp_oid_compare(vp->name, vp->namelen, 00690 name + current->namelen, 00691 name_len - current->namelen); 00692 00693 if (name_len - current->namelen > vp->namelen) { 00694 common_len = vp->namelen; 00695 } else { 00696 common_len = name_len - current->namelen; 00697 } 00698 00699 rc2 = snmp_oid_compare(vp->name, common_len, 00700 name + current->namelen, common_len); 00701 00702 if (rc >= 0) { 00703 break; /* All following variables belong to the second subtree */ 00704 } 00705 00706 current->variables_len++; 00707 if (rc2 < 0) { 00708 new_sub->variables_len--; 00709 cp = (char *) new_sub->variables; 00710 new_sub->variables = (struct variable *)(cp + 00711 new_sub->variables_width); 00712 } 00713 vp = (struct variable *) ((char *) vp + current->variables_width); 00714 } 00715 00716 /* Delegated trees should retain their variables regardless */ 00717 if (current->variables_len > 0 && 00718 IS_DELEGATED((u_char) current->variables[0].type)) { 00719 new_sub->variables_len = 1; 00720 new_sub->variables = current->variables; 00721 } 00722 00723 /* Propogate this split down through any children */ 00724 if (current->children) { 00725 new_sub->children = netsnmp_subtree_split(current->children, 00726 name, name_len); 00727 } 00728 00729 /* Retain the correct linking of the list */ 00730 for (ptr = current; ptr != NULL; ptr = ptr->children) { 00731 netsnmp_subtree_change_next(ptr, new_sub); 00732 } 00733 for (ptr = new_sub; ptr != NULL; ptr = ptr->children) { 00734 netsnmp_subtree_change_prev(ptr, current); 00735 } 00736 for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) { 00737 netsnmp_subtree_change_prev(ptr, new_sub); 00738 } 00739 00740 return new_sub; 00741 } 00742 00751 int 00752 netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name) 00753 { 00754 netsnmp_subtree *tree1, *tree2; 00755 netsnmp_subtree *prev, *next; 00756 00757 if (new_sub == NULL) { 00758 return MIB_REGISTERED_OK; /* Degenerate case */ 00759 } 00760 00761 if (!netsnmp_subtree_find_first(context_name)) { 00762 static int inloop = 0; 00763 if (!inloop) { 00764 oid ccitt[1] = { 0 }; 00765 oid iso[1] = { 1 }; 00766 oid joint_ccitt_iso[1] = { 2 }; 00767 inloop = 1; 00768 netsnmp_register_null_context(snmp_duplicate_objid(ccitt, 1), 1, 00769 context_name); 00770 netsnmp_register_null_context(snmp_duplicate_objid(iso, 1), 1, 00771 context_name); 00772 netsnmp_register_null_context(snmp_duplicate_objid(joint_ccitt_iso, 1), 00773 1, context_name); 00774 inloop = 0; 00775 } 00776 } 00777 00778 /* Find the subtree that contains the start of the new subtree (if 00779 any)...*/ 00780 00781 tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len, 00782 NULL, context_name); 00783 00784 /* ... and the subtree that follows the new one (NULL implies this is the 00785 final region covered). */ 00786 00787 if (tree1 == NULL) { 00788 tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len, 00789 NULL, context_name); 00790 } else { 00791 tree2 = tree1->next; 00792 } 00793 00794 /* Handle new subtrees that start in virgin territory. */ 00795 00796 if (tree1 == NULL) { 00797 netsnmp_subtree *new2 = NULL; 00798 /* Is there any overlap with later subtrees? */ 00799 if (tree2 && snmp_oid_compare(new_sub->end_a, new_sub->end_len, 00800 tree2->start_a, tree2->start_len) > 0) { 00801 new2 = netsnmp_subtree_split(new_sub, 00802 tree2->start_a, tree2->start_len); 00803 } 00804 00805 /* Link the new subtree (less any overlapping region) with the list of 00806 existing registrations. */ 00807 00808 if (tree2) { 00809 netsnmp_subtree_change_prev(new_sub, tree2->prev); 00810 netsnmp_subtree_change_prev(tree2, new_sub); 00811 } else { 00812 netsnmp_subtree_change_prev(new_sub, 00813 netsnmp_subtree_find_prev(new_sub->start_a, 00814 new_sub->start_len, NULL, context_name)); 00815 00816 if (new_sub->prev) { 00817 netsnmp_subtree_change_next(new_sub->prev, new_sub); 00818 } else { 00819 netsnmp_subtree_replace_first(new_sub, context_name); 00820 } 00821 00822 netsnmp_subtree_change_next(new_sub, tree2); 00823 00824 /* If there was any overlap, recurse to merge in the overlapping 00825 region (including anything that may follow the overlap). */ 00826 if (new2) { 00827 return netsnmp_subtree_load(new2, context_name); 00828 } 00829 } 00830 } else { 00831 /* If the new subtree starts *within* an existing registration 00832 (rather than at the same point as it), then split the existing 00833 subtree at this point. */ 00834 00835 if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len, 00836 tree1->start_a, tree1->start_len) != 0) { 00837 tree1 = netsnmp_subtree_split(tree1, new_sub->start_a, 00838 new_sub->start_len); 00839 } 00840 00841 if (tree1 == NULL) { 00842 return MIB_REGISTRATION_FAILED; 00843 } 00844 00845 /* Now consider the end of this existing subtree: 00846 00847 If it matches the new subtree precisely, 00848 simply merge the new one into the list of children 00849 00850 If it includes the whole of the new subtree, 00851 split it at the appropriate point, and merge again 00852 00853 If the new subtree extends beyond this existing region, 00854 split it, and recurse to merge the two parts. */ 00855 00856 switch (snmp_oid_compare(new_sub->end_a, new_sub->end_len, 00857 tree1->end_a, tree1->end_len)) { 00858 00859 case -1: 00860 /* Existing subtree contains new one. */ 00861 netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len); 00862 /* Fall Through */ 00863 00864 case 0: 00865 /* The two trees match precisely. */ 00866 00867 /* Note: This is the only point where the original registration 00868 OID ("name") is used. */ 00869 00870 prev = NULL; 00871 next = tree1; 00872 00873 while (next && next->namelen > new_sub->namelen) { 00874 prev = next; 00875 next = next->children; 00876 } 00877 00878 while (next && next->namelen == new_sub->namelen && 00879 next->priority < new_sub->priority ) { 00880 prev = next; 00881 next = next->children; 00882 } 00883 00884 if (next && (next->namelen == new_sub->namelen) && 00885 (next->priority == new_sub->priority)) { 00886 if (new_sub->namelen != 1) { /* ignore root OID dups */ 00887 size_t out_len = 0; 00888 size_t buf_len = 0; 00889 char *buf = NULL; 00890 int buf_overflow = 0; 00891 00892 netsnmp_sprint_realloc_objid((u_char **) &buf, &buf_len, &out_len, 00893 1, &buf_overflow, 00894 new_sub->start_a, 00895 new_sub->start_len); 00896 snmp_log(LOG_ERR, 00897 "duplicate registration: MIB modules %s and %s (oid %s%s).\n", 00898 next->label_a, new_sub->label_a, 00899 buf ? buf : "", 00900 buf_overflow ? " [TRUNCATED]" : ""); 00901 free(buf); 00902 } 00903 return MIB_DUPLICATE_REGISTRATION; 00904 } 00905 00906 if (prev) { 00907 prev->children = new_sub; 00908 new_sub->children = next; 00909 netsnmp_subtree_change_prev(new_sub, prev->prev); 00910 netsnmp_subtree_change_next(new_sub, prev->next); 00911 } else { 00912 new_sub->children = next; 00913 netsnmp_subtree_change_prev(new_sub, next->prev); 00914 netsnmp_subtree_change_next(new_sub, next->next); 00915 00916 for (next = new_sub->next; next != NULL;next = next->children){ 00917 netsnmp_subtree_change_prev(next, new_sub); 00918 } 00919 00920 for (prev = new_sub->prev; prev != NULL;prev = prev->children){ 00921 netsnmp_subtree_change_next(prev, new_sub); 00922 } 00923 } 00924 break; 00925 00926 case 1: 00927 /* New subtree contains the existing one. */ 00928 { 00929 netsnmp_subtree *new2 = 00930 netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len); 00931 int res = netsnmp_subtree_load(new_sub, context_name); 00932 if (res != MIB_REGISTERED_OK) { 00933 netsnmp_remove_subtree(new2); 00934 netsnmp_subtree_free(new2); 00935 return res; 00936 } 00937 return netsnmp_subtree_load(new2, context_name); 00938 } 00939 } 00940 } 00941 return 0; 00942 } 00943 00950 void 00951 clear_subtree (netsnmp_subtree *sub) { 00952 00953 netsnmp_subtree *c; 00954 00955 if (sub == NULL) 00956 return; 00957 00958 for(c = sub; c;) { 00959 sub = c; 00960 c = c->children; 00961 netsnmp_subtree_free(sub); 00962 } 00963 00964 } 00965 00966 netsnmp_subtree * 00967 netsnmp_subtree_find_prev(const oid *name, size_t len, netsnmp_subtree *subtree, 00968 const char *context_name) 00969 { 00970 lookup_cache *lookup_cache = NULL; 00971 netsnmp_subtree *myptr = NULL, *previous = NULL; 00972 int cmp = 1; 00973 size_t ll_off = 0; 00974 00975 if (subtree) { 00976 myptr = subtree; 00977 } else { 00978 /* look through everything */ 00979 if (lookup_cache_size) { 00980 lookup_cache = lookup_cache_find(context_name, name, len, &cmp); 00981 if (lookup_cache) { 00982 myptr = lookup_cache->next; 00983 previous = lookup_cache->previous; 00984 } 00985 if (!myptr) 00986 myptr = netsnmp_subtree_find_first(context_name); 00987 } else { 00988 myptr = netsnmp_subtree_find_first(context_name); 00989 } 00990 } 00991 00992 /* 00993 * this optimization causes a segfault on sf cf alpha-linux1. 00994 * ifdef out until someone figures out why and fixes it. xxx-rks 20051117 00995 */ 00996 #ifndef __alpha 00997 #define WTEST_OPTIMIZATION 1 00998 #endif 00999 #ifdef WTEST_OPTIMIZATION 01000 DEBUGMSGTL(("wtest","oid in: ")); 01001 DEBUGMSGOID(("wtest", name, len)); 01002 DEBUGMSG(("wtest","\n")); 01003 #endif 01004 for (; myptr != NULL; previous = myptr, myptr = myptr->next) { 01005 #ifdef WTEST_OPTIMIZATION 01006 /* Compare the incoming oid with the linked list. If we have 01007 results of previous compares, its faster to make sure the 01008 length we differed in the last check is greater than the 01009 length between this pointer and the last then we don't need 01010 to actually perform a comparison */ 01011 DEBUGMSGTL(("wtest","oid cmp: ")); 01012 DEBUGMSGOID(("wtest", myptr->start_a, myptr->start_len)); 01013 DEBUGMSG(("wtest"," --- off = %lu, in off = %lu test = %d\n", 01014 (unsigned long)myptr->oid_off, (unsigned long)ll_off, 01015 !(ll_off && myptr->oid_off && 01016 myptr->oid_off > ll_off))); 01017 if (!(ll_off && myptr->oid_off && myptr->oid_off > ll_off) && 01018 netsnmp_oid_compare_ll(name, len, 01019 myptr->start_a, myptr->start_len, 01020 &ll_off) < 0) { 01021 #else 01022 if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) { 01023 #endif 01024 if (lookup_cache_size && previous && cmp) { 01025 if (lookup_cache) { 01026 lookup_cache_replace(lookup_cache, myptr, previous); 01027 } else { 01028 lookup_cache_add(context_name, myptr, previous); 01029 } 01030 } 01031 return previous; 01032 } 01033 } 01034 return previous; 01035 } 01036 01037 netsnmp_subtree * 01038 netsnmp_subtree_find_next(const oid *name, size_t len, 01039 netsnmp_subtree *subtree, const char *context_name) 01040 { 01041 netsnmp_subtree *myptr = NULL; 01042 01043 myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name); 01044 01045 if (myptr != NULL) { 01046 myptr = myptr->next; 01047 while (myptr != NULL && (myptr->variables == NULL || 01048 myptr->variables_len == 0)) { 01049 myptr = myptr->next; 01050 } 01051 return myptr; 01052 } else if (subtree != NULL && snmp_oid_compare(name, len, 01053 subtree->start_a, subtree->start_len) < 0) { 01054 return subtree; 01055 } else { 01056 return NULL; 01057 } 01058 } 01059 01060 netsnmp_subtree * 01061 netsnmp_subtree_find(const oid *name, size_t len, netsnmp_subtree *subtree, 01062 const char *context_name) 01063 { 01064 netsnmp_subtree *myptr; 01065 01066 myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name); 01067 if (myptr && myptr->end_a && 01068 snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) { 01069 return myptr; 01070 } 01071 01072 return NULL; 01073 } 01074 01076 /* End of Subtrees maintaining code */ 01077 01097 int 01098 netsnmp_register_mib(const char *moduleName, 01099 struct variable *var, 01100 size_t varsize, 01101 size_t numvars, 01102 oid * mibloc, 01103 size_t mibloclen, 01104 int priority, 01105 int range_subid, 01106 oid range_ubound, 01107 netsnmp_session * ss, 01108 const char *context, 01109 int timeout, 01110 int flags, 01111 netsnmp_handler_registration *reginfo, 01112 int perform_callback) 01113 { 01114 netsnmp_subtree *subtree, *sub2; 01115 int res; 01116 struct register_parameters reg_parms; 01117 int old_lookup_cache_val = netsnmp_get_lookup_cache_size(); 01118 01119 if (moduleName == NULL || 01120 mibloc == NULL) { 01121 /* Shouldn't happen ??? */ 01122 netsnmp_handler_registration_free(reginfo); 01123 return MIB_REGISTRATION_FAILED; 01124 } 01125 subtree = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree)); 01126 if (subtree == NULL) { 01127 netsnmp_handler_registration_free(reginfo); 01128 return MIB_REGISTRATION_FAILED; 01129 } 01130 01131 DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName)); 01132 DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid, 01133 range_ubound)); 01134 DEBUGMSG(("register_mib", " with context \"%s\"\n", 01135 SNMP_STRORNULL(context))); 01136 01137 /* 01138 * verify that the passed context is equal to the context 01139 * in the reginfo. 01140 * (which begs the question, why do we have both? It appears that the 01141 * reginfo item didn't appear til 5.2) 01142 */ 01143 if( ((NULL == context) && (NULL != reginfo->contextName)) || 01144 ((NULL != context) && (NULL == reginfo->contextName)) || 01145 ( ((NULL != context) && (NULL != reginfo->contextName)) && 01146 (0 != strcmp(context, reginfo->contextName))) ) { 01147 snmp_log(LOG_WARNING,"context passed during registration does not " 01148 "equal the reginfo contextName! ('%s' != '%s')\n", 01149 context, reginfo->contextName); 01150 netsnmp_assert(!"register context == reginfo->contextName"); /* always false */ 01151 } 01152 01153 /* Create the new subtree node being registered. */ 01154 01155 subtree->reginfo = reginfo; 01156 subtree->name_a = snmp_duplicate_objid(mibloc, mibloclen); 01157 subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen); 01158 subtree->end_a = snmp_duplicate_objid(mibloc, mibloclen); 01159 subtree->label_a = strdup(moduleName); 01160 if (subtree->name_a == NULL || subtree->start_a == NULL || 01161 subtree->end_a == NULL || subtree->label_a == NULL) { 01162 netsnmp_subtree_free(subtree); /* also frees reginfo */ 01163 return MIB_REGISTRATION_FAILED; 01164 } 01165 subtree->namelen = (u_char)mibloclen; 01166 subtree->start_len = (u_char)mibloclen; 01167 subtree->end_len = (u_char)mibloclen; 01168 subtree->end_a[mibloclen - 1]++; 01169 01170 if (var != NULL) { 01171 subtree->variables = (struct variable *)malloc(varsize*numvars); 01172 if (subtree->variables == NULL) { 01173 netsnmp_subtree_free(subtree); /* also frees reginfo */ 01174 return MIB_REGISTRATION_FAILED; 01175 } 01176 memcpy(subtree->variables, var, numvars*varsize); 01177 subtree->variables_len = numvars; 01178 subtree->variables_width = varsize; 01179 } 01180 subtree->priority = priority; 01181 subtree->timeout = timeout; 01182 subtree->range_subid = range_subid; 01183 subtree->range_ubound = range_ubound; 01184 subtree->session = ss; 01185 subtree->flags = (u_char)flags; /* used to identify instance oids */ 01186 subtree->flags |= SUBTREE_ATTACHED; 01187 subtree->global_cacheid = reginfo->global_cacheid; 01188 01189 netsnmp_set_lookup_cache_size(0); 01190 res = netsnmp_subtree_load(subtree, context); 01191 01192 /* If registering a range, use the first subtree as a template for the 01193 rest of the range. */ 01194 01195 if (res == MIB_REGISTERED_OK && range_subid != 0) { 01196 int i; 01197 for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) { 01198 sub2 = netsnmp_subtree_deepcopy(subtree); 01199 01200 if (sub2 == NULL) { 01201 unregister_mib_context(mibloc, mibloclen, priority, 01202 range_subid, range_ubound, context); 01203 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 01204 invalidate_lookup_cache(context); 01205 return MIB_REGISTRATION_FAILED; 01206 } 01207 01208 sub2->name_a[range_subid - 1] = i; 01209 sub2->start_a[range_subid - 1] = i; 01210 sub2->end_a[range_subid - 1] = i; /* XXX - ???? */ 01211 if (range_subid == (int)mibloclen) { 01212 ++sub2->end_a[range_subid - 1]; 01213 } 01214 sub2->flags |= SUBTREE_ATTACHED; 01215 sub2->global_cacheid = reginfo->global_cacheid; 01216 /* FRQ This is essential for requests to succeed! */ 01217 sub2->reginfo->rootoid[range_subid - 1] = i; 01218 01219 res = netsnmp_subtree_load(sub2, context); 01220 if (res != MIB_REGISTERED_OK) { 01221 unregister_mib_context(mibloc, mibloclen, priority, 01222 range_subid, range_ubound, context); 01223 netsnmp_remove_subtree(sub2); 01224 netsnmp_subtree_free(sub2); 01225 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 01226 invalidate_lookup_cache(context); 01227 return res; 01228 } 01229 } 01230 } else if (res == MIB_DUPLICATE_REGISTRATION || 01231 res == MIB_REGISTRATION_FAILED) { 01232 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 01233 invalidate_lookup_cache(context); 01234 netsnmp_subtree_free(subtree); 01235 return res; 01236 } 01237 01238 /* 01239 * mark the MIB as detached, if there's no master agent present as of now 01240 */ 01241 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 01242 NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) { 01243 extern struct snmp_session *main_session; 01244 if (main_session == NULL) { 01245 register_mib_detach_node(subtree); 01246 } 01247 } 01248 01249 if (res == MIB_REGISTERED_OK && perform_callback) { 01250 memset(®_parms, 0x0, sizeof(reg_parms)); 01251 reg_parms.name = mibloc; 01252 reg_parms.namelen = mibloclen; 01253 reg_parms.priority = priority; 01254 reg_parms.range_subid = range_subid; 01255 reg_parms.range_ubound = range_ubound; 01256 reg_parms.timeout = timeout; 01257 reg_parms.flags = (u_char) flags; 01258 reg_parms.contextName = context; 01259 reg_parms.session = ss; 01260 reg_parms.reginfo = reginfo; 01261 reg_parms.contextName = context; 01262 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01263 SNMPD_CALLBACK_REGISTER_OID, ®_parms); 01264 } 01265 01266 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 01267 invalidate_lookup_cache(context); 01268 return res; 01269 } 01270 01274 static void 01275 register_mib_reattach_node(netsnmp_subtree *s) 01276 { 01277 if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) { 01278 struct register_parameters reg_parms; 01279 /* 01280 * only do registrations that are not the top level nodes 01281 */ 01282 memset(®_parms, 0x0, sizeof(reg_parms)); 01283 01284 /* 01285 * XXX: do this better 01286 */ 01287 reg_parms.name = s->name_a; 01288 reg_parms.namelen = s->namelen; 01289 reg_parms.priority = s->priority; 01290 reg_parms.range_subid = s->range_subid; 01291 reg_parms.range_ubound = s->range_ubound; 01292 reg_parms.timeout = s->timeout; 01293 reg_parms.flags = s->flags; 01294 reg_parms.session = s->session; 01295 reg_parms.reginfo = s->reginfo; 01296 /* XXX: missing in subtree: reg_parms.contextName = s->context; */ 01297 if ((NULL != s->reginfo) && (NULL != s->reginfo->contextName)) 01298 reg_parms.contextName = s->reginfo->contextName; 01299 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01300 SNMPD_CALLBACK_REGISTER_OID, ®_parms); 01301 s->flags |= SUBTREE_ATTACHED; 01302 } 01303 } 01304 01307 void 01308 register_mib_reattach(void) 01309 { 01310 netsnmp_subtree *s, *t; 01311 subtree_context_cache *ptr; 01312 01313 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 01314 for (s = ptr->first_subtree; s != NULL; s = s->next) { 01315 register_mib_reattach_node(s); 01316 for (t = s->children; t != NULL; t = t->children) { 01317 register_mib_reattach_node(t); 01318 } 01319 } 01320 } 01321 } 01322 01328 static void 01329 register_mib_detach_node(netsnmp_subtree *s) 01330 { 01331 if (s != NULL) { 01332 s->flags = s->flags & ~SUBTREE_ATTACHED; 01333 } 01334 } 01335 01340 void 01341 register_mib_detach(void) 01342 { 01343 netsnmp_subtree *s, *t; 01344 subtree_context_cache *ptr; 01345 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 01346 for (s = ptr->first_subtree; s != NULL; s = s->next) { 01347 register_mib_detach_node(s); 01348 for (t = s->children; t != NULL; t = t->children) { 01349 register_mib_detach_node(t); 01350 } 01351 } 01352 } 01353 } 01354 01402 int 01403 register_mib_context(const char *moduleName, 01404 struct variable *var, 01405 size_t varsize, 01406 size_t numvars, 01407 const oid * mibloc, 01408 size_t mibloclen, 01409 int priority, 01410 int range_subid, 01411 oid range_ubound, 01412 netsnmp_session * ss, 01413 const char *context, int timeout, int flags) 01414 { 01415 return netsnmp_register_old_api(moduleName, var, varsize, numvars, 01416 mibloc, mibloclen, priority, 01417 range_subid, range_ubound, ss, context, 01418 timeout, flags); 01419 } 01420 01467 int 01468 register_mib_range(const char *moduleName, 01469 struct variable *var, 01470 size_t varsize, 01471 size_t numvars, 01472 const oid * mibloc, 01473 size_t mibloclen, 01474 int priority, 01475 int range_subid, oid range_ubound, netsnmp_session * ss) 01476 { 01477 return register_mib_context(moduleName, var, varsize, numvars, 01478 mibloc, mibloclen, priority, 01479 range_subid, range_ubound, ss, "", -1, 0); 01480 } 01481 01516 int 01517 register_mib_priority(const char *moduleName, 01518 struct variable *var, 01519 size_t varsize, 01520 size_t numvars, 01521 const oid * mibloc, size_t mibloclen, int priority) 01522 { 01523 return register_mib_range(moduleName, var, varsize, numvars, 01524 mibloc, mibloclen, priority, 0, 0, NULL); 01525 } 01526 01556 int 01557 register_mib(const char *moduleName, 01558 struct variable *var, 01559 size_t varsize, 01560 size_t numvars, const oid * mibloc, size_t mibloclen) 01561 { 01562 return register_mib_priority(moduleName, var, varsize, numvars, 01563 mibloc, mibloclen, DEFAULT_MIB_PRIORITY); 01564 } 01565 01577 void 01578 netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev, const char *context) 01579 { 01580 netsnmp_subtree *ptr; 01581 01582 DEBUGMSGTL(("register_mib", "unload(")); 01583 if (sub != NULL) { 01584 DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len)); 01585 } else { 01586 DEBUGMSG(("register_mib", "[NIL]")); 01587 } 01588 DEBUGMSG(("register_mib", ", ")); 01589 if (prev != NULL) { 01590 DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len)); 01591 } else { 01592 DEBUGMSG(("register_mib", "[NIL]")); 01593 } 01594 DEBUGMSG(("register_mib", ")\n")); 01595 01596 if (prev != NULL) { /* non-leading entries are easy */ 01597 prev->children = sub->children; 01598 invalidate_lookup_cache(context); 01599 return; 01600 } 01601 /* 01602 * otherwise, we need to amend our neighbours as well 01603 */ 01604 01605 if (sub->children == NULL) { /* just remove this node completely */ 01606 for (ptr = sub->prev; ptr; ptr = ptr->children) { 01607 netsnmp_subtree_change_next(ptr, sub->next); 01608 } 01609 for (ptr = sub->next; ptr; ptr = ptr->children) { 01610 netsnmp_subtree_change_prev(ptr, sub->prev); 01611 } 01612 01613 if (sub->prev == NULL) { 01614 netsnmp_subtree_replace_first(sub->next, context); 01615 } 01616 01617 } else { 01618 for (ptr = sub->prev; ptr; ptr = ptr->children) 01619 netsnmp_subtree_change_next(ptr, sub->children); 01620 for (ptr = sub->next; ptr; ptr = ptr->children) 01621 netsnmp_subtree_change_prev(ptr, sub->children); 01622 01623 if (sub->prev == NULL) { 01624 netsnmp_subtree_replace_first(sub->children, context); 01625 } 01626 } 01627 invalidate_lookup_cache(context); 01628 } 01629 01662 int 01663 unregister_mib_context(oid * name, size_t len, int priority, 01664 int range_subid, oid range_ubound, 01665 const char *context) 01666 { 01667 netsnmp_subtree *list, *myptr; 01668 netsnmp_subtree *prev, *child, *next; /* loop through children */ 01669 struct register_parameters reg_parms; 01670 int old_lookup_cache_val = netsnmp_get_lookup_cache_size(); 01671 int unregistering = 1; 01672 int orig_subid_val = -1; 01673 01674 netsnmp_set_lookup_cache_size(0); 01675 01676 if ((range_subid > 0) && ((size_t)range_subid <= len)) 01677 orig_subid_val = name[range_subid-1]; 01678 01679 while(unregistering){ 01680 DEBUGMSGTL(("register_mib", "unregistering ")); 01681 DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound)); 01682 DEBUGMSG(("register_mib", "\n")); 01683 01684 list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context), 01685 context); 01686 if (list == NULL) { 01687 return MIB_NO_SUCH_REGISTRATION; 01688 } 01689 01690 for (child = list, prev = NULL; child != NULL; 01691 prev = child, child = child->children) { 01692 if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 && 01693 child->priority == priority) { 01694 break; /* found it */ 01695 } 01696 } 01697 01698 if (child == NULL) { 01699 return MIB_NO_SUCH_REGISTRATION; 01700 } 01701 01702 netsnmp_subtree_unload(child, prev, context); 01703 myptr = child; /* remember this for later */ 01704 01705 /* 01706 * Now handle any occurances in the following subtrees, 01707 * as a result of splitting this range. Due to the 01708 * nature of the way such splits work, the first 01709 * subtree 'slice' that doesn't refer to the given 01710 * name marks the end of the original region. 01711 * 01712 * This should also serve to register ranges. 01713 */ 01714 01715 for (list = myptr->next; list != NULL; list = next) { 01716 next = list->next; /* list gets freed sometimes; cache next */ 01717 for (child = list, prev = NULL; child != NULL; 01718 prev = child, child = child->children) { 01719 if ((netsnmp_oid_equals(child->name_a, child->namelen, 01720 name, len) == 0) && 01721 (child->priority == priority)) { 01722 netsnmp_subtree_unload(child, prev, context); 01723 netsnmp_subtree_free(child); 01724 break; 01725 } 01726 } 01727 if (child == NULL) /* Didn't find the given name */ 01728 break; 01729 } 01730 01731 /* Maybe we are in a range... */ 01732 if (orig_subid_val != -1){ 01733 if (++name[range_subid-1] >= orig_subid_val+range_ubound) 01734 { 01735 unregistering=0; 01736 name[range_subid-1] = orig_subid_val; 01737 } 01738 } 01739 else { 01740 unregistering=0; 01741 } 01742 } 01743 01744 memset(®_parms, 0x0, sizeof(reg_parms)); 01745 reg_parms.name = name; 01746 reg_parms.namelen = len; 01747 reg_parms.priority = priority; 01748 reg_parms.range_subid = range_subid; 01749 reg_parms.range_ubound = range_ubound; 01750 reg_parms.flags = 0x00; /* this is okay I think */ 01751 reg_parms.contextName = context; 01752 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01753 SNMPD_CALLBACK_UNREGISTER_OID, ®_parms); 01754 01755 netsnmp_subtree_free(myptr); 01756 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 01757 invalidate_lookup_cache(context); 01758 return MIB_UNREGISTERED_OK; 01759 } 01760 01761 #ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW 01762 int 01763 netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority, 01764 int var_subid, oid range_ubound, 01765 const char *context) 01766 { 01767 netsnmp_subtree *list, *myptr, *futureptr; 01768 netsnmp_subtree *prev, *child; /* loop through children */ 01769 struct register_parameters reg_parms; 01770 oid range_lbound = name[var_subid - 1]; 01771 01772 DEBUGMSGTL(("register_mib", "unregistering ")); 01773 DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound)); 01774 DEBUGMSG(("register_mib", "\n")); 01775 01776 for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) { 01777 list = netsnmp_subtree_find(name, len, 01778 netsnmp_subtree_find_first(context), context); 01779 01780 if (list == NULL) { 01781 continue; 01782 } 01783 01784 for (child = list, prev = NULL; child != NULL; 01785 prev = child, child = child->children) { 01786 01787 if (netsnmp_oid_equals(child->name_a, child->namelen, 01788 name, len) == 0 && 01789 (child->priority == priority)) { 01790 break; /* found it */ 01791 } 01792 } 01793 01794 if (child == NULL) { 01795 continue; 01796 } 01797 01798 netsnmp_subtree_unload(child, prev, context); 01799 myptr = child; /* remember this for later */ 01800 01801 for (list = myptr->next; list != NULL; list = futureptr) { 01802 /* remember the next spot in the list in case we free this node */ 01803 futureptr = list->next; 01804 01805 /* check each child */ 01806 for (child = list, prev = NULL; child != NULL; 01807 prev = child, child = child->children) { 01808 01809 if (netsnmp_oid_equals(child->name_a, child->namelen, 01810 name, len) == 0 && 01811 (child->priority == priority)) { 01812 netsnmp_subtree_unload(child, prev, context); 01813 netsnmp_subtree_free(child); 01814 break; 01815 } 01816 } 01817 01818 /* XXX: wjh: not sure why we're bailing here */ 01819 if (child == NULL) { /* Didn't find the given name */ 01820 break; 01821 } 01822 } 01823 netsnmp_subtree_free(myptr); 01824 } 01825 01826 name[var_subid - 1] = range_lbound; 01827 memset(®_parms, 0x0, sizeof(reg_parms)); 01828 reg_parms.name = name; 01829 reg_parms.namelen = len; 01830 reg_parms.priority = priority; 01831 reg_parms.range_subid = var_subid; 01832 reg_parms.range_ubound = range_ubound; 01833 reg_parms.flags = 0x00; /* this is okay I think */ 01834 reg_parms.contextName = context; 01835 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01836 SNMPD_CALLBACK_UNREGISTER_OID, ®_parms); 01837 01838 return 0; 01839 } 01840 #endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW */ 01841 01872 int 01873 unregister_mib_range(oid * name, size_t len, int priority, 01874 int range_subid, oid range_ubound) 01875 { 01876 return unregister_mib_context(name, len, priority, range_subid, 01877 range_ubound, ""); 01878 } 01879 01901 int 01902 unregister_mib_priority(oid * name, size_t len, int priority) 01903 { 01904 return unregister_mib_range(name, len, priority, 0, 0); 01905 } 01906 01922 int 01923 unregister_mib(oid * name, size_t len) 01924 { 01925 return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY); 01926 } 01927 01935 void 01936 unregister_mibs_by_session(netsnmp_session * ss) 01937 { 01938 netsnmp_subtree *list, *list2; 01939 netsnmp_subtree *child, *prev, *next_child; 01940 struct register_parameters rp; 01941 subtree_context_cache *contextptr; 01942 01943 DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n", 01944 ss, (ss && ss->contextName) ? ss->contextName : "[NIL]")); 01945 01946 for (contextptr = get_top_context_cache(); contextptr != NULL; 01947 contextptr = contextptr->next) { 01948 for (list = contextptr->first_subtree; list != NULL; list = list2) { 01949 list2 = list->next; 01950 01951 for (child = list, prev = NULL; child != NULL; child = next_child){ 01952 next_child = child->children; 01953 01954 if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && 01955 child->session == ss) || 01956 (!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session && 01957 child->session->subsession == ss)) { 01958 01959 memset(&rp,0x0,sizeof(rp)); 01960 rp.name = child->name_a; 01961 child->name_a = NULL; 01962 rp.namelen = child->namelen; 01963 rp.priority = child->priority; 01964 rp.range_subid = child->range_subid; 01965 rp.range_ubound = child->range_ubound; 01966 rp.timeout = child->timeout; 01967 rp.flags = child->flags; 01968 if ((NULL != child->reginfo) && 01969 (NULL != child->reginfo->contextName)) 01970 rp.contextName = child->reginfo->contextName; 01971 01972 if (child->reginfo != NULL) { 01973 /* 01974 * Don't let's free the session pointer just yet! 01975 */ 01976 child->reginfo->handler->myvoid = NULL; 01977 netsnmp_handler_registration_free(child->reginfo); 01978 child->reginfo = NULL; 01979 } 01980 01981 netsnmp_subtree_unload(child, prev, contextptr->context_name); 01982 netsnmp_subtree_free(child); 01983 01984 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01985 SNMPD_CALLBACK_UNREGISTER_OID, &rp); 01986 SNMP_FREE(rp.name); 01987 } else { 01988 prev = child; 01989 } 01990 } 01991 } 01992 netsnmp_subtree_join(contextptr->first_subtree); 01993 } 01994 } 01995 02011 int 02012 in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type) 02013 { 02014 struct view_parameters view_parms; 02015 02016 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 02017 /* Enable bypassing of view-based access control */ 02018 return VACM_SUCCESS; 02019 } 02020 02021 /* 02022 * check for v1 and counter64s, since snmpv1 doesn't support it 02023 */ 02024 #ifndef NETSNMP_DISABLE_SNMPV1 02025 if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) { 02026 return VACM_NOTINVIEW; 02027 } 02028 #endif 02029 02030 view_parms.pdu = pdu; 02031 view_parms.name = name; 02032 if (namelen != NULL) { 02033 view_parms.namelen = *namelen; 02034 } else { 02035 view_parms.namelen = 0; 02036 } 02037 view_parms.errorcode = 0; 02038 view_parms.check_subtree = 0; 02039 02040 switch (pdu->version) { 02041 #ifndef NETSNMP_DISABLE_SNMPV1 02042 case SNMP_VERSION_1: 02043 #endif 02044 #ifndef NETSNMP_DISABLE_SNMPV2C 02045 case SNMP_VERSION_2c: 02046 #endif 02047 case SNMP_VERSION_3: 02048 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 02049 SNMPD_CALLBACK_ACM_CHECK, &view_parms); 02050 return view_parms.errorcode; 02051 } 02052 return VACM_NOSECNAME; 02053 } 02054 02065 int 02066 check_access(netsnmp_pdu *pdu) 02067 { /* IN - pdu being checked */ 02068 struct view_parameters view_parms; 02069 view_parms.pdu = pdu; 02070 view_parms.name = NULL; 02071 view_parms.namelen = 0; 02072 view_parms.errorcode = 0; 02073 view_parms.check_subtree = 0; 02074 02075 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 02076 /* Enable bypassing of view-based access control */ 02077 return 0; 02078 } 02079 02080 switch (pdu->version) { 02081 #ifndef NETSNMP_DISABLE_SNMPV1 02082 case SNMP_VERSION_1: 02083 #endif 02084 #ifndef NETSNMP_DISABLE_SNMPV2C 02085 case SNMP_VERSION_2c: 02086 #endif 02087 case SNMP_VERSION_3: 02088 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 02089 SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms); 02090 return view_parms.errorcode; 02091 } 02092 return 1; 02093 } 02094 02109 int 02110 netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen) 02111 { /* IN - pdu being checked */ 02112 struct view_parameters view_parms; 02113 view_parms.pdu = pdu; 02114 view_parms.name = name; 02115 view_parms.namelen = namelen; 02116 view_parms.errorcode = 0; 02117 view_parms.check_subtree = 1; 02118 02119 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 02120 /* Enable bypassing of view-based access control */ 02121 return 0; 02122 } 02123 02124 switch (pdu->version) { 02125 #ifndef NETSNMP_DISABLE_SNMPV1 02126 case SNMP_VERSION_1: 02127 #endif 02128 #ifndef NETSNMP_DISABLE_SNMPV2C 02129 case SNMP_VERSION_2c: 02130 #endif 02131 case SNMP_VERSION_3: 02132 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 02133 SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms); 02134 return view_parms.errorcode; 02135 } 02136 return 1; 02137 } 02138 02139 netsnmp_feature_child_of(get_session_for_oid,netsnmp_unused) 02140 #ifndef NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID 02141 netsnmp_session * 02142 get_session_for_oid(const oid *name, size_t len, const char *context_name) 02143 { 02144 netsnmp_subtree *myptr; 02145 02146 myptr = netsnmp_subtree_find_prev(name, len, 02147 netsnmp_subtree_find_first(context_name), 02148 context_name); 02149 02150 while (myptr && myptr->variables == NULL) { 02151 myptr = myptr->next; 02152 } 02153 02154 if (myptr == NULL) { 02155 return NULL; 02156 } else { 02157 return myptr->session; 02158 } 02159 } 02160 #endif /* NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID */ 02161 02162 void 02163 setup_tree(void) 02164 { 02165 oid ccitt[1] = { 0 }; 02166 oid iso[1] = { 1 }; 02167 oid joint_ccitt_iso[1] = { 2 }; 02168 02169 #ifdef USING_AGENTX_SUBAGENT_MODULE 02170 int role = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 02171 NETSNMP_DS_AGENT_ROLE); 02172 02173 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 02174 MASTER_AGENT); 02175 #endif 02176 02177 /* 02178 * we need to have the oid's in the heap, that we can *free* it for every case, 02179 * thats the purpose of the duplicate_objid's 02180 */ 02181 netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1); 02182 netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1); 02183 netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1); 02184 02185 #ifdef USING_AGENTX_SUBAGENT_MODULE 02186 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 02187 role); 02188 #endif 02189 } 02190 02191 int 02192 remove_tree_entry (oid *name, size_t len) { 02193 02194 netsnmp_subtree *sub = NULL; 02195 02196 if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) { 02197 return MIB_NO_SUCH_REGISTRATION; 02198 } 02199 02200 return unregister_mib_context(name, len, sub->priority, 02201 sub->range_subid, sub->range_ubound, ""); 02202 02203 } 02204 02205 02206 void 02207 shutdown_tree(void) { 02208 oid ccitt[1] = { 0 }; 02209 oid iso[1] = { 1 }; 02210 oid joint_ccitt_iso[1] = { 2 }; 02211 02212 DEBUGMSGTL(("agent_registry", "shut down tree\n")); 02213 02214 remove_tree_entry(joint_ccitt_iso, 1); 02215 remove_tree_entry(iso, 1); 02216 remove_tree_entry(ccitt, 1); 02217 02218 } 02219 02220 extern void dump_idx_registry(void); 02221 void 02222 dump_registry(void) 02223 { 02224 struct variable *vp = NULL; 02225 netsnmp_subtree *myptr, *myptr2; 02226 u_char *s = NULL, *e = NULL, *v = NULL; 02227 size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0; 02228 int i = 0; 02229 02230 if ((s = (u_char *) calloc(sl, 1)) != NULL && 02231 (e = (u_char *) calloc(sl, 1)) != NULL && 02232 (v = (u_char *) calloc(sl, 1)) != NULL) { 02233 02234 subtree_context_cache *ptr; 02235 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 02236 printf("Subtrees for Context: %s\n", ptr->context_name); 02237 for (myptr = ptr->first_subtree; myptr != NULL; 02238 myptr = myptr->next) { 02239 sl_o = el_o = vl_o = 0; 02240 02241 if (!sprint_realloc_objid(&s, &sl, &sl_o, 1, 02242 myptr->start_a, 02243 myptr->start_len)) { 02244 break; 02245 } 02246 if (!sprint_realloc_objid(&e, &el, &el_o, 1, 02247 myptr->end_a, 02248 myptr->end_len)) { 02249 break; 02250 } 02251 02252 if (myptr->variables) { 02253 printf("%02x ( %s - %s ) [", myptr->flags, s, e); 02254 for (i = 0, vp = myptr->variables; 02255 i < myptr->variables_len; i++) { 02256 vl_o = 0; 02257 if (!sprint_realloc_objid 02258 (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) { 02259 break; 02260 } 02261 printf("%s, ", v); 02262 vp = (struct variable *) ((char *) vp + 02263 myptr->variables_width); 02264 } 02265 printf("]\n"); 02266 } else { 02267 printf("%02x %s - %s \n", myptr->flags, s, e); 02268 } 02269 for (myptr2 = myptr; myptr2 != NULL; 02270 myptr2 = myptr2->children) { 02271 if (myptr2->label_a && myptr2->label_a[0]) { 02272 if (strcmp(myptr2->label_a, "old_api") == 0) { 02273 struct variable *vp = 02274 (struct variable*)myptr2->reginfo->handler->myvoid; 02275 02276 if (!sprint_realloc_objid(&s, &sl, &sl_o, 1, 02277 vp->name, vp->namelen)) { 02278 continue; 02279 } 02280 printf("\t%s[%s] %p var %s\n", myptr2->label_a, 02281 myptr2->reginfo->handlerName ? 02282 myptr2->reginfo->handlerName : "no-name", 02283 myptr2->reginfo, s); 02284 } else { 02285 printf("\t%s %s %p\n", myptr2->label_a, 02286 myptr2->reginfo->handlerName ? 02287 myptr2->reginfo->handlerName : "no-handler-name", 02288 myptr2->reginfo); 02289 } 02290 } 02291 } 02292 } 02293 } 02294 } 02295 02296 SNMP_FREE(s); 02297 SNMP_FREE(e); 02298 SNMP_FREE(v); 02299 02300 dump_idx_registry(); 02301 } 02302 02304 /* End of MIB registration code */ 02305 02306 02314 int external_signal_scheduled[NUM_EXTERNAL_SIGS]; 02315 void (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int); 02316 02317 #ifndef WIN32 02318 02319 /* 02320 * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines 02321 * below for every single that might be handled by register_signal(). 02322 */ 02323 02324 RETSIGTYPE 02325 agent_SIGCHLD_handler(int sig) 02326 { 02327 external_signal_scheduled[SIGCHLD]++; 02328 #ifndef HAVE_SIGACTION 02329 /* 02330 * signal() sucks. It *might* have SysV semantics, which means that 02331 * * a signal handler is reset once it gets called. Ensure that it 02332 * * remains active. 02333 */ 02334 signal(SIGCHLD, agent_SIGCHLD_handler); 02335 #endif 02336 } 02337 02352 int 02353 register_signal(int sig, void (*func) (int)) 02354 { 02355 02356 switch (sig) { 02357 #if defined(SIGCHLD) 02358 case SIGCHLD: 02359 #ifdef HAVE_SIGACTION 02360 { 02361 static struct sigaction act; 02362 act.sa_handler = agent_SIGCHLD_handler; 02363 sigemptyset(&act.sa_mask); 02364 act.sa_flags = 0; 02365 sigaction(SIGCHLD, &act, NULL); 02366 } 02367 #else 02368 signal(SIGCHLD, agent_SIGCHLD_handler); 02369 #endif 02370 break; 02371 #endif 02372 default: 02373 snmp_log(LOG_CRIT, 02374 "register_signal: signal %d cannot be handled\n", sig); 02375 return SIG_REGISTRATION_FAILED; 02376 } 02377 02378 external_signal_handler[sig] = func; 02379 external_signal_scheduled[sig] = 0; 02380 02381 DEBUGMSGTL(("register_signal", "registered signal %d\n", sig)); 02382 return SIG_REGISTERED_OK; 02383 } 02384 02391 int 02392 unregister_signal(int sig) 02393 { 02394 signal(sig, SIG_DFL); 02395 DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig)); 02396 return SIG_UNREGISTERED_OK; 02397 } 02398 02399 #endif /* !WIN32 */ 02400 02402 /* End of signals support code */ 02403