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