234 lines
7.6 KiB
C
234 lines
7.6 KiB
C
/*
|
|
* 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 copyrighted by:
|
|
* Copyright (c) 2016 VMware, Inc. All rights reserved.
|
|
* Use is subject to license terms specified in the COPYING file
|
|
* distributed with the Net-SNMP package.
|
|
*/
|
|
|
|
#include <net-snmp/net-snmp-config.h>
|
|
|
|
#include <net-snmp/net-snmp-includes.h>
|
|
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
|
|
|
#include <net-snmp/agent/scalar_group.h>
|
|
|
|
#include <stdlib.h>
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
|
|
#include <net-snmp/agent/instance.h>
|
|
#include <net-snmp/agent/serialize.h>
|
|
|
|
static netsnmp_scalar_group*
|
|
clone_scalar_group(netsnmp_scalar_group* src)
|
|
{
|
|
netsnmp_scalar_group *t = SNMP_MALLOC_TYPEDEF(netsnmp_scalar_group);
|
|
if(t != NULL) {
|
|
t->lbound = src->lbound;
|
|
t->ubound = src->ubound;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
/** @defgroup scalar_group_group scalar_group
|
|
* Process groups of scalars.
|
|
* @ingroup leaf
|
|
* @{
|
|
*/
|
|
netsnmp_mib_handler *
|
|
netsnmp_get_scalar_group_handler(oid first, oid last)
|
|
{
|
|
netsnmp_mib_handler *ret = NULL;
|
|
netsnmp_scalar_group *sgroup = NULL;
|
|
|
|
ret = netsnmp_create_handler("scalar_group",
|
|
netsnmp_scalar_group_helper_handler);
|
|
if (ret) {
|
|
sgroup = SNMP_MALLOC_TYPEDEF(netsnmp_scalar_group);
|
|
if (NULL == sgroup) {
|
|
netsnmp_handler_free(ret);
|
|
ret = NULL;
|
|
}
|
|
else {
|
|
sgroup->lbound = first;
|
|
sgroup->ubound = last;
|
|
ret->myvoid = (void *)sgroup;
|
|
ret->data_free = free;
|
|
ret->data_clone = (void *(*)(void *))clone_scalar_group;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
netsnmp_register_scalar_group(netsnmp_handler_registration *reginfo,
|
|
oid first, oid last)
|
|
{
|
|
netsnmp_mib_handler *h1, *h2;
|
|
|
|
h1 = netsnmp_get_instance_handler();
|
|
h2 = netsnmp_get_scalar_group_handler(first, last);
|
|
|
|
if (h1 && h2) {
|
|
if (netsnmp_inject_handler(reginfo, h1) == SNMPERR_SUCCESS) {
|
|
h1 = NULL;
|
|
if (netsnmp_inject_handler(reginfo, h2) == SNMPERR_SUCCESS)
|
|
return netsnmp_register_serialize(reginfo);
|
|
}
|
|
}
|
|
|
|
snmp_log(LOG_ERR, "register read only scalar group failed\n");
|
|
netsnmp_handler_free(h1);
|
|
netsnmp_handler_free(h2);
|
|
netsnmp_handler_registration_free(reginfo);
|
|
|
|
return MIB_REGISTRATION_FAILED;
|
|
}
|
|
|
|
|
|
int
|
|
netsnmp_scalar_group_helper_handler(netsnmp_mib_handler *handler,
|
|
netsnmp_handler_registration *reginfo,
|
|
netsnmp_agent_request_info *reqinfo,
|
|
netsnmp_request_info *requests)
|
|
{
|
|
netsnmp_variable_list *var = requests->requestvb;
|
|
|
|
netsnmp_scalar_group *sgroup = (netsnmp_scalar_group *)handler->myvoid;
|
|
int ret, cmp;
|
|
int namelen;
|
|
oid subid, root_tmp[MAX_OID_LEN], *root_save;
|
|
|
|
DEBUGMSGTL(("helper:scalar_group", "Got request:\n"));
|
|
namelen = SNMP_MIN(requests->requestvb->name_length,
|
|
reginfo->rootoid_len);
|
|
cmp = snmp_oid_compare(requests->requestvb->name, namelen,
|
|
reginfo->rootoid, reginfo->rootoid_len);
|
|
|
|
DEBUGMSGTL(( "helper:scalar_group", " cmp=%d, oid:", cmp));
|
|
DEBUGMSGOID(("helper:scalar_group", var->name, var->name_length));
|
|
DEBUGMSG(( "helper:scalar_group", "\n"));
|
|
|
|
/*
|
|
* copy root oid to root_tmp, set instance to 0. (subid set later on)
|
|
* save rootoid, since we'll replace it before calling next handler,
|
|
* and need to restore it afterwards.
|
|
*/
|
|
memcpy(root_tmp, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid));
|
|
root_tmp[reginfo->rootoid_len + 1] = 0;
|
|
root_save = reginfo->rootoid;
|
|
|
|
switch (reqinfo->mode) {
|
|
/*
|
|
* The handling of "exact" requests is basically the same.
|
|
* The only difference between GET and SET requests is the
|
|
* error/exception to return on failure.
|
|
*/
|
|
#ifndef NETSNMP_NO_WRITE_SUPPORT
|
|
case MODE_SET_RESERVE1:
|
|
case MODE_SET_RESERVE2:
|
|
case MODE_SET_ACTION:
|
|
case MODE_SET_COMMIT:
|
|
case MODE_SET_UNDO:
|
|
case MODE_SET_FREE:
|
|
#endif /* NETSNMP_NO_WRITE_SUPPORT */
|
|
case MODE_GET:
|
|
ret = reqinfo->mode == MODE_GET ? SNMP_NOSUCHOBJECT : SNMP_ERR_NOCREATION;
|
|
if (cmp != 0 ||
|
|
requests->requestvb->name_length <= reginfo->rootoid_len) {
|
|
/*
|
|
* Common prefix doesn't match, or only *just* matches
|
|
* the registered root (so can't possibly match a scalar)
|
|
*/
|
|
netsnmp_set_request_error(reqinfo, requests, ret);
|
|
return SNMP_ERR_NOERROR;
|
|
} else {
|
|
/*
|
|
* Otherwise,
|
|
* extract the object subidentifier from the request,
|
|
* check this is (probably) valid, and then fudge the
|
|
* registered 'rootoid' to match, before passing the
|
|
* request off to the next handler ('scalar').
|
|
*
|
|
* Note that we don't bother checking instance subidentifiers
|
|
* here. That's left to the scalar helper.
|
|
*/
|
|
subid = requests->requestvb->name[reginfo->rootoid_len];
|
|
if (subid < sgroup->lbound ||
|
|
subid > sgroup->ubound) {
|
|
netsnmp_set_request_error(reqinfo, requests, ret);
|
|
return SNMP_ERR_NOERROR;
|
|
}
|
|
root_tmp[reginfo->rootoid_len] = subid;
|
|
reginfo->rootoid_len += 2;
|
|
reginfo->rootoid = root_tmp;
|
|
ret = netsnmp_call_next_handler(handler, reginfo, reqinfo,
|
|
requests);
|
|
reginfo->rootoid = root_save;
|
|
reginfo->rootoid_len -= 2;
|
|
return ret;
|
|
}
|
|
break;
|
|
|
|
case MODE_GETNEXT:
|
|
/*
|
|
* If we're being asked for something before (or exactly matches)
|
|
* the registered root OID, then start with the first object.
|
|
* If we're being asked for something that exactly matches an object
|
|
* OID, then that's what we pass down.
|
|
* Otherwise, we pass down the OID of the *next* object....
|
|
*/
|
|
if (cmp < 0 ||
|
|
requests->requestvb->name_length <= reginfo->rootoid_len) {
|
|
subid = sgroup->lbound;
|
|
} else if (requests->requestvb->name_length == reginfo->rootoid_len+1)
|
|
subid = requests->requestvb->name[reginfo->rootoid_len];
|
|
else
|
|
subid = requests->requestvb->name[reginfo->rootoid_len]+1;
|
|
|
|
/*
|
|
* ... always assuming this is (potentially) valid, of course.
|
|
*/
|
|
if (subid < sgroup->lbound)
|
|
subid = sgroup->lbound;
|
|
else if (subid > sgroup->ubound)
|
|
return SNMP_ERR_NOERROR;
|
|
|
|
root_tmp[reginfo->rootoid_len] = subid;
|
|
reginfo->rootoid_len += 2;
|
|
reginfo->rootoid = root_tmp;
|
|
ret = netsnmp_call_next_handler(handler, reginfo, reqinfo,
|
|
requests);
|
|
/*
|
|
* If we didn't get an answer (due to holes in the group)
|
|
* set things up to retry again.
|
|
*/
|
|
if (!requests->delegated &&
|
|
(requests->requestvb->type == ASN_NULL ||
|
|
requests->requestvb->type == SNMP_NOSUCHOBJECT ||
|
|
requests->requestvb->type == SNMP_NOSUCHINSTANCE)) {
|
|
snmp_set_var_objid(requests->requestvb,
|
|
reginfo->rootoid, reginfo->rootoid_len - 1);
|
|
requests->requestvb->name[reginfo->rootoid_len - 2] = ++subid;
|
|
requests->requestvb->type = ASN_PRIV_RETRY;
|
|
}
|
|
reginfo->rootoid = root_save;
|
|
reginfo->rootoid_len -= 2;
|
|
return ret;
|
|
}
|
|
/*
|
|
* got here only if illegal mode found
|
|
*/
|
|
return SNMP_ERR_GENERR;
|
|
}
|
|
|
|
/** @}
|
|
*/
|