Blame agent/agent_registry.c

Packit Service b38f0b
/*
Packit Service b38f0b
 * agent_registry.c
Packit Service b38f0b
 */
Packit Service b38f0b
/* Portions of this file are subject to the following copyright(s).  See
Packit Service b38f0b
 * the Net-SNMP's COPYING file for more details and other copyrights
Packit Service b38f0b
 * that may apply:
Packit Service b38f0b
 */
Packit Service b38f0b
/*
Packit Service b38f0b
 * Portions of this file are copyrighted by:
Packit Service b38f0b
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
Packit Service b38f0b
 * Use is subject to license terms specified in the COPYING file
Packit Service b38f0b
 * distributed with the Net-SNMP package.
Packit Service b38f0b
 *
Packit Service b38f0b
 * Portions of this file are copyrighted by:
Packit Service b38f0b
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
Packit Service b38f0b
 * Use is subject to license terms specified in the COPYING file
Packit Service b38f0b
 * distributed with the Net-SNMP package.
Packit Service b38f0b
 */
Packit Service b38f0b
/** @defgroup agent_registry Registry of MIB subtrees, modules, sessions, etc
Packit Service b38f0b
 *     Maintain a registry of MIB subtrees, together with related information
Packit Service b38f0b
 *     regarding MIB modules, sessions, etc
Packit Service b38f0b
 *   @ingroup agent
Packit Service b38f0b
 *
Packit Service b38f0b
 * @{
Packit Service b38f0b
 */
Packit Service b38f0b
Packit Service b38f0b
#define IN_SNMP_VARS_C
Packit Service b38f0b
Packit Service b38f0b
#include <net-snmp/net-snmp-config.h>
Packit Service b38f0b
#include <net-snmp/net-snmp-features.h>
Packit Service b38f0b
Packit Service b38f0b
#include <signal.h>
Packit Service b38f0b
#if HAVE_STRING_H
Packit Service b38f0b
#include <string.h>
Packit Service b38f0b
#endif
Packit Service b38f0b
#if HAVE_STDLIB_H
Packit Service b38f0b
#include <stdlib.h>
Packit Service b38f0b
#endif
Packit Service b38f0b
#include <sys/types.h>
Packit Service b38f0b
#include <stdio.h>
Packit Service b38f0b
#include <fcntl.h>
Packit Service b38f0b
#if TIME_WITH_SYS_TIME
Packit Service b38f0b
# include <sys/time.h>
Packit Service b38f0b
# include <time.h>
Packit Service b38f0b
#else
Packit Service b38f0b
# if HAVE_SYS_TIME_H
Packit Service b38f0b
#  include <sys/time.h>
Packit Service b38f0b
# else
Packit Service b38f0b
#  include <time.h>
Packit Service b38f0b
# endif
Packit Service b38f0b
#endif
Packit Service b38f0b
#if HAVE_NETINET_IN_H
Packit Service b38f0b
#include <netinet/in.h>
Packit Service b38f0b
#endif
Packit Service b38f0b
Packit Service b38f0b
#include <net-snmp/net-snmp-includes.h>
Packit Service b38f0b
#include <net-snmp/library/snmp_assert.h>
Packit Service b38f0b
#include <net-snmp/agent/net-snmp-agent-includes.h>
Packit Service b38f0b
#include <net-snmp/agent/agent_callbacks.h>
Packit Service b38f0b
Packit Service b38f0b
#include "snmpd.h"
Packit Service b38f0b
#include "agent_global_vars.h"
Packit Service b38f0b
#include "mibgroup/struct.h"
Packit Service b38f0b
#include <net-snmp/agent/old_api.h>
Packit Service b38f0b
#include <net-snmp/agent/null.h>
Packit Service b38f0b
#include <net-snmp/agent/table.h>
Packit Service b38f0b
#include <net-snmp/agent/table_iterator.h>
Packit Service b38f0b
#include <net-snmp/agent/agent_index.h>
Packit Service b38f0b
#include <net-snmp/agent/agent_registry.h>
Packit Service b38f0b
Packit Service b38f0b
#ifdef USING_AGENTX_SUBAGENT_MODULE
Packit Service b38f0b
#include "agentx/subagent.h"
Packit Service b38f0b
#include "agentx/client.h"
Packit Service b38f0b
#endif
Packit Service b38f0b
Packit Service b38f0b
netsnmp_feature_child_of(agent_registry_all, libnetsnmpagent)
Packit Service b38f0b
Packit Service b38f0b
netsnmp_feature_child_of(unregister_mib_table_row, agent_registry_all)
Packit Service b38f0b
Packit Service b38f0b
/** @defgroup agent_lookup_cache Lookup cache, storing the registered OIDs.
Packit Service b38f0b
 *     Maintain the cache used for locating sub-trees and OIDs.
Packit Service b38f0b
 *   @ingroup agent_registry
Packit Service b38f0b
 *
Packit Service b38f0b
 * @{
Packit Service b38f0b
 */
Packit Service b38f0b
Packit Service b38f0b
/**  Lookup cache - default size.*/
Packit Service b38f0b
#define SUBTREE_DEFAULT_CACHE_SIZE 8
Packit Service b38f0b
/**  Lookup cache - max acceptable size.*/
Packit Service b38f0b
#define SUBTREE_MAX_CACHE_SIZE     32
Packit Service b38f0b
int lookup_cache_size = 0; /*enabled later after registrations are loaded */
Packit Service b38f0b
Packit Service b38f0b
typedef struct lookup_cache_s {
Packit Service b38f0b
   netsnmp_subtree *next;
Packit Service b38f0b
   netsnmp_subtree *previous;
Packit Service b38f0b
} lookup_cache;
Packit Service b38f0b
Packit Service b38f0b
typedef struct lookup_cache_context_s {
Packit Service b38f0b
   char *context;
Packit Service b38f0b
   struct lookup_cache_context_s *next;
Packit Service b38f0b
   int thecachecount;
Packit Service b38f0b
   int currentpos;
Packit Service b38f0b
   lookup_cache cache[SUBTREE_MAX_CACHE_SIZE];
Packit Service b38f0b
} lookup_cache_context;
Packit Service b38f0b
Packit Service b38f0b
static lookup_cache_context *thecontextcache = NULL;
Packit Service b38f0b
Packit Service b38f0b
/** Set the lookup cache size for optimized agent registration performance.
Packit Service b38f0b
 * Note that it is only used by master agent - sub-agent doesn't need the cache.
Packit Service b38f0b
 * The rough guide is that the cache size should be equal to the maximum
Packit Service b38f0b
 * number of simultaneous managers you expect to talk to the agent (M) times 80%
Packit Service b38f0b
 * (or so, he says randomly) the average number (N) of varbinds you
Packit Service b38f0b
 * expect to receive in a given request for a manager.  ie, M times N.
Packit Service b38f0b
 * Bigger does NOT necessarily mean better.  Certainly 16 should be an
Packit Service b38f0b
 * upper limit.  32 is the hard coded limit.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param newsize set to the maximum size of a cache for a given
Packit Service b38f0b
 * context.  Set to 0 to completely disable caching, or to -1 to set
Packit Service b38f0b
 * to the default cache size (8), or to a number of your chosing.  The
Packit Service b38f0b
 */
