net-snmp 5.7
agent_registry.c
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(&reg_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, &reg_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(&reg_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, &reg_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(&reg_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, &reg_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(&reg_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, &reg_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