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