blob: 34d1357e482c8668e4033f9bac162ca354eae81c [file] [log] [blame]
/*
* snmp_vars.c - return a pointer to the named variable.
*
*
*/
/***********************************************************
Copyright 1988, 1989, 1990 by Carnegie Mellon University
Copyright 1989 TGV, Incorporated
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 and TGV not be used
in advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
CMU AND TGV DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
EVENT SHALL CMU OR TGV 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.
******************************************************************/
/*
* additions, fixes and enhancements for Linux by Erik Schoenfelder
* (schoenfr@ibr.cs.tu-bs.de) 1994/1995.
* Linux additions taken from CMU to UCD stack by Jennifer Bray of Origin
* (jbray@origin-at.co.uk) 1997
*/
#include <config.h>
#if STDC_HEADERS
#include <string.h>
#include <stdlib.h>
#else
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <fcntl.h>
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif
#include <netinet/ip.h>
#if HAVE_SYS_QUEUE_H
#include <sys/queue.h>
#endif
#if HAVE_SYS_STREAM_H
#include <sys/stream.h>
#endif
#if HAVE_NET_ROUTE_H
#include <net/route.h>
#endif
#if HAVE_NETINET_IN_PCB_H
#include <netinet/in_pcb.h>
#endif
#if HAVE_INET_MIB2_H
#include <inet/mib2.h>
#endif
#include "mibincl.h"
#include "snmpv3.h"
#include "snmpusm.h"
#include "../snmplib/system.h"
#include "kernel.h"
#include "snmp_vars.h"
#include "mibgroup/struct.h"
#include "mibgroup/mib_module_includes.h"
#include "read_config.h"
#include "snmp_vars.h"
#include "agent_read_config.h"
#include "mib_module_config.h"
#include "agent_registry.h"
#if USING_MIBII_VACM_VARS_MODULE
#include "mibgroup/mibII/vacm_vars.h"
#endif
#include "snmpd.h"
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
extern struct subtree *subtrees;
int subtree_size;
int subtree_malloc_size;
/*
* Each variable name is placed in the variable table, without the
* terminating substring that determines the instance of the variable. When
* a string is found that is lexicographicly preceded by the input string,
* the function for that entry is called to find the method of access of the
* instance of the named variable. If that variable is not found, NULL is
* returned, and the search through the table continues (it will probably
* stop at the next entry). If it is found, the function returns a character
* pointer and a length or a function pointer. The former is the address
* of the operand, the latter is a write routine for the variable.
*
* u_char *
* findVar(name, length, exact, var_len, write_method)
* oid *name; IN/OUT - input name requested, output name found
* int length; IN/OUT - number of sub-ids in the in and out oid's
* int exact; IN - TRUE if an exact match was requested.
* int len; OUT - length of variable or 0 if function returned.
* int write_method; OUT - pointer to function to set variable,
* otherwise 0
*
* The writeVar function is returned to handle row addition or complex
* writes that require boundary checking or executing an action.
* This routine will be called three times for each varbind in the packet.
* The first time for each varbind, action is set to RESERVE1. The type
* and value should be checked during this pass. If any other variables
* in the MIB depend on this variable, this variable will be stored away
* (but *not* committed!) in a place where it can be found by a call to
* writeVar for a dependent variable, even in the same PDU. During
* the second pass, action is set to RESERVE2. If this variable is dependent
* on any other variables, it will check them now. It must check to see
* if any non-committed values have been stored for variables in the same
* PDU that it depends on. Sometimes resources will need to be reserved
* in the first two passes to guarantee that the operation can proceed
* during the third pass. During the third pass, if there were no errors
* in the first two passes, writeVar is called for every varbind with action
* set to COMMIT. It is now that the values should be written. If there
* were errors during the first two passes, writeVar is called in the third
* pass once for each varbind, with the action set to FREE. An opportunity
* is thus provided to free those resources reserved in the first two passes.
*
* writeVar(action, var_val, var_val_type, var_val_len, statP, name, name_len)
* int action; IN - RESERVE1, RESERVE2, COMMIT, or FREE
* u_char *var_val; IN - input or output buffer space
* u_char var_val_type; IN - type of input buffer
* int var_val_len; IN - input and output buffer len
* u_char *statP; IN - pointer to local statistic
* oid *name IN - pointer to name requested
* int name_len IN - number of sub-ids in the name
*/
long long_return;
#ifndef ibm032
u_char return_buf[258];
#else
u_char return_buf[256]; /* nee 64 */
#endif
void
init_agent (void)
{
#ifdef CAN_USE_NLIST
init_kmem("/dev/kmem");
#endif
setup_tree();
#include "mibgroup/mib_module_inits.h"
init_agent_read_config();
#ifdef TESTING
auto_nlist_print_tree(-2, 0);
#endif
} /* end init_agent() */
oid nullOid[] = {0,0};
int nullOidLen = sizeof(nullOid)/sizeof(oid);
oid sysUpTimeOid[] = {1,3,6,1,2,1,1,3,0};
int sysUpTimeOidLen = sizeof(sysUpTimeOid)/sizeof(oid);
/*
* getStatPtr - return a pointer to the named variable, as well as it's
* type, length, and access control list.
* Now uses 'search_subtree' (recursively) and 'search_subtree_vars'
* to do most of the work
*
* If an exact match for the variable name exists, it is returned. If not,
* and exact is false, the next variable lexicographically after the
* requested one is returned.
*
* If no appropriate variable can be found, NULL is returned.
*/
static int found;
static u_char *
search_subtree_vars(struct subtree *tp,
oid *name, /* IN - name of var, OUT - name matched */
size_t *namelen, /* IN -number of sub-ids in name,
OUT - subid-is in matched name */
u_char *type, /* OUT - type of matched variable */
size_t *len, /* OUT - length of matched variable */
u_short *acl, /* OUT - access control list */
int exact, /* IN - TRUE if exact match wanted */
WriteMethod **write_method,
struct snmp_pdu *pdu, /* IN - relevant auth info re PDU */
int *noSuchObject)
{
register struct variable *vp;
struct variable compat_var, *cvp = &compat_var;
register int x;
u_char *access = NULL;
int result;
oid *suffix;
size_t suffixlen;
if ( tp->variables == NULL )
return NULL;
result = compare_tree(name, *namelen, tp->name, tp->namelen);
suffixlen = *namelen - tp->namelen;
suffix = name + tp->namelen;
/* the following is part of the setup for the compatability
structure below that has been moved out of the main loop.
*/
memcpy(cvp->name, tp->name, tp->namelen * sizeof(oid));
for(x = 0, vp = tp->variables; x < tp->variables_len;
vp =(struct variable *)((char *)vp +tp->variables_width), x++){
/* if exact and ALWAYS
if next and result >= 0 */
/* and if vp->namelen != 0 -- Wes */
if (vp->namelen && (exact || result >= 0)){
result = compare_tree(suffix, suffixlen, vp->name,
vp->namelen);
}
/* if exact and result == 0
if next and result <= 0 */
/* or if vp->namelen == 0 -- Wes */
if ((!exact && (result <= 0)) || (exact && (result == 0)) ||
vp->namelen == 0) {
/* builds an old (long) style variable structure to retain
compatability with var_* functions written previously.
*/
if (vp->namelen)
memcpy((cvp->name + tp->namelen),
vp->name, vp->namelen * sizeof(oid));
cvp->namelen = tp->namelen + vp->namelen;
cvp->type = vp->type;
cvp->magic = vp->magic;
cvp->acl = vp->acl;
cvp->findVar = vp->findVar;
*write_method = NULL;
access = (*(vp->findVar))(cvp, name, namelen, exact,
len, write_method);
if (*write_method)
*acl = cvp->acl;
/* check for permission to view this part of the OID tree */
if ((access != NULL || (*write_method != NULL && exact)) &&
!in_a_view(name, namelen, pdu, cvp->type)) {
access = NULL;
*write_method = NULL;
} else if (exact){
found = TRUE;
}
/* this code is incorrect if there is
a view configuration that exludes a particular
instance of a variable. It would return noSuchObject,
which would be an error */
if (access != NULL || (*write_method != NULL && exact))
break;
}
/* if exact and result <= 0 */
if (exact && (result <= 0)){
*type = cvp->type;
*acl = cvp->acl;
if (found)
*noSuchObject = FALSE;
else
*noSuchObject = TRUE;
return NULL;
}
}
if (access != NULL || (exact && *write_method != NULL)) {
*type = cvp->type;
*acl = cvp->acl;
return access;
}
return NULL;
}
u_char *
getStatPtr(
oid *name, /* IN - name of var, OUT - name matched */
size_t *namelen, /* IN -number of sub-ids in name,
OUT - subid-is in matched name */
u_char *type, /* OUT - type of matched variable */
size_t *len, /* OUT - length of matched variable */
u_short *acl, /* OUT - access control list */
int exact, /* IN - TRUE if exact match wanted */
WriteMethod **write_method,
struct snmp_pdu *pdu, /* IN - relevant auth info re PDU */
int *noSuchObject)
{
struct subtree *tp, *prev;
oid save[MAX_OID_LEN];
size_t savelen = 0;
u_char result_type;
u_short result_acl;
u_char *search_return=NULL;
found = FALSE;
if (!exact){
memcpy(save, name, *namelen * sizeof(oid));
savelen = *namelen;
}
*write_method = NULL;
for (tp = subtrees, prev=NULL; tp != NULL ; prev=tp, tp = tp->next ) {
if ( snmp_oid_compare( tp->name, tp->namelen, name, *namelen ) >= 0 )
break;
}
if ( tp != NULL && prev != NULL &&
snmp_oid_compare( tp->name, tp->namelen, name, *namelen ) > 0 )
tp = prev;
/*
tp = find_subtree_previous(name, *namelen, NULL);
if ( tp->next &&
snmp_oid_compare( tp->next->name, tp->next->namelen,
name, *namelen ) == 0 )
tp = tp->next;
*/
while ( search_return == NULL && tp != NULL ) {
search_return = search_subtree_vars( tp, name, namelen, &result_type,
len, &result_acl, exact, write_method,
pdu, noSuchObject);
if ( search_return != NULL || (*write_method != NULL && exact))
break;
tp = tp->next;
}
if ( tp == NULL ) {
if (!search_return && !exact){
memcpy(name, save, savelen * sizeof(oid));
*namelen = savelen;
}
if (found)
*noSuchObject = FALSE;
else
*noSuchObject = TRUE;
return NULL;
}
*type = result_type;
*acl = result_acl;
return search_return;
}