summaryrefslogtreecommitdiff
path: root/cleopatre/application/spidnetsnmp/agent/snmp_agent.c
diff options
context:
space:
mode:
Diffstat (limited to 'cleopatre/application/spidnetsnmp/agent/snmp_agent.c')
-rw-r--r--cleopatre/application/spidnetsnmp/agent/snmp_agent.c3689
1 files changed, 0 insertions, 3689 deletions
diff --git a/cleopatre/application/spidnetsnmp/agent/snmp_agent.c b/cleopatre/application/spidnetsnmp/agent/snmp_agent.c
deleted file mode 100644
index 90e927baf5..0000000000
--- a/cleopatre/application/spidnetsnmp/agent/snmp_agent.c
+++ /dev/null
@@ -1,3689 +0,0 @@
-/*
- * snmp_agent.c
- *
- * Simple Network Management Protocol (RFC 1067).
- */
-/* Portions of this file are subject to the following copyright(s). See
- * the Net-SNMP's COPYING file for more details and other copyrights
- * that may apply:
- */
-/* Portions of this file are subject to the following copyrights. See
- * the Net-SNMP's COPYING file for more details and other copyrights
- * that may apply:
- */
-/***********************************************************
- Copyright 1988, 1989 by Carnegie Mellon University
-
- All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the name of CMU not be
-used in advertising or publicity pertaining to distribution of the
-software without specific, written prior permission.
-
-CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
-CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
-ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
-SOFTWARE.
-******************************************************************/
-/*
- * Portions of this file are copyrighted by:
- * Copyright © 2003 Sun Microsystems, Inc. All rights
- * reserved. Use is subject to license terms specified in the
- * COPYING file distributed with the Net-SNMP package.
- */
-/** @defgroup snmp_agent net-snmp agent related processing
- * @ingroup agent
- *
- * @{
- */
-#include <net-snmp/net-snmp-config.h>
-
-#include <sys/types.h>
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if HAVE_STRING_H
-#include <string.h>
-#endif
-#if TIME_WITH_SYS_TIME
-# ifdef WIN32
-# include <sys/timeb.h>
-# else
-# include <sys/time.h>
-# endif
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-#if HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#if HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#include <errno.h>
-#if HAVE_WINSOCK_H
-#include <winsock.h>
-#endif
-
-#define SNMP_NEED_REQUEST_LIST
-#include <net-snmp/net-snmp-includes.h>
-#include <net-snmp/agent/net-snmp-agent-includes.h>
-#include <net-snmp/library/snmp_assert.h>
-
-#if HAVE_SYSLOG_H
-#include <syslog.h>
-#endif
-
-#ifdef NETSNMP_USE_LIBWRAP
-#include <tcpd.h>
-int allow_severity = LOG_INFO;
-int deny_severity = LOG_WARNING;
-#endif
-
-#include "snmpd.h"
-#include "mibgroup/struct.h"
-#include "mibgroup/util_funcs.h"
-#include <net-snmp/agent/mib_module_config.h>
-#include <net-snmp/agent/mib_modules.h>
-
-#ifdef USING_AGENTX_PROTOCOL_MODULE
-#include "agentx/protocol.h"
-#endif
-
-#ifdef USING_AGENTX_MASTER_MODULE
-#include "agentx/master.h"
-#endif
-
-#ifdef USING_SMUX_MODULE
-#include "smux/smux.h"
-#endif
-
-oid version_sysoid[] = { NETSNMP_SYSTEM_MIB };
-int version_sysoid_len = OID_LENGTH(version_sysoid);
-
-#define SNMP_ADDRCACHE_SIZE 10
-#define SNMP_ADDRCACHE_MAXAGE 300 /* in seconds */
-
-enum {
- SNMP_ADDRCACHE_UNUSED = 0,
- SNMP_ADDRCACHE_USED = 1
-};
-
-struct addrCache {
- char *addr;
- int status;
- struct timeval lastHit;
-};
-
-static struct addrCache addrCache[SNMP_ADDRCACHE_SIZE];
-int log_addresses = 0;
-
-
-
-typedef struct _agent_nsap {
- int handle;
- netsnmp_transport *t;
- void *s; /* Opaque internal session pointer. */
- struct _agent_nsap *next;
-} agent_nsap;
-
-static agent_nsap *agent_nsap_list = NULL;
-static netsnmp_agent_session *agent_session_list = NULL;
-netsnmp_agent_session *netsnmp_processing_set = NULL;
-netsnmp_agent_session *agent_delegated_list = NULL;
-netsnmp_agent_session *netsnmp_agent_queued_list = NULL;
-
-
-int netsnmp_agent_check_packet(netsnmp_session *,
- struct netsnmp_transport_s *,
- void *, int);
-int netsnmp_agent_check_parse(netsnmp_session *, netsnmp_pdu *,
- int);
-void delete_subnetsnmp_tree_cache(netsnmp_agent_session *asp);
-int handle_pdu(netsnmp_agent_session *asp);
-int netsnmp_handle_request(netsnmp_agent_session *asp,
- int status);
-int netsnmp_wrap_up_request(netsnmp_agent_session *asp,
- int status);
-int check_delayed_request(netsnmp_agent_session *asp);
-int handle_getnext_loop(netsnmp_agent_session *asp);
-int handle_set_loop(netsnmp_agent_session *asp);
-
-int netsnmp_check_queued_chain_for(netsnmp_agent_session *asp);
-int netsnmp_add_queued(netsnmp_agent_session *asp);
-int netsnmp_remove_from_delegated(netsnmp_agent_session *asp);
-
-
-static int current_globalid = 0;
-
-int netsnmp_running = 1;
-
-int
-netsnmp_allocate_globalcacheid(void)
-{
- return ++current_globalid;
-}
-
-int
-netsnmp_get_local_cachid(netsnmp_cachemap *cache_store, int globalid)
-{
- while (cache_store != NULL) {
- if (cache_store->globalid == globalid)
- return cache_store->cacheid;
- cache_store = cache_store->next;
- }
- return -1;
-}
-
-netsnmp_cachemap *
-netsnmp_get_or_add_local_cachid(netsnmp_cachemap **cache_store,
- int globalid, int localid)
-{
- netsnmp_cachemap *tmpp;
-
- tmpp = SNMP_MALLOC_TYPEDEF(netsnmp_cachemap);
- if (*cache_store) {
- tmpp->next = *cache_store;
- *cache_store = tmpp;
- } else {
- *cache_store = tmpp;
- }
-
- tmpp->globalid = globalid;
- tmpp->cacheid = localid;
- return tmpp;
-}
-
-void
-netsnmp_free_cachemap(netsnmp_cachemap *cache_store)
-{
- netsnmp_cachemap *tmpp;
- while (cache_store) {
- tmpp = cache_store;
- cache_store = cache_store->next;
- SNMP_FREE(tmpp);
- }
-}
-
-
-typedef struct agent_set_cache_s {
- /*
- * match on these 2
- */
- int transID;
- netsnmp_session *sess;
-
- /*
- * store this info
- */
- netsnmp_tree_cache *treecache;
- int treecache_len;
- int treecache_num;
-
- int vbcount;
- netsnmp_request_info *requests;
- netsnmp_variable_list *saved_vars;
- netsnmp_data_list *agent_data;
-
- /*
- * list
- */
- struct agent_set_cache_s *next;
-} agent_set_cache;
-
-static agent_set_cache *Sets = NULL;
-
-agent_set_cache *
-save_set_cache(netsnmp_agent_session *asp)
-{
- agent_set_cache *ptr;
-
- if (!asp || !asp->reqinfo || !asp->pdu)
- return NULL;
-
- ptr = SNMP_MALLOC_TYPEDEF(agent_set_cache);
- if (ptr == NULL)
- return NULL;
-
- /*
- * Save the important information
- */
- DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p saved in cache (mode %d)\n",
- asp, asp->reqinfo, asp->pdu->command));
- ptr->transID = asp->pdu->transid;
- ptr->sess = asp->session;
- ptr->treecache = asp->treecache;
- ptr->treecache_len = asp->treecache_len;
- ptr->treecache_num = asp->treecache_num;
- ptr->agent_data = asp->reqinfo->agent_data;
- ptr->requests = asp->requests;
- ptr->saved_vars = asp->pdu->variables; /* requests contains pointers to variables */
- ptr->vbcount = asp->vbcount;
-
- /*
- * make the agent forget about what we've saved
- */
- asp->treecache = NULL;
- asp->reqinfo->agent_data = NULL;
- asp->pdu->variables = NULL;
- asp->requests = NULL;
-
- ptr->next = Sets;
- Sets = ptr;
-
- return ptr;
-}
-
-int
-get_set_cache(netsnmp_agent_session *asp)
-{
- agent_set_cache *ptr, *prev = NULL;
-
- for (ptr = Sets; ptr != NULL; ptr = ptr->next) {
- if (ptr->sess == asp->session && ptr->transID == asp->pdu->transid) {
- /*
- * remove this item from list
- */
- if (prev)
- prev->next = ptr->next;
- else
- Sets = ptr->next;
-
- /*
- * found it. Get the needed data
- */
- asp->treecache = ptr->treecache;
- asp->treecache_len = ptr->treecache_len;
- asp->treecache_num = ptr->treecache_num;
-
- /*
- * Free previously allocated requests before overwriting by
- * cached ones, otherwise memory leaks!
- */
- if (asp->requests) {
- /*
- * I don't think this case should ever happen. Please email
- * the net-snmp-coders@lists.sourceforge.net if you have
- * a test case that hits this assert. -- rstory
- */
- int i;
- netsnmp_assert(NULL == asp->requests); /* see note above */
- for (i = 0; i < asp->vbcount; i++) {
- netsnmp_free_request_data_sets(&asp->requests[i]);
- }
- free(asp->requests);
- }
- /*
- * If we replace asp->requests with the info from the set cache,
- * we should replace asp->pdu->variables also with the cached
- * info, as asp->requests contains pointers to them. And we
- * should also free the current asp->pdu->variables list...
- */
- if (ptr->saved_vars) {
- if (asp->pdu->variables)
- snmp_free_varbind(asp->pdu->variables);
- asp->pdu->variables = ptr->saved_vars;
- asp->vbcount = ptr->vbcount;
- } else {
- /*
- * when would we not have saved variables? someone
- * let me know if they hit this assert. -- rstory
- */
- netsnmp_assert(NULL != ptr->saved_vars);
- }
- asp->requests = ptr->requests;
-
- netsnmp_assert(NULL != asp->reqinfo);
- asp->reqinfo->asp = asp;
- asp->reqinfo->agent_data = ptr->agent_data;
-
- /*
- * update request reqinfo, if it's out of date.
- * yyy-rks: investigate when/why sometimes they match,
- * sometimes they don't.
- */
- if(asp->requests->agent_req_info != asp->reqinfo) {
- /*
- * - one don't match case: agentx subagents. prev asp & reqinfo
- * freed, request reqinfo ptrs not cleared.
- */
- netsnmp_request_info *tmp = asp->requests;
- DEBUGMSGTL(("verbose:asp",
- " reqinfo %p doesn't match cached reqinfo %p\n",
- asp->reqinfo, asp->requests->agent_req_info));
- for(; tmp; tmp = tmp->next)
- tmp->agent_req_info = asp->reqinfo;
- } else {
- /*
- * - match case: ?
- */
- DEBUGMSGTL(("verbose:asp",
- " reqinfo %p matches cached reqinfo %p\n",
- asp->reqinfo, asp->requests->agent_req_info));
- }
-
- SNMP_FREE(ptr);
- return SNMP_ERR_NOERROR;
- }
- prev = ptr;
- }
- return SNMP_ERR_GENERR;
-}
-
-/* Bulkcache holds the values for the *repeating* varbinds (only),
- * but ordered "by column" - i.e. the repetitions for each
- * repeating varbind follow on immediately from one another,
- * rather than being interleaved, as required by the protocol.
- *
- * So we need to rearrange the varbind list so it's ordered "by row".
- *
- * In the following code chunk:
- * n = # non-repeating varbinds
- * r = # repeating varbinds
- * asp->vbcount = # varbinds in the incoming PDU
- * (So asp->vbcount = n+r)
- *
- * repeats = Desired # of repetitions (of 'r' varbinds)
- */
-NETSNMP_STATIC_INLINE void
-_reorder_getbulk(netsnmp_agent_session *asp)
-{
- int i, n = 0, r = 0;
- int repeats = asp->pdu->errindex;
- int j, k;
- int all_eoMib;
- netsnmp_variable_list *prev = NULL, *curr;
-
- if (asp->vbcount == 0) /* Nothing to do! */
- return;
-
- if (asp->pdu->errstat < asp->vbcount) {
- n = asp->pdu->errstat;
- } else {
- n = asp->vbcount;
- }
- if ((r = asp->vbcount - n) < 0) {
- r = 0;
- }
-
- /* we do nothing if there is nothing repeated */
- if (r == 0)
- return;
-
- /* Fix endOfMibView entries. */
- for (i = 0; i < r; i++) {
- prev = NULL;
- for (j = 0; j < repeats; j++) {
- curr = asp->bulkcache[i * repeats + j];
- /*
- * If we don't have a valid name for a given repetition
- * (and probably for all the ones that follow as well),
- * extend the previous result to indicate 'endOfMibView'.
- * Or if the repetition already has type endOfMibView make
- * sure it has the correct objid (i.e. that of the previous
- * entry or that of the original request).
- */
- if (curr->name_length == 0 || curr->type == SNMP_ENDOFMIBVIEW) {
- if (prev == NULL) {
- /* Use objid from original pdu. */
- prev = asp->orig_pdu->variables;
- for (k = i; prev && k > 0; k--)
- prev = prev->next_variable;
- }
- if (prev) {
- snmp_set_var_objid(curr, prev->name, prev->name_length);
- snmp_set_var_typed_value(curr, SNMP_ENDOFMIBVIEW, NULL, 0);
- }
- }
- prev = curr;
- }
- }
-
- /*
- * For each of the original repeating varbinds (except the last),
- * go through the block of results for that varbind,
- * and link each instance to the corresponding instance
- * in the next block.
- */
- for (i = 0; i < r - 1; i++) {
- for (j = 0; j < repeats; j++) {
- asp->bulkcache[i * repeats + j]->next_variable =
- asp->bulkcache[(i + 1) * repeats + j];
- }
- }
-
- /*
- * For the last of the original repeating varbinds,
- * go through that block of results, and link each
- * instance to the *next* instance in the *first* block.
- *
- * The very last instance of this block is left untouched
- * since it (correctly) points to the end of the list.
- */
- for (j = 0; j < repeats - 1; j++) {
- asp->bulkcache[(r - 1) * repeats + j]->next_variable =
- asp->bulkcache[j + 1];
- }
-
- /*
- * If we've got a full row of endOfMibViews, then we
- * can truncate the result varbind list after that.
- *
- * Look for endOfMibView exception values in the list of
- * repetitions for the first varbind, and check the
- * corresponding instances for the other varbinds
- * (following the next_variable links).
- *
- * If they're all endOfMibView too, then we can terminate
- * the linked list there, and free any redundant varbinds.
- */
- all_eoMib = 0;
- for (i = 0; i < repeats; i++) {
- if (asp->bulkcache[i]->type == SNMP_ENDOFMIBVIEW) {
- all_eoMib = 1;
- for (j = 1, prev=asp->bulkcache[i];
- j < r;
- j++, prev=prev->next_variable) {
- if (prev->type != SNMP_ENDOFMIBVIEW) {
- all_eoMib = 0;
- break; /* Found a real value */
- }
- }
- if (all_eoMib) {
- /*
- * This is indeed a full endOfMibView row.
- * Terminate the list here & free the rest.
- */
- snmp_free_varbind( prev->next_variable );
- prev->next_variable = NULL;
- break;
- }
- }
- }
-}
-
-
-/* EndOfMibView replies to a GETNEXT request should according to RFC3416
- * have the object ID set to that of the request. Our tree search
- * algorithm will sometimes break that requirement. This function will
- * fix that.
- */
-NETSNMP_STATIC_INLINE void
-_fix_endofmibview(netsnmp_agent_session *asp)
-{
- netsnmp_variable_list *vb, *ovb;
-
- if (asp->vbcount == 0) /* Nothing to do! */
- return;
-
- for (vb = asp->pdu->variables, ovb = asp->orig_pdu->variables;
- vb && ovb; vb = vb->next_variable, ovb = ovb->next_variable) {
- if (vb->type == SNMP_ENDOFMIBVIEW)
- snmp_set_var_objid(vb, ovb->name, ovb->name_length);
- }
-}
-
-
-int
-getNextSessID()
-{
- static int SessionID = 0;
-
- return ++SessionID;
-}
-
-/**
- * This function checks for packets arriving on the SNMP port and
- * processes them(snmp_read) if some are found, using the select(). If block
- * is non zero, the function call blocks until a packet arrives
- *
- * @param block used to control blocking in the select() function, 1 = block
- * forever, and 0 = don't block
- *
- * @return Returns a positive integer if packets were processed, and -1 if an
- * error was found.
- *
- */
-int
-agent_check_and_process(int block)
-{
- int numfds;
- fd_set fdset;
- struct timeval timeout = { LONG_MAX, 0 }, *tvp = &timeout;
- int count;
- int fakeblock = 0;
-
- numfds = 0;
- FD_ZERO(&fdset);
- snmp_select_info(&numfds, &fdset, tvp, &fakeblock);
- if (block != 0 && fakeblock != 0) {
- /*
- * There are no alarms registered, and the caller asked for blocking, so
- * let select() block forever.
- */
-
- tvp = NULL;
- } else if (block != 0 && fakeblock == 0) {
- /*
- * The caller asked for blocking, but there is an alarm due sooner than
- * LONG_MAX seconds from now, so use the modified timeout returned by
- * snmp_select_info as the timeout for select().
- */
-
- } else if (block == 0) {
- /*
- * The caller does not want us to block at all.
- */
-
- tvp->tv_sec = 0;
- tvp->tv_usec = 0;
- }
-
- count = select(numfds, &fdset, 0, 0, tvp);
-
- if (count > 0) {
- /*
- * packets found, process them
- */
- snmp_read(&fdset);
- } else
- switch (count) {
- case 0:
- snmp_timeout();
- break;
- case -1:
- if (errno != EINTR) {
- snmp_log_perror("select");
- }
- return -1;
- default:
- snmp_log(LOG_ERR, "select returned %d\n", count);
- return -1;
- } /* endif -- count>0 */
-
- /*
- * Run requested alarms.
- */
- run_alarms();
-
- netsnmp_check_outstanding_agent_requests();
-
- return count;
-}
-
-
-/*
- * Set up the address cache.
- */
-void
-netsnmp_addrcache_initialise(void)
-{
- int i = 0;
-
- for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
- addrCache[i].addr = NULL;
- addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
- }
-}
-
-/*
- * Adds a new entry to the cache of addresses that
- * have recently made connections to the agent.
- * Returns 0 if the entry already exists (but updates
- * the entry with a new timestamp) and 1 if the
- * entry did not previously exist.
- *
- * Implements a simple LRU cache replacement
- * policy. Uses a linear search, which should be
- * okay, as long as SNMP_ADDRCACHE_SIZE remains
- * relatively small.
- *
- * @retval 0 : updated existing entry
- * @retval 1 : added new entry
- */
-int
-netsnmp_addrcache_add(const char *addr)
-{
- int oldest = -1; /* Index of the oldest cache entry */
- int unused = -1; /* Index of the first free cache entry */
- int i; /* Looping variable */
- int rc = -1;
- struct timeval now; /* What time is it now? */
- struct timeval aged; /* Oldest allowable cache entry */
-
- /*
- * First get the current and oldest allowable timestamps
- */
- gettimeofday(&now, (struct timezone*) NULL);
- aged.tv_sec = now.tv_sec - SNMP_ADDRCACHE_MAXAGE;
- aged.tv_usec = now.tv_usec;
-
- /*
- * Now look for a place to put this thing
- */
- for(i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
- if (addrCache[i].status == SNMP_ADDRCACHE_UNUSED) { /* If unused */
- /*
- * remember this location, in case addr isn't in the cache
- */
- if (unused < 0)
- unused = i;
- }
- else { /* If used */
- if ((NULL != addr) && (strcmp(addrCache[i].addr, addr) == 0)) {
- /*
- * found a match
- */
- memcpy(&addrCache[i].lastHit, &now, sizeof(struct timeval));
- if (timercmp(&addrCache[i].lastHit, &aged, <))
- rc = 1; /* should have expired, so is new */
- else
- rc = 0; /* not expired, so is existing entry */
- break;
- }
- else {
- /*
- * Used, but not this address. check if it's stale.
- */
- if (timercmp(&addrCache[i].lastHit, &aged, <)) {
- /*
- * Stale, reuse
- */
- SNMP_FREE(addrCache[i].addr);
- addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
- /*
- * remember this location, in case addr isn't in the cache
- */
- if (unused < 0)
- unused = i;
- }
- else {
- /*
- * Still fresh, but a candidate for LRU replacement
- */
- if (oldest < 0)
- oldest = i;
- else if (timercmp(&addrCache[i].lastHit,
- &addrCache[oldest].lastHit, <))
- oldest = i;
- } /* fresh */
- } /* used, no match */
- } /* used */
- } /* for loop */
-
- if ((-1 == rc) && (NULL != addr)) {
- /*
- * We didn't find the entry in the cache
- */
- if (unused >= 0) {
- /*
- * If we have a slot free anyway, use it
- */
- addrCache[unused].addr = strdup(addr);
- addrCache[unused].status = SNMP_ADDRCACHE_USED;
- memcpy(&addrCache[unused].lastHit, &now, sizeof(struct timeval));
- }
- else { /* Otherwise, replace oldest entry */
- if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_AGENT_VERBOSE))
- snmp_log(LOG_INFO, "Purging address from address cache: %s",
- addrCache[oldest].addr);
-
- free(addrCache[oldest].addr);
- addrCache[oldest].addr = strdup(addr);
- memcpy(&addrCache[oldest].lastHit, &now, sizeof(struct timeval));
- }
- rc = 1;
- }
- if ((log_addresses && (1 == rc)) ||
- netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_AGENT_VERBOSE)) {
- snmp_log(LOG_INFO, "Received SNMP packet(s) from %s\n", addr);
- }
-
- return rc;
-}
-
-/*
- * Age the entries in the address cache.
- *
- * backwards compatability; not used anywhere
- */
-void
-netsnmp_addrcache_age(void)
-{
- (void)netsnmp_addrcache_add(NULL);
-}
-
-/*******************************************************************-o-******
- * netsnmp_agent_check_packet
- *
- * Parameters:
- * session, transport, transport_data, transport_data_length
- *
- * Returns:
- * 1 On success.
- * 0 On error.
- *
- * Handler for all incoming messages (a.k.a. packets) for the agent. If using
- * the libwrap utility, log the connection and deny/allow the access. Print
- * output when appropriate, and increment the incoming counter.
- *
- */
-
-int
-netsnmp_agent_check_packet(netsnmp_session * session,
- netsnmp_transport *transport,
- void *transport_data, int transport_data_length)
-{
- char *addr_string = NULL;
-#ifdef NETSNMP_USE_LIBWRAP
- char *tcpudpaddr, *name;
- short not_log_connection;
-
- name = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
- NETSNMP_DS_LIB_APPTYPE);
-
- /* not_log_connection will be 1 if we should skip the messages */
- not_log_connection = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS);
-
- /*
- * handle the error case
- * default to logging the messages
- */
- if (not_log_connection == SNMPERR_GENERR) not_log_connection = 0;
-#endif
-
- /*
- * Log the message and/or dump the message.
- * Optionally cache the network address of the sender.
- */
-
- if (transport != NULL && transport->f_fmtaddr != NULL) {
- /*
- * Okay I do know how to format this address for logging.
- */
- addr_string = transport->f_fmtaddr(transport, transport_data,
- transport_data_length);
- /*
- * Don't forget to free() it.
- */
- }
-#ifdef NETSNMP_USE_LIBWRAP
- /* Catch udp,udp6,tcp,tcp6 transports using "[" */
- tcpudpaddr = strstr(addr_string, "[");
- if ( tcpudpaddr != 0 ) {
- char sbuf[64];
- char *xp;
- strncpy(sbuf, tcpudpaddr + 1, sizeof(sbuf));
- sbuf[sizeof(sbuf)-1] = '\0';
- xp = strstr(sbuf, "]");
- if (xp)
- *xp = '\0';
-
- if (hosts_ctl(name, STRING_UNKNOWN, sbuf, STRING_UNKNOWN)) {
- if (!not_log_connection) {
- snmp_log(allow_severity, "Connection from %s\n", addr_string);
- }
- } else {
- snmp_log(deny_severity, "Connection from %s REFUSED\n",
- addr_string);
- SNMP_FREE(addr_string);
- return 0;
- }
- } else {
- /*
- * don't log callback connections.
- * What about 'Local IPC', 'IPX' and 'AAL5 PVC'?
- */
- if (0 == strncmp(addr_string, "callback", 8))
- ;
- else if (hosts_ctl(name, STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN)){
- if (!not_log_connection) {
- snmp_log(allow_severity, "Connection from <UNKNOWN> (%s)\n", addr_string);
- };
- SNMP_FREE(addr_string);
- addr_string = strdup("<UNKNOWN>");
- } else {
- snmp_log(deny_severity, "Connection from <UNKNOWN> (%s) REFUSED\n", addr_string);
- SNMP_FREE(addr_string);
- return 0;
- }
- }
-#endif /*NETSNMP_USE_LIBWRAP */
-
- snmp_increment_statistic(STAT_SNMPINPKTS);
-
- if (addr_string != NULL) {
- netsnmp_addrcache_add(addr_string);
- SNMP_FREE(addr_string);
- }
- return 1;
-}
-
-
-int
-netsnmp_agent_check_parse(netsnmp_session * session, netsnmp_pdu *pdu,
- int result)
-{
- if (result == 0) {
- if (snmp_get_do_logging() &&
- netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_AGENT_VERBOSE)) {
- netsnmp_variable_list *var_ptr;
-
- switch (pdu->command) {
- case SNMP_MSG_GET:
- snmp_log(LOG_DEBUG, " GET message\n");
- break;
- case SNMP_MSG_GETNEXT:
- snmp_log(LOG_DEBUG, " GETNEXT message\n");
- break;
- case SNMP_MSG_RESPONSE:
- snmp_log(LOG_DEBUG, " RESPONSE message\n");
- break;
- case SNMP_MSG_SET:
- snmp_log(LOG_DEBUG, " SET message\n");
- break;
- case SNMP_MSG_TRAP:
- snmp_log(LOG_DEBUG, " TRAP message\n");
- break;
- case SNMP_MSG_GETBULK:
- snmp_log(LOG_DEBUG, " GETBULK message, non-rep=%ld, max_rep=%ld\n",
- pdu->errstat, pdu->errindex);
- break;
- case SNMP_MSG_INFORM:
- snmp_log(LOG_DEBUG, " INFORM message\n");
- break;
- case SNMP_MSG_TRAP2:
- snmp_log(LOG_DEBUG, " TRAP2 message\n");
- break;
- case SNMP_MSG_REPORT:
- snmp_log(LOG_DEBUG, " REPORT message\n");
- break;
-
- case SNMP_MSG_INTERNAL_SET_RESERVE1:
- snmp_log(LOG_DEBUG, " INTERNAL RESERVE1 message\n");
- break;
-
- case SNMP_MSG_INTERNAL_SET_RESERVE2:
- snmp_log(LOG_DEBUG, " INTERNAL RESERVE2 message\n");
- break;
-
- case SNMP_MSG_INTERNAL_SET_ACTION:
- snmp_log(LOG_DEBUG, " INTERNAL ACTION message\n");
- break;
-
- case SNMP_MSG_INTERNAL_SET_COMMIT:
- snmp_log(LOG_DEBUG, " INTERNAL COMMIT message\n");
- break;
-
- case SNMP_MSG_INTERNAL_SET_FREE:
- snmp_log(LOG_DEBUG, " INTERNAL FREE message\n");
- break;
-
- case SNMP_MSG_INTERNAL_SET_UNDO:
- snmp_log(LOG_DEBUG, " INTERNAL UNDO message\n");
- break;
-
- default:
- snmp_log(LOG_DEBUG, " UNKNOWN message, type=%02X\n",
- pdu->command);
- snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
- return 0;
- }
-
- for (var_ptr = pdu->variables; var_ptr != NULL;
- var_ptr = var_ptr->next_variable) {
- size_t c_oidlen = 256, c_outlen = 0;
- u_char *c_oid = (u_char *) malloc(c_oidlen);
-
- if (c_oid) {
- if (!sprint_realloc_objid
- (&c_oid, &c_oidlen, &c_outlen, 1, var_ptr->name,
- var_ptr->name_length)) {
- snmp_log(LOG_DEBUG, " -- %s [TRUNCATED]\n",
- c_oid);
- } else {
- snmp_log(LOG_DEBUG, " -- %s\n", c_oid);
- }
- SNMP_FREE(c_oid);
- }
- }
- }
- return 1;
- }
- return 0; /* XXX: does it matter what the return value
- * is? Yes: if we return 0, then the PDU is
- * dumped. */
-}
-
-
-/*
- * Global access to the primary session structure for this agent.
- * for Index Allocation use initially.
- */
-
-/*
- * I don't understand what this is for at the moment. AFAICS as long as it
- * gets set and points at a session, that's fine. ???
- */
-
-netsnmp_session *main_session = NULL;
-
-
-
-/*
- * Set up an agent session on the given transport. Return a handle
- * which may later be used to de-register this transport. A return
- * value of -1 indicates an error.
- */
-
-int
-netsnmp_register_agent_nsap(netsnmp_transport *t)
-{
- netsnmp_session *s, *sp = NULL;
- agent_nsap *a = NULL, *n = NULL, **prevNext = &agent_nsap_list;
- int handle = 0;
- void *isp = NULL;
-
- if (t == NULL) {
- return -1;
- }
-
- DEBUGMSGTL(("netsnmp_register_agent_nsap", "fd %d\n", t->sock));
-
- n = (agent_nsap *) malloc(sizeof(agent_nsap));
- if (n == NULL) {
- return -1;
- }
- s = (netsnmp_session *) malloc(sizeof(netsnmp_session));
- if (s == NULL) {
- SNMP_FREE(n);
- return -1;
- }
- memset(s, 0, sizeof(netsnmp_session));
- snmp_sess_init(s);
-
- /*
- * Set up the session appropriately for an agent.
- */
-
- s->version = SNMP_DEFAULT_VERSION;
- s->callback = handle_snmp_packet;
- s->authenticator = NULL;
- s->flags = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_AGENT_FLAGS);
- s->isAuthoritative = SNMP_SESS_AUTHORITATIVE;
-
- sp = snmp_add(s, t, netsnmp_agent_check_packet,
- netsnmp_agent_check_parse);
- if (sp == NULL) {
- SNMP_FREE(s);
- SNMP_FREE(n);
- return -1;
- }
-
- isp = snmp_sess_pointer(sp);
- if (isp == NULL) { /* over-cautious */
- SNMP_FREE(s);
- SNMP_FREE(n);
- return -1;
- }
-
- n->s = isp;
- n->t = t;
-
- if (main_session == NULL) {
- main_session = snmp_sess_session(isp);
- }
-
- for (a = agent_nsap_list; a != NULL && handle + 1 >= a->handle;
- a = a->next) {
- handle = a->handle;
- prevNext = &(a->next);
- }
-
- if (handle < INT_MAX) {
- n->handle = handle + 1;
- n->next = a;
- *prevNext = n;
- SNMP_FREE(s);
- return n->handle;
- } else {
- SNMP_FREE(s);
- SNMP_FREE(n);
- return -1;
- }
-}
-
-void
-netsnmp_deregister_agent_nsap(int handle)
-{
- agent_nsap *a = NULL, **prevNext = &agent_nsap_list;
- int main_session_deregistered = 0;
-
- DEBUGMSGTL(("netsnmp_deregister_agent_nsap", "handle %d\n", handle));
-
- for (a = agent_nsap_list; a != NULL && a->handle < handle; a = a->next) {
- prevNext = &(a->next);
- }
-
- if (a != NULL && a->handle == handle) {
- *prevNext = a->next;
- if (main_session == snmp_sess_session(a->s)) {
- main_session_deregistered = 1;
- }
- snmp_close(snmp_sess_session(a->s));
- /*
- * The above free()s the transport and session pointers.
- */
- SNMP_FREE(a);
- }
-
- /*
- * If we've deregistered the session that main_session used to point to,
- * then make it point to another one, or in the last resort, make it equal
- * to NULL. Basically this shouldn't ever happen in normal operation
- * because main_session starts off pointing at the first session added by
- * init_master_agent(), which then discards the handle.
- */
-
- if (main_session_deregistered) {
- if (agent_nsap_list != NULL) {
- DEBUGMSGTL(("snmp_agent",
- "WARNING: main_session ptr changed from %p to %p\n",
- main_session, snmp_sess_session(agent_nsap_list->s)));
- main_session = snmp_sess_session(agent_nsap_list->s);
- } else {
- DEBUGMSGTL(("snmp_agent",
- "WARNING: main_session ptr changed from %p to NULL\n",
- main_session));
- main_session = NULL;
- }
- }
-}
-
-
-
-/*
- *
- * This function has been modified to use the experimental
- * netsnmp_register_agent_nsap interface. The major responsibility of this
- * function now is to interpret a string specified to the agent (via -p on the
- * command line, or from a configuration file) as a list of agent NSAPs on
- * which to listen for SNMP packets. Typically, when you add a new transport
- * domain "foo", you add code here such that if the "foo" code is compiled
- * into the agent (SNMP_TRANSPORT_FOO_DOMAIN is defined), then a token of the
- * form "foo:bletch-3a0054ef%wob&wob" gets turned into the appropriate
- * transport descriptor. netsnmp_register_agent_nsap is then called with that
- * transport descriptor and sets up a listening agent session on it.
- *
- * Everything then works much as normal: the agent runs in an infinite loop
- * (in the snmpd.c/receive()routine), which calls snmp_read() when a request
- * is readable on any of the given transports. This routine then traverses
- * the library 'Sessions' list to identify the relevant session and eventually
- * invokes '_sess_read'. This then processes the incoming packet, calling the
- * pre_parse, parse, post_parse and callback routines in turn.
- *
- * JBPN 20001117
- */
-
-int
-init_master_agent(void)
-{
- netsnmp_transport *transport;
- char *cptr;
- char buf[SPRINT_MAX_LEN];
- char *st;
-
- /* default to a default cache size */
- netsnmp_set_lookup_cache_size(-1);
-
- if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
- DEBUGMSGTL(("snmp_agent",
- "init_master_agent; not master agent\n"));
-
- netsnmp_assert("agent role !master && !sub_agent");
-
- return 0; /* No error if ! MASTER_AGENT */
- }
-#ifdef USING_AGENTX_MASTER_MODULE
- if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_AGENT_AGENTX_MASTER) == 1)
- real_init_master();
-#endif
-#ifdef USING_SMUX_MODULE
- if(should_init("smux"))
- real_init_smux();
-#endif
-
- /*
- * Have specific agent ports been specified?
- */
- cptr = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_AGENT_PORTS);
-
- if (cptr) {
- snprintf(buf, sizeof(buf), "%s", cptr);
- buf[ sizeof(buf)-1 ] = 0;
- } else {
- /*
- * No, so just specify the default port.
- */
- buf[0] = 0;
- }
-
- DEBUGMSGTL(("snmp_agent", "final port spec: \"%s\"\n", buf));
- st = buf;
- do {
- /*
- * Specification format:
- *
- * NONE: (a pseudo-transport)
- * UDP:[address:]port (also default if no transport is specified)
- * TCP:[address:]port (if supported)
- * Unix:pathname (if supported)
- * AAL5PVC:itf.vpi.vci (if supported)
- * IPX:[network]:node[/port] (if supported)
- *
- */
-
- cptr = st;
- st = strchr(st, ',');
- if (st)
- *st++ = '\0';
-
- DEBUGMSGTL(("snmp_agent", "installing master agent on port %s\n",
- cptr));
-
- if (strncasecmp(cptr, "none", 4) == 0) {
- DEBUGMSGTL(("snmp_agent",
- "init_master_agent; pseudo-transport \"none\" "
- "requested\n"));
- return 0;
- }
- transport = netsnmp_transport_open_server("snmp", cptr);
-
- if (transport == NULL) {
- snmp_log(LOG_ERR, "Error opening specified endpoint \"%s\"\n",
- cptr);
- return 1;
- }
-
- if (netsnmp_register_agent_nsap(transport) == 0) {
- snmp_log(LOG_ERR,
- "Error registering specified transport \"%s\" as an "
- "agent NSAP\n", cptr);
- return 1;
- } else {
- DEBUGMSGTL(("snmp_agent",
- "init_master_agent; \"%s\" registered as an agent "
- "NSAP\n", cptr));
- }
- } while(st && *st != '\0');
-
- return 0;
-}
-
-void
-clear_nsap_list(void)
-{
- DEBUGMSGTL(("clear_nsap_list", "clear the nsap list\n"));
-
- while (agent_nsap_list != NULL)
- netsnmp_deregister_agent_nsap(agent_nsap_list->handle);
-}
-
-void
-shutdown_master_agent(void)
-{
- clear_nsap_list();
-}
-
-
-netsnmp_agent_session *
-init_agent_snmp_session(netsnmp_session * session, netsnmp_pdu *pdu)
-{
- netsnmp_agent_session *asp = (netsnmp_agent_session *)
- calloc(1, sizeof(netsnmp_agent_session));
-
- if (asp == NULL) {
- return NULL;
- }
-
- DEBUGMSGTL(("snmp_agent","agent_sesion %08p created\n", asp));
- asp->session = session;
- asp->pdu = snmp_clone_pdu(pdu);
- asp->orig_pdu = snmp_clone_pdu(pdu);
- asp->rw = READ;
- asp->exact = TRUE;
- asp->next = NULL;
- asp->mode = RESERVE1;
- asp->status = SNMP_ERR_NOERROR;
- asp->index = 0;
- asp->oldmode = 0;
- asp->treecache_num = -1;
- asp->treecache_len = 0;
- asp->reqinfo = SNMP_MALLOC_TYPEDEF(netsnmp_agent_request_info);
- DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p created\n",
- asp, asp->reqinfo));
-
- return asp;
-}
-
-void
-free_agent_snmp_session(netsnmp_agent_session *asp)
-{
- if (!asp)
- return;
-
- DEBUGMSGTL(("snmp_agent","agent_session %08p released\n", asp));
-
- netsnmp_remove_from_delegated(asp);
-
- DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p freed\n",
- asp, asp->reqinfo));
- if (asp->orig_pdu)
- snmp_free_pdu(asp->orig_pdu);
- if (asp->pdu)
- snmp_free_pdu(asp->pdu);
- if (asp->reqinfo)
- netsnmp_free_agent_request_info(asp->reqinfo);
- if (asp->treecache) {
- SNMP_FREE(asp->treecache);
- }
- if (asp->bulkcache) {
- SNMP_FREE(asp->bulkcache);
- }
- if (asp->requests) {
- int i;
- for (i = 0; i < asp->vbcount; i++) {
- netsnmp_free_request_data_sets(&asp->requests[i]);
- }
- SNMP_FREE(asp->requests);
- }
- if (asp->cache_store) {
- netsnmp_free_cachemap(asp->cache_store);
- asp->cache_store = NULL;
- }
- SNMP_FREE(asp);
-}
-
-int
-netsnmp_check_for_delegated(netsnmp_agent_session *asp)
-{
- int i;
- netsnmp_request_info *request;
-
- if (NULL == asp->treecache)
- return 0;
-
- for (i = 0; i <= asp->treecache_num; i++) {
- for (request = asp->treecache[i].requests_begin; request;
- request = request->next) {
- if (request->delegated)
- return 1;
- }
- }
- return 0;
-}
-
-int
-netsnmp_check_delegated_chain_for(netsnmp_agent_session *asp)
-{
- netsnmp_agent_session *asptmp;
- for (asptmp = agent_delegated_list; asptmp; asptmp = asptmp->next) {
- if (asptmp == asp)
- return 1;
- }
- return 0;
-}
-
-int
-netsnmp_check_for_delegated_and_add(netsnmp_agent_session *asp)
-{
- if (netsnmp_check_for_delegated(asp)) {
- if (!netsnmp_check_delegated_chain_for(asp)) {
- /*
- * add to delegated request chain
- */
- asp->next = agent_delegated_list;
- agent_delegated_list = asp;
- DEBUGMSGTL(("snmp_agent", "delegate session == %08p\n", asp));
- }
- return 1;
- }
- return 0;
-}
-
-int
-netsnmp_remove_from_delegated(netsnmp_agent_session *asp)
-{
- netsnmp_agent_session *curr, *prev = NULL;
-
- for (curr = agent_delegated_list; curr; prev = curr, curr = curr->next) {
- /*
- * is this us?
- */
- if (curr != asp)
- continue;
-
- /*
- * remove from queue
- */
- if (prev != NULL)
- prev->next = asp->next;
- else
- agent_delegated_list = asp->next;
-
- DEBUGMSGTL(("snmp_agent", "remove delegated session == %08p\n", asp));
-
- return 1;
- }
-
- return 0;
-}
-
-/*
- * netsnmp_remove_delegated_requests_for_session
- *
- * called when a session is being closed. Check all delegated requests to
- * see if the are waiting on this session, and if set, set the status for
- * that request to GENERR.
- */
-int
-netsnmp_remove_delegated_requests_for_session(netsnmp_session *sess)
-{
- netsnmp_agent_session *asp;
- int count = 0;
-
- for (asp = agent_delegated_list; asp; asp = asp->next) {
- /*
- * check each request
- */
- netsnmp_request_info *request;
- for(request = asp->requests; request; request = request->next) {
- /*
- * check session
- */
- netsnmp_assert(NULL!=request->subtree);
- if(request->subtree->session != sess)
- continue;
-
- /*
- * matched! mark request as done
- */
- netsnmp_request_set_error(request, SNMP_ERR_GENERR);
- ++count;
- }
- }
-
- /*
- * if we found any, that request may be finished now
- */
- if(count) {
- DEBUGMSGTL(("snmp_agent", "removed %d delegated request(s) for session "
- "%08p\n", count, sess));
- netsnmp_check_outstanding_agent_requests();
- }
-
- return count;
-}
-
-int
-netsnmp_check_queued_chain_for(netsnmp_agent_session *asp)
-{
- netsnmp_agent_session *asptmp;
- for (asptmp = netsnmp_agent_queued_list; asptmp; asptmp = asptmp->next) {
- if (asptmp == asp)
- return 1;
- }
- return 0;
-}
-
-int
-netsnmp_add_queued(netsnmp_agent_session *asp)
-{
- netsnmp_agent_session *asp_tmp;
-
- /*
- * first item?
- */
- if (NULL == netsnmp_agent_queued_list) {
- netsnmp_agent_queued_list = asp;
- return 1;
- }
-
-
- /*
- * add to end of queued request chain
- */
- asp_tmp = netsnmp_agent_queued_list;
- for (; asp_tmp; asp_tmp = asp_tmp->next) {
- /*
- * already in queue?
- */
- if (asp_tmp == asp)
- break;
-
- /*
- * end of queue?
- */
- if (NULL == asp_tmp->next)
- asp_tmp->next = asp;
- }
- return 1;
-}
-
-
-int
-netsnmp_wrap_up_request(netsnmp_agent_session *asp, int status)
-{
- netsnmp_variable_list *var_ptr;
- int i;
-
- /*
- * if this request was a set, clear the global now that we are
- * done.
- */
- if (asp == netsnmp_processing_set) {
- DEBUGMSGTL(("snmp_agent", "SET request complete, asp = %08p\n",
- asp));
- netsnmp_processing_set = NULL;
- }
-
- if (asp->pdu) {
- /*
- * If we've got an error status, then this needs to be
- * passed back up to the higher levels....
- */
- if ( status != 0 && asp->status == 0 )
- asp->status = status;
-
- switch (asp->pdu->command) {
- case SNMP_MSG_INTERNAL_SET_BEGIN:
- case SNMP_MSG_INTERNAL_SET_RESERVE1:
- case SNMP_MSG_INTERNAL_SET_RESERVE2:
- case SNMP_MSG_INTERNAL_SET_ACTION:
- /*
- * some stuff needs to be saved in special subagent cases
- */
- save_set_cache(asp);
- break;
-
- case SNMP_MSG_GETNEXT:
- _fix_endofmibview(asp);
- break;
-
- case SNMP_MSG_GETBULK:
- /*
- * for a GETBULK response we need to rearrange the varbinds
- */
- _reorder_getbulk(asp);
- break;
- }
-
- /*
- * May need to "dumb down" a SET error status for a
- * v1 query. See RFC2576 - section 4.3
- */
-#ifndef NETSNMP_DISABLE_SNMPV1
- if ((asp->pdu->command == SNMP_MSG_SET) &&
- (asp->pdu->version == SNMP_VERSION_1)) {
- switch (asp->status) {
- case SNMP_ERR_WRONGVALUE:
- case SNMP_ERR_WRONGENCODING:
- case SNMP_ERR_WRONGTYPE:
- case SNMP_ERR_WRONGLENGTH:
- case SNMP_ERR_INCONSISTENTVALUE:
- status = SNMP_ERR_BADVALUE;
- asp->status = SNMP_ERR_BADVALUE;
- break;
- case SNMP_ERR_NOACCESS:
- case SNMP_ERR_NOTWRITABLE:
- case SNMP_ERR_NOCREATION:
- case SNMP_ERR_INCONSISTENTNAME:
- case SNMP_ERR_AUTHORIZATIONERROR:
- status = SNMP_ERR_NOSUCHNAME;
- asp->status = SNMP_ERR_NOSUCHNAME;
- break;
- case SNMP_ERR_RESOURCEUNAVAILABLE:
- case SNMP_ERR_COMMITFAILED:
- case SNMP_ERR_UNDOFAILED:
- status = SNMP_ERR_GENERR;
- asp->status = SNMP_ERR_GENERR;
- break;
- }
- }
- /*
- * Similarly we may need to "dumb down" v2 exception
- * types to throw an error for a v1 query.
- * See RFC2576 - section 4.1.2.3
- */
- if ((asp->pdu->command != SNMP_MSG_SET) &&
- (asp->pdu->version == SNMP_VERSION_1)) {
- for (var_ptr = asp->pdu->variables, i = 1;
- var_ptr != NULL; var_ptr = var_ptr->next_variable, i++) {
- switch (var_ptr->type) {
- case SNMP_NOSUCHOBJECT:
- case SNMP_NOSUCHINSTANCE:
- case SNMP_ENDOFMIBVIEW:
- case ASN_COUNTER64:
- status = SNMP_ERR_NOSUCHNAME;
- asp->status = SNMP_ERR_NOSUCHNAME;
- asp->index = i;
- break;
- }
- }
- }
-#endif /* snmpv1 support */
- } /** if asp->pdu */
-
- /*
- * Update the snmp error-count statistics
- * XXX - should we include the V2 errors in this or not?
- */
-#define INCLUDE_V2ERRORS_IN_V1STATS
-
- switch (status) {
-#ifdef INCLUDE_V2ERRORS_IN_V1STATS
- case SNMP_ERR_WRONGVALUE:
- case SNMP_ERR_WRONGENCODING:
- case SNMP_ERR_WRONGTYPE:
- case SNMP_ERR_WRONGLENGTH:
- case SNMP_ERR_INCONSISTENTVALUE:
-#endif
- case SNMP_ERR_BADVALUE:
- snmp_increment_statistic(STAT_SNMPOUTBADVALUES);
- break;
-#ifdef INCLUDE_V2ERRORS_IN_V1STATS
- case SNMP_ERR_NOACCESS:
- case SNMP_ERR_NOTWRITABLE:
- case SNMP_ERR_NOCREATION:
- case SNMP_ERR_INCONSISTENTNAME:
- case SNMP_ERR_AUTHORIZATIONERROR:
-#endif
- case SNMP_ERR_NOSUCHNAME:
- snmp_increment_statistic(STAT_SNMPOUTNOSUCHNAMES);
- break;
-#ifdef INCLUDE_V2ERRORS_IN_V1STATS
- case SNMP_ERR_RESOURCEUNAVAILABLE:
- case SNMP_ERR_COMMITFAILED:
- case SNMP_ERR_UNDOFAILED:
-#endif
- case SNMP_ERR_GENERR:
- snmp_increment_statistic(STAT_SNMPOUTGENERRS);
- break;
-
- case SNMP_ERR_TOOBIG:
- snmp_increment_statistic(STAT_SNMPOUTTOOBIGS);
- break;
- }
-
- if ((status == SNMP_ERR_NOERROR) && (asp->pdu)) {
- snmp_increment_statistic_by((asp->pdu->command == SNMP_MSG_SET ?
- STAT_SNMPINTOTALSETVARS :
- STAT_SNMPINTOTALREQVARS),
- count_varbinds(asp->pdu->variables));
- } else {
- /*
- * Use a copy of the original request
- * to report failures.
- */
- snmp_free_pdu(asp->pdu);
- asp->pdu = asp->orig_pdu;
- asp->orig_pdu = NULL;
- }
- if (asp->pdu) {
- asp->pdu->command = SNMP_MSG_RESPONSE;
- asp->pdu->errstat = asp->status;
- asp->pdu->errindex = asp->index;
- if (!snmp_send(asp->session, asp->pdu)) {
- netsnmp_variable_list *var_ptr;
- snmp_perror("send response");
- for (var_ptr = asp->pdu->variables; var_ptr != NULL;
- var_ptr = var_ptr->next_variable) {
- size_t c_oidlen = 256, c_outlen = 0;
- u_char *c_oid = (u_char *) malloc(c_oidlen);
-
- if (c_oid) {
- if (!sprint_realloc_objid (&c_oid, &c_oidlen, &c_outlen, 1,
- var_ptr->name,
- var_ptr->name_length)) {
- snmp_log(LOG_ERR, " -- %s [TRUNCATED]\n", c_oid);
- } else {
- snmp_log(LOG_ERR, " -- %s\n", c_oid);
- }
- SNMP_FREE(c_oid);
- }
- }
- snmp_free_pdu(asp->pdu);
- asp->pdu = NULL;
- }
- snmp_increment_statistic(STAT_SNMPOUTPKTS);
- snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES);
- asp->pdu = NULL; /* yyy-rks: redundant, no? */
- netsnmp_remove_and_free_agent_snmp_session(asp);
- }
- return 1;
-}
-
-void
-dump_sess_list(void)
-{
- netsnmp_agent_session *a;
-
- DEBUGMSGTL(("snmp_agent", "DUMP agent_sess_list -> "));
- for (a = agent_session_list; a != NULL; a = a->next) {
- DEBUGMSG(("snmp_agent", "%08p[session %08p] -> ", a, a->session));
- }
- DEBUGMSG(("snmp_agent", "[NIL]\n"));
-}
-
-void
-netsnmp_remove_and_free_agent_snmp_session(netsnmp_agent_session *asp)
-{
- netsnmp_agent_session *a, **prevNext = &agent_session_list;
-
- DEBUGMSGTL(("snmp_agent", "REMOVE session == %08p\n", asp));
-
- for (a = agent_session_list; a != NULL; a = *prevNext) {
- if (a == asp) {
- *prevNext = a->next;
- a->next = NULL;
- free_agent_snmp_session(a);
- asp = NULL;
- break;
- } else {
- prevNext = &(a->next);
- }
- }
-
- if (a == NULL && asp != NULL) {
- /*
- * We coulnd't find it on the list, so free it anyway.
- */
- free_agent_snmp_session(asp);
- }
-}
-
-void
-netsnmp_free_agent_snmp_session_by_session(netsnmp_session * sess,
- void (*free_request)
- (netsnmp_request_list *))
-{
- netsnmp_agent_session *a, *next, **prevNext = &agent_session_list;
-
- DEBUGMSGTL(("snmp_agent", "REMOVE session == %08p\n", sess));
-
- for (a = agent_session_list; a != NULL; a = next) {
- if (a->session == sess) {
- *prevNext = a->next;
- next = a->next;
- free_agent_snmp_session(a);
- } else {
- prevNext = &(a->next);
- next = a->next;
- }
- }
-}
-
-/** handles an incoming SNMP packet into the agent */
-int
-handle_snmp_packet(int op, netsnmp_session * session, int reqid,
- netsnmp_pdu *pdu, void *magic)
-{
- netsnmp_agent_session *asp;
- int status, access_ret, rc;
-
- /*
- * We only support receiving here.
- */
- if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
- return 1;
- }
-
- /*
- * RESPONSE messages won't get this far, but TRAP-like messages
- * might.
- */
- if (pdu->command == SNMP_MSG_TRAP || pdu->command == SNMP_MSG_INFORM ||
- pdu->command == SNMP_MSG_TRAP2) {
- DEBUGMSGTL(("snmp_agent", "received trap-like PDU (%02x)\n",
- pdu->command));
- pdu->command = SNMP_MSG_TRAP2;
- snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS);
- return 1;
- }
-
- /*
- * send snmpv3 authfail trap.
- */
- if (pdu->version == SNMP_VERSION_3 &&
- session->s_snmp_errno == SNMPERR_USM_AUTHENTICATIONFAILURE) {
- send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
- return 1;
- }
-
- if (magic == NULL) {
- asp = init_agent_snmp_session(session, pdu);
- status = SNMP_ERR_NOERROR;
- } else {
- asp = (netsnmp_agent_session *) magic;
- status = asp->status;
- }
-
- if ((access_ret = check_access(asp->pdu)) != 0) {
- if (access_ret == VACM_NOSUCHCONTEXT) {
- /*
- * rfc3413 section 3.2, step 5 says that we increment the
- * counter but don't return a response of any kind
- */
-
- /*
- * we currently don't support unavailable contexts, as
- * there is no reason to that I currently know of
- */
- snmp_increment_statistic(STAT_SNMPUNKNOWNCONTEXTS);
-
- /*
- * drop the request
- */
- netsnmp_remove_and_free_agent_snmp_session(asp);
- return 0;
- } else {
- /*
- * access control setup is incorrect
- */
- send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
-#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
-#if defined(NETSNMP_DISABLE_SNMPV1)
- if (asp->pdu->version != SNMP_VERSION_2c) {
-#else
-#if defined(NETSNMP_DISABLE_SNMPV2C)
- if (asp->pdu->version != SNMP_VERSION_1) {
-#else
- if (asp->pdu->version != SNMP_VERSION_1
- && asp->pdu->version != SNMP_VERSION_2c) {
-#endif
-#endif
- asp->pdu->errstat = SNMP_ERR_AUTHORIZATIONERROR;
- asp->pdu->command = SNMP_MSG_RESPONSE;
- snmp_increment_statistic(STAT_SNMPOUTPKTS);
- if (!snmp_send(asp->session, asp->pdu))
- snmp_free_pdu(asp->pdu);
- asp->pdu = NULL;
- netsnmp_remove_and_free_agent_snmp_session(asp);
- return 1;
- } else {
-#endif /* support for community based SNMP */
- /*
- * drop the request
- */
- netsnmp_remove_and_free_agent_snmp_session(asp);
- return 0;
-#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
- }
-#endif /* support for community based SNMP */
- }
- }
-
- rc = netsnmp_handle_request(asp, status);
-
- /*
- * done
- */
- DEBUGMSGTL(("snmp_agent", "end of handle_snmp_packet, asp = %08p\n",
- asp));
- return rc;
-}
-
-netsnmp_request_info *
-netsnmp_add_varbind_to_cache(netsnmp_agent_session *asp, int vbcount,
- netsnmp_variable_list * varbind_ptr,
- netsnmp_subtree *tp)
-{
- netsnmp_request_info *request = NULL;
- int cacheid;
-
- DEBUGMSGTL(("snmp_agent", "add_vb_to_cache(%8p, %d, ", asp, vbcount));
- DEBUGMSGOID(("snmp_agent", varbind_ptr->name,
- varbind_ptr->name_length));
- DEBUGMSG(("snmp_agent", ", %8p)\n", tp));
-
- if (tp &&
- (asp->pdu->command == SNMP_MSG_GETNEXT ||
- asp->pdu->command == SNMP_MSG_GETBULK)) {
- int result;
- int prefix_len;
-
- prefix_len = netsnmp_oid_find_prefix(tp->start_a,
- tp->start_len,
- tp->end_a, tp->end_len);
- if (prefix_len < 1) {
- result = VACM_NOTINVIEW; /* ack... bad bad thing happened */
- } else {
- result =
- netsnmp_acm_check_subtree(asp->pdu, tp->start_a, prefix_len);
- }
-
- while (result == VACM_NOTINVIEW) {
- /* the entire subtree is not in view. Skip it. */
- /** @todo make this be more intelligent about ranges.
- Right now we merely take the highest level
- commonality of a registration range and use that.
- At times we might be able to be smarter about
- checking the range itself as opposed to the node
- above where the range exists, but I doubt this will
- come up all that frequently. */
- tp = tp->next;
- if (tp) {
- prefix_len = netsnmp_oid_find_prefix(tp->start_a,
- tp->start_len,
- tp->end_a,
- tp->end_len);
- if (prefix_len < 1) {
- /* ack... bad bad thing happened */
- result = VACM_NOTINVIEW;
- } else {
- result =
- netsnmp_acm_check_subtree(asp->pdu,
- tp->start_a, prefix_len);
- }
- }
- else
- break;
- }
- }
- if (tp == NULL) {
- /*
- * no appropriate registration found
- */
- /*
- * make up the response ourselves
- */
- switch (asp->pdu->command) {
- case SNMP_MSG_GETNEXT:
- case SNMP_MSG_GETBULK:
- varbind_ptr->type = SNMP_ENDOFMIBVIEW;
- break;
-
- case SNMP_MSG_SET:
- case SNMP_MSG_GET:
- varbind_ptr->type = SNMP_NOSUCHOBJECT;
- break;
-
- default:
- return NULL; /* shouldn't get here */
- }
- } else {
- DEBUGMSGTL(("snmp_agent", "tp->start "));
- DEBUGMSGOID(("snmp_agent", tp->start_a, tp->start_len));
- DEBUGMSG(("snmp_agent", ", tp->end "));
- DEBUGMSGOID(("snmp_agent", tp->end_a, tp->end_len));
- DEBUGMSG(("snmp_agent", ", \n"));
-
- /*
- * malloc the request structure
- */
- request = &(asp->requests[vbcount - 1]);
- request->index = vbcount;
- request->delegated = 0;
- request->processed = 0;
- request->status = 0;
- request->subtree = tp;
- request->agent_req_info = asp->reqinfo;
- if (request->parent_data) {
- netsnmp_free_request_data_sets(request);
- }
- DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n",
- asp, asp->reqinfo));
-
- /*
- * for non-SET modes, set the type to NULL
- */
- if (!MODE_IS_SET(asp->pdu->command)) {
- DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n",
- asp, asp->reqinfo));
- if (varbind_ptr->type == ASN_PRIV_INCL_RANGE) {
- DEBUGMSGTL(("snmp_agent", "varbind %d is inclusive\n",
- request->index));
- request->inclusive = 1;
- }
- varbind_ptr->type = ASN_NULL;
- }
-
- /*
- * place them in a cache
- */
- if (tp->global_cacheid) {
- /*
- * we need to merge all marked subtrees together
- */
- if (asp->cache_store && -1 !=
- (cacheid = netsnmp_get_local_cachid(asp->cache_store,
- tp->global_cacheid))) {
- } else {
- cacheid = ++(asp->treecache_num);
- netsnmp_get_or_add_local_cachid(&asp->cache_store,
- tp->global_cacheid,
- cacheid);
- goto mallocslot; /* XXX: ick */
- }
- } else if (tp->cacheid > -1 && tp->cacheid <= asp->treecache_num &&
- asp->treecache[tp->cacheid].subtree == tp) {
- /*
- * we have already added a request to this tree
- * pointer before
- */
- cacheid = tp->cacheid;
- } else {
- cacheid = ++(asp->treecache_num);
- mallocslot:
- /*
- * new slot needed
- */
- if (asp->treecache_num >= asp->treecache_len) {
- /*
- * exapand cache array
- */
- /*
- * WWW: non-linear expansion needed (with cap)
- */
-#define CACHE_GROW_SIZE 16
- asp->treecache_len =
- (asp->treecache_len + CACHE_GROW_SIZE);
- asp->treecache =
- realloc(asp->treecache,
- sizeof(netsnmp_tree_cache) *
- asp->treecache_len);
- if (asp->treecache == NULL)
- return NULL;
- memset(&(asp->treecache[cacheid]), 0x00,
- sizeof(netsnmp_tree_cache) * (CACHE_GROW_SIZE));
- }
- asp->treecache[cacheid].subtree = tp;
- asp->treecache[cacheid].requests_begin = request;
- tp->cacheid = cacheid;
- }
-
- /*
- * if this is a search type, get the ending range oid as well
- */
- if (asp->pdu->command == SNMP_MSG_GETNEXT ||
- asp->pdu->command == SNMP_MSG_GETBULK) {
- request->range_end = tp->end_a;
- request->range_end_len = tp->end_len;
- } else {
- request->range_end = NULL;
- request->range_end_len = 0;
- }
-
- /*
- * link into chain
- */
- if (asp->treecache[cacheid].requests_end)
- asp->treecache[cacheid].requests_end->next = request;
- request->next = NULL;
- request->prev = asp->treecache[cacheid].requests_end;
- asp->treecache[cacheid].requests_end = request;
-
- /*
- * add the given request to the list of requests they need
- * to handle results for
- */
- request->requestvb = request->requestvb_start = varbind_ptr;
- }
- return request;
-}
-
-/*
- * check the ACM(s) for the results on each of the varbinds.
- * If ACM disallows it, replace the value with type
- *
- * Returns number of varbinds with ACM errors
- */
-int
-check_acm(netsnmp_agent_session *asp, u_char type)
-{
- int view;
- int i, j, k;
- netsnmp_request_info *request;
- int ret = 0;
- netsnmp_variable_list *vb, *vb2, *vbc;
- int earliest = 0;
-
- for (i = 0; i <= asp->treecache_num; i++) {
- for (request = asp->treecache[i].requests_begin;
- request; request = request->next) {
- /*
- * for each request, run it through in_a_view()
- */
- earliest = 0;
- for(j = request->repeat, vb = request->requestvb_start;
- vb && j > -1;
- j--, vb = vb->next_variable) {
- if (vb->type != ASN_NULL &&
- vb->type != ASN_PRIV_RETRY) { /* not yet processed */
- view =
- in_a_view(vb->name, &vb->name_length,
- asp->pdu, vb->type);
-
- /*
- * if a ACM error occurs, mark it as type passed in
- */
- if (view != VACM_SUCCESS) {
- ret++;
- if (request->repeat < request->orig_repeat) {
- /* basically this means a GETBULK */
- request->repeat++;
- if (!earliest) {
- request->requestvb = vb;
- earliest = 1;
- }
-
- /* ugh. if a whole now exists, we need to
- move the contents up the chain and fill
- in at the end else we won't end up
- lexographically sorted properly */
- if (j > -1 && vb->next_variable &&
- vb->next_variable->type != ASN_NULL &&
- vb->next_variable->type != ASN_PRIV_RETRY) {
- for(k = j, vbc = vb, vb2 = vb->next_variable;
- k > -2 && vbc && vb2;
- k--, vbc = vb2, vb2 = vb2->next_variable) {
- /* clone next into the current */
- snmp_clone_var(vb2, vbc);
- vbc->next_variable = vb2;
- }
- }
- }
- snmp_set_var_typed_value(vb, type, NULL, 0);
- }
- }
- }
- }
- }
- return ret;
-}
-
-
-int
-netsnmp_create_subtree_cache(netsnmp_agent_session *asp)
-{
- netsnmp_subtree *tp;
- netsnmp_variable_list *varbind_ptr, *vbsave, *vbptr, **prevNext;
- int view;
- int vbcount = 0;
- int bulkcount = 0, bulkrep = 0;
- int i = 0, n = 0, r = 0;
- netsnmp_request_info *request;
-
- if (asp->treecache == NULL && asp->treecache_len == 0) {
- asp->treecache_len = SNMP_MAX(1 + asp->vbcount / 4, 16);
- asp->treecache =
- calloc(asp->treecache_len, sizeof(netsnmp_tree_cache));
- if (asp->treecache == NULL)
- return SNMP_ERR_GENERR;
- }
- asp->treecache_num = -1;
-
- if (asp->pdu->command == SNMP_MSG_GETBULK) {
- /*
- * getbulk prep
- */
- int count = count_varbinds(asp->pdu->variables);
- if (asp->pdu->errstat < 0) {
- asp->pdu->errstat = 0;
- }
- if (asp->pdu->errindex < 0) {
- asp->pdu->errindex = 0;
- }
-
- if (asp->pdu->errstat < count) {
- n = asp->pdu->errstat;
- } else {
- n = count;
- }
- if ((r = count - n) <= 0) {
- r = 0;
- asp->bulkcache = NULL;
- } else {
- int maxbulk =
- netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_AGENT_MAX_GETBULKREPEATS);
- int maxresponses =
- netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
- NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES);
-
- if (maxresponses == 0)
- maxresponses = 100; /* more than reasonable default */
-
- /* ensure that the total number of responses fits in a mallocable
- * result vector
- */
- if (maxresponses < 0 ||
- maxresponses > INT_MAX / sizeof(struct varbind_list *))
- maxresponses = INT_MAX / sizeof(struct varbind_list *);
-
- /* ensure that the maximum number of repetitions will fit in the
- * result vector
- */
- if (maxbulk <= 0 || maxbulk > maxresponses / r)
- maxbulk = maxresponses / r;
-
- /* limit getbulk number of repeats to a configured size */
- if (asp->pdu->errindex > maxbulk) {
- asp->pdu->errindex = maxbulk;
- DEBUGMSGTL(("snmp_agent",
- "truncating number of getbulk repeats to %d\n",
- asp->pdu->errindex));
- }
-
- asp->bulkcache =
- (netsnmp_variable_list **) malloc(
- asp->pdu->errindex * r * sizeof(struct varbind_list *));
-
- if (!asp->bulkcache) {
- DEBUGMSGTL(("snmp_agent", "Bulkcache malloc failed\n"));
- return SNMP_ERR_GENERR;
- }
- }
- DEBUGMSGTL(("snmp_agent", "GETBULK N = %d, M = %d, R = %d\n",
- n, asp->pdu->errindex, r));
- }
-
- /*
- * collect varbinds into their registered trees
- */
- prevNext = &(asp->pdu->variables);
- for (varbind_ptr = asp->pdu->variables; varbind_ptr;
- varbind_ptr = vbsave) {
-
- /*
- * getbulk mess with this pointer, so save it
- */
- vbsave = varbind_ptr->next_variable;
-
- if (asp->pdu->command == SNMP_MSG_GETBULK) {
- if (n > 0) {
- n--;
- } else {
- /*
- * repeate request varbinds on GETBULK. These will
- * have to be properly rearranged later though as
- * responses are supposed to actually be interlaced
- * with each other. This is done with the asp->bulkcache.
- */
- bulkrep = asp->pdu->errindex - 1;
- if (asp->pdu->errindex > 0) {
- vbptr = varbind_ptr;
- asp->bulkcache[bulkcount++] = vbptr;
-
- for (i = 1; i < asp->pdu->errindex; i++) {
- vbptr->next_variable =
- SNMP_MALLOC_STRUCT(variable_list);
- /*
- * don't clone the oid as it's got to be
- * overwritten anyway
- */
- if (!vbptr->next_variable) {
- /*
- * XXXWWW: ack!!!
- */
- DEBUGMSGTL(("snmp_agent", "NextVar malloc failed\n"));
- } else {
- vbptr = vbptr->next_variable;
- vbptr->name_length = 0;
- vbptr->type = ASN_NULL;
- asp->bulkcache[bulkcount++] = vbptr;
- }
- }
- vbptr->next_variable = vbsave;
- } else {
- /*
- * 0 repeats requested for this varbind, so take it off
- * the list.
- */
- vbptr = varbind_ptr;
- *prevNext = vbptr->next_variable;
- vbptr->next_variable = NULL;
- snmp_free_varbind(vbptr);
- asp->vbcount--;
- continue;
- }
- }
- }
-
- /*
- * count the varbinds
- */
- ++vbcount;
-
- /*
- * find the owning tree
- */
- tp = netsnmp_subtree_find(varbind_ptr->name, varbind_ptr->name_length,
- NULL, asp->pdu->contextName);
-
- /*
- * check access control
- */
- switch (asp->pdu->command) {
- case SNMP_MSG_GET:
- view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
- asp->pdu, varbind_ptr->type);
- if (view != VACM_SUCCESS)
- snmp_set_var_typed_value(varbind_ptr, SNMP_NOSUCHOBJECT,
- NULL, 0);
- break;
-
- case SNMP_MSG_SET:
- view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
- asp->pdu, varbind_ptr->type);
- if (view != VACM_SUCCESS) {
- asp->index = vbcount;
- return SNMP_ERR_NOACCESS;
- }
- break;
-
- case SNMP_MSG_GETNEXT:
- case SNMP_MSG_GETBULK:
- default:
- view = VACM_SUCCESS;
- /*
- * XXXWWW: check VACM here to see if "tp" is even worthwhile
- */
- }
- if (view == VACM_SUCCESS) {
- request = netsnmp_add_varbind_to_cache(asp, vbcount, varbind_ptr,
- tp);
- if (request && asp->pdu->command == SNMP_MSG_GETBULK) {
- request->repeat = request->orig_repeat = bulkrep;
- }
- }
-
- prevNext = &(varbind_ptr->next_variable);
- }
-
- return SNMPERR_SUCCESS;
-}
-
-/*
- * this function is only applicable in getnext like contexts
- */
-int
-netsnmp_reassign_requests(netsnmp_agent_session *asp)
-{
- /*
- * assume all the requests have been filled or rejected by the
- * subtrees, so reassign the rejected ones to the next subtree in
- * the chain
- */
-
- int i;
-
- /*
- * get old info
- */
- netsnmp_tree_cache *old_treecache = asp->treecache;
-
- /*
- * malloc new space
- */
- asp->treecache =
- (netsnmp_tree_cache *) calloc(asp->treecache_len,
- sizeof(netsnmp_tree_cache));
- asp->treecache_num = -1;
- if (asp->cache_store) {
- netsnmp_free_cachemap(asp->cache_store);
- asp->cache_store = NULL;
- }
-
- for (i = 0; i < asp->vbcount; i++) {
- if (asp->requests[i].requestvb == NULL) {
- /*
- * Occurs when there's a mixture of still active
- * and "endOfMibView" repetitions
- */
- continue;
- }
- if (asp->requests[i].requestvb->type == ASN_NULL) {
- if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index,
- asp->requests[i].requestvb,
- asp->requests[i].subtree->next)) {
- if (old_treecache != NULL) {
- SNMP_FREE(old_treecache);
- old_treecache = NULL;
- }
- }
- } else if (asp->requests[i].requestvb->type == ASN_PRIV_RETRY) {
- /*
- * re-add the same subtree
- */
- asp->requests[i].requestvb->type = ASN_NULL;
- if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index,
- asp->requests[i].requestvb,
- asp->requests[i].subtree)) {
- if (old_treecache != NULL) {
- SNMP_FREE(old_treecache);
- old_treecache = NULL;
- }
- }
- }
- }
-
- if (old_treecache != NULL) {
- SNMP_FREE(old_treecache);
- }
- return SNMP_ERR_NOERROR;
-}
-
-void
-netsnmp_delete_request_infos(netsnmp_request_info *reqlist)
-{
- while (reqlist) {
- netsnmp_free_request_data_sets(reqlist);
- reqlist = reqlist->next;
- }
-}
-
-void
-netsnmp_delete_subtree_cache(netsnmp_agent_session *asp)
-{
- while (asp->treecache_num >= 0) {
- /*
- * don't delete subtrees
- */
- netsnmp_delete_request_infos(asp->treecache[asp->treecache_num].
- requests_begin);
- asp->treecache_num--;
- }
-}
-
-/*
- * check all requests for errors
- *
- * @Note:
- * This function is a little different from the others in that
- * it does not use any linked lists, instead using the original
- * asp requests array. This is of particular importance for
- * cases where the linked lists are unreliable. One known instance
- * of this scenario occurs when the row_merge helper is used, which
- * may temporarily disrupts linked lists during its (and its childrens)
- * handling of requests.
- */
-int
-netsnmp_check_all_requests_error(netsnmp_agent_session *asp,
- int look_for_specific)
-{
- int i;
-
- /*
- * find any errors marked in the requests
- */
- for( i = 0; i < asp->vbcount; ++i ) {
- if ((SNMP_ERR_NOERROR != asp->requests[i].status) &&
- (!look_for_specific ||
- asp->requests[i].status == look_for_specific))
- return asp->requests[i].status;
- }
-
- return SNMP_ERR_NOERROR;
-}
-
-int
-netsnmp_check_requests_error(netsnmp_request_info *requests)
-{
- /*
- * find any errors marked in the requests
- */
- for (;requests;requests = requests->next) {
- if (requests->status != SNMP_ERR_NOERROR)
- return requests->status;
- }
- return SNMP_ERR_NOERROR;
-}
-
-int
-netsnmp_check_requests_status(netsnmp_agent_session *asp,
- netsnmp_request_info *requests,
- int look_for_specific)
-{
- /*
- * find any errors marked in the requests
- */
- while (requests) {
- if(requests->agent_req_info != asp->reqinfo) {
- DEBUGMSGTL(("verbose:asp",
- "**reqinfo %p doesn't match cached reqinfo %p\n",
- asp->reqinfo, requests->agent_req_info));
- }
- if (requests->status != SNMP_ERR_NOERROR &&
- (!look_for_specific || requests->status == look_for_specific)
- && (look_for_specific || asp->index == 0
- || requests->index < asp->index)) {
- asp->index = requests->index;
- asp->status = requests->status;
- }
- requests = requests->next;
- }
- return asp->status;
-}
-
-int
-netsnmp_check_all_requests_status(netsnmp_agent_session *asp,
- int look_for_specific)
-{
- int i;
- for (i = 0; i <= asp->treecache_num; i++) {
- netsnmp_check_requests_status(asp,
- asp->treecache[i].requests_begin,
- look_for_specific);
- }
- return asp->status;
-}
-
-int
-handle_var_requests(netsnmp_agent_session *asp)
-{
- int i, retstatus = SNMP_ERR_NOERROR,
- status = SNMP_ERR_NOERROR, final_status = SNMP_ERR_NOERROR;
- netsnmp_handler_registration *reginfo;
-
- asp->reqinfo->asp = asp;
- asp->reqinfo->mode = asp->mode;
-
- /*
- * now, have the subtrees in the cache go search for their results
- */
- for (i = 0; i <= asp->treecache_num; i++) {
- /*
- * don't call handlers w/null reginfo.
- * - when is this? sub agent disconnected while request processing?
- * - should this case encompass more of this subroutine?
- * - does check_request_status make send if handlers weren't called?
- */
- if(NULL != asp->treecache[i].subtree->reginfo) {
- reginfo = asp->treecache[i].subtree->reginfo;
- status = netsnmp_call_handlers(reginfo, asp->reqinfo,
- asp->treecache[i].requests_begin);
- }
- else
- status = SNMP_ERR_GENERR;
-
- /*
- * find any errors marked in the requests. For later parts of
- * SET processing, only check for new errors specific to that
- * set processing directive (which must superceed the previous
- * errors).
- */
- switch (asp->mode) {
- case MODE_SET_COMMIT:
- retstatus = netsnmp_check_requests_status(asp,
- asp->treecache[i].
- requests_begin,
- SNMP_ERR_COMMITFAILED);
- break;
-
- case MODE_SET_UNDO:
- retstatus = netsnmp_check_requests_status(asp,
- asp->treecache[i].
- requests_begin,
- SNMP_ERR_UNDOFAILED);
- break;
-
- default:
- retstatus = netsnmp_check_requests_status(asp,
- asp->treecache[i].
- requests_begin, 0);
- break;
- }
-
- /*
- * always take lowest varbind if possible
- */
- if (retstatus != SNMP_ERR_NOERROR) {
- status = retstatus;
- }
-
- /*
- * other things we know less about (no index)
- */
- /*
- * WWW: drop support for this?
- */
- if (final_status == SNMP_ERR_NOERROR && status != SNMP_ERR_NOERROR) {
- /*
- * we can't break here, since some processing needs to be
- * done for all requests anyway (IE, SET handling for UNDO
- * needs to be called regardless of previous status
- * results.
- * WWW: This should be predictable though and
- * breaking should be possible in some cases (eg GET,
- * GETNEXT, ...)
- */
- final_status = status;
- }
- }
-
- return final_status;
-}
-
-/*
- * loop through our sessions known delegated sessions and check to see
- * if they've completed yet. If there are no more delegated sessions,
- * check for and process any queued requests
- */
-void
-netsnmp_check_outstanding_agent_requests(void)
-{
- netsnmp_agent_session *asp, *prev_asp = NULL, *next_asp = NULL;
-
- /*
- * deal with delegated requests
- */
- for (asp = agent_delegated_list; asp; asp = next_asp) {
- next_asp = asp->next; /* save in case we clean up asp */
- if (!netsnmp_check_for_delegated(asp)) {
-
- /*
- * we're done with this one, remove from queue
- */
- if (prev_asp != NULL)
- prev_asp->next = asp->next;
- else
- agent_delegated_list = asp->next;
- asp->next = NULL;
-
- /*
- * check request status
- */
- netsnmp_check_all_requests_status(asp, 0);
-
- /*
- * continue processing or finish up
- */
- check_delayed_request(asp);
-
- /*
- * if head was removed, don't drop it if it
- * was it re-queued
- */
- if ((prev_asp == NULL) && (agent_delegated_list == asp)) {
- prev_asp = asp;
- }
- } else {
-
- /*
- * asp is still on the queue
- */
- prev_asp = asp;
- }
- }
-
- /*
- * if we are processing a set and there are more delegated
- * requests, keep waiting before getting to queued requests.
- */
- if (netsnmp_processing_set && (NULL != agent_delegated_list))
- return;
-
- while (netsnmp_agent_queued_list) {
-
- /*
- * if we are processing a set, the first item better be
- * the set being (or waiting to be) processed.
- */
- netsnmp_assert((!netsnmp_processing_set) ||
- (netsnmp_processing_set == netsnmp_agent_queued_list));
-
- /*
- * if the top request is a set, don't pop it
- * off if there are delegated requests
- */
- if ((netsnmp_agent_queued_list->pdu->command == SNMP_MSG_SET) &&
- (agent_delegated_list)) {
-
- netsnmp_assert(netsnmp_processing_set == NULL);
-
- netsnmp_processing_set = netsnmp_agent_queued_list;
- DEBUGMSGTL(("snmp_agent", "SET request remains queued while "
- "delegated requests finish, asp = %08p\n", asp));
- break;
- }
-
- /*
- * pop the first request and process it
- */
- asp = netsnmp_agent_queued_list;
- netsnmp_agent_queued_list = asp->next;
- DEBUGMSGTL(("snmp_agent",
- "processing queued request, asp = %08p\n", asp));
-
- netsnmp_handle_request(asp, asp->status);
-
- /*
- * if we hit a set, stop
- */
- if (NULL != netsnmp_processing_set)
- break;
- }
-}
-
-/** Decide if the requested transaction_id is still being processed
- within the agent. This is used to validate whether a delayed cache
- (containing possibly freed pointers) is still usable.
-
- returns SNMPERR_SUCCESS if it's still valid, or SNMPERR_GENERR if not. */
-int
-netsnmp_check_transaction_id(int transaction_id)
-{
- netsnmp_agent_session *asp, *prev_asp = NULL;
-
- for (asp = agent_delegated_list; asp; prev_asp = asp, asp = asp->next) {
- if (asp->pdu->transid == transaction_id)
- return SNMPERR_SUCCESS;
- }
- return SNMPERR_GENERR;
-}
-
-
-/*
- * check_delayed_request(asp)
- *
- * Called to rexamine a set of requests and continue processing them
- * once all the previous (delayed) requests have been handled one way
- * or another.
- */
-
-int
-check_delayed_request(netsnmp_agent_session *asp)
-{
- int status = SNMP_ERR_NOERROR;
-
- DEBUGMSGTL(("snmp_agent", "processing delegated request, asp = %08p\n",
- asp));
-
- switch (asp->mode) {
- case SNMP_MSG_GETBULK:
- case SNMP_MSG_GETNEXT:
- netsnmp_check_all_requests_status(asp, 0);
- handle_getnext_loop(asp);
- if (netsnmp_check_for_delegated(asp) &&
- netsnmp_check_transaction_id(asp->pdu->transid) !=
- SNMPERR_SUCCESS) {
- /*
- * add to delegated request chain
- */
- if (!netsnmp_check_delegated_chain_for(asp)) {
- asp->next = agent_delegated_list;
- agent_delegated_list = asp;
- }
- }
- break;
-
- case MODE_SET_COMMIT:
- netsnmp_check_all_requests_status(asp, SNMP_ERR_COMMITFAILED);
- goto settop;
-
- case MODE_SET_UNDO:
- netsnmp_check_all_requests_status(asp, SNMP_ERR_UNDOFAILED);
- goto settop;
-
- case MODE_SET_BEGIN:
- case MODE_SET_RESERVE1:
- case MODE_SET_RESERVE2:
- case MODE_SET_ACTION:
- case MODE_SET_FREE:
- settop:
- /* If we should do only one pass, this mean we */
- /* should not reenter this function */
- if ((asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) {
- /* We should have finished the processing after the first */
- /* handle_set_loop, so just wrap up */
- break;
- }
- handle_set_loop(asp);
- if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) {
-
- if (netsnmp_check_for_delegated_and_add(asp)) {
- /*
- * add to delegated request chain
- */
- if (!asp->status)
- asp->status = status;
- }
-
- return SNMP_ERR_NOERROR;
- }
- break;
-
- default:
- break;
- }
-
- /*
- * if we don't have anything outstanding (delegated), wrap up
- */
- if (!netsnmp_check_for_delegated(asp))
- return netsnmp_wrap_up_request(asp, status);
-
- return 1;
-}
-
-/** returns 1 if there are valid GETNEXT requests left. Returns 0 if not. */
-int
-check_getnext_results(netsnmp_agent_session *asp)
-{
- /*
- * get old info
- */
- netsnmp_tree_cache *old_treecache = asp->treecache;
- int old_treecache_num = asp->treecache_num;
- int count = 0;
- int i, special = 0;
- netsnmp_request_info *request;
-
- if (asp->mode == SNMP_MSG_GET) {
- /*
- * Special case for doing INCLUSIVE getNext operations in
- * AgentX subagents.
- */
- DEBUGMSGTL(("snmp_agent",
- "asp->mode == SNMP_MSG_GET in ch_getnext\n"));
- asp->mode = asp->oldmode;
- special = 1;
- }
-
- for (i = 0; i <= old_treecache_num; i++) {
- for (request = old_treecache[i].requests_begin; request;
- request = request->next) {
-
- /*
- * If we have just done the special case AgentX GET, then any
- * requests which were not INCLUSIVE will now have a wrong
- * response, so junk them and retry from the same place (except
- * that this time the handler will be called in "inexact"
- * mode).
- */
-
- if (special) {
- if (!request->inclusive) {
- DEBUGMSGTL(("snmp_agent",
- "request %d wasn't inclusive\n",
- request->index));
- snmp_set_var_typed_value(request->requestvb,
- ASN_PRIV_RETRY, NULL, 0);
- } else if (request->requestvb->type == ASN_NULL ||
- request->requestvb->type == SNMP_NOSUCHINSTANCE ||
- request->requestvb->type == SNMP_NOSUCHOBJECT) {
- /*
- * it was inclusive, but no results. Still retry this
- * search.
- */
- snmp_set_var_typed_value(request->requestvb,
- ASN_PRIV_RETRY, NULL, 0);
- }
- }
-
- /*
- * out of range?
- */
- if (snmp_oid_compare(request->requestvb->name,
- request->requestvb->name_length,
- request->range_end,
- request->range_end_len) >= 0) {
- /*
- * ack, it's beyond the accepted end of range.
- */
- /*
- * fix it by setting the oid to the end of range oid instead
- */
- DEBUGMSGTL(("check_getnext_results",
- "request response %d out of range\n",
- request->index));
- /*
- * I'm not sure why inclusive is set unconditionally here (see
- * comments for revision 1.161), but it causes a problem for
- * GETBULK over an overridden variable. The bulk-to-next
- * handler re-uses the same request for multiple varbinds,
- * and once inclusive was set, it was never cleared. So, a
- * hack. Instead of setting it to 1, set it to 2, so bulk-to
- * next can clear it later. As of the time of this hack, all
- * checks of this var are boolean checks (not == 1), so this
- * should be safe. Cross your fingers.
- */
- request->inclusive = 2;
- /*
- * XXX: should set this to the original OID?
- */
- snmp_set_var_objid(request->requestvb,
- request->range_end,
- request->range_end_len);
- snmp_set_var_typed_value(request->requestvb, ASN_NULL,
- NULL, 0);
- }
-
- /*
- * mark any existent requests with illegal results as NULL
- */
- if (request->requestvb->type == SNMP_ENDOFMIBVIEW) {
- /*
- * illegal response from a subagent. Change it back to NULL
- * xxx-rks: err, how do we know this is a subagent?
- */
- request->requestvb->type = ASN_NULL;
- request->inclusive = 1;
- }
-
- if (request->requestvb->type == ASN_NULL ||
- request->requestvb->type == ASN_PRIV_RETRY ||
- (asp->reqinfo->mode == MODE_GETBULK
- && request->repeat > 0))
- count++;
- }
- }
- return count;
-}
-
-/** repeatedly calls getnext handlers looking for an answer till all
- requests are satisified. It's expected that one pass has been made
- before entering this function */
-int
-handle_getnext_loop(netsnmp_agent_session *asp)
-{
- int status;
- netsnmp_variable_list *var_ptr;
-
- /*
- * loop
- */
- while (netsnmp_running) {
-
- /*
- * bail for now if anything is delegated.
- */
- if (netsnmp_check_for_delegated(asp)) {
- return SNMP_ERR_NOERROR;
- }
-
- /*
- * check vacm against results
- */
- check_acm(asp, ASN_PRIV_RETRY);
-
- /*
- * need to keep going we're not done yet.
- */
- if (!check_getnext_results(asp))
- /*
- * nothing left, quit now
- */
- break;
-
- /*
- * never had a request (empty pdu), quit now
- */
- /*
- * XXXWWW: huh? this would be too late, no? shouldn't we
- * catch this earlier?
- */
- /*
- * if (count == 0)
- * break;
- */
-
- DEBUGIF("results") {
- DEBUGMSGTL(("results",
- "getnext results, before next pass:\n"));
- for (var_ptr = asp->pdu->variables; var_ptr;
- var_ptr = var_ptr->next_variable) {
- DEBUGMSGTL(("results", "\t"));
- DEBUGMSGVAR(("results", var_ptr));
- DEBUGMSG(("results", "\n"));
- }
- }
-
- netsnmp_reassign_requests(asp);
- status = handle_var_requests(asp);
- if (status != SNMP_ERR_NOERROR) {
- return status; /* should never really happen */
- }
- }
- return SNMP_ERR_NOERROR;
-}
-
-int
-handle_set(netsnmp_agent_session *asp)
-{
- int status;
- /*
- * SETS require 3-4 passes through the var_op_list.
- * The first two
- * passes verify that all types, lengths, and values are valid
- * and may reserve resources and the third does the set and a
- * fourth executes any actions. Then the identical GET RESPONSE
- * packet is returned.
- * If either of the first two passes returns an error, another
- * pass is made so that any reserved resources can be freed.
- * If the third pass returns an error, another pass is
- * made so that
- * any changes can be reversed.
- * If the fourth pass (or any of the error handling passes)
- * return an error, we'd rather not know about it!
- */
- if (!(asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) {
- switch (asp->mode) {
- case MODE_SET_BEGIN:
- snmp_increment_statistic(STAT_SNMPINSETREQUESTS);
- asp->rw = WRITE; /* WWW: still needed? */
- asp->mode = MODE_SET_RESERVE1;
- asp->status = SNMP_ERR_NOERROR;
- break;
-
- case MODE_SET_RESERVE1:
-
- if (asp->status != SNMP_ERR_NOERROR)
- asp->mode = MODE_SET_FREE;
- else
- asp->mode = MODE_SET_RESERVE2;
- break;
-
- case MODE_SET_RESERVE2:
- if (asp->status != SNMP_ERR_NOERROR)
- asp->mode = MODE_SET_FREE;
- else
- asp->mode = MODE_SET_ACTION;
- break;
-
- case MODE_SET_ACTION:
- if (asp->status != SNMP_ERR_NOERROR)
- asp->mode = MODE_SET_UNDO;
- else
- asp->mode = MODE_SET_COMMIT;
- break;
-
- case MODE_SET_COMMIT:
- if (asp->status != SNMP_ERR_NOERROR) {
- asp->mode = FINISHED_FAILURE;
- } else {
- asp->mode = FINISHED_SUCCESS;
- }
- break;
-
- case MODE_SET_UNDO:
- asp->mode = FINISHED_FAILURE;
- break;
-
- case MODE_SET_FREE:
- asp->mode = FINISHED_FAILURE;
- break;
- }
- }
-
- if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) {
- DEBUGMSGTL(("agent_set", "doing set mode = %d (%s)\n", asp->mode,
- se_find_label_in_slist("agent_mode", asp->mode)));
- status = handle_var_requests(asp);
- DEBUGMSGTL(("agent_set", "did set mode = %d, status = %d\n",
- asp->mode, status));
- if ((status != SNMP_ERR_NOERROR && asp->status == SNMP_ERR_NOERROR) ||
- status == SNMP_ERR_COMMITFAILED ||
- status == SNMP_ERR_UNDOFAILED) {
- asp->status = status;
- }
- }
- return asp->status;
-}
-
-int
-handle_set_loop(netsnmp_agent_session *asp)
-{
- while (asp->mode != FINISHED_FAILURE && asp->mode != FINISHED_SUCCESS) {
- handle_set(asp);
- if (netsnmp_check_for_delegated(asp)) {
- return SNMP_ERR_NOERROR;
- }
- if (asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY) {
- return asp->status;
- }
- }
- return asp->status;
-}
-
-int
-netsnmp_handle_request(netsnmp_agent_session *asp, int status)
-{
- /*
- * if this isn't a delegated request trying to finish,
- * processing of a set request should not start until all
- * delegated requests have completed, and no other new requests
- * should be processed until the set request completes.
- */
- if ((0 == netsnmp_check_delegated_chain_for(asp)) &&
- (asp != netsnmp_processing_set)) {
- /*
- * if we are processing a set and this is not a delegated
- * request, queue the request
- */
- if (netsnmp_processing_set) {
- netsnmp_add_queued(asp);
- DEBUGMSGTL(("snmp_agent",
- "request queued while processing set, "
- "asp = %08p\n", asp));
- return 1;
- }
-
- /*
- * check for set request
- */
- if (asp->pdu->command == SNMP_MSG_SET) {
- netsnmp_processing_set = asp;
-
- /*
- * if there are delegated requests, we must wait for them
- * to finish.
- */
- if (agent_delegated_list) {
- DEBUGMSGTL(("snmp_agent", "SET request queued while "
- "delegated requests finish, asp = %08p\n",
- asp));
- netsnmp_add_queued(asp);
- return 1;
- }
- }
- }
-
- /*
- * process the request
- */
- status = handle_pdu(asp);
-
- /*
- * print the results in appropriate debugging mode
- */
- DEBUGIF("results") {
- netsnmp_variable_list *var_ptr;
- DEBUGMSGTL(("results", "request results (status = %d):\n",
- status));
- for (var_ptr = asp->pdu->variables; var_ptr;
- var_ptr = var_ptr->next_variable) {
- DEBUGMSGTL(("results", "\t"));
- DEBUGMSGVAR(("results", var_ptr));
- DEBUGMSG(("results", "\n"));
- }
- }
-
- /*
- * check for uncompleted requests
- */
- if (netsnmp_check_for_delegated_and_add(asp)) {
- /*
- * add to delegated request chain
- */
- asp->status = status;
- } else {
- /*
- * if we don't have anything outstanding (delegated), wrap up
- */
- return netsnmp_wrap_up_request(asp, status);
- }
-
- return 1;
-}
-
-/**
- * This function calls into netsnmp_set_mode_request_error, sets
- * error_value given a reqinfo->mode value. It's used to send specific
- * errors back to the agent to process accordingly.
- *
- * If error_value is set to SNMP_NOSUCHOBJECT, SNMP_NOSUCHINSTANCE,
- * or SNMP_ENDOFMIBVIEW the following is applicable:
- * Sets the error_value to request->requestvb->type if
- * reqinfo->mode value is set to MODE_GET. If the reqinfo->mode
- * value is set to MODE_GETNEXT or MODE_GETBULK the code calls
- * snmp_log logging an error message.
- *
- * Otherwise, the request->status value is checked, if it's < 0
- * snmp_log is called with an error message and SNMP_ERR_GENERR is
- * assigned to request->status. If the request->status value is >= 0 the
- * error_value is set to request->status.
- *
- * @param reqinfo is a pointer to the netsnmp_agent_request_info struct. It
- * contains the reqinfo->mode which is required to set error_value or
- * log error messages.
- *
- * @param request is a pointer to the netsnmp_request_info struct. The
- * error_value is set to request->requestvb->type
- *
- * @param error_value is the exception value you want to set, below are
- * possible values.
- * - SNMP_NOSUCHOBJECT
- * - SNMP_NOSUCHINSTANCE
- * - SNMP_ENDOFMIBVIEW
- * - SNMP_ERR_NOERROR
- * - SNMP_ERR_TOOBIG
- * - SNMP_ERR_NOSUCHNAME
- * - SNMP_ERR_BADVALUE
- * - SNMP_ERR_READONLY
- * - SNMP_ERR_GENERR
- * - SNMP_ERR_NOACCESS
- * - SNMP_ERR_WRONGTYPE
- * - SNMP_ERR_WRONGLENGTH
- * - SNMP_ERR_WRONGENCODING
- * - SNMP_ERR_WRONGVALUE
- * - SNMP_ERR_NOCREATION
- * - SNMP_ERR_INCONSISTENTVALUE
- * - SNMP_ERR_RESOURCEUNAVAILABLE
- * - SNMP_ERR_COMMITFAILED
- * - SNMP_ERR_UNDOFAILED
- * - SNMP_ERR_AUTHORIZATIONERROR
- * - SNMP_ERR_NOTWRITABLE
- * - SNMP_ERR_INCONSISTENTNAME
- *
- * @return Returns error_value under all conditions.
- */
-int
-handle_pdu(netsnmp_agent_session *asp)
-{
- int status, inclusives = 0;
- netsnmp_variable_list *v = NULL;
-
- /*
- * for illegal requests, mark all nodes as ASN_NULL
- */
- switch (asp->pdu->command) {
-
- case SNMP_MSG_INTERNAL_SET_RESERVE2:
- case SNMP_MSG_INTERNAL_SET_ACTION:
- case SNMP_MSG_INTERNAL_SET_COMMIT:
- case SNMP_MSG_INTERNAL_SET_FREE:
- case SNMP_MSG_INTERNAL_SET_UNDO:
- status = get_set_cache(asp);
- if (status != SNMP_ERR_NOERROR)
- return status;
- break;
-
- case SNMP_MSG_GET:
- case SNMP_MSG_GETNEXT:
- case SNMP_MSG_GETBULK:
- for (v = asp->pdu->variables; v != NULL; v = v->next_variable) {
- if (v->type == ASN_PRIV_INCL_RANGE) {
- /*
- * Leave the type for now (it gets set to
- * ASN_NULL in netsnmp_add_varbind_to_cache,
- * called by create_subnetsnmp_tree_cache below).
- * If we set it to ASN_NULL now, we wouldn't be
- * able to distinguish INCLUSIVE search
- * ranges.
- */
- inclusives++;
- } else {
- snmp_set_var_typed_value(v, ASN_NULL, NULL, 0);
- }
- }
- /*
- * fall through
- */
-
- case SNMP_MSG_INTERNAL_SET_BEGIN:
- case SNMP_MSG_INTERNAL_SET_RESERVE1:
- default:
- asp->vbcount = count_varbinds(asp->pdu->variables);
- if (asp->vbcount) /* efence doesn't like 0 size allocs */
- asp->requests = (netsnmp_request_info *)
- calloc(asp->vbcount, sizeof(netsnmp_request_info));
- /*
- * collect varbinds
- */
- status = netsnmp_create_subtree_cache(asp);
- if (status != SNMP_ERR_NOERROR)
- return status;
- }
-
- asp->mode = asp->pdu->command;
- switch (asp->mode) {
- case SNMP_MSG_GET:
- /*
- * increment the message type counter
- */
- snmp_increment_statistic(STAT_SNMPINGETREQUESTS);
-
- /*
- * check vacm ahead of time
- */
- check_acm(asp, SNMP_NOSUCHOBJECT);
-
- /*
- * get the results
- */
- status = handle_var_requests(asp);
-
- /*
- * Deal with unhandled results -> noSuchInstance (rather
- * than noSuchObject -- in that case, the type will
- * already have been set to noSuchObject when we realised
- * we couldn't find an appropriate tree).
- */
- if (status == SNMP_ERR_NOERROR)
- snmp_replace_var_types(asp->pdu->variables, ASN_NULL,
- SNMP_NOSUCHINSTANCE);
- break;
-
- case SNMP_MSG_GETNEXT:
- snmp_increment_statistic(STAT_SNMPINGETNEXTS);
- /*
- * fall through
- */
-
- case SNMP_MSG_GETBULK: /* note: there is no getbulk stat */
- /*
- * loop through our mib tree till we find an
- * appropriate response to return to the caller.
- */
-
- if (inclusives) {
- /*
- * This is a special case for AgentX INCLUSIVE getNext
- * requests where a result lexi-equal to the request is okay
- * but if such a result does not exist, we still want the
- * lexi-next one. So basically we do a GET first, and if any
- * of the INCLUSIVE requests are satisfied, we use that
- * value. Then, unsatisfied INCLUSIVE requests, and
- * non-INCLUSIVE requests get done as normal.
- */
-
- DEBUGMSGTL(("snmp_agent", "inclusive range(s) in getNext\n"));
- asp->oldmode = asp->mode;
- asp->mode = SNMP_MSG_GET;
- }
-
- /*
- * first pass
- */
- status = handle_var_requests(asp);
- if (status != SNMP_ERR_NOERROR) {
- if (!inclusives)
- return status; /* should never really happen */
- else
- asp->status = SNMP_ERR_NOERROR;
- }
-
- /*
- * loop through our mib tree till we find an
- * appropriate response to return to the caller.
- */
-
- status = handle_getnext_loop(asp);
- break;
-
- case SNMP_MSG_SET:
-#ifdef NETSNMP_DISABLE_SET_SUPPORT
- return SNMP_ERR_NOTWRITABLE;
-#else
- /*
- * check access permissions first
- */
- if (check_acm(asp, SNMP_NOSUCHOBJECT))
- return SNMP_ERR_NOTWRITABLE;
-
- asp->mode = MODE_SET_BEGIN;
- status = handle_set_loop(asp);
-#endif
- break;
-
- case SNMP_MSG_INTERNAL_SET_BEGIN:
- case SNMP_MSG_INTERNAL_SET_RESERVE1:
- case SNMP_MSG_INTERNAL_SET_RESERVE2:
- case SNMP_MSG_INTERNAL_SET_ACTION:
- case SNMP_MSG_INTERNAL_SET_COMMIT:
- case SNMP_MSG_INTERNAL_SET_FREE:
- case SNMP_MSG_INTERNAL_SET_UNDO:
- asp->pdu->flags |= UCD_MSG_FLAG_ONE_PASS_ONLY;
- status = handle_set_loop(asp);
- /*
- * asp related cache is saved in cleanup
- */
- break;
-
- case SNMP_MSG_RESPONSE:
- snmp_increment_statistic(STAT_SNMPINGETRESPONSES);
- return SNMP_ERR_NOERROR;
-
- case SNMP_MSG_TRAP:
- case SNMP_MSG_TRAP2:
- snmp_increment_statistic(STAT_SNMPINTRAPS);
- return SNMP_ERR_NOERROR;
-
- default:
- /*
- * WWW: are reports counted somewhere ?
- */
- snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
- return SNMPERR_GENERR; /* shouldn't get here */
- /*
- * WWW
- */
- }
- return status;
-}
-
-/** set error for a request
- * \internal external interface: netsnmp_request_set_error
- */
-NETSNMP_STATIC_INLINE int
-_request_set_error(netsnmp_request_info *request, int mode, int error_value)
-{
- if (!request)
- return SNMPERR_NO_VARS;
-
- request->processed = 1;
- request->delegated = REQUEST_IS_NOT_DELEGATED;
-
- switch (error_value) {
- case SNMP_NOSUCHOBJECT:
- case SNMP_NOSUCHINSTANCE:
- case SNMP_ENDOFMIBVIEW:
- /*
- * these are exceptions that should be put in the varbind
- * in the case of a GET but should be translated for a SET
- * into a real error status code and put in the request
- */
- switch (mode) {
- case MODE_GET:
- case MODE_GETNEXT:
- case MODE_GETBULK:
- request->requestvb->type = error_value;
- return SNMPERR_SUCCESS;
-
- /*
- * These are technically illegal to set by the
- * client APIs for these modes. But accepting
- * them here allows the 'sparse_table' helper to
- * provide some common table handling processing
- *
- snmp_log(LOG_ERR, "Illegal error_value %d for mode %d ignored\n",
- error_value, mode);
- return SNMPERR_VALUE;
- */
-
- default:
- request->status = SNMP_ERR_NOSUCHNAME; /* WWW: correct? */
- return SNMPERR_SUCCESS;
- }
- break; /* never get here */
-
- default:
- if (error_value < 0) {
- /*
- * illegal local error code. translate to generr
- */
- /*
- * WWW: full translation map?
- */
- snmp_log(LOG_ERR, "Illegal error_value %d translated to %d\n",
- error_value, SNMP_ERR_GENERR);
- request->status = SNMP_ERR_GENERR;
- } else {
- /*
- * WWW: translations and mode checking?
- */
- request->status = error_value;
- }
- return SNMPERR_SUCCESS;
- }
- return SNMPERR_SUCCESS;
-}
-
-/** set error for a request
- * @param request request which has error
- * @param error_value error value for request
- */
-int
-netsnmp_request_set_error(netsnmp_request_info *request, int error_value)
-{
- if (!request || !request->agent_req_info)
- return SNMPERR_NO_VARS;
-
- return _request_set_error(request, request->agent_req_info->mode,
- error_value);
-}
-
-/** set error for a request within a request list
- * @param request head of the request list
- * @param error_value error value for request
- * @param idx index of the request which has the error
- */
-int
-netsnmp_request_set_error_idx(netsnmp_request_info *request,
- int error_value, int idx)
-{
- int i;
- netsnmp_request_info *req = request;
-
- if (!request || !request->agent_req_info)
- return SNMPERR_NO_VARS;
-
- /*
- * Skip to the indicated varbind
- */
- for ( i=2; i<idx; i++) {
- req = req->next;
- if (!req)
- return SNMPERR_NO_VARS;
- }
-
- return _request_set_error(req, request->agent_req_info->mode,
- error_value);
-}
-
-/** set error for all requests
- * @param requests request list
- * @param error error value for requests
- * @return SNMPERR_SUCCESS, or an error code
- */
-NETSNMP_INLINE int
-netsnmp_request_set_error_all( netsnmp_request_info *requests, int error)
-{
- int mode, rc, result = SNMPERR_SUCCESS;
-
- if((NULL == requests) || (NULL == requests->agent_req_info))
- return SNMPERR_NO_VARS;
-
- mode = requests->agent_req_info->mode; /* every req has same mode */
-
- for(; requests ; requests = requests->next) {
-
- /** paranoid sanity checks */
- netsnmp_assert(NULL != requests->agent_req_info);
- netsnmp_assert(mode == requests->agent_req_info->mode);
-
- /*
- * set error for this request. Log any errors, save the last
- * to return to the user.
- */
- if((rc = _request_set_error(requests, mode, error))) {
- snmp_log(LOG_WARNING,"got %d while setting request error\n", rc);
- result = rc;
- }
- }
- return result;
-}
-
-extern struct timeval starttime;
-
- /*
- * Return the value of 'sysUpTime' at the given marker
- */
-u_long
-netsnmp_marker_uptime(marker_t pm)
-{
- u_long res;
- marker_t start = (marker_t) & starttime;
-
- res = uatime_hdiff(start, pm);
- return res; /* atime_diff works in msec, not csec */
-}
-
- /*
- * struct timeval equivalents of these
- */
-u_long
-netsnmp_timeval_uptime(struct timeval * tv)
-{
- return netsnmp_marker_uptime((marker_t) tv);
-}
-
- /*
- * Return the current value of 'sysUpTime'
- */
-u_long
-netsnmp_get_agent_uptime(void)
-{
- struct timeval now;
- gettimeofday(&now, NULL);
-
- return netsnmp_timeval_uptime(&now);
-}
-
-
-
-NETSNMP_INLINE void
-netsnmp_agent_add_list_data(netsnmp_agent_request_info *ari,
- netsnmp_data_list *node)
-{
- if (ari) {
- if (ari->agent_data) {
- netsnmp_add_list_data(&ari->agent_data, node);
- } else {
- ari->agent_data = node;
- }
- }
-}
-
-NETSNMP_INLINE int
-netsnmp_agent_remove_list_data(netsnmp_agent_request_info *ari,
- const char * name)
-{
- if ((NULL == ari) || (NULL == ari->agent_data))
- return 1;
-
- return netsnmp_remove_list_node(&ari->agent_data, name);
-}
-
-NETSNMP_INLINE void *
-netsnmp_agent_get_list_data(netsnmp_agent_request_info *ari,
- const char *name)
-{
- if (ari) {
- return netsnmp_get_list_data(ari->agent_data, name);
- }
- return NULL;
-}
-
-NETSNMP_INLINE void
-netsnmp_free_agent_data_set(netsnmp_agent_request_info *ari)
-{
- if (ari) {
- netsnmp_free_list_data(ari->agent_data);
- }
-}
-
-NETSNMP_INLINE void
-netsnmp_free_agent_data_sets(netsnmp_agent_request_info *ari)
-{
- if (ari) {
- netsnmp_free_all_list_data(ari->agent_data);
- }
-}
-
-NETSNMP_INLINE void
-netsnmp_free_agent_request_info(netsnmp_agent_request_info *ari)
-{
- if (ari) {
- if (ari->agent_data) {
- netsnmp_free_all_list_data(ari->agent_data);
- }
- SNMP_FREE(ari);
- }
-}
-
-/*************************************************************************
- *
- * deprecated functions
- *
- */
-
-/** set error for a request
- * \deprecated, use netsnmp_request_set_error instead
- * @param reqinfo agent_request_info pointer for request
- * @param request request_info pointer
- * @param error_value error value for requests
- * @return error_value
- */
-int
-netsnmp_set_request_error(netsnmp_agent_request_info *reqinfo,
- netsnmp_request_info *request, int error_value)
-{
- if (!request || !reqinfo)
- return error_value;
-
- _request_set_error(request, reqinfo->mode, error_value);
-
- return error_value;
-}
-
-/** set error for a request
- * \deprecated, use netsnmp_request_set_error instead
- * @param mode Net-SNMP agent processing mode
- * @param request request_info pointer
- * @param error_value error value for requests
- * @return error_value
- */
-int
-netsnmp_set_mode_request_error(int mode, netsnmp_request_info *request,
- int error_value)
-{
- _request_set_error(request, mode, error_value);
-
- return error_value;
-}
-
-/** set error for all request
- * \deprecated use netsnmp_request_set_error_all
- * @param reqinfo agent_request_info pointer for requests
- * @param requests request list
- * @param error_value error value for requests
- * @return error_value
- */
-int
-netsnmp_set_all_requests_error(netsnmp_agent_request_info *reqinfo,
- netsnmp_request_info *requests,
- int error_value)
-{
- netsnmp_request_set_error_all(requests, error_value);
- return error_value;
-}
-/** @} */