Packit Service b38f0b
void
Packit Service b38f0b
netsnmp_set_lookup_cache_size(int newsize) {
Packit Service b38f0b
    if (newsize < 0)
Packit Service b38f0b
        lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE;
Packit Service b38f0b
    else if (newsize < SUBTREE_MAX_CACHE_SIZE)
Packit Service b38f0b
        lookup_cache_size = newsize;
Packit Service b38f0b
    else
Packit Service b38f0b
        lookup_cache_size = SUBTREE_MAX_CACHE_SIZE;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Retrieves the current value of the lookup cache size
Packit Service b38f0b
 *  Should be called from master agent only - sub-agent doesn't need the cache.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return the current lookup cache size
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
netsnmp_get_lookup_cache_size(void) {
Packit Service b38f0b
    return lookup_cache_size;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Returns lookup cache entry for the context of given name.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param context Name of the context. Name is case sensitive.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return the lookup cache context
Packit Service b38f0b
 */
Packit Service b38f0b
NETSNMP_STATIC_INLINE lookup_cache_context *
Packit Service b38f0b
get_context_lookup_cache(const char *context) {
Packit Service b38f0b
    lookup_cache_context *ptr;
Packit Service b38f0b
    if (!context)
Packit Service b38f0b
        context = "";
Packit Service b38f0b
Packit Service b38f0b
    for(ptr = thecontextcache; ptr; ptr = ptr->next) {
Packit Service b38f0b
        if (strcmp(ptr->context, context) == 0)
Packit Service b38f0b
            break;
Packit Service b38f0b
    }
Packit Service b38f0b
    if (!ptr) {
Packit Service b38f0b
        if (netsnmp_subtree_find_first(context)) {
Packit Service b38f0b
            ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context);
Packit Service b38f0b
            ptr->next = thecontextcache;
Packit Service b38f0b
            ptr->context = strdup(context);
Packit Service b38f0b
            thecontextcache = ptr;
Packit Service b38f0b
        } else {
Packit Service b38f0b
            return NULL;
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
    return ptr;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Adds an entry to the Lookup Cache under specified context name.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param context  Name of the context. Name is case sensitive.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param next     Next subtree item.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param previous Previous subtree item.
Packit Service b38f0b
 */
Packit Service b38f0b
NETSNMP_STATIC_INLINE void
Packit Service b38f0b
lookup_cache_add(const char *context,
Packit Service b38f0b
                 netsnmp_subtree *next, netsnmp_subtree *previous) {
Packit Service b38f0b
    lookup_cache_context *cptr;
Packit Service b38f0b
Packit Service b38f0b
    if ((cptr = get_context_lookup_cache(context)) == NULL)
Packit Service b38f0b
        return;
Packit Service b38f0b
Packit Service b38f0b
    if (cptr->thecachecount < lookup_cache_size)
Packit Service b38f0b
        cptr->thecachecount++;
Packit Service b38f0b
Packit Service b38f0b
    cptr->cache[cptr->currentpos].next = next;
Packit Service b38f0b
    cptr->cache[cptr->currentpos].previous = previous;
Packit Service b38f0b
Packit Service b38f0b
    if (++cptr->currentpos >= lookup_cache_size)
Packit Service b38f0b
        cptr->currentpos = 0;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** @private
Packit Service b38f0b
 *  Replaces next and previous pointer in given Lookup Cache.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param ptr      Lookup Cache pointer.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param next     Next subtree item.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param previous Previous subtree item.
Packit Service b38f0b
 */
Packit Service b38f0b
NETSNMP_STATIC_INLINE void
Packit Service b38f0b
lookup_cache_replace(lookup_cache *ptr,
Packit Service b38f0b
                     netsnmp_subtree *next, netsnmp_subtree *previous) {
Packit Service b38f0b
Packit Service b38f0b
    ptr->next = next;
Packit Service b38f0b
    ptr->previous = previous;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Finds an entry in the Lookup Cache.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param context  Case sensitive name of the context.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param name     The OID we're searching for.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param name_len Number of sub-ids (single integers) in the OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param retcmp   Value set to snmp_oid_compare() call result.
Packit Service b38f0b
 *                  The value, if set, is always nonnegative.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return gives Lookup Cache entry, or NULL if not found.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @see snmp_oid_compare()
Packit Service b38f0b
 */
Packit Service b38f0b
NETSNMP_STATIC_INLINE lookup_cache *
Packit Service b38f0b
lookup_cache_find(const char *context, const oid *name, size_t name_len,
Packit Service b38f0b
                  int *retcmp) {
Packit Service b38f0b
    lookup_cache_context *cptr;
Packit Service b38f0b
    lookup_cache *ret = NULL;
Packit Service b38f0b
    int cmp;
Packit Service b38f0b
    int i;
Packit Service b38f0b
Packit Service b38f0b
    if ((cptr = get_context_lookup_cache(context)) == NULL)
Packit Service b38f0b
        return NULL;
Packit Service b38f0b
Packit Service b38f0b
    for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) {
Packit Service b38f0b
        if (cptr->cache[i].previous->start_a)
Packit Service b38f0b
            cmp = snmp_oid_compare(name, name_len,
Packit Service b38f0b
                                   cptr->cache[i].previous->start_a,
Packit Service b38f0b
                                   cptr->cache[i].previous->start_len);
Packit Service b38f0b
        else
Packit Service b38f0b
            cmp = 1;
Packit Service b38f0b
        if (cmp >= 0) {
Packit Service b38f0b
            *retcmp = cmp;
Packit Service b38f0b
            ret = &(cptr->cache[i]);
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
    return ret;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** @private
Packit Service b38f0b
 *  Clears cache count and position in Lookup Cache.
Packit Service b38f0b
 */
Packit Service b38f0b
NETSNMP_STATIC_INLINE void
Packit Service b38f0b
invalidate_lookup_cache(const char *context) {
Packit Service b38f0b
    lookup_cache_context *cptr;
Packit Service b38f0b
    if ((cptr = get_context_lookup_cache(context)) != NULL) {
Packit Service b38f0b
        cptr->thecachecount = 0;
Packit Service b38f0b
        cptr->currentpos = 0;
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
void
Packit Service b38f0b
clear_lookup_cache(void) {
Packit Service b38f0b
Packit Service b38f0b
    lookup_cache_context *ptr = NULL, *next = NULL;
Packit Service b38f0b
Packit Service b38f0b
    ptr = thecontextcache;
Packit Service b38f0b
    while (ptr) {
Packit Service b38f0b
	next = ptr->next;
Packit Service b38f0b
	SNMP_FREE(ptr->context);
Packit Service b38f0b
	SNMP_FREE(ptr);
Packit Service b38f0b
	ptr = next;
Packit Service b38f0b
    }
Packit Service b38f0b
    thecontextcache = NULL; /* !!! */
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/**  @} */
Packit Service b38f0b
/* End of Lookup cache code */
Packit Service b38f0b
Packit Service b38f0b
/** @defgroup agent_context_cache Context cache, storing the OIDs under their contexts.
Packit Service b38f0b
 *     Maintain the cache used for locating sub-trees registered under different contexts.
Packit Service b38f0b
 *   @ingroup agent_registry
Packit Service b38f0b
 *
Packit Service b38f0b
 * @{
Packit Service b38f0b
 */
Packit Service b38f0b
subtree_context_cache *context_subtrees = NULL;
Packit Service b38f0b
Packit Service b38f0b
/** Returns the top element of context subtrees cache.
Packit Service b38f0b
 *  Use it if you wish to sweep through the cache elements.
Packit Service b38f0b
 *  Note that the return may be NULL (cache may be empty).
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return pointer to topmost context subtree cache element.
Packit Service b38f0b
 */
Packit Service b38f0b
subtree_context_cache *
Packit Service b38f0b
get_top_context_cache(void)
Packit Service b38f0b
{
Packit Service b38f0b
    return context_subtrees;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Finds the first subtree registered under given context.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param context_name Text name of the context we're searching for.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return pointer to the first subtree element, or NULL if not found.
Packit Service b38f0b
 */
Packit Service b38f0b
netsnmp_subtree *
Packit Service b38f0b
netsnmp_subtree_find_first(const char *context_name)
Packit Service b38f0b
{
Packit Service b38f0b
    subtree_context_cache *ptr;
Packit Service b38f0b
Packit Service b38f0b
    if (!context_name) {
Packit Service b38f0b
        context_name = "";
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n", 
Packit Service b38f0b
		context_name));
Packit Service b38f0b
    for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
Packit Service b38f0b
        if (ptr->context_name != NULL && 
Packit Service b38f0b
	    strcmp(ptr->context_name, context_name) == 0) {
Packit Service b38f0b
            DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name));
Packit Service b38f0b
            return ptr->first_subtree;
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
    DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n", 
Packit Service b38f0b
		context_name));
Packit Service b38f0b
    return NULL;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Adds the subtree to Context Cache under given context name.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param context_name Text name of the context we're adding.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param new_tree The subtree to be added.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return copy of the new_tree pointer, or NULL if cannot add.
Packit Service b38f0b
 */
Packit Service b38f0b
netsnmp_subtree *
Packit Service b38f0b
add_subtree(netsnmp_subtree *new_tree, const char *context_name)
Packit Service b38f0b
{
Packit Service b38f0b
    subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache);
Packit Service b38f0b
    
Packit Service b38f0b
    if (!context_name) {
Packit Service b38f0b
        context_name = "";
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    if (!ptr) {
Packit Service b38f0b
        return NULL;
Packit Service b38f0b
    }
Packit Service b38f0b
    
Packit Service b38f0b
    DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n",	
Packit Service b38f0b
		context_name));
Packit Service b38f0b
Packit Service b38f0b
    ptr->next = context_subtrees;
Packit Service b38f0b
    ptr->first_subtree = new_tree;
Packit Service b38f0b
    ptr->context_name = strdup(context_name);
Packit Service b38f0b
    context_subtrees = ptr;
Packit Service b38f0b
Packit Service b38f0b
    return ptr->first_subtree;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
void
Packit Service b38f0b
netsnmp_remove_subtree(netsnmp_subtree *tree)
Packit Service b38f0b
{
Packit Service b38f0b
    subtree_context_cache *ptr;
Packit Service b38f0b
Packit Service b38f0b
    if (!tree->prev) {
Packit Service b38f0b
        for (ptr = context_subtrees; ptr; ptr = ptr->next)
Packit Service b38f0b
            if (ptr->first_subtree == tree)
Packit Service b38f0b
                break;
Packit Service b38f0b
        netsnmp_assert(ptr);
Packit Service b38f0b
        if (ptr)
Packit Service b38f0b
            ptr->first_subtree = tree->next;
Packit Service b38f0b
    } else
Packit Service b38f0b
        tree->prev->next = tree->next;
Packit Service b38f0b
Packit Service b38f0b
    if (tree->next)
Packit Service b38f0b
        tree->next->prev = tree->prev;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Replaces first subtree registered under given context name.
Packit Service b38f0b
 *  Overwrites a subtree pointer in Context Cache for the context name.
Packit Service b38f0b
 *  The previous subtree pointer is lost. If there's no subtree
Packit Service b38f0b
 *  under the supplied name, then a new cache item is created.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param new_tree     The new subtree to be set.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param context_name Text name of the context we're replacing.
Packit Service b38f0b
 *                      It is case sensitive.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @return copy of the new_tree pointer, or NULL on error.
Packit Service b38f0b
 */
Packit Service b38f0b
netsnmp_subtree *
Packit Service b38f0b
netsnmp_subtree_replace_first(netsnmp_subtree *new_tree, 
Packit Service b38f0b
			      const char *context_name)
Packit Service b38f0b
{
Packit Service b38f0b
    subtree_context_cache *ptr;
Packit Service b38f0b
    if (!context_name) {
Packit Service b38f0b
        context_name = "";
Packit Service b38f0b
    }
Packit Service b38f0b
    for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) {
Packit Service b38f0b
        if (ptr->context_name != NULL &&
Packit Service b38f0b
	    strcmp(ptr->context_name, context_name) == 0) {
Packit Service b38f0b
            ptr->first_subtree = new_tree;
Packit Service b38f0b
            return ptr->first_subtree;
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
    return add_subtree(new_tree, context_name);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
Packit Service b38f0b
void clear_subtree (netsnmp_subtree *sub);
Packit Service b38f0b
Packit Service b38f0b
/** Completely clears both the Context cache and the Lookup cache.
Packit Service b38f0b
 */
Packit Service b38f0b
void
Packit Service b38f0b
clear_context(void) {
Packit Service b38f0b
Packit Service b38f0b
    subtree_context_cache *ptr = NULL, *next = NULL;
Packit Service b38f0b
    netsnmp_subtree *t, *u;
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("agent_registry", "clear context\n"));
Packit Service b38f0b
Packit Service b38f0b
    ptr = get_top_context_cache(); 
Packit Service b38f0b
    while (ptr) {
Packit Service b38f0b
	next = ptr->next;
Packit Service b38f0b
Packit Service b38f0b
	for (t = ptr->first_subtree; t; t = u) {
Packit Service b38f0b
            u = t->next;
Packit Service b38f0b
	    clear_subtree(t);
Packit Service b38f0b
	}
Packit Service b38f0b
Packit Service b38f0b
        free(NETSNMP_REMOVE_CONST(char*, ptr->context_name));
Packit Service b38f0b
        SNMP_FREE(ptr);
Packit Service b38f0b
Packit Service b38f0b
	ptr = next;
Packit Service b38f0b
    }
Packit Service b38f0b
    context_subtrees = NULL; /* !!! */
Packit Service b38f0b
    clear_lookup_cache();
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/**  @} */
Packit Service b38f0b
/* End of Context cache code */
Packit Service b38f0b
Packit Service b38f0b
/** @defgroup agent_mib_subtree Maintaining MIB subtrees.
Packit Service b38f0b
 *     Maintaining MIB nodes and subtrees.
Packit Service b38f0b
 *   @ingroup agent_registry
Packit Service b38f0b
 *
Packit Service b38f0b
 * @{
Packit Service b38f0b
 */
Packit Service b38f0b
Packit Service b38f0b
static void register_mib_detach_node(netsnmp_subtree *s);
Packit Service b38f0b
Packit Service b38f0b
/** Frees single subtree item.
Packit Service b38f0b
 *  Deallocated memory for given netsnmp_subtree item, including
Packit Service b38f0b
 *  Handle Registration structure stored inside this item.
Packit Service b38f0b
 *  After calling this function, the pointer is invalid
Packit Service b38f0b
 *  and should be set to NULL.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param a The subtree item to dispose.
Packit Service b38f0b
 */
Packit Service b38f0b
void
Packit Service b38f0b
netsnmp_subtree_free(netsnmp_subtree *a)
Packit Service b38f0b
{
Packit Service b38f0b
  if (a != NULL) {
Packit Service b38f0b
    if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen, 
Packit Service b38f0b
					     a->start_a, a->start_len) == 0) {
Packit Service b38f0b
      SNMP_FREE(a->variables);
Packit Service b38f0b
    }
Packit Service b38f0b
    SNMP_FREE(a->name_a);
Packit Service b38f0b
    a->namelen = 0;
Packit Service b38f0b
    SNMP_FREE(a->start_a);
Packit Service b38f0b
    a->start_len = 0;
Packit Service b38f0b
    SNMP_FREE(a->end_a);
Packit Service b38f0b
    a->end_len = 0;
Packit Service b38f0b
    SNMP_FREE(a->label_a);
Packit Service b38f0b
    netsnmp_handler_registration_free(a->reginfo);
Packit Service b38f0b
    a->reginfo = NULL;
Packit Service b38f0b
    SNMP_FREE(a);
Packit Service b38f0b
  }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Creates deep copy of a subtree item.
Packit Service b38f0b
 *  Duplicates all properties stored in the structure, including
Packit Service b38f0b
 *  Handle Registration structure stored inside the item.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param a The subtree item to copy.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return deep copy of the subtree item, or NULL on error.
Packit Service b38f0b
 */
Packit Service b38f0b
netsnmp_subtree *
Packit Service b38f0b
netsnmp_subtree_deepcopy(netsnmp_subtree *a)
Packit Service b38f0b
{
Packit Service b38f0b
  netsnmp_subtree *b = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
Packit Service b38f0b
Packit Service b38f0b
  if (b != NULL) {
Packit Service b38f0b
    memcpy(b, a, sizeof(netsnmp_subtree));
Packit Service b38f0b
    b->name_a  = snmp_duplicate_objid(a->name_a,  a->namelen);
Packit Service b38f0b
    b->start_a = snmp_duplicate_objid(a->start_a, a->start_len);
Packit Service b38f0b
    b->end_a   = snmp_duplicate_objid(a->end_a,   a->end_len);
Packit Service b38f0b
    b->label_a = strdup(a->label_a);
Packit Service b38f0b
    
Packit Service b38f0b
    if (b->name_a == NULL || b->start_a == NULL || 
Packit Service b38f0b
	b->end_a  == NULL || b->label_a == NULL) {
Packit Service b38f0b
      netsnmp_subtree_free(b);
Packit Service b38f0b
      return NULL;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    if (a->variables != NULL) {
Packit Service b38f0b
      b->variables = (struct variable *)malloc(a->variables_len * 
Packit Service b38f0b
					       a->variables_width);
Packit Service b38f0b
      if (b->variables != NULL) {
Packit Service b38f0b
	memcpy(b->variables, a->variables,a->variables_len*a->variables_width);
Packit Service b38f0b
      } else {
Packit Service b38f0b
	netsnmp_subtree_free(b);
Packit Service b38f0b
	return NULL;
Packit Service b38f0b
      }
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    if (a->reginfo != NULL) {
Packit Service b38f0b
      b->reginfo = netsnmp_handler_registration_dup(a->reginfo);
Packit Service b38f0b
      if (b->reginfo == NULL) {
Packit Service b38f0b
	netsnmp_subtree_free(b);
Packit Service b38f0b
	return NULL;
Packit Service b38f0b
      }
Packit Service b38f0b
    }
Packit Service b38f0b
  }
Packit Service b38f0b
  return b;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** @private
Packit Service b38f0b
 *  Replaces next subtree pointer in given subtree.
Packit Service b38f0b
 */
Packit Service b38f0b
NETSNMP_STATIC_INLINE void
Packit Service b38f0b
netsnmp_subtree_change_next(netsnmp_subtree *ptr, netsnmp_subtree *thenext)
Packit Service b38f0b
{
Packit Service b38f0b
    ptr->next = thenext;
Packit Service b38f0b
    if (thenext)
Packit Service b38f0b
        netsnmp_oid_compare_ll(ptr->start_a,
Packit Service b38f0b
                               ptr->start_len,
Packit Service b38f0b
                               thenext->start_a,
Packit Service b38f0b
                               thenext->start_len,
Packit Service b38f0b
                               &thenext->oid_off);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** @private
Packit Service b38f0b
 *  Replaces previous subtree pointer in given subtree.
Packit Service b38f0b
 */
Packit Service b38f0b
NETSNMP_STATIC_INLINE void
Packit Service b38f0b
netsnmp_subtree_change_prev(netsnmp_subtree *ptr, netsnmp_subtree *theprev)
Packit Service b38f0b
{
Packit Service b38f0b
    ptr->prev = theprev;
Packit Service b38f0b
    if (theprev)
Packit Service b38f0b
        netsnmp_oid_compare_ll(theprev->start_a,
Packit Service b38f0b
                               theprev->start_len,
Packit Service b38f0b
                               ptr->start_a,
Packit Service b38f0b
                               ptr->start_len,
Packit Service b38f0b
                               &ptr->oid_off);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
netsnmp_feature_child_of(netsnmp_subtree_compare,netsnmp_unused)
Packit Service b38f0b
#ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_SUBTREE_COMPARE
Packit Service b38f0b
/** Compares OIDs of given subtrees.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param ap,bp Pointers to the subtrees to be compared.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return OIDs lexicographical comparison result.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @see snmp_oid_compare()
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp)
Packit Service b38f0b
{
Packit Service b38f0b
    return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen);
Packit Service b38f0b
}
Packit Service b38f0b
#endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_SUBTREE_COMPARE */
Packit Service b38f0b
Packit Service b38f0b
/** Joins the given subtree with the current tree.
Packit Service b38f0b
 *  Trees are joined and the one supplied as parameter is freed.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param root The subtree to be merged with current subtree.
Packit Service b38f0b
 *              Do not use the pointer after joining - it may be invalid.
Packit Service b38f0b
 */
Packit Service b38f0b
void
Packit Service b38f0b
netsnmp_subtree_join(netsnmp_subtree *root)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *s, *tmp, *c, *d;
Packit Service b38f0b
Packit Service b38f0b
    while (root != NULL) {
Packit Service b38f0b
        s = root->next;
Packit Service b38f0b
        while (s != NULL && root->reginfo == s->reginfo) {
Packit Service b38f0b
            tmp = s->next;
Packit Service b38f0b
            DEBUGMSGTL(("subtree", "root start "));
Packit Service b38f0b
            DEBUGMSGOID(("subtree", root->start_a, root->start_len));
Packit Service b38f0b
            DEBUGMSG(("subtree", " (original end "));
Packit Service b38f0b
            DEBUGMSGOID(("subtree", root->end_a, root->end_len));
Packit Service b38f0b
            DEBUGMSG(("subtree", ")\n"));
Packit Service b38f0b
            DEBUGMSGTL(("subtree", "  JOINING to "));
Packit Service b38f0b
            DEBUGMSGOID(("subtree", s->start_a, s->start_len));
Packit Service b38f0b
Packit Service b38f0b
	    SNMP_FREE(root->end_a);
Packit Service b38f0b
	    root->end_a   = s->end_a;
Packit Service b38f0b
            root->end_len = s->end_len;
Packit Service b38f0b
	    s->end_a      = NULL;
Packit Service b38f0b
Packit Service b38f0b
            for (c = root; c != NULL; c = c->children) {
Packit Service b38f0b
                netsnmp_subtree_change_next(c, s->next);
Packit Service b38f0b
            }
Packit Service b38f0b
            for (c = s; c != NULL; c = c->children) {
Packit Service b38f0b
                netsnmp_subtree_change_prev(c, root);
Packit Service b38f0b
            }
Packit Service b38f0b
            DEBUGMSG(("subtree", " so new end "));
Packit Service b38f0b
            DEBUGMSGOID(("subtree", root->end_a, root->end_len));
Packit Service b38f0b
            DEBUGMSG(("subtree", "\n"));
Packit Service b38f0b
            /*
Packit Service b38f0b
             * Probably need to free children too?  
Packit Service b38f0b
             */
Packit Service b38f0b
            for (c = s->children; c != NULL; c = d) {
Packit Service b38f0b
                d = c->children;
Packit Service b38f0b
                netsnmp_subtree_free(c);
Packit Service b38f0b
            }
Packit Service b38f0b
            netsnmp_subtree_free(s);
Packit Service b38f0b
            s = tmp;
Packit Service b38f0b
        }
Packit Service b38f0b
        root = root->next;
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
Packit Service b38f0b
/** Split the subtree into two at the specified point.
Packit Service b38f0b
 *  Subtrees of the given OID and separated and formed into the
Packit Service b38f0b
 *  returned subtree.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param current The element at which splitting is started.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param name The OID we'd like to split.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param name_len Length of the OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return head of the new (second) subtree.
Packit Service b38f0b
 */
Packit Service b38f0b
netsnmp_subtree *
Packit Service b38f0b
netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len)
Packit Service b38f0b
{
Packit Service b38f0b
    struct variable *vp = NULL;
Packit Service b38f0b
    netsnmp_subtree *new_sub, *ptr;
Packit Service b38f0b
    int i = 0, rc = 0, rc2 = 0;
Packit Service b38f0b
    size_t common_len = 0;
Packit Service b38f0b
    char *cp;
Packit Service b38f0b
    oid *tmp_a, *tmp_b;
Packit Service b38f0b
Packit Service b38f0b
    if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) {
Packit Service b38f0b
	/* Split comes after the end of this subtree */
Packit Service b38f0b
        return NULL;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    new_sub = netsnmp_subtree_deepcopy(current);
Packit Service b38f0b
    if (new_sub == NULL) {
Packit Service b38f0b
        return NULL;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /*  Set up the point of division.  */
Packit Service b38f0b
    tmp_a = snmp_duplicate_objid(name, name_len);
Packit Service b38f0b
    if (tmp_a == NULL) {
Packit Service b38f0b
	netsnmp_subtree_free(new_sub);
Packit Service b38f0b
	return NULL;
Packit Service b38f0b
    }
Packit Service b38f0b
    tmp_b = snmp_duplicate_objid(name, name_len);
Packit Service b38f0b
    if (tmp_b == NULL) {
Packit Service b38f0b
	netsnmp_subtree_free(new_sub);
Packit Service b38f0b
	SNMP_FREE(tmp_a);
Packit Service b38f0b
	return NULL;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    SNMP_FREE(current->end_a);
Packit Service b38f0b
    current->end_a = tmp_a;
Packit Service b38f0b
    current->end_len = name_len;
Packit Service b38f0b
    if (new_sub->start_a != NULL) {
Packit Service b38f0b
	SNMP_FREE(new_sub->start_a);
Packit Service b38f0b
    }
Packit Service b38f0b
    new_sub->start_a = tmp_b;
Packit Service b38f0b
    new_sub->start_len = name_len;
Packit Service b38f0b
Packit Service b38f0b
    /*  Split the variables between the two new subtrees.  */
Packit Service b38f0b
    i = current->variables_len;
Packit Service b38f0b
    current->variables_len = 0;
Packit Service b38f0b
Packit Service b38f0b
    for (vp = current->variables; i > 0; i--) {
Packit Service b38f0b
	/*  Note that the variable "name" field omits the prefix common to the
Packit Service b38f0b
	    whole registration, hence the strange comparison here.  */
Packit Service b38f0b
Packit Service b38f0b
	rc = snmp_oid_compare(vp->name, vp->namelen,
Packit Service b38f0b
			      name     + current->namelen, 
Packit Service b38f0b
			      name_len - current->namelen);
Packit Service b38f0b
Packit Service b38f0b
        if (name_len - current->namelen > vp->namelen) {
Packit Service b38f0b
            common_len = vp->namelen;
Packit Service b38f0b
        } else {
Packit Service b38f0b
            common_len = name_len - current->namelen;
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
        rc2 = snmp_oid_compare(vp->name, common_len,
Packit Service b38f0b
                               name + current->namelen, common_len);
Packit Service b38f0b
Packit Service b38f0b
        if (rc >= 0) {
Packit Service b38f0b
            break;  /* All following variables belong to the second subtree */
Packit Service b38f0b
	}
Packit Service b38f0b
Packit Service b38f0b
        current->variables_len++;
Packit Service b38f0b
        if (rc2 < 0) {
Packit Service b38f0b
            new_sub->variables_len--;
Packit Service b38f0b
            cp = (char *) new_sub->variables;
Packit Service b38f0b
            new_sub->variables = (struct variable *)(cp + 
Packit Service b38f0b
						     new_sub->variables_width);
Packit Service b38f0b
        }
Packit Service b38f0b
        vp = (struct variable *) ((char *) vp + current->variables_width);
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /* Delegated trees should retain their variables regardless */
Packit Service b38f0b
    if (current->variables_len > 0 &&
Packit Service b38f0b
        IS_DELEGATED((u_char) current->variables[0].type)) {
Packit Service b38f0b
        new_sub->variables_len = 1;
Packit Service b38f0b
        new_sub->variables = current->variables;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /* Propogate this split down through any children */
Packit Service b38f0b
    if (current->children) {
Packit Service b38f0b
        new_sub->children = netsnmp_subtree_split(current->children, 
Packit Service b38f0b
						  name, name_len);
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /* Retain the correct linking of the list */
Packit Service b38f0b
    for (ptr = current; ptr != NULL; ptr = ptr->children) {
Packit Service b38f0b
        netsnmp_subtree_change_next(ptr, new_sub);
Packit Service b38f0b
    }
Packit Service b38f0b
    for (ptr = new_sub; ptr != NULL; ptr = ptr->children) {
Packit Service b38f0b
        netsnmp_subtree_change_prev(ptr, current);
Packit Service b38f0b
    }
Packit Service b38f0b
    for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) {
Packit Service b38f0b
        netsnmp_subtree_change_prev(ptr, new_sub);
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    return new_sub;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Loads the subtree under given context name.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param new_sub The subtree to be loaded into current subtree.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param context_name Text name of the context we're searching for.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return gives MIB_REGISTERED_OK on success, error code otherwise.
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *tree1, *tree2;
Packit Service b38f0b
    netsnmp_subtree *prev, *next;
Packit Service b38f0b
Packit Service b38f0b
    if (new_sub == NULL) {
Packit Service b38f0b
        return MIB_REGISTERED_OK;       /* Degenerate case */
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    if (!netsnmp_subtree_find_first(context_name)) {
Packit Service b38f0b
        static int inloop = 0;
Packit Service b38f0b
        if (!inloop) {
Packit Service b38f0b
            oid ccitt[1]           = { 0 };
Packit Service b38f0b
            oid iso[1]             = { 1 };
Packit Service b38f0b
            oid joint_ccitt_iso[1] = { 2 };
Packit Service b38f0b
            inloop = 1;
Packit Service b38f0b
            netsnmp_register_null_context(snmp_duplicate_objid(ccitt, 1), 1,
Packit Service b38f0b
                                          context_name);
Packit Service b38f0b
            netsnmp_register_null_context(snmp_duplicate_objid(iso, 1), 1,
Packit Service b38f0b
                                          context_name);
Packit Service b38f0b
            netsnmp_register_null_context(snmp_duplicate_objid(joint_ccitt_iso, 1),
Packit Service b38f0b
                                          1, context_name);
Packit Service b38f0b
            inloop = 0;
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /*  Find the subtree that contains the start of the new subtree (if
Packit Service b38f0b
	any)...*/
Packit Service b38f0b
Packit Service b38f0b
    tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len, 
Packit Service b38f0b
				 NULL, context_name);
Packit Service b38f0b
Packit Service b38f0b
    /*  ... and the subtree that follows the new one (NULL implies this is the
Packit Service b38f0b
	final region covered).  */
Packit Service b38f0b
Packit Service b38f0b
    if (tree1 == NULL) {
Packit Service b38f0b
	tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len,
Packit Service b38f0b
					  NULL, context_name);
Packit Service b38f0b
    } else {
Packit Service b38f0b
	tree2 = tree1->next;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /*  Handle new subtrees that start in virgin territory.  */
Packit Service b38f0b
Packit Service b38f0b
    if (tree1 == NULL) {
Packit Service b38f0b
        /*netsnmp_subtree *new2 = NULL;*/
Packit Service b38f0b
	/*  Is there any overlap with later subtrees?  */
Packit Service b38f0b
	if (tree2 && snmp_oid_compare(new_sub->end_a, new_sub->end_len,
Packit Service b38f0b
				      tree2->start_a, tree2->start_len) > 0) {
Packit Service b38f0b
	    /*new2 =*/
Packit Service b38f0b
            netsnmp_subtree_split(new_sub, tree2->start_a, tree2->start_len);
Packit Service b38f0b
	}
Packit Service b38f0b
Packit Service b38f0b
	/*  Link the new subtree (less any overlapping region) with the list of
Packit Service b38f0b
	    existing registrations.  */
Packit Service b38f0b
Packit Service b38f0b
	if (tree2) {
Packit Service b38f0b
            netsnmp_subtree_change_prev(new_sub, tree2->prev);
Packit Service b38f0b
            netsnmp_subtree_change_prev(tree2, new_sub);
Packit Service b38f0b
	} else {
Packit Service b38f0b
            netsnmp_subtree_change_prev(new_sub,
Packit Service b38f0b
                                        netsnmp_subtree_find_prev(new_sub->start_a,
Packit Service b38f0b
                                                                  new_sub->start_len, NULL, context_name));
Packit Service b38f0b
Packit Service b38f0b
	    if (new_sub->prev) {
Packit Service b38f0b
                netsnmp_subtree_change_next(new_sub->prev, new_sub);
Packit Service b38f0b
	    } else {
Packit Service b38f0b
		netsnmp_subtree_replace_first(new_sub, context_name);
Packit Service b38f0b
	    }
Packit Service b38f0b
Packit Service b38f0b
            netsnmp_subtree_change_next(new_sub, tree2);
Packit Service b38f0b
Packit Service b38f0b
#if 0
Packit Service b38f0b
            /* The code below cannot be reached which is why it has been
Packit Service b38f0b
               surrounded with #if 0 / #endif. */
Packit Service b38f0b
	    /* If there was any overlap, recurse to merge in the overlapping
Packit Service b38f0b
	       region (including anything that may follow the overlap).  */
Packit Service b38f0b
	    if (new2) {
Packit Service b38f0b
		return netsnmp_subtree_load(new2, context_name);
Packit Service b38f0b
	    }
Packit Service b38f0b
#endif
Packit Service b38f0b
	}
Packit Service b38f0b
    } else {
Packit Service b38f0b
	/*  If the new subtree starts *within* an existing registration
Packit Service b38f0b
	    (rather than at the same point as it), then split the existing
Packit Service b38f0b
	    subtree at this point.  */
Packit Service b38f0b
Packit Service b38f0b
	if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len, 
Packit Service b38f0b
			     tree1->start_a,   tree1->start_len) != 0) {
Packit Service b38f0b
	    tree1 = netsnmp_subtree_split(tree1, new_sub->start_a, 
Packit Service b38f0b
					  new_sub->start_len);
Packit Service b38f0b
	}
Packit Service b38f0b
Packit Service b38f0b
        if (tree1 == NULL) {
Packit Service b38f0b
            return MIB_REGISTRATION_FAILED;
Packit Service b38f0b
	}
Packit Service b38f0b
Packit Service b38f0b
	/*  Now consider the end of this existing subtree:
Packit Service b38f0b
	    
Packit Service b38f0b
	    If it matches the new subtree precisely,
Packit Service b38f0b
	            simply merge the new one into the list of children
Packit Service b38f0b
Packit Service b38f0b
	    If it includes the whole of the new subtree,
Packit Service b38f0b
		    split it at the appropriate point, and merge again
Packit Service b38f0b
     
Packit Service b38f0b
	    If the new subtree extends beyond this existing region,
Packit Service b38f0b
	            split it, and recurse to merge the two parts.  */
Packit Service b38f0b
Packit Service b38f0b
	switch (snmp_oid_compare(new_sub->end_a, new_sub->end_len,
Packit Service b38f0b
                                 tree1->end_a, tree1->end_len)) {
Packit Service b38f0b
Packit Service b38f0b
	case -1:
Packit Service b38f0b
	    /*  Existing subtree contains new one.  */
Packit Service b38f0b
	    netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len);
Packit Service b38f0b
	    /* Fall Through */
Packit Service b38f0b
Packit Service b38f0b
	case  0:
Packit Service b38f0b
	    /*  The two trees match precisely.  */
Packit Service b38f0b
Packit Service b38f0b
	    /*  Note: This is the only point where the original registration
Packit Service b38f0b
	        OID ("name") is used.  */
Packit Service b38f0b
Packit Service b38f0b
	    prev = NULL;
Packit Service b38f0b
	    next = tree1;
Packit Service b38f0b
	
Packit Service b38f0b
	    while (next && next->namelen > new_sub->namelen) {
Packit Service b38f0b
		prev = next;
Packit Service b38f0b
		next = next->children;
Packit Service b38f0b
	    }
Packit Service b38f0b
Packit Service b38f0b
	    while (next && next->namelen == new_sub->namelen &&
Packit Service b38f0b
		   next->priority < new_sub->priority ) {
Packit Service b38f0b
		prev = next;
Packit Service b38f0b
		next = next->children;
Packit Service b38f0b
	    }
Packit Service b38f0b
	
Packit Service b38f0b
	    if (next && (next->namelen  == new_sub->namelen) &&
Packit Service b38f0b
		(next->priority == new_sub->priority)) {
Packit Service b38f0b
                if (new_sub->namelen != 1) {    /* ignore root OID dups */
Packit Service b38f0b
                    size_t          out_len = 0;
Packit Service b38f0b
                    size_t          buf_len = 0;
Packit Service b38f0b
                    char           *buf = NULL;
Packit Service b38f0b
                    int             buf_overflow = 0;
Packit Service b38f0b
Packit Service b38f0b
                    netsnmp_sprint_realloc_objid((u_char **) &buf, &buf_len, &out_len,
Packit Service b38f0b
                                                 1, &buf_overflow,
Packit Service b38f0b
                                                 new_sub->start_a,
Packit Service b38f0b
                                                 new_sub->start_len);
Packit Service b38f0b
                    snmp_log(LOG_ERR,
Packit Service b38f0b
                             "duplicate registration: MIB modules %s and %s (oid %s%s).\n",
Packit Service b38f0b
                             next->label_a, new_sub->label_a,
Packit Service b38f0b
                             buf ? buf : "",
Packit Service b38f0b
                             buf_overflow ? " [TRUNCATED]" : "");
Packit Service b38f0b
                    free(buf);
Packit Service b38f0b
                }
Packit Service b38f0b
		return MIB_DUPLICATE_REGISTRATION;
Packit Service b38f0b
	    }
Packit Service b38f0b
Packit Service b38f0b
	    if (prev) {
Packit Service b38f0b
		prev->children    = new_sub;
Packit Service b38f0b
		new_sub->children = next;
Packit Service b38f0b
                netsnmp_subtree_change_prev(new_sub, prev->prev);
Packit Service b38f0b
                netsnmp_subtree_change_next(new_sub, prev->next);
Packit Service b38f0b
	    } else {
Packit Service b38f0b
		new_sub->children = next;
Packit Service b38f0b
                netsnmp_subtree_change_prev(new_sub, next->prev);
Packit Service b38f0b
                netsnmp_subtree_change_next(new_sub, next->next);
Packit Service b38f0b
	
Packit Service b38f0b
		for (next = new_sub->next; next != NULL;next = next->children){
Packit Service b38f0b
                    netsnmp_subtree_change_prev(next, new_sub);
Packit Service b38f0b
		}
Packit Service b38f0b
Packit Service b38f0b
		for (prev = new_sub->prev; prev != NULL;prev = prev->children){
Packit Service b38f0b
                    netsnmp_subtree_change_next(prev, new_sub);
Packit Service b38f0b
		}
Packit Service b38f0b
	    }
Packit Service b38f0b
	    break;
Packit Service b38f0b
Packit Service b38f0b
	case  1:
Packit Service b38f0b
	    /*  New subtree contains the existing one.  */
Packit Service b38f0b
            {
Packit Service b38f0b
                netsnmp_subtree *new2 =
Packit Service b38f0b
                    netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len);
Packit Service b38f0b
                int res = netsnmp_subtree_load(new_sub, context_name);
Packit Service b38f0b
                if (res != MIB_REGISTERED_OK) {
Packit Service b38f0b
                    netsnmp_remove_subtree(new2);
Packit Service b38f0b
                    netsnmp_subtree_free(new2);
Packit Service b38f0b
                    return res;
Packit Service b38f0b
                }
Packit Service b38f0b
                return netsnmp_subtree_load(new2, context_name);
Packit Service b38f0b
            }
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
    return 0;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Free the given subtree and all its children.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param sub Subtree branch to be cleared and freed.
Packit Service b38f0b
 *             After the call, this pointer is invalid
Packit Service b38f0b
 *             and should be set to NULL.
Packit Service b38f0b
 */
Packit Service b38f0b
void
Packit Service b38f0b
clear_subtree (netsnmp_subtree *sub) {
Packit Service b38f0b
Packit Service b38f0b
    netsnmp_subtree *c;
Packit Service b38f0b
    
Packit Service b38f0b
    if (sub == NULL)
Packit Service b38f0b
	return;
Packit Service b38f0b
Packit Service b38f0b
    for(c = sub; c;) {
Packit Service b38f0b
        sub = c;
Packit Service b38f0b
        c = c->children;
Packit Service b38f0b
        netsnmp_subtree_free(sub);
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
netsnmp_subtree *
Packit Service b38f0b
netsnmp_subtree_find_prev(const oid *name, size_t len, netsnmp_subtree *subtree,
Packit Service b38f0b
			  const char *context_name)
Packit Service b38f0b
{
Packit Service b38f0b
    lookup_cache *lookup_cache = NULL;
Packit Service b38f0b
    netsnmp_subtree *myptr = NULL, *previous = NULL;
Packit Service b38f0b
    int cmp = 1;
Packit Service b38f0b
    size_t ll_off = 0;
Packit Service b38f0b
Packit Service b38f0b
    if (subtree) {
Packit Service b38f0b
        myptr = subtree;
Packit Service b38f0b
    } else {
Packit Service b38f0b
	/* look through everything */
Packit Service b38f0b
        if (lookup_cache_size) {
Packit Service b38f0b
            lookup_cache = lookup_cache_find(context_name, name, len, &cmp);
Packit Service b38f0b
            if (lookup_cache) {
Packit Service b38f0b
                myptr = lookup_cache->next;
Packit Service b38f0b
                previous = lookup_cache->previous;
Packit Service b38f0b
            }
Packit Service b38f0b
            if (!myptr)
Packit Service b38f0b
                myptr = netsnmp_subtree_find_first(context_name);
Packit Service b38f0b
        } else {
Packit Service b38f0b
            myptr = netsnmp_subtree_find_first(context_name);
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /*
Packit Service b38f0b
     * this optimization causes a segfault on sf cf alpha-linux1.
Packit Service b38f0b
     * ifdef out until someone figures out why and fixes it. xxx-rks 20051117
Packit Service b38f0b
     */
Packit Service b38f0b
#ifndef __alpha
Packit Service b38f0b
#define WTEST_OPTIMIZATION 1
Packit Service b38f0b
#endif
Packit Service b38f0b
#ifdef WTEST_OPTIMIZATION
Packit Service b38f0b
    DEBUGMSGTL(("wtest","oid in: "));
Packit Service b38f0b
    DEBUGMSGOID(("wtest", name, len));
Packit Service b38f0b
    DEBUGMSG(("wtest","\n"));
Packit Service b38f0b
#endif
Packit Service b38f0b
    for (; myptr != NULL; previous = myptr, myptr = myptr->next) {
Packit Service b38f0b
#ifdef WTEST_OPTIMIZATION
Packit Service b38f0b
        /* Compare the incoming oid with the linked list.  If we have
Packit Service b38f0b
           results of previous compares, its faster to make sure the
Packit Service b38f0b
           length we differed in the last check is greater than the
Packit Service b38f0b
           length between this pointer and the last then we don't need
Packit Service b38f0b
           to actually perform a comparison */
Packit Service b38f0b
        DEBUGMSGTL(("wtest","oid cmp: "));
Packit Service b38f0b
        DEBUGMSGOID(("wtest", myptr->start_a, myptr->start_len));
Packit Service b38f0b
        DEBUGMSG(("wtest","  --- off = %lu, in off = %lu test = %d\n",
Packit Service b38f0b
                  (unsigned long)myptr->oid_off, (unsigned long)ll_off,
Packit Service b38f0b
                  !(ll_off && myptr->oid_off &&
Packit Service b38f0b
                    myptr->oid_off > ll_off)));
Packit Service b38f0b
        if (!(ll_off && myptr->oid_off && myptr->oid_off > ll_off) &&
Packit Service b38f0b
            netsnmp_oid_compare_ll(name, len,
Packit Service b38f0b
                                   myptr->start_a, myptr->start_len,
Packit Service b38f0b
                                   &ll_off) < 0) {
Packit Service b38f0b
#else
Packit Service b38f0b
        if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) {
Packit Service b38f0b
#endif
Packit Service b38f0b
            if (lookup_cache_size && previous && cmp) {
Packit Service b38f0b
                if (lookup_cache) {
Packit Service b38f0b
                    lookup_cache_replace(lookup_cache, myptr, previous);
Packit Service b38f0b
                } else {
Packit Service b38f0b
                    lookup_cache_add(context_name, myptr, previous);
Packit Service b38f0b
                }
Packit Service b38f0b
            }
Packit Service b38f0b
            return previous;
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
    return previous;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
netsnmp_subtree *
Packit Service b38f0b
netsnmp_subtree_find_next(const oid *name, size_t len,
Packit Service b38f0b
			  netsnmp_subtree *subtree, const char *context_name)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *myptr = NULL;
Packit Service b38f0b
Packit Service b38f0b
    myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
Packit Service b38f0b
Packit Service b38f0b
    if (myptr != NULL) {
Packit Service b38f0b
        myptr = myptr->next;
Packit Service b38f0b
        while (myptr != NULL && (myptr->variables == NULL || 
Packit Service b38f0b
				 myptr->variables_len == 0)) {
Packit Service b38f0b
            myptr = myptr->next;
Packit Service b38f0b
        }
Packit Service b38f0b
        return myptr;
Packit Service b38f0b
    } else if (subtree != NULL && snmp_oid_compare(name, len, 
Packit Service b38f0b
				   subtree->start_a, subtree->start_len) < 0) {
Packit Service b38f0b
        return subtree;
Packit Service b38f0b
    } else {
Packit Service b38f0b
        return NULL;
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
netsnmp_subtree *
Packit Service b38f0b
netsnmp_subtree_find(const oid *name, size_t len, netsnmp_subtree *subtree, 
Packit Service b38f0b
		     const char *context_name)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *myptr;
Packit Service b38f0b
Packit Service b38f0b
    myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name);
Packit Service b38f0b
    if (myptr && myptr->end_a &&
Packit Service b38f0b
        snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) {
Packit Service b38f0b
        return myptr;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    return NULL;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/**  @} */
Packit Service b38f0b
/* End of Subtrees maintaining code */
Packit Service b38f0b
Packit Service b38f0b
/** @defgroup agent_mib_registering Registering and unregistering MIB subtrees.
Packit Service b38f0b
 *     Adding and removing MIB nodes to the database under their contexts.
Packit Service b38f0b
 *   @ingroup agent_registry
Packit Service b38f0b
 *
Packit Service b38f0b
 * @{
Packit Service b38f0b
 */
Packit Service b38f0b
Packit Service b38f0b
Packit Service b38f0b
/** Registers a MIB handler.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param moduleName
Packit Service b38f0b
 *  @param var
Packit Service b38f0b
 *  @param varsize
Packit Service b38f0b
 *  @param numvars
Packit Service b38f0b
 *  @param  mibloc
Packit Service b38f0b
 *  @param mibloclen
Packit Service b38f0b
 *  @param priority
Packit Service b38f0b
 *  @param range_subid
Packit Service b38f0b
 *  @param range_ubound
Packit Service b38f0b
 *  @param  ss
Packit Service b38f0b
 *  @param context
Packit Service b38f0b
 *  @param timeout
Packit Service b38f0b
 *  @param flags
Packit Service b38f0b
 *  @param reginfo Registration handler structure.
Packit Service b38f0b
 *                 In a case of failure, it will be freed.
Packit Service b38f0b
 *  @param perform_callback
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return gives MIB_REGISTERED_OK or MIB_* error code.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @see netsnmp_register_handler()
Packit Service b38f0b
 *  @see register_agentx_list()
Packit Service b38f0b
 *  @see netsnmp_handler_registration_free()
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
netsnmp_register_mib(const char *moduleName,
Packit Service b38f0b
                     struct variable *var,
Packit Service b38f0b
                     size_t varsize,
Packit Service b38f0b
                     size_t numvars,
Packit Service b38f0b
                     oid * mibloc,
Packit Service b38f0b
                     size_t mibloclen,
Packit Service b38f0b
                     int priority,
Packit Service b38f0b
                     int range_subid,
Packit Service b38f0b
                     oid range_ubound,
Packit Service b38f0b
                     netsnmp_session * ss,
Packit Service b38f0b
                     const char *context,
Packit Service b38f0b
                     int timeout,
Packit Service b38f0b
                     int flags,
Packit Service b38f0b
                     netsnmp_handler_registration *reginfo,
Packit Service b38f0b
                     int perform_callback)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *subtree, *sub2;
Packit Service b38f0b
    int             res;
Packit Service b38f0b
    struct register_parameters reg_parms;
Packit Service b38f0b
    int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
Packit Service b38f0b
Packit Service b38f0b
    if (moduleName == NULL ||
Packit Service b38f0b
        mibloc     == NULL) {
Packit Service b38f0b
        /* Shouldn't happen ??? */
Packit Service b38f0b
        netsnmp_handler_registration_free(reginfo);
Packit Service b38f0b
        return MIB_REGISTRATION_FAILED;
Packit Service b38f0b
    }
Packit Service b38f0b
    subtree = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree));
Packit Service b38f0b
    if (subtree == NULL) {
Packit Service b38f0b
        netsnmp_handler_registration_free(reginfo);
Packit Service b38f0b
        return MIB_REGISTRATION_FAILED;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName));
Packit Service b38f0b
    DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid,
Packit Service b38f0b
                      range_ubound));
Packit Service b38f0b
    DEBUGMSG(("register_mib", " with context \"%s\"\n",
Packit Service b38f0b
              SNMP_STRORNULL(context)));
Packit Service b38f0b
Packit Service b38f0b
    /*
Packit Service b38f0b
     * verify that the passed context is equal to the context
Packit Service b38f0b
     * in the reginfo.
Packit Service b38f0b
     * (which begs the question, why do we have both? It appears that the
Packit Service b38f0b
     *  reginfo item didn't appear til 5.2)
Packit Service b38f0b
     */
Packit Service b38f0b
    if( ((NULL == context) && (NULL != reginfo->contextName)) ||
Packit Service b38f0b
        ((NULL != context) && (NULL == reginfo->contextName)) ||
Packit Service b38f0b
        ( ((NULL != context) && (NULL != reginfo->contextName)) &&
Packit Service b38f0b
          (0 != strcmp(context, reginfo->contextName))) ) {
Packit Service b38f0b
        snmp_log(LOG_WARNING,"context passed during registration does not "
Packit Service b38f0b
                 "equal the reginfo contextName! ('%s' != '%s')\n",
Packit Service b38f0b
                 context, reginfo->contextName);
Packit Service b38f0b
        netsnmp_assert(!"register context == reginfo->contextName"); /* always false */
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /*  Create the new subtree node being registered.  */
Packit Service b38f0b
Packit Service b38f0b
    subtree->reginfo = reginfo;
Packit Service b38f0b
    subtree->name_a  = snmp_duplicate_objid(mibloc, mibloclen);
Packit Service b38f0b
    subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen);
Packit Service b38f0b
    subtree->end_a   = snmp_duplicate_objid(mibloc, mibloclen);
Packit Service b38f0b
    subtree->label_a = strdup(moduleName);
Packit Service b38f0b
    if (subtree->name_a == NULL || subtree->start_a == NULL || 
Packit Service b38f0b
	subtree->end_a  == NULL || subtree->label_a == NULL) {
Packit Service b38f0b
	netsnmp_subtree_free(subtree); /* also frees reginfo */
Packit Service b38f0b
	return MIB_REGISTRATION_FAILED;
Packit Service b38f0b
    }
Packit Service b38f0b
    subtree->namelen   = (u_char)mibloclen;
Packit Service b38f0b
    subtree->start_len = (u_char)mibloclen;
Packit Service b38f0b
    subtree->end_len   = (u_char)mibloclen;
Packit Service b38f0b
    subtree->end_a[mibloclen - 1]++;
Packit Service b38f0b
Packit Service b38f0b
    if (var != NULL) {
Packit Service b38f0b
	subtree->variables = (struct variable *)malloc(varsize*numvars);
Packit Service b38f0b
	if (subtree->variables == NULL) {
Packit Service b38f0b
	    netsnmp_subtree_free(subtree); /* also frees reginfo */
Packit Service b38f0b
	    return MIB_REGISTRATION_FAILED;
Packit Service b38f0b
	}
Packit Service b38f0b
	memcpy(subtree->variables, var, numvars*varsize);
Packit Service b38f0b
	subtree->variables_len = numvars;
Packit Service b38f0b
	subtree->variables_width = varsize;
Packit Service b38f0b
    }
Packit Service b38f0b
    subtree->priority = priority;
Packit Service b38f0b
    subtree->timeout = timeout;
Packit Service b38f0b
    subtree->range_subid = range_subid;
Packit Service b38f0b
    subtree->range_ubound = range_ubound;
Packit Service b38f0b
    subtree->session = ss;
Packit Service b38f0b
    subtree->flags = (u_char)flags;    /*  used to identify instance oids  */
Packit Service b38f0b
    subtree->flags |= SUBTREE_ATTACHED;
Packit Service b38f0b
    subtree->global_cacheid = reginfo->global_cacheid;
Packit Service b38f0b
Packit Service b38f0b
    netsnmp_set_lookup_cache_size(0);
Packit Service b38f0b
    res = netsnmp_subtree_load(subtree, context);
Packit Service b38f0b
Packit Service b38f0b
    /*  If registering a range, use the first subtree as a template for the
Packit Service b38f0b
	rest of the range.  */
Packit Service b38f0b
Packit Service b38f0b
    if (res == MIB_REGISTERED_OK && range_subid != 0) {
Packit Service b38f0b
        int i;
Packit Service b38f0b
	for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) {
Packit Service b38f0b
	    sub2 = netsnmp_subtree_deepcopy(subtree);
Packit Service b38f0b
Packit Service b38f0b
	    if (sub2 == NULL) {
Packit Service b38f0b
                unregister_mib_context(mibloc, mibloclen, priority,
Packit Service b38f0b
                                       range_subid, range_ubound, context);
Packit Service b38f0b
                netsnmp_set_lookup_cache_size(old_lookup_cache_val);
Packit Service b38f0b
                invalidate_lookup_cache(context);
Packit Service b38f0b
                return MIB_REGISTRATION_FAILED;
Packit Service b38f0b
            }
Packit Service b38f0b
Packit Service b38f0b
            sub2->name_a[range_subid - 1]  = i;
Packit Service b38f0b
            sub2->start_a[range_subid - 1] = i;
Packit Service b38f0b
            sub2->end_a[range_subid - 1]   = i;     /* XXX - ???? */
Packit Service b38f0b
            if (range_subid == (int)mibloclen) {
Packit Service b38f0b
                ++sub2->end_a[range_subid - 1];
Packit Service b38f0b
            }
Packit Service b38f0b
            sub2->flags |= SUBTREE_ATTACHED;
Packit Service b38f0b
            sub2->global_cacheid = reginfo->global_cacheid;
Packit Service b38f0b
            /* FRQ This is essential for requests to succeed! */
Packit Service b38f0b
            sub2->reginfo->rootoid[range_subid - 1]  = i;
Packit Service b38f0b
Packit Service b38f0b
            res = netsnmp_subtree_load(sub2, context);
Packit Service b38f0b
            if (res != MIB_REGISTERED_OK) {
Packit Service b38f0b
                unregister_mib_context(mibloc, mibloclen, priority,
Packit Service b38f0b
                                       range_subid, range_ubound, context);
Packit Service b38f0b
                netsnmp_remove_subtree(sub2);
Packit Service b38f0b
		netsnmp_subtree_free(sub2);
Packit Service b38f0b
                netsnmp_set_lookup_cache_size(old_lookup_cache_val);
Packit Service b38f0b
                invalidate_lookup_cache(context);
Packit Service b38f0b
                return res;
Packit Service b38f0b
            }
Packit Service b38f0b
        }
Packit Service b38f0b
    } else if (res == MIB_DUPLICATE_REGISTRATION ||
Packit Service b38f0b
               res == MIB_REGISTRATION_FAILED) {
Packit Service b38f0b
        netsnmp_set_lookup_cache_size(old_lookup_cache_val);
Packit Service b38f0b
        invalidate_lookup_cache(context);
Packit Service b38f0b
        netsnmp_subtree_free(subtree);
Packit Service b38f0b
        return res;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /*
Packit Service b38f0b
     * mark the MIB as detached, if there's no master agent present as of now 
Packit Service b38f0b
     */
Packit Service b38f0b
    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
Packit Service b38f0b
			       NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
Packit Service b38f0b
        if (main_session == NULL) {
Packit Service b38f0b
            register_mib_detach_node(subtree);
Packit Service b38f0b
	}
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    if (res == MIB_REGISTERED_OK && perform_callback) {
Packit Service b38f0b
        memset(&reg_parms, 0x0, sizeof(reg_parms));
Packit Service b38f0b
        reg_parms.name = mibloc;
Packit Service b38f0b
        reg_parms.namelen = mibloclen;
Packit Service b38f0b
        reg_parms.priority = priority;
Packit Service b38f0b
        reg_parms.range_subid = range_subid;
Packit Service b38f0b
        reg_parms.range_ubound = range_ubound;
Packit Service b38f0b
        reg_parms.timeout = timeout;
Packit Service b38f0b
        reg_parms.flags = (u_char) flags;
Packit Service b38f0b
        reg_parms.contextName = context;
Packit Service b38f0b
        reg_parms.session = ss;
Packit Service b38f0b
        reg_parms.reginfo = reginfo;
Packit Service b38f0b
        reg_parms.contextName = context;
Packit Service b38f0b
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit Service b38f0b
                            SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    netsnmp_set_lookup_cache_size(old_lookup_cache_val);
Packit Service b38f0b
    invalidate_lookup_cache(context);
Packit Service b38f0b
    return res;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** @private
Packit Service b38f0b
 *  Reattach a particular node.  
Packit Service b38f0b
 */
Packit Service b38f0b
static void
Packit Service b38f0b
register_mib_reattach_node(netsnmp_subtree *s)
Packit Service b38f0b
{
Packit Service b38f0b
    if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) {
Packit Service b38f0b
        struct register_parameters reg_parms;
Packit Service b38f0b
        /*
Packit Service b38f0b
         * only do registrations that are not the top level nodes 
Packit Service b38f0b
         */
Packit Service b38f0b
        memset(&reg_parms, 0x0, sizeof(reg_parms));
Packit Service b38f0b
Packit Service b38f0b
        /*
Packit Service b38f0b
         * XXX: do this better 
Packit Service b38f0b
         */
Packit Service b38f0b
        reg_parms.name = s->name_a;
Packit Service b38f0b
        reg_parms.namelen = s->namelen;
Packit Service b38f0b
        reg_parms.priority = s->priority;
Packit Service b38f0b
        reg_parms.range_subid = s->range_subid;
Packit Service b38f0b
        reg_parms.range_ubound = s->range_ubound;
Packit Service b38f0b
        reg_parms.timeout = s->timeout;
Packit Service b38f0b
        reg_parms.flags = s->flags;
Packit Service b38f0b
        reg_parms.session = s->session;
Packit Service b38f0b
        reg_parms.reginfo = s->reginfo;
Packit Service b38f0b
        /* XXX: missing in subtree: reg_parms.contextName = s->context; */
Packit Service b38f0b
        if ((NULL != s->reginfo) && (NULL != s->reginfo->contextName))
Packit Service b38f0b
            reg_parms.contextName = s->reginfo->contextName;
Packit Service b38f0b
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit Service b38f0b
                            SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
Packit Service b38f0b
        s->flags |= SUBTREE_ATTACHED;
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Call callbacks to reattach all our nodes.  
Packit Service b38f0b
 */
Packit Service b38f0b
void
Packit Service b38f0b
register_mib_reattach(void)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *s, *t;
Packit Service b38f0b
    subtree_context_cache *ptr;
Packit Service b38f0b
Packit Service b38f0b
    for (ptr = context_subtrees; ptr; ptr = ptr->next) {
Packit Service b38f0b
        for (s = ptr->first_subtree; s != NULL; s = s->next) {
Packit Service b38f0b
            register_mib_reattach_node(s);
Packit Service b38f0b
            for (t = s->children; t != NULL; t = t->children) {
Packit Service b38f0b
                register_mib_reattach_node(t);
Packit Service b38f0b
            }
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** @private
Packit Service b38f0b
 *  Mark a node as detached.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param s The note to be marked
Packit Service b38f0b
 */
Packit Service b38f0b
static void
Packit Service b38f0b
register_mib_detach_node(netsnmp_subtree *s)
Packit Service b38f0b
{
Packit Service b38f0b
    if (s != NULL) {
Packit Service b38f0b
        s->flags = s->flags & ~SUBTREE_ATTACHED;
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Mark all our registered OIDs as detached.
Packit Service b38f0b
 *  This is only really useful for subagent protocols, when
Packit Service b38f0b
 *  a connection is lost or the subagent is being shut down.  
Packit Service b38f0b
 */
Packit Service b38f0b
void
Packit Service b38f0b
register_mib_detach(void)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *s, *t;
Packit Service b38f0b
    subtree_context_cache *ptr;
Packit Service b38f0b
    for (ptr = context_subtrees; ptr; ptr = ptr->next) {
Packit Service b38f0b
        for (s = ptr->first_subtree; s != NULL; s = s->next) {
Packit Service b38f0b
            register_mib_detach_node(s);
Packit Service b38f0b
            for (t = s->children; t != NULL; t = t->children) {
Packit Service b38f0b
                register_mib_detach_node(t);
Packit Service b38f0b
            }
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Register a new module into the MIB database, with all possible custom options
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  moduleName Text name of the module.
Packit Service b38f0b
 *                     The given name will be used to identify the module
Packit Service b38f0b
 *                     inside the agent.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  var        Array of variables to be registered in the module.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  varsize    Size of a single variable in var array.
Packit Service b38f0b
 *                     The size is normally equal to sizeof(struct variable),
Packit Service b38f0b
 *                     but if we wish to use shorter (or longer) OIDs, then we
Packit Service b38f0b
 *                     could use different variant of the variable structure.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  numvars    Number of variables in the var array.
Packit Service b38f0b
 *                     This is how many variables the function will try to register.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  mibloc     Base OID of the module.
Packit Service b38f0b
 *                     All OIDs in var array should be sub-oids of the base OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  mibloclen  Length of the base OID.
Packit Service b38f0b
 *                     Number of integers making up the base OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  priority   Registration priority.
Packit Service b38f0b
 *                     Used to achieve a desired configuration when different
Packit Service b38f0b
 *                     sessions register identical or overlapping regions.
Packit Service b38f0b
 *                     Primarily used with AgentX subagent registrations.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param range_subid If non-zero, the module is registered against a range
Packit Service b38f0b
 *                     of OIDs, with this parameter identifying the relevant
Packit Service b38f0b
 *                     subidentifier - see RFC 2741 for details.
Packit Service b38f0b
 *                     Typically used to register a single row of a table.
Packit Service b38f0b
 *                     If zero, then register the module against the full OID subtree.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param range_ubound The end of the range being registered (see RFC 2741)
Packit Service b38f0b
 *                     If range_subid is zero, then this parameter is ignored.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param ss 
Packit Service b38f0b
 *  @param context
Packit Service b38f0b
 *  @param timeout 
Packit Service b38f0b
 *  @param flags 
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @see register_mib()
Packit Service b38f0b
 *  @see register_mib_priority()
Packit Service b38f0b
 *  @see register_mib_range()
Packit Service b38f0b
 *  @see unregister_mib()
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
register_mib_context(const char *moduleName,
Packit Service b38f0b
                     const struct variable *var,
Packit Service b38f0b
                     size_t varsize,
Packit Service b38f0b
                     size_t numvars,
Packit Service b38f0b
                     const oid * mibloc,
Packit Service b38f0b
                     size_t mibloclen,
Packit Service b38f0b
                     int priority,
Packit Service b38f0b
                     int range_subid,
Packit Service b38f0b
                     oid range_ubound,
Packit Service b38f0b
                     netsnmp_session * ss,
Packit Service b38f0b
                     const char *context, int timeout, int flags)
Packit Service b38f0b
{
Packit Service b38f0b
    return netsnmp_register_old_api(moduleName, var, varsize, numvars,
Packit Service b38f0b
                                    mibloc, mibloclen, priority,
Packit Service b38f0b
                                    range_subid, range_ubound, ss, context,
Packit Service b38f0b
                                    timeout, flags);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Register a new module into the MIB database, as being responsible
Packit Service b38f0b
 *   for a range of OIDs (typically a single row of a table).
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  moduleName Text name of the module.
Packit Service b38f0b
 *                     The given name will be used to identify the module
Packit Service b38f0b
 *                     inside the agent.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  var        Array of variables to be registered in the module.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  varsize    Size of a single variable in var array.
Packit Service b38f0b
 *                     The size is normally equal to sizeof(struct variable),
Packit Service b38f0b
 *                     but if we wish to use shorter (or longer) OIDs, then we
Packit Service b38f0b
 *                     could use different variant of the variable structure.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  numvars    Number of variables in the var array.
Packit Service b38f0b
 *                     This is how many variables the function will try to register.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  mibloc     Base OID of the module.
Packit Service b38f0b
 *                     All OIDs in var array should be sub-oids of the base OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  mibloclen  Length of the base OID.
Packit Service b38f0b
 *                     Number of integers making up the base OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  priority   Registration priority.
Packit Service b38f0b
 *                     Used to achieve a desired configuration when different
Packit Service b38f0b
 *                     sessions register identical or overlapping regions.
Packit Service b38f0b
 *                     Primarily used with AgentX subagent registrations.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param range_subid If non-zero, the module is registered against a range
Packit Service b38f0b
 *                     of OIDs, with this parameter identifying the relevant
Packit Service b38f0b
 *                     subidentifier - see RFC 2741 for details.
Packit Service b38f0b
 *                     Typically used to register a single row of a table.
Packit Service b38f0b
 *                     If zero, then register the module against the full OID subtree.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param range_ubound The end of the range being registered (see RFC 2741)
Packit Service b38f0b
 *                     If range_subid is zero, then this parameter is ignored.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param ss 
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @see register_mib()
Packit Service b38f0b
 *  @see register_mib_priority()
Packit Service b38f0b
 *  @see register_mib_context()
Packit Service b38f0b
 *  @see unregister_mib()
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
register_mib_range(const char *moduleName,
Packit Service b38f0b
                   const struct variable *var,
Packit Service b38f0b
                   size_t varsize,
Packit Service b38f0b
                   size_t numvars,
Packit Service b38f0b
                   const oid * mibloc,
Packit Service b38f0b
                   size_t mibloclen,
Packit Service b38f0b
                   int priority,
Packit Service b38f0b
                   int range_subid, oid range_ubound, netsnmp_session * ss)
Packit Service b38f0b
{
Packit Service b38f0b
    return register_mib_context(moduleName, var, varsize, numvars,
Packit Service b38f0b
                                mibloc, mibloclen, priority,
Packit Service b38f0b
                                range_subid, range_ubound, ss, "", -1, 0);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Register a new module into the MIB database, with a non-default priority
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  moduleName Text name of the module.
Packit Service b38f0b
 *                     The given name will be used to identify the module
Packit Service b38f0b
 *                     inside the agent.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  var        Array of variables to be registered in the module.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  varsize    Size of a single variable in var array.
Packit Service b38f0b
 *                     The size is normally equal to sizeof(struct variable),
Packit Service b38f0b
 *                     but if we wish to use shorter (or longer) OIDs, then we
Packit Service b38f0b
 *                     could use different variant of the variable structure.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  numvars    Number of variables in the var array.
Packit Service b38f0b
 *                     This is how many variables the function will try to register.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  mibloc     Base OID of the module.
Packit Service b38f0b
 *                     All OIDs in var array should be sub-oids of the base OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  mibloclen  Length of the base OID.
Packit Service b38f0b
 *                     Number of integers making up the base OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  priority   Registration priority.
Packit Service b38f0b
 *                     Used to achieve a desired configuration when different
Packit Service b38f0b
 *                     sessions register identical or overlapping regions.
Packit Service b38f0b
 *                     Primarily used with AgentX subagent registrations.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @see register_mib()
Packit Service b38f0b
 *  @see register_mib_range()
Packit Service b38f0b
 *  @see register_mib_context()
Packit Service b38f0b
 *  @see unregister_mib()
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
register_mib_priority(const char *moduleName,
Packit Service b38f0b
                      const struct variable *var,
Packit Service b38f0b
                      size_t varsize,
Packit Service b38f0b
                      size_t numvars,
Packit Service b38f0b
                      const oid * mibloc, size_t mibloclen, int priority)
Packit Service b38f0b
{
Packit Service b38f0b
    return register_mib_range(moduleName, var, varsize, numvars,
Packit Service b38f0b
                              mibloc, mibloclen, priority, 0, 0, NULL);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Register a new module into the MIB database, using default priority and context
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  moduleName Text name of the module.
Packit Service b38f0b
 *                     The given name will be used to identify the module
Packit Service b38f0b
 *                     inside the agent.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  var        Array of variables to be registered in the module.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  varsize    Size of a single variable in var array.
Packit Service b38f0b
 *                     The size is normally equal to sizeof(struct variable),
Packit Service b38f0b
 *                     but if we wish to use shorter (or longer) OIDs, then we
Packit Service b38f0b
 *                     could use different variant of the variable structure.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  numvars    Number of variables in the var array.
Packit Service b38f0b
 *                     This is how many variables the function will try to register.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  mibloc     Base OID of the module.
Packit Service b38f0b
 *                     All OIDs in var array should be sub-oids of the base OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  mibloclen  Length of the base OID.
Packit Service b38f0b
 *                     Number of integers making up the base OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return gives SNMPERR_SUCCESS or SNMPERR_* error code.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @see register_mib_priority()
Packit Service b38f0b
 *  @see register_mib_range()
Packit Service b38f0b
 *  @see register_mib_context()
Packit Service b38f0b
 *  @see unregister_mib()
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
register_mib(const char *moduleName,
Packit Service b38f0b
             const struct variable *var,
Packit Service b38f0b
             size_t varsize,
Packit Service b38f0b
             size_t numvars, const oid * mibloc, size_t mibloclen)
Packit Service b38f0b
{
Packit Service b38f0b
    return register_mib_priority(moduleName, var, varsize, numvars,
Packit Service b38f0b
                                 mibloc, mibloclen, DEFAULT_MIB_PRIORITY);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** @private
Packit Service b38f0b
 *  Unloads a subtree from MIB tree.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  sub     The sub-tree which is being removed.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  prev    Previous entry, before the unloaded one.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param  context Name of the context which is being removed.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @see unregister_mib_context()
Packit Service b38f0b
 */
Packit Service b38f0b
void
Packit Service b38f0b
netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev, const char *context)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *ptr;
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("register_mib", "unload("));
Packit Service b38f0b
    if (sub != NULL) {
Packit Service b38f0b
        DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len));
Packit Service b38f0b
    } else {
Packit Service b38f0b
        DEBUGMSG(("register_mib", "[NIL]"));
Packit Service b38f0b
        return;
Packit Service b38f0b
    }
Packit Service b38f0b
    DEBUGMSG(("register_mib", ", "));
Packit Service b38f0b
    if (prev != NULL) {
Packit Service b38f0b
        DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len));
Packit Service b38f0b
    } else {
Packit Service b38f0b
        DEBUGMSG(("register_mib", "[NIL]"));
Packit Service b38f0b
    }
Packit Service b38f0b
    DEBUGMSG(("register_mib", ")\n"));
Packit Service b38f0b
Packit Service b38f0b
    if (prev != NULL) {         /* non-leading entries are easy */
Packit Service b38f0b
        prev->children = sub->children;
Packit Service b38f0b
        invalidate_lookup_cache(context);
Packit Service b38f0b
        return;
Packit Service b38f0b
    }
Packit Service b38f0b
    /*
Packit Service b38f0b
     * otherwise, we need to amend our neighbours as well 
Packit Service b38f0b
     */
Packit Service b38f0b
Packit Service b38f0b
    if (sub->children == NULL) {        /* just remove this node completely */
Packit Service b38f0b
        for (ptr = sub->prev; ptr; ptr = ptr->children) {
Packit Service b38f0b
            netsnmp_subtree_change_next(ptr, sub->next);
Packit Service b38f0b
        }
Packit Service b38f0b
        for (ptr = sub->next; ptr; ptr = ptr->children) {
Packit Service b38f0b
            netsnmp_subtree_change_prev(ptr, sub->prev);
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
	if (sub->prev == NULL) {
Packit Service b38f0b
	    netsnmp_subtree_replace_first(sub->next, context);
Packit Service b38f0b
	}
Packit Service b38f0b
Packit Service b38f0b
    } else {
Packit Service b38f0b
        for (ptr = sub->prev; ptr; ptr = ptr->children)
Packit Service b38f0b
            netsnmp_subtree_change_next(ptr, sub->children);
Packit Service b38f0b
        for (ptr = sub->next; ptr; ptr = ptr->children)
Packit Service b38f0b
            netsnmp_subtree_change_prev(ptr, sub->children);
Packit Service b38f0b
Packit Service b38f0b
	if (sub->prev == NULL) {
Packit Service b38f0b
	    netsnmp_subtree_replace_first(sub->children, context);
Packit Service b38f0b
	}
Packit Service b38f0b
    }
Packit Service b38f0b
    invalidate_lookup_cache(context);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/**
Packit Service b38f0b
 * Unregisters a module registered against a given OID (or range) in a specified context. 
Packit Service b38f0b
 * Typically used when a module has multiple contexts defined.
Packit Service b38f0b
 * The parameters priority, range_subid, range_ubound and context
Packit Service b38f0b
 * should match those used to register the module originally.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param name  the specific OID to unregister if it conatins the associated
Packit Service b38f0b
 *              context.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param len   the length of the OID, use  OID_LENGTH macro.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param priority  a value between 1 and 255, used to achieve a desired
Packit Service b38f0b
 *                  configuration when different sessions register identical or
Packit Service b38f0b
 *                  overlapping regions.  Subagents with no particular
Packit Service b38f0b
 *                  knowledge of priority should register with the default
Packit Service b38f0b
 *                  value of 127.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param range_subid  permits specifying a range in place of one of a subtree
Packit Service b38f0b
 *                     sub-identifiers.  When this value is zero, no range is
Packit Service b38f0b
 *                     being specified.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param range_ubound  the upper bound of a sub-identifier's range.
Packit Service b38f0b
 *                      This field is present only if range_subid is not 0.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param context  a context name that has been created
Packit Service b38f0b
 *
Packit Service b38f0b
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
Packit Service b38f0b
 * 
Packit Service b38f0b
 * @see unregister_mib()
Packit Service b38f0b
 * @see unregister_mib_priority()
Packit Service b38f0b
 * @see unregister_mib_range()
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
unregister_mib_context(oid * name, size_t len, int priority,
Packit Service b38f0b
                       int range_subid, oid range_ubound,
Packit Service b38f0b
                       const char *context)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *list, *myptr = NULL;
Packit Service b38f0b
    netsnmp_subtree *prev, *child, *next; /* loop through children */
Packit Service b38f0b
    struct register_parameters reg_parms;
Packit Service b38f0b
    int old_lookup_cache_val = netsnmp_get_lookup_cache_size();
Packit Service b38f0b
    int unregistering = 1;
Packit Service b38f0b
    int orig_subid_val = -1;
Packit Service b38f0b
Packit Service b38f0b
    netsnmp_set_lookup_cache_size(0);
Packit Service b38f0b
Packit Service b38f0b
    if ((range_subid > 0) &&  ((size_t)range_subid <= len))
Packit Service b38f0b
        orig_subid_val = name[range_subid-1];
Packit Service b38f0b
Packit Service b38f0b
    while(unregistering){
Packit Service b38f0b
        DEBUGMSGTL(("register_mib", "unregistering "));
Packit Service b38f0b
        DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound));
Packit Service b38f0b
        DEBUGMSG(("register_mib", "\n"));
Packit Service b38f0b
Packit Service b38f0b
        list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context),
Packit Service b38f0b
                    context);
Packit Service b38f0b
        if (list == NULL) {
Packit Service b38f0b
            return MIB_NO_SUCH_REGISTRATION;
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
        for (child = list, prev = NULL; child != NULL;
Packit Service b38f0b
            prev = child, child = child->children) {
Packit Service b38f0b
            if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 &&
Packit Service b38f0b
                child->priority == priority) {
Packit Service b38f0b
                break;              /* found it */
Packit Service b38f0b
             }
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
        if (child == NULL) {
Packit Service b38f0b
            return MIB_NO_SUCH_REGISTRATION;
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
        netsnmp_subtree_unload(child, prev, context);
Packit Service b38f0b
        myptr = child;              /* remember this for later */
Packit Service b38f0b
Packit Service b38f0b
        /*
Packit Service b38f0b
        *  Now handle any occurances in the following subtrees,
Packit Service b38f0b
        *      as a result of splitting this range.  Due to the
Packit Service b38f0b
        *      nature of the way such splits work, the first
Packit Service b38f0b
        *      subtree 'slice' that doesn't refer to the given
Packit Service b38f0b
        *      name marks the end of the original region.
Packit Service b38f0b
        *
Packit Service b38f0b
        *  This should also serve to register ranges.
Packit Service b38f0b
        */
Packit Service b38f0b
Packit Service b38f0b
        for (list = myptr->next; list != NULL; list = next) {
Packit Service b38f0b
            next = list->next; /* list gets freed sometimes; cache next */
Packit Service b38f0b
            for (child = list, prev = NULL; child != NULL;
Packit Service b38f0b
                prev = child, child = child->children) {
Packit Service b38f0b
                if ((netsnmp_oid_equals(child->name_a, child->namelen,
Packit Service b38f0b
                    name, len) == 0) &&
Packit Service b38f0b
            (child->priority == priority)) {
Packit Service b38f0b
                    netsnmp_subtree_unload(child, prev, context);
Packit Service b38f0b
                    netsnmp_subtree_free(child);
Packit Service b38f0b
                    break;
Packit Service b38f0b
                }
Packit Service b38f0b
            }
Packit Service b38f0b
            if (child == NULL)      /* Didn't find the given name */
Packit Service b38f0b
                break;
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
        /* Maybe we are in a range... */
Packit Service b38f0b
        if (orig_subid_val != -1){
Packit Service b38f0b
            if (++name[range_subid-1] >= orig_subid_val+range_ubound)
Packit Service b38f0b
                {
Packit Service b38f0b
                unregistering=0;
Packit Service b38f0b
                name[range_subid-1] = orig_subid_val;
Packit Service b38f0b
                }
Packit Service b38f0b
        }
Packit Service b38f0b
        else {
Packit Service b38f0b
            unregistering=0;
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    memset(&reg_parms, 0x0, sizeof(reg_parms));
Packit Service b38f0b
    reg_parms.name = name;
Packit Service b38f0b
    reg_parms.namelen = len;
Packit Service b38f0b
    reg_parms.priority = priority;
Packit Service b38f0b
    reg_parms.range_subid = range_subid;
Packit Service b38f0b
    reg_parms.range_ubound = range_ubound;
Packit Service b38f0b
    reg_parms.flags = 0x00;     /*  this is okay I think  */
Packit Service b38f0b
    reg_parms.contextName = context;
Packit Service b38f0b
    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit Service b38f0b
                        SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
Packit Service b38f0b
Packit Service b38f0b
    netsnmp_subtree_free(myptr);
Packit Service b38f0b
    netsnmp_set_lookup_cache_size(old_lookup_cache_val);
Packit Service b38f0b
    invalidate_lookup_cache(context);
Packit Service b38f0b
    return MIB_UNREGISTERED_OK;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
#ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW
Packit Service b38f0b
int
Packit Service b38f0b
netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority,
Packit Service b38f0b
                                 int var_subid, oid range_ubound,
Packit Service b38f0b
                                 const char *context)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *list, *myptr, *futureptr;
Packit Service b38f0b
    netsnmp_subtree *prev, *child;       /* loop through children */
Packit Service b38f0b
    struct register_parameters reg_parms;
Packit Service b38f0b
    oid             range_lbound = name[var_subid - 1];
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("register_mib", "unregistering "));
Packit Service b38f0b
    DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound));
Packit Service b38f0b
    DEBUGMSG(("register_mib", "\n"));
Packit Service b38f0b
Packit Service b38f0b
    for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) {
Packit Service b38f0b
        list = netsnmp_subtree_find(name, len, 
Packit Service b38f0b
				netsnmp_subtree_find_first(context), context);
Packit Service b38f0b
Packit Service b38f0b
        if (list == NULL) {
Packit Service b38f0b
            continue;
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
        for (child = list, prev = NULL; child != NULL;
Packit Service b38f0b
             prev = child, child = child->children) {
Packit Service b38f0b
Packit Service b38f0b
            if (netsnmp_oid_equals(child->name_a, child->namelen, 
Packit Service b38f0b
				 name, len) == 0 && 
Packit Service b38f0b
		(child->priority == priority)) {
Packit Service b38f0b
                break;          /* found it */
Packit Service b38f0b
            }
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
        if (child == NULL) {
Packit Service b38f0b
            continue;
Packit Service b38f0b
        }
Packit Service b38f0b
Packit Service b38f0b
        netsnmp_subtree_unload(child, prev, context);
Packit Service b38f0b
        myptr = child;          /* remember this for later */
Packit Service b38f0b
Packit Service b38f0b
        for (list = myptr->next; list != NULL; list = futureptr) {
Packit Service b38f0b
            /* remember the next spot in the list in case we free this node */
Packit Service b38f0b
            futureptr = list->next;
Packit Service b38f0b
Packit Service b38f0b
            /* check each child */
Packit Service b38f0b
            for (child = list, prev = NULL; child != NULL;
Packit Service b38f0b
                 prev = child, child = child->children) {
Packit Service b38f0b
Packit Service b38f0b
                if (netsnmp_oid_equals(child->name_a, child->namelen, 
Packit Service b38f0b
				      name, len) == 0 &&
Packit Service b38f0b
                    (child->priority == priority)) {
Packit Service b38f0b
                    netsnmp_subtree_unload(child, prev, context);
Packit Service b38f0b
                    netsnmp_subtree_free(child);
Packit Service b38f0b
                    break;
Packit Service b38f0b
                }
Packit Service b38f0b
            }
Packit Service b38f0b
Packit Service b38f0b
            /* XXX: wjh: not sure why we're bailing here */
Packit Service b38f0b
            if (child == NULL) {        /* Didn't find the given name */
Packit Service b38f0b
                break;
Packit Service b38f0b
            }
Packit Service b38f0b
        }
Packit Service b38f0b
        netsnmp_subtree_free(myptr);
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    name[var_subid - 1] = range_lbound;
Packit Service b38f0b
    memset(&reg_parms, 0x0, sizeof(reg_parms));
Packit Service b38f0b
    reg_parms.name = name;
Packit Service b38f0b
    reg_parms.namelen = len;
Packit Service b38f0b
    reg_parms.priority = priority;
Packit Service b38f0b
    reg_parms.range_subid = var_subid;
Packit Service b38f0b
    reg_parms.range_ubound = range_ubound;
Packit Service b38f0b
    reg_parms.flags = 0x00;     /*  this is okay I think  */
Packit Service b38f0b
    reg_parms.contextName = context;
Packit Service b38f0b
    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit Service b38f0b
                        SNMPD_CALLBACK_UNREGISTER_OID, &reg_parms);
Packit Service b38f0b
Packit Service b38f0b
    return 0;
Packit Service b38f0b
}
Packit Service b38f0b
#endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW */
Packit Service b38f0b
Packit Service b38f0b
/**
Packit Service b38f0b
 * Unregisters a module registered against a given OID (or range) in the default context. 
Packit Service b38f0b
 * Typically used when a module has multiple contexts defined.
Packit Service b38f0b
 * The parameters priority, range_subid, and range_ubound should
Packit Service b38f0b
 * match those used to register the module originally.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param name  the specific OID to unregister if it conatins the associated
Packit Service b38f0b
 *              context.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param len   the length of the OID, use  OID_LENGTH macro.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param priority  a value between 1 and 255, used to achieve a desired
Packit Service b38f0b
 *                  configuration when different sessions register identical or
Packit Service b38f0b
 *                  overlapping regions.  Subagents with no particular
Packit Service b38f0b
 *                  knowledge of priority should register with the default
Packit Service b38f0b
 *                  value of 127.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param range_subid  permits specifying a range in place of one of a subtree
Packit Service b38f0b
 *                     sub-identifiers.  When this value is zero, no range is
Packit Service b38f0b
 *                     being specified.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param range_ubound  the upper bound of a sub-identifier's range.
Packit Service b38f0b
 *                      This field is present only if range_subid is not 0.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
Packit Service b38f0b
 * 
Packit Service b38f0b
 * @see unregister_mib()
Packit Service b38f0b
 * @see unregister_mib_priority()
Packit Service b38f0b
 * @see unregister_mib_context()
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
unregister_mib_range(oid * name, size_t len, int priority,
Packit Service b38f0b
                     int range_subid, oid range_ubound)
Packit Service b38f0b
{
Packit Service b38f0b
    return unregister_mib_context(name, len, priority, range_subid,
Packit Service b38f0b
                                  range_ubound, "");
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/**
Packit Service b38f0b
 * Unregisters a module registered against a given OID at the specified priority.
Packit Service b38f0b
 * The priority parameter should match that used to register the module originally.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param name  the specific OID to unregister if it conatins the associated
Packit Service b38f0b
 *              context.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param len   the length of the OID, use  OID_LENGTH macro.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param priority  a value between 1 and 255, used to achieve a desired
Packit Service b38f0b
 *                  configuration when different sessions register identical or
Packit Service b38f0b
 *                  overlapping regions.  Subagents with no particular
Packit Service b38f0b
 *                  knowledge of priority should register with the default
Packit Service b38f0b
 *                  value of 127.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
Packit Service b38f0b
 * 
Packit Service b38f0b
 * @see unregister_mib()
Packit Service b38f0b
 * @see unregister_mib_range()
Packit Service b38f0b
 * @see unregister_mib_context()
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
unregister_mib_priority(oid * name, size_t len, int priority)
Packit Service b38f0b
{
Packit Service b38f0b
    return unregister_mib_range(name, len, priority, 0, 0);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/**
Packit Service b38f0b
 * Unregisters a module registered against a given OID at the default priority.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param name  the specific OID to unregister if it conatins the associated
Packit Service b38f0b
 *              context.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param len   the length of the OID, use  OID_LENGTH macro.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @return gives MIB_UNREGISTERED_OK or MIB_* error code.
Packit Service b38f0b
 * 
Packit Service b38f0b
 * @see unregister_mib_priority()
Packit Service b38f0b
 * @see unregister_mib_context()
Packit Service b38f0b
 * @see unregister_mib_range()
Packit Service b38f0b
 * @see unregister_agentx_list()
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
unregister_mib(oid * name, size_t len)
Packit Service b38f0b
{
Packit Service b38f0b
    return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY);
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Unregisters subtree of OIDs bounded to given session.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param ss Session which OIDs will be removed from tree.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @see unregister_mib()
Packit Service b38f0b
 *  @see unregister_agentx_list()
Packit Service b38f0b
 */
Packit Service b38f0b
void
Packit Service b38f0b
unregister_mibs_by_session(netsnmp_session * ss)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *list, *list2;
Packit Service b38f0b
    netsnmp_subtree *child, *prev, *next_child;
Packit Service b38f0b
    struct register_parameters rp;
Packit Service b38f0b
    subtree_context_cache *contextptr;
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n",
Packit Service b38f0b
		ss, (ss && ss->contextName) ? ss->contextName : "[NIL]"));
Packit Service b38f0b
Packit Service b38f0b
    for (contextptr = get_top_context_cache(); contextptr != NULL;
Packit Service b38f0b
         contextptr = contextptr->next) {
Packit Service b38f0b
        for (list = contextptr->first_subtree; list != NULL; list = list2) {
Packit Service b38f0b
            list2 = list->next;
Packit Service b38f0b
Packit Service b38f0b
            for (child = list, prev = NULL; child != NULL; child = next_child){
Packit Service b38f0b
                next_child = child->children;
Packit Service b38f0b
Packit Service b38f0b
                if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) &&
Packit Service b38f0b
		     child->session == ss) ||
Packit Service b38f0b
                    (!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session &&
Packit Service b38f0b
                     child->session->subsession == ss)) {
Packit Service b38f0b
Packit Service b38f0b
                    memset(&rp,0x0,sizeof(rp));
Packit Service b38f0b
                    rp.name = child->name_a;
Packit Service b38f0b
		    child->name_a = NULL;
Packit Service b38f0b
                    rp.namelen = child->namelen;
Packit Service b38f0b
                    rp.priority = child->priority;
Packit Service b38f0b
                    rp.range_subid = child->range_subid;
Packit Service b38f0b
                    rp.range_ubound = child->range_ubound;
Packit Service b38f0b
                    rp.timeout = child->timeout;
Packit Service b38f0b
                    rp.flags = child->flags;
Packit Service b38f0b
                    if ((NULL != child->reginfo) &&
Packit Service b38f0b
                        (NULL != child->reginfo->contextName))
Packit Service b38f0b
                        rp.contextName = child->reginfo->contextName;
Packit Service b38f0b
Packit Service b38f0b
                    if (child->reginfo != NULL) {
Packit Service b38f0b
                        /*
Packit Service b38f0b
                         * Don't let's free the session pointer just yet!  
Packit Service b38f0b
                         */
Packit Service b38f0b
                        child->reginfo->handler->myvoid = NULL;
Packit Service b38f0b
                        netsnmp_handler_registration_free(child->reginfo);
Packit Service b38f0b
			child->reginfo = NULL;
Packit Service b38f0b
                    }
Packit Service b38f0b
Packit Service b38f0b
                    netsnmp_subtree_unload(child, prev, contextptr->context_name);
Packit Service b38f0b
                    netsnmp_subtree_free(child);
Packit Service b38f0b
Packit Service b38f0b
                    snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit Service b38f0b
                                        SNMPD_CALLBACK_UNREGISTER_OID, &rp);
Packit Service b38f0b
		    SNMP_FREE(rp.name);
Packit Service b38f0b
                } else {
Packit Service b38f0b
                    prev = child;
Packit Service b38f0b
                }
Packit Service b38f0b
            }
Packit Service b38f0b
        }
Packit Service b38f0b
        netsnmp_subtree_join(contextptr->first_subtree);
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Determines if given PDU is allowed to see (or update) a given OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param name    The OID to check access for.
Packit Service b38f0b
 *                On return, this parameter holds the OID actually matched
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param namelen Number of sub-identifiers in the OID.
Packit Service b38f0b
 *                On return, this parameter holds the length of the matched OID
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param pdu     PDU requesting access to the OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param type    ANS.1 type of the value at given OID.
Packit Service b38f0b
 *                (Used for catching SNMPv1 requests for SMIv2-only objects)
Packit Service b38f0b
 *
Packit Service b38f0b
 * @return gives VACM_SUCCESS if the OID is in the PDU, otherwise error code.
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type)
Packit Service b38f0b
{
Packit Service b38f0b
    struct view_parameters view_parms;
Packit Service b38f0b
Packit Service b38f0b
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
Packit Service b38f0b
	/* Enable bypassing of view-based access control */
Packit Service b38f0b
        return VACM_SUCCESS;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    /*
Packit Service b38f0b
     * check for v1 and counter64s, since snmpv1 doesn't support it 
Packit Service b38f0b
     */
Packit Service b38f0b
#ifndef NETSNMP_DISABLE_SNMPV1
Packit Service b38f0b
    if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) {
Packit Service b38f0b
        return VACM_NOTINVIEW;
Packit Service b38f0b
    }
Packit Service b38f0b
#endif
Packit Service b38f0b
Packit Service b38f0b
    view_parms.pdu = pdu;
Packit Service b38f0b
    view_parms.name = name;
Packit Service b38f0b
    if (namelen != NULL) {
Packit Service b38f0b
        view_parms.namelen = *namelen;
Packit Service b38f0b
    } else {
Packit Service b38f0b
        view_parms.namelen = 0;
Packit Service b38f0b
    }
Packit Service b38f0b
    view_parms.errorcode = 0;
Packit Service b38f0b
    view_parms.check_subtree = 0;
Packit Service b38f0b
Packit Service b38f0b
    switch (pdu->version) {
Packit Service b38f0b
#ifndef NETSNMP_DISABLE_SNMPV1
Packit Service b38f0b
    case SNMP_VERSION_1:
Packit Service b38f0b
#endif
Packit Service b38f0b
#ifndef NETSNMP_DISABLE_SNMPV2C
Packit Service b38f0b
    case SNMP_VERSION_2c:
Packit Service b38f0b
#endif
Packit Service b38f0b
   case SNMP_VERSION_3:
Packit Service b38f0b
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
Packit Service b38f0b
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit Service b38f0b
                            SNMPD_CALLBACK_ACM_CHECK, &view_parms);
Packit Service b38f0b
        return view_parms.errorcode;
Packit Service b38f0b
    }
Packit Service b38f0b
  unsupported_version:
Packit Service b38f0b
    return VACM_NOSECNAME;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Determines if the given PDU request could potentially succeed.
Packit Service b38f0b
 *  (Preliminary, OID-independent validation)
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param pdu     PDU requesting access
Packit Service b38f0b
 *
Packit Service b38f0b
 * @return gives VACM_SUCCESS   if the entire MIB tree is accessible
Packit Service b38f0b
 *               VACM_NOTINVIEW if the entire MIB tree is inaccessible
Packit Service b38f0b
 *               VACM_SUBTREE_UNKNOWN if some portions are accessible
Packit Service b38f0b
 *               other codes may returned on error
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
check_access(netsnmp_pdu *pdu)
Packit Service b38f0b
{                               /* IN - pdu being checked */
Packit Service b38f0b
    struct view_parameters view_parms;
Packit Service b38f0b
    view_parms.pdu = pdu;
Packit Service b38f0b
    view_parms.name = NULL;
Packit Service b38f0b
    view_parms.namelen = 0;
Packit Service b38f0b
    view_parms.errorcode = 0;
Packit Service b38f0b
    view_parms.check_subtree = 0;
Packit Service b38f0b
Packit Service b38f0b
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
Packit Service b38f0b
	/* Enable bypassing of view-based access control */
Packit Service b38f0b
        return 0;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    switch (pdu->version) {
Packit Service b38f0b
#ifndef NETSNMP_DISABLE_SNMPV1
Packit Service b38f0b
    case SNMP_VERSION_1:
Packit Service b38f0b
#endif
Packit Service b38f0b
#ifndef NETSNMP_DISABLE_SNMPV2C
Packit Service b38f0b
    case SNMP_VERSION_2c:
Packit Service b38f0b
#endif
Packit Service b38f0b
    case SNMP_VERSION_3:
Packit Service b38f0b
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
Packit Service b38f0b
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit Service b38f0b
                            SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms);
Packit Service b38f0b
        return view_parms.errorcode;
Packit Service b38f0b
    }
Packit Service b38f0b
  unsupported_version:
Packit Service b38f0b
    return 1;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Determines if the given PDU request could potentially access
Packit Service b38f0b
 *   the specified MIB subtree
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param pdu     PDU requesting access
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param name    The OID to check access for.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @param namelen Number of sub-identifiers in the OID.
Packit Service b38f0b
 *
Packit Service b38f0b
 * @return gives VACM_SUCCESS   if the entire MIB tree is accessible
Packit Service b38f0b
 *               VACM_NOTINVIEW if the entire MIB tree is inaccessible
Packit Service b38f0b
 *               VACM_SUBTREE_UNKNOWN if some portions are accessible
Packit Service b38f0b
 *               other codes may returned on error
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen)
Packit Service b38f0b
{                               /* IN - pdu being checked */
Packit Service b38f0b
    struct view_parameters view_parms;
Packit Service b38f0b
    view_parms.pdu = pdu;
Packit Service b38f0b
    view_parms.name = name;
Packit Service b38f0b
    view_parms.namelen = namelen;
Packit Service b38f0b
    view_parms.errorcode = 0;
Packit Service b38f0b
    view_parms.check_subtree = 1;
Packit Service b38f0b
Packit Service b38f0b
    if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) {
Packit Service b38f0b
	/* Enable bypassing of view-based access control */
Packit Service b38f0b
        return 0;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    switch (pdu->version) {
Packit Service b38f0b
#ifndef NETSNMP_DISABLE_SNMPV1
Packit Service b38f0b
    case SNMP_VERSION_1:
Packit Service b38f0b
#endif
Packit Service b38f0b
#ifndef NETSNMP_DISABLE_SNMPV2C
Packit Service b38f0b
    case SNMP_VERSION_2c:
Packit Service b38f0b
#endif
Packit Service b38f0b
    case SNMP_VERSION_3:
Packit Service b38f0b
        NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version);
Packit Service b38f0b
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
Packit Service b38f0b
                            SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms);
Packit Service b38f0b
        return view_parms.errorcode;
Packit Service b38f0b
    }
Packit Service b38f0b
  unsupported_version:
Packit Service b38f0b
    return 1;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
netsnmp_feature_child_of(get_session_for_oid,netsnmp_unused)
Packit Service b38f0b
#ifndef NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID
Packit Service b38f0b
netsnmp_session *
Packit Service b38f0b
get_session_for_oid(const oid *name, size_t len, const char *context_name)
Packit Service b38f0b
{
Packit Service b38f0b
    netsnmp_subtree *myptr;
Packit Service b38f0b
Packit Service b38f0b
    myptr = netsnmp_subtree_find_prev(name, len, 
Packit Service b38f0b
				      netsnmp_subtree_find_first(context_name),
Packit Service b38f0b
				      context_name);
Packit Service b38f0b
Packit Service b38f0b
    while (myptr && myptr->variables == NULL) {
Packit Service b38f0b
        myptr = myptr->next;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    if (myptr == NULL) {
Packit Service b38f0b
        return NULL;
Packit Service b38f0b
    } else {
Packit Service b38f0b
        return myptr->session;
Packit Service b38f0b
    }
Packit Service b38f0b
}
Packit Service b38f0b
#endif /* NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID */
Packit Service b38f0b
Packit Service b38f0b
void
Packit Service b38f0b
setup_tree(void)
Packit Service b38f0b
{
Packit Service b38f0b
    oid ccitt[1]           = { 0 };
Packit Service b38f0b
    oid iso[1]             = { 1 };
Packit Service b38f0b
    oid joint_ccitt_iso[1] = { 2 };
Packit Service b38f0b
Packit Service b38f0b
#ifdef USING_AGENTX_SUBAGENT_MODULE
Packit Service b38f0b
    int role =  netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
Packit Service b38f0b
				       NETSNMP_DS_AGENT_ROLE);
Packit Service b38f0b
Packit Service b38f0b
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
Packit Service b38f0b
			   MASTER_AGENT);
Packit Service b38f0b
#endif
Packit Service b38f0b
Packit Service b38f0b
    /* 
Packit Service b38f0b
     * we need to have the oid's in the heap, that we can *free* it for every case, 
Packit Service b38f0b
     * thats the purpose of the duplicate_objid's
Packit Service b38f0b
     */
Packit Service b38f0b
    netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1);
Packit Service b38f0b
    netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1);
Packit Service b38f0b
    netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1);
Packit Service b38f0b
Packit Service b38f0b
#ifdef USING_AGENTX_SUBAGENT_MODULE
Packit Service b38f0b
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 
Packit Service b38f0b
			   role);
Packit Service b38f0b
#endif
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
int 
Packit Service b38f0b
remove_tree_entry (oid *name, size_t len) {
Packit Service b38f0b
Packit Service b38f0b
    netsnmp_subtree *sub = NULL;
Packit Service b38f0b
Packit Service b38f0b
    if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) {
Packit Service b38f0b
	return MIB_NO_SUCH_REGISTRATION;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    return unregister_mib_context(name, len, sub->priority,
Packit Service b38f0b
				  sub->range_subid, sub->range_ubound, "");
Packit Service b38f0b
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
Packit Service b38f0b
void
Packit Service b38f0b
shutdown_tree(void) {
Packit Service b38f0b
    oid ccitt[1]           = { 0 };
Packit Service b38f0b
    oid iso[1]             = { 1 };
Packit Service b38f0b
    oid joint_ccitt_iso[1] = { 2 };
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("agent_registry", "shut down tree\n"));
Packit Service b38f0b
Packit Service b38f0b
    remove_tree_entry(joint_ccitt_iso, 1);
Packit Service b38f0b
    remove_tree_entry(iso, 1);
Packit Service b38f0b
    remove_tree_entry(ccitt, 1);
Packit Service b38f0b
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
void
Packit Service b38f0b
dump_registry(void)
Packit Service b38f0b
{
Packit Service b38f0b
    struct variable *vp = NULL;
Packit Service b38f0b
    netsnmp_subtree *myptr, *myptr2;
Packit Service b38f0b
    u_char *s = NULL, *e = NULL, *v = NULL;
Packit Service b38f0b
    size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0;
Packit Service b38f0b
    int i = 0;
Packit Service b38f0b
Packit Service b38f0b
    if ((s = (u_char *) calloc(sl, 1)) != NULL &&
Packit Service b38f0b
        (e = (u_char *) calloc(sl, 1)) != NULL &&
Packit Service b38f0b
        (v = (u_char *) calloc(sl, 1)) != NULL) {
Packit Service b38f0b
Packit Service b38f0b
        subtree_context_cache *ptr;
Packit Service b38f0b
        for (ptr = context_subtrees; ptr; ptr = ptr->next) {
Packit Service b38f0b
            printf("Subtrees for Context: %s\n", ptr->context_name);
Packit Service b38f0b
            for (myptr = ptr->first_subtree; myptr != NULL;
Packit Service b38f0b
                 myptr = myptr->next) {
Packit Service b38f0b
                sl_o = el_o = vl_o = 0;
Packit Service b38f0b
Packit Service b38f0b
                if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
Packit Service b38f0b
                                          myptr->start_a,
Packit Service b38f0b
                                          myptr->start_len)) {
Packit Service b38f0b
                    break;
Packit Service b38f0b
                }
Packit Service b38f0b
                if (!sprint_realloc_objid(&e, &el, &el_o, 1,
Packit Service b38f0b
                                          myptr->end_a,
Packit Service b38f0b
					  myptr->end_len)) {
Packit Service b38f0b
                    break;
Packit Service b38f0b
                }
Packit Service b38f0b
Packit Service b38f0b
                if (myptr->variables) {
Packit Service b38f0b
                    printf("%02x ( %s - %s ) [", myptr->flags, s, e);
Packit Service b38f0b
                    for (i = 0, vp = myptr->variables;
Packit Service b38f0b
                         i < myptr->variables_len; i++) {
Packit Service b38f0b
                        vl_o = 0;
Packit Service b38f0b
                        if (!sprint_realloc_objid
Packit Service b38f0b
                            (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) {
Packit Service b38f0b
                            break;
Packit Service b38f0b
                        }
Packit Service b38f0b
                        printf("%s, ", v);
Packit Service b38f0b
                        vp = (struct variable *) ((char *) vp +
Packit Service b38f0b
                                                  myptr->variables_width);
Packit Service b38f0b
                    }
Packit Service b38f0b
                    printf("]\n");
Packit Service b38f0b
                } else {
Packit Service b38f0b
                    printf("%02x   %s - %s  \n", myptr->flags, s, e);
Packit Service b38f0b
                }
Packit Service b38f0b
                for (myptr2 = myptr; myptr2 != NULL;
Packit Service b38f0b
                     myptr2 = myptr2->children) {
Packit Service b38f0b
                    if (myptr2->label_a && myptr2->label_a[0]) {
Packit Service b38f0b
                        if (strcmp(myptr2->label_a, "old_api") == 0) {
Packit Service b38f0b
                            struct variable *vp =
Packit Service b38f0b
                                (struct variable*)myptr2->reginfo->handler->myvoid;
Packit Service b38f0b
Packit Service b38f0b
                            if (!sprint_realloc_objid(&s, &sl, &sl_o, 1,
Packit Service b38f0b
                                                 vp->name, vp->namelen)) {
Packit Service b38f0b
                                continue;
Packit Service b38f0b
                            }
Packit Service b38f0b
                            printf("\t%s[%s] %p var %s\n", myptr2->label_a,
Packit Service b38f0b
                                   myptr2->reginfo->handlerName ?
Packit Service b38f0b
                                   myptr2->reginfo->handlerName : "no-name",
Packit Service b38f0b
                                   myptr2->reginfo, s);
Packit Service b38f0b
                        } else {
Packit Service b38f0b
                            printf("\t%s %s %p\n", myptr2->label_a,
Packit Service b38f0b
                                   myptr2->reginfo->handlerName ?
Packit Service b38f0b
                                   myptr2->reginfo->handlerName : "no-handler-name",
Packit Service b38f0b
                                   myptr2->reginfo);
Packit Service b38f0b
                        }
Packit Service b38f0b
                    }
Packit Service b38f0b
                }
Packit Service b38f0b
            }
Packit Service b38f0b
        }
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    SNMP_FREE(s);
Packit Service b38f0b
    SNMP_FREE(e);
Packit Service b38f0b
    SNMP_FREE(v);
Packit Service b38f0b
Packit Service b38f0b
    dump_idx_registry();
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/**  @} */
Packit Service b38f0b
/* End of MIB registration code */
Packit Service b38f0b
Packit Service b38f0b
Packit Service b38f0b
netsnmp_feature_child_of(register_signal, netsnmp_unused)
Packit Service b38f0b
#ifndef NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL
Packit Service b38f0b
Packit Service b38f0b
/** @defgroup agent_signals POSIX signals support for agents.
Packit Service b38f0b
 *     Registering and unregistering signal handlers.
Packit Service b38f0b
 *   @ingroup agent_registry
Packit Service b38f0b
 *
Packit Service b38f0b
 * @{
Packit Service b38f0b
 */
Packit Service b38f0b
Packit Service b38f0b
int             external_signal_scheduled[NUM_EXTERNAL_SIGS];
Packit Service b38f0b
void            (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int);
Packit Service b38f0b
Packit Service b38f0b
#ifndef WIN32
Packit Service b38f0b
Packit Service b38f0b
/*
Packit Service b38f0b
 * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines
Packit Service b38f0b
 *       below for every single that might be handled by register_signal().
Packit Service b38f0b
 */
Packit Service b38f0b
Packit Service b38f0b
RETSIGTYPE
Packit Service b38f0b
agent_SIGCHLD_handler(int sig)
Packit Service b38f0b
{
Packit Service b38f0b
    external_signal_scheduled[SIGCHLD]++;
Packit Service b38f0b
#ifndef HAVE_SIGACTION
Packit Service b38f0b
    /*
Packit Service b38f0b
     * signal() sucks. It *might* have SysV semantics, which means that
Packit Service b38f0b
     * * a signal handler is reset once it gets called. Ensure that it
Packit Service b38f0b
     * * remains active.
Packit Service b38f0b
     */
Packit Service b38f0b
    signal(SIGCHLD, agent_SIGCHLD_handler);
Packit Service b38f0b
#endif
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Registers a POSIX Signal handler.
Packit Service b38f0b
 *  Implements the signal registering process for POSIX and non-POSIX
Packit Service b38f0b
 *  systems. Also, unifies the way signals work.
Packit Service b38f0b
 *  Note that the signal handler should register itself again with
Packit Service b38f0b
 *  signal() call before end of execution to prevent possible problems.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param sig POSIX Signal ID number, as defined in signal.h.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param func New signal handler function.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return value is SIG_REGISTERED_OK for success and
Packit Service b38f0b
 *        SIG_REGISTRATION_FAILED if the registration can't
Packit Service b38f0b
 *        be handled.
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
register_signal(int sig, void (*func) (int))
Packit Service b38f0b
{
Packit Service b38f0b
Packit Service b38f0b
    switch (sig) {
Packit Service b38f0b
#if defined(SIGCHLD)
Packit Service b38f0b
    case SIGCHLD:
Packit Service b38f0b
#ifdef HAVE_SIGACTION
Packit Service b38f0b
        {
Packit Service b38f0b
            static struct sigaction act;
Packit Service b38f0b
            act.sa_handler = agent_SIGCHLD_handler;
Packit Service b38f0b
            sigemptyset(&act.sa_mask);
Packit Service b38f0b
            act.sa_flags = 0;
Packit Service b38f0b
            sigaction(SIGCHLD, &act, NULL);
Packit Service b38f0b
        }
Packit Service b38f0b
#else
Packit Service b38f0b
        signal(SIGCHLD, agent_SIGCHLD_handler);
Packit Service b38f0b
#endif
Packit Service b38f0b
        break;
Packit Service b38f0b
#endif
Packit Service b38f0b
    default:
Packit Service b38f0b
        snmp_log(LOG_CRIT,
Packit Service b38f0b
                 "register_signal: signal %d cannot be handled\n", sig);
Packit Service b38f0b
        return SIG_REGISTRATION_FAILED;
Packit Service b38f0b
    }
Packit Service b38f0b
Packit Service b38f0b
    external_signal_handler[sig] = func;
Packit Service b38f0b
    external_signal_scheduled[sig] = 0;
Packit Service b38f0b
Packit Service b38f0b
    DEBUGMSGTL(("register_signal", "registered signal %d\n", sig));
Packit Service b38f0b
    return SIG_REGISTERED_OK;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
/** Unregisters a POSIX Signal handler.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @param sig POSIX Signal ID number, as defined in signal.h.
Packit Service b38f0b
 *
Packit Service b38f0b
 *  @return value is SIG_UNREGISTERED_OK for success, or error code.
Packit Service b38f0b
 */
Packit Service b38f0b
int
Packit Service b38f0b
unregister_signal(int sig)
Packit Service b38f0b
{
Packit Service b38f0b
    signal(sig, SIG_DFL);
Packit Service b38f0b
    DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig));
Packit Service b38f0b
    return SIG_UNREGISTERED_OK;
Packit Service b38f0b
}
Packit Service b38f0b
Packit Service b38f0b
#endif                          /* !WIN32 */
Packit Service b38f0b
Packit Service b38f0b
/**  @} */
Packit Service b38f0b
/* End of signals support code */
Packit Service b38f0b
Packit Service b38f0b
#endif /* NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL */
Packit Service b38f0b
Packit Service b38f0b
/**  @} */
Packit Service b38f0b