1146 lines
26 KiB
C
1146 lines
26 KiB
C
/*
|
|
* Copyright (c) 2001-2003
|
|
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
|
|
* All rights reserved.
|
|
*
|
|
* Author: Harti Brandt <harti@freebsd.org>
|
|
*
|
|
* Redistribution of this software and documentation and use in source and
|
|
* binary forms, with or without modification, are permitted provided that
|
|
* the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code or documentation must retain the above
|
|
* copyright notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the Institute nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
|
|
* AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
* FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $Begemot: bsnmp/snmpd/action.c,v 1.53 2003/01/28 13:44:35 hbb Exp $
|
|
*
|
|
* Variable access for SNMPd
|
|
*/
|
|
#include <sys/types.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/un.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <syslog.h>
|
|
|
|
#include "snmpmod.h"
|
|
#include "snmpd.h"
|
|
#include "tree.h"
|
|
#include "oid.h"
|
|
|
|
static const struct asn_oid
|
|
oid_begemotSnmpdModuleTable = OIDX_begemotSnmpdModuleTable;
|
|
|
|
/*
|
|
* Get a string value from the KERN sysctl subtree.
|
|
*/
|
|
static char *
|
|
act_getkernstring(int id)
|
|
{
|
|
int mib[2];
|
|
size_t len;
|
|
char *string;
|
|
|
|
mib[0] = CTL_KERN;
|
|
mib[1] = id;
|
|
if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0)
|
|
return (NULL);
|
|
if ((string = malloc(len)) == NULL)
|
|
return (NULL);
|
|
if (sysctl(mib, 2, string, &len, NULL, 0) != 0) {
|
|
free(string);
|
|
return (NULL);
|
|
}
|
|
return (string);
|
|
}
|
|
|
|
/*
|
|
* Get an integer value from the KERN sysctl subtree.
|
|
*/
|
|
static char *
|
|
act_getkernint(int id)
|
|
{
|
|
int mib[2];
|
|
size_t len;
|
|
u_long value;
|
|
char *string;
|
|
|
|
mib[0] = CTL_KERN;
|
|
mib[1] = id;
|
|
len = sizeof(value);
|
|
if (sysctl(mib, 2, &value, &len, NULL, 0) != 0)
|
|
return (NULL);
|
|
|
|
if ((string = malloc(20)) == NULL)
|
|
return (NULL);
|
|
sprintf(string, "%lu", value);
|
|
return (string);
|
|
}
|
|
|
|
/*
|
|
* Initialize global variables of the system group.
|
|
*/
|
|
int
|
|
init_actvals(void)
|
|
{
|
|
char *v[4];
|
|
u_int i;
|
|
size_t len;
|
|
|
|
if ((systemg.name = act_getkernstring(KERN_HOSTNAME)) == NULL)
|
|
return (-1);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
v[1] = NULL;
|
|
|
|
if ((v[0] = act_getkernstring(KERN_HOSTNAME)) == NULL)
|
|
goto err;
|
|
if ((v[1] = act_getkernint(KERN_HOSTID)) == NULL)
|
|
goto err;
|
|
if ((v[2] = act_getkernstring(KERN_OSTYPE)) == NULL)
|
|
goto err;
|
|
if ((v[3] = act_getkernstring(KERN_OSRELEASE)) == NULL)
|
|
goto err;
|
|
|
|
for (i = 0, len = 0; i < 4; i++)
|
|
len += strlen(v[i]) + 1;
|
|
|
|
if ((systemg.descr = malloc(len)) == NULL)
|
|
goto err;
|
|
sprintf(systemg.descr, "%s %s %s %s", v[0], v[1], v[2], v[3]);
|
|
|
|
return (0);
|
|
|
|
err:
|
|
for (i = 0; i < 4; i++)
|
|
if (v[i] != NULL)
|
|
free(v[i]);
|
|
return (-1);
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************
|
|
*
|
|
* System group
|
|
*/
|
|
int
|
|
op_system_group(struct snmp_context *ctx, struct snmp_value *value,
|
|
u_int sub, u_int iidx __unused, enum snmp_op op)
|
|
{
|
|
asn_subid_t which = value->var.subs[sub - 1];
|
|
|
|
switch (op) {
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
abort();
|
|
|
|
case SNMP_OP_GET:
|
|
break;
|
|
|
|
case SNMP_OP_SET:
|
|
switch (which) {
|
|
|
|
case LEAF_sysDescr:
|
|
if (community != COMM_INITIALIZE)
|
|
return (SNMP_ERR_NOT_WRITEABLE);
|
|
return (string_save(value, ctx, -1, &systemg.descr));
|
|
|
|
case LEAF_sysObjectId:
|
|
if (community != COMM_INITIALIZE)
|
|
return (SNMP_ERR_NOT_WRITEABLE);
|
|
return (oid_save(value, ctx, &systemg.object_id));
|
|
|
|
case LEAF_sysContact:
|
|
return (string_save(value, ctx, -1, &systemg.contact));
|
|
|
|
case LEAF_sysName:
|
|
return (string_save(value, ctx, -1, &systemg.name));
|
|
|
|
case LEAF_sysLocation:
|
|
return (string_save(value, ctx, -1, &systemg.location));
|
|
}
|
|
return (SNMP_ERR_NO_CREATION);
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
switch (which) {
|
|
|
|
case LEAF_sysDescr:
|
|
string_rollback(ctx, &systemg.descr);
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_sysObjectId:
|
|
oid_rollback(ctx, &systemg.object_id);
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_sysContact:
|
|
string_rollback(ctx, &systemg.contact);
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_sysName:
|
|
string_rollback(ctx, &systemg.name);
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_sysLocation:
|
|
string_rollback(ctx, &systemg.location);
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_COMMIT:
|
|
switch (which) {
|
|
|
|
case LEAF_sysDescr:
|
|
string_commit(ctx);
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_sysObjectId:
|
|
oid_commit(ctx);
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_sysContact:
|
|
string_commit(ctx);
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_sysName:
|
|
string_commit(ctx);
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_sysLocation:
|
|
string_commit(ctx);
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
}
|
|
|
|
/*
|
|
* Come here for GET.
|
|
*/
|
|
switch (which) {
|
|
|
|
case LEAF_sysDescr:
|
|
return (string_get(value, systemg.descr, -1));
|
|
case LEAF_sysObjectId:
|
|
return (oid_get(value, &systemg.object_id));
|
|
case LEAF_sysUpTime:
|
|
value->v.uint32 = get_ticks() - start_tick;
|
|
break;
|
|
case LEAF_sysContact:
|
|
return (string_get(value, systemg.contact, -1));
|
|
case LEAF_sysName:
|
|
return (string_get(value, systemg.name, -1));
|
|
case LEAF_sysLocation:
|
|
return (string_get(value, systemg.location, -1));
|
|
case LEAF_sysServices:
|
|
value->v.integer = systemg.services;
|
|
break;
|
|
case LEAF_sysORLastChange:
|
|
value->v.uint32 = systemg.or_last_change;
|
|
break;
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
/*************************************************************
|
|
*
|
|
* Debug group
|
|
*/
|
|
int
|
|
op_debug(struct snmp_context *ctx, struct snmp_value *value, u_int sub,
|
|
u_int iidx __unused, enum snmp_op op)
|
|
{
|
|
asn_subid_t which = value->var.subs[sub - 1];
|
|
|
|
switch (op) {
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
abort();
|
|
|
|
case SNMP_OP_GET:
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdDebugDumpPdus:
|
|
value->v.integer = TRUTH_MK(debug.dump_pdus);
|
|
break;
|
|
|
|
case LEAF_begemotSnmpdDebugSnmpTrace:
|
|
value->v.uint32 = snmp_trace;
|
|
break;
|
|
|
|
case LEAF_begemotSnmpdDebugSyslogPri:
|
|
value->v.integer = debug.logpri;
|
|
break;
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_SET:
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdDebugDumpPdus:
|
|
if (!TRUTH_OK(value->v.integer))
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
ctx->scratch->int1 = debug.dump_pdus;
|
|
debug.dump_pdus = TRUTH_GET(value->v.integer);
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotSnmpdDebugSnmpTrace:
|
|
ctx->scratch->int1 = snmp_trace;
|
|
snmp_trace = value->v.uint32;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotSnmpdDebugSyslogPri:
|
|
if (value->v.integer < 0 || value->v.integer > 8)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
ctx->scratch->int1 = debug.logpri;
|
|
debug.logpri = (u_int)value->v.integer;
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
return (SNMP_ERR_NO_CREATION);
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdDebugDumpPdus:
|
|
debug.dump_pdus = ctx->scratch->int1;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotSnmpdDebugSnmpTrace:
|
|
snmp_trace = ctx->scratch->int1;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotSnmpdDebugSyslogPri:
|
|
debug.logpri = ctx->scratch->int1;
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_COMMIT:
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdDebugDumpPdus:
|
|
case LEAF_begemotSnmpdDebugSnmpTrace:
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotSnmpdDebugSyslogPri:
|
|
if (debug.logpri == 0)
|
|
setlogmask(0);
|
|
else
|
|
setlogmask(LOG_UPTO(debug.logpri - 1));
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
}
|
|
abort();
|
|
}
|
|
|
|
/*************************************************************
|
|
*
|
|
* OR Table
|
|
*/
|
|
int
|
|
op_or_table(struct snmp_context *ctx __unused, struct snmp_value *value,
|
|
u_int sub, u_int iidx __unused, enum snmp_op op)
|
|
{
|
|
struct objres *objres;
|
|
|
|
switch (op) {
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
if ((objres = NEXT_OBJECT_INT(&objres_list, &value->var, sub))
|
|
== NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
value->var.subs[sub] = objres->index;
|
|
value->var.len = sub + 1;
|
|
break;
|
|
|
|
case SNMP_OP_GET:
|
|
if ((objres = FIND_OBJECT_INT(&objres_list, &value->var, sub))
|
|
== NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
break;
|
|
|
|
case SNMP_OP_SET:
|
|
if ((objres = FIND_OBJECT_INT(&objres_list, &value->var, sub))
|
|
== NULL)
|
|
return (SNMP_ERR_NO_CREATION);
|
|
return (SNMP_ERR_NOT_WRITEABLE);
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
case SNMP_OP_COMMIT:
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
/*
|
|
* Come here for GET, GETNEXT.
|
|
*/
|
|
switch (value->var.subs[sub - 1]) {
|
|
|
|
case LEAF_sysORID:
|
|
value->v.oid = objres->oid;
|
|
break;
|
|
|
|
case LEAF_sysORDescr:
|
|
return (string_get(value, objres->descr, -1));
|
|
|
|
case LEAF_sysORUpTime:
|
|
value->v.uint32 = objres->uptime;
|
|
break;
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
/*************************************************************
|
|
*
|
|
* mib-2 snmp
|
|
*/
|
|
int
|
|
op_snmp(struct snmp_context *ctx, struct snmp_value *value,
|
|
u_int sub, u_int iidx __unused, enum snmp_op op)
|
|
{
|
|
switch (op) {
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
abort();
|
|
|
|
case SNMP_OP_GET:
|
|
switch (value->var.subs[sub - 1]) {
|
|
|
|
case LEAF_snmpInPkts:
|
|
value->v.uint32 = snmpd_stats.inPkts;
|
|
break;
|
|
|
|
case LEAF_snmpInBadVersions:
|
|
value->v.uint32 = snmpd_stats.inBadVersions;
|
|
break;
|
|
|
|
case LEAF_snmpInBadCommunityNames:
|
|
value->v.uint32 = snmpd_stats.inBadCommunityNames;
|
|
break;
|
|
|
|
case LEAF_snmpInBadCommunityUses:
|
|
value->v.uint32 = snmpd_stats.inBadCommunityUses;
|
|
break;
|
|
|
|
case LEAF_snmpInASNParseErrs:
|
|
value->v.uint32 = snmpd_stats.inASNParseErrs;
|
|
break;
|
|
|
|
case LEAF_snmpEnableAuthenTraps:
|
|
value->v.integer = TRUTH_MK(snmpd.auth_traps);
|
|
break;
|
|
|
|
case LEAF_snmpSilentDrops:
|
|
value->v.uint32 = snmpd_stats.silentDrops;
|
|
break;
|
|
|
|
case LEAF_snmpProxyDrops:
|
|
value->v.uint32 = snmpd_stats.proxyDrops;
|
|
break;
|
|
|
|
default:
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_SET:
|
|
switch (value->var.subs[sub - 1]) {
|
|
case LEAF_snmpEnableAuthenTraps:
|
|
if (!TRUTH_OK(value->v.integer))
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
ctx->scratch->int1 = value->v.integer;
|
|
snmpd.auth_traps = TRUTH_GET(value->v.integer);
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
switch (value->var.subs[sub - 1]) {
|
|
case LEAF_snmpEnableAuthenTraps:
|
|
snmpd.auth_traps = ctx->scratch->int1;
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_COMMIT:
|
|
switch (value->var.subs[sub - 1]) {
|
|
case LEAF_snmpEnableAuthenTraps:
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
}
|
|
abort();
|
|
}
|
|
|
|
/*************************************************************
|
|
*
|
|
* SNMPd statistics group
|
|
*/
|
|
int
|
|
op_snmpd_stats(struct snmp_context *ctx __unused, struct snmp_value *value,
|
|
u_int sub, u_int iidx __unused, enum snmp_op op)
|
|
{
|
|
switch (op) {
|
|
|
|
case SNMP_OP_GET:
|
|
switch (value->var.subs[sub - 1]) {
|
|
|
|
case LEAF_begemotSnmpdStatsNoRxBufs:
|
|
value->v.uint32 = snmpd_stats.noRxbuf;
|
|
break;
|
|
|
|
case LEAF_begemotSnmpdStatsNoTxBufs:
|
|
value->v.uint32 = snmpd_stats.noTxbuf;
|
|
break;
|
|
|
|
case LEAF_begemotSnmpdStatsInTooLongPkts:
|
|
value->v.uint32 = snmpd_stats.inTooLong;
|
|
break;
|
|
|
|
case LEAF_begemotSnmpdStatsInBadPduTypes:
|
|
value->v.uint32 = snmpd_stats.inBadPduTypes;
|
|
break;
|
|
|
|
default:
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_SET:
|
|
case SNMP_OP_ROLLBACK:
|
|
case SNMP_OP_COMMIT:
|
|
case SNMP_OP_GETNEXT:
|
|
abort();
|
|
}
|
|
abort();
|
|
}
|
|
|
|
/*
|
|
* SNMPd configuration scalars
|
|
*/
|
|
int
|
|
op_snmpd_config(struct snmp_context *ctx, struct snmp_value *value,
|
|
u_int sub, u_int iidx __unused, enum snmp_op op)
|
|
{
|
|
asn_subid_t which = value->var.subs[sub - 1];
|
|
|
|
switch (op) {
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
abort();
|
|
|
|
case SNMP_OP_GET:
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdTransmitBuffer:
|
|
value->v.integer = snmpd.txbuf;
|
|
break;
|
|
case LEAF_begemotSnmpdReceiveBuffer:
|
|
value->v.integer = snmpd.rxbuf;
|
|
break;
|
|
case LEAF_begemotSnmpdCommunityDisable:
|
|
value->v.integer = TRUTH_MK(snmpd.comm_dis);
|
|
break;
|
|
case LEAF_begemotSnmpdTrap1Addr:
|
|
return (ip_get(value, snmpd.trap1addr));
|
|
default:
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_SET:
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdTransmitBuffer:
|
|
ctx->scratch->int1 = snmpd.txbuf;
|
|
if (value->v.integer < 484 ||
|
|
value->v.integer > 65535)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
snmpd.txbuf = value->v.integer;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotSnmpdReceiveBuffer:
|
|
ctx->scratch->int1 = snmpd.rxbuf;
|
|
if (value->v.integer < 484 ||
|
|
value->v.integer > 65535)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
snmpd.rxbuf = value->v.integer;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotSnmpdCommunityDisable:
|
|
ctx->scratch->int1 = snmpd.comm_dis;
|
|
if (!TRUTH_OK(value->v.integer))
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
if (TRUTH_GET(value->v.integer)) {
|
|
snmpd.comm_dis = 1;
|
|
} else {
|
|
if (snmpd.comm_dis)
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case LEAF_begemotSnmpdTrap1Addr:
|
|
return (ip_save(value, ctx, snmpd.trap1addr));
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdTransmitBuffer:
|
|
snmpd.rxbuf = ctx->scratch->int1;
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_begemotSnmpdReceiveBuffer:
|
|
snmpd.txbuf = ctx->scratch->int1;
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_begemotSnmpdCommunityDisable:
|
|
snmpd.comm_dis = ctx->scratch->int1;
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_begemotSnmpdTrap1Addr:
|
|
ip_rollback(ctx, snmpd.trap1addr);
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_COMMIT:
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdTransmitBuffer:
|
|
case LEAF_begemotSnmpdReceiveBuffer:
|
|
case LEAF_begemotSnmpdCommunityDisable:
|
|
return (SNMP_ERR_NOERROR);
|
|
case LEAF_begemotSnmpdTrap1Addr:
|
|
ip_commit(ctx);
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
}
|
|
abort();
|
|
}
|
|
|
|
/*
|
|
* The community table
|
|
*/
|
|
int
|
|
op_community(struct snmp_context *ctx, struct snmp_value *value,
|
|
u_int sub, u_int iidx __unused, enum snmp_op op)
|
|
{
|
|
asn_subid_t which = value->var.subs[sub - 1];
|
|
struct community *c;
|
|
|
|
switch (op) {
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
if ((community != COMM_INITIALIZE && snmpd.comm_dis) ||
|
|
(c = NEXT_OBJECT_OID(&community_list, &value->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
index_append(&value->var, sub, &c->index);
|
|
break;
|
|
|
|
case SNMP_OP_GET:
|
|
if ((community != COMM_INITIALIZE && snmpd.comm_dis) ||
|
|
(c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
break;
|
|
|
|
case SNMP_OP_SET:
|
|
if ((community != COMM_INITIALIZE && snmpd.comm_dis) ||
|
|
(c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL)
|
|
return (SNMP_ERR_NO_CREATION);
|
|
if (which != LEAF_begemotSnmpdCommunityString)
|
|
return (SNMP_ERR_NOT_WRITEABLE);
|
|
return (string_save(value, ctx, -1, &c->string));
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
if (which == LEAF_begemotSnmpdCommunityString) {
|
|
if ((c = FIND_OBJECT_OID(&community_list, &value->var,
|
|
sub)) == NULL)
|
|
string_free(ctx);
|
|
else
|
|
string_rollback(ctx, &c->string);
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
|
|
case SNMP_OP_COMMIT:
|
|
if (which == LEAF_begemotSnmpdCommunityString) {
|
|
if ((c = FIND_OBJECT_OID(&community_list, &value->var,
|
|
sub)) == NULL)
|
|
string_free(ctx);
|
|
else
|
|
string_commit(ctx);
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdCommunityString:
|
|
return (string_get(value, c->string, -1));
|
|
|
|
case LEAF_begemotSnmpdCommunityDescr:
|
|
return (string_get(value, c->descr, -1));
|
|
}
|
|
abort();
|
|
}
|
|
|
|
/*
|
|
* Port table
|
|
*/
|
|
int
|
|
op_snmp_port(struct snmp_context *ctx, struct snmp_value *value,
|
|
u_int sub, u_int iidx, enum snmp_op op)
|
|
{
|
|
asn_subid_t which = value->var.subs[sub-1];
|
|
struct snmp_port *p;
|
|
u_int8_t addr[4];
|
|
u_int32_t port;
|
|
|
|
switch (op) {
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
if ((p = NEXT_OBJECT_OID(&snmp_port_list, &value->var, sub))
|
|
== NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
index_append(&value->var, sub, &p->index);
|
|
break;
|
|
|
|
case SNMP_OP_GET:
|
|
if ((p = FIND_OBJECT_OID(&snmp_port_list, &value->var, sub))
|
|
== NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
break;
|
|
|
|
case SNMP_OP_SET:
|
|
p = FIND_OBJECT_OID(&snmp_port_list, &value->var, sub);
|
|
ctx->scratch->int1 = (p != NULL);
|
|
|
|
if (which != LEAF_begemotSnmpdPortStatus)
|
|
abort();
|
|
if (!TRUTH_OK(value->v.integer))
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int2 = TRUTH_GET(value->v.integer);
|
|
|
|
if (ctx->scratch->int2) {
|
|
/* open an SNMP port */
|
|
if (p != NULL)
|
|
/* already open - do nothing */
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
if (index_decode(&value->var, sub, iidx, addr, &port))
|
|
return (SNMP_ERR_NO_CREATION);
|
|
return (open_snmp_port(addr, port, &p));
|
|
|
|
} else {
|
|
/* close SNMP port - do in commit */
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
p = FIND_OBJECT_OID(&snmp_port_list, &value->var, sub);
|
|
if (ctx->scratch->int1 == 0) {
|
|
/* did not exist */
|
|
if (ctx->scratch->int2 == 1) {
|
|
/* created */
|
|
if (p != NULL)
|
|
close_snmp_port(p);
|
|
}
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_COMMIT:
|
|
p = FIND_OBJECT_OID(&snmp_port_list, &value->var, sub);
|
|
if (ctx->scratch->int1 == 1) {
|
|
/* did exist */
|
|
if (ctx->scratch->int2 == 0) {
|
|
/* delete */
|
|
if (p != NULL)
|
|
close_snmp_port(p);
|
|
}
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
/*
|
|
* Come here to fetch the value
|
|
*/
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdPortStatus:
|
|
value->v.integer = 1;
|
|
break;
|
|
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
/*
|
|
* Local port table
|
|
*/
|
|
int
|
|
op_local_port(struct snmp_context *ctx, struct snmp_value *value,
|
|
u_int sub, u_int iidx, enum snmp_op op)
|
|
{
|
|
asn_subid_t which = value->var.subs[sub-1];
|
|
struct local_port *p;
|
|
u_char *name;
|
|
size_t namelen;
|
|
|
|
switch (op) {
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
if ((p = NEXT_OBJECT_OID(&local_port_list, &value->var, sub))
|
|
== NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
index_append(&value->var, sub, &p->index);
|
|
break;
|
|
|
|
case SNMP_OP_GET:
|
|
if ((p = FIND_OBJECT_OID(&local_port_list, &value->var, sub))
|
|
== NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
break;
|
|
|
|
case SNMP_OP_SET:
|
|
p = FIND_OBJECT_OID(&local_port_list, &value->var, sub);
|
|
ctx->scratch->int1 = (p != NULL);
|
|
|
|
if (which != LEAF_begemotSnmpdLocalPortStatus)
|
|
abort();
|
|
if (!TRUTH_OK(value->v.integer))
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
|
|
ctx->scratch->int2 = TRUTH_GET(value->v.integer);
|
|
|
|
if (ctx->scratch->int2) {
|
|
/* open a local port */
|
|
if (p != NULL)
|
|
/* already open - do nothing */
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
if (index_decode(&value->var, sub, iidx,
|
|
&name, &namelen))
|
|
return (SNMP_ERR_NO_CREATION);
|
|
return (open_local_port(name, namelen, &p));
|
|
|
|
} else {
|
|
/* close local port - do in commit */
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
p = FIND_OBJECT_OID(&local_port_list, &value->var, sub);
|
|
if (ctx->scratch->int1 == 0) {
|
|
/* did not exist */
|
|
if (ctx->scratch->int2 == 1) {
|
|
/* created */
|
|
if (p != NULL)
|
|
close_local_port(p);
|
|
}
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_COMMIT:
|
|
p = FIND_OBJECT_OID(&local_port_list, &value->var, sub);
|
|
if (ctx->scratch->int1 == 1) {
|
|
/* did exist */
|
|
if (ctx->scratch->int2 == 0) {
|
|
/* delete */
|
|
if (p != NULL)
|
|
close_local_port(p);
|
|
}
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
/*
|
|
* Come here to fetch the value
|
|
*/
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdLocalPortStatus:
|
|
value->v.integer = 1;
|
|
break;
|
|
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Module table.
|
|
*/
|
|
struct module_dep {
|
|
struct snmp_dependency dep;
|
|
u_char section[LM_SECTION_MAX + 1];
|
|
u_char *path;
|
|
struct lmodule *m;
|
|
};
|
|
|
|
static void
|
|
finish_unload(struct snmp_context *ctx __unused, int fail, void *arg)
|
|
{
|
|
struct lmodule *m = arg;
|
|
|
|
if (!fail) {
|
|
lm_unload(m);
|
|
}
|
|
}
|
|
|
|
static void
|
|
finish_load(struct snmp_context *ctx __unused, int fail, void *arg)
|
|
{
|
|
struct lmodule *m = arg;
|
|
|
|
if (!fail) {
|
|
lm_start(m);
|
|
}
|
|
}
|
|
|
|
static int
|
|
dep_modules(struct snmp_context *ctx, struct snmp_dependency *dep,
|
|
enum snmp_depop op)
|
|
{
|
|
struct module_dep *mdep = (struct module_dep *)(void *)dep;
|
|
|
|
switch (op) {
|
|
|
|
case SNMP_DEPOP_COMMIT:
|
|
if (mdep->path == NULL) {
|
|
/* unload - find the module */
|
|
TAILQ_FOREACH(mdep->m, &lmodules, link)
|
|
if (strcmp(mdep->m->section, mdep->section) == 0)
|
|
break;
|
|
if (mdep->m == NULL)
|
|
return (SNMP_ERR_NOERROR);
|
|
if (snmp_set_atfinish(ctx, finish_unload, mdep->m))
|
|
return (SNMP_ERR_RES_UNAVAIL);
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
/* load */
|
|
if ((mdep->m = lm_load(mdep->path, mdep->section)) == NULL)
|
|
return (SNMP_ERR_RES_UNAVAIL);
|
|
if (snmp_set_atfinish(ctx, finish_load, mdep->m)) {
|
|
lm_unload(mdep->m);
|
|
return (SNMP_ERR_RES_UNAVAIL);
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_DEPOP_ROLLBACK:
|
|
if (mdep->path == NULL) {
|
|
/* rollback unload - the finish function takes care */
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
/* rollback load */
|
|
lm_unload(mdep->m);
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
}
|
|
|
|
int
|
|
op_modules(struct snmp_context *ctx, struct snmp_value *value,
|
|
u_int sub, u_int iidx, enum snmp_op op)
|
|
{
|
|
asn_subid_t which = value->var.subs[sub - 1];
|
|
struct lmodule *m;
|
|
u_char *section, *ptr;
|
|
size_t seclen;
|
|
struct module_dep *mdep;
|
|
struct asn_oid idx;
|
|
|
|
switch (op) {
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
if ((m = NEXT_OBJECT_OID(&lmodules, &value->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
index_append(&value->var, sub, &m->index);
|
|
break;
|
|
|
|
case SNMP_OP_GET:
|
|
if ((m = FIND_OBJECT_OID(&lmodules, &value->var, sub)) == NULL)
|
|
return (SNMP_ERR_NOSUCHNAME);
|
|
break;
|
|
|
|
case SNMP_OP_SET:
|
|
m = FIND_OBJECT_OID(&lmodules, &value->var, sub);
|
|
if (which != LEAF_begemotSnmpdModulePath) {
|
|
if (m == NULL)
|
|
return (SNMP_ERR_NO_CREATION);
|
|
return (SNMP_ERR_NOT_WRITEABLE);
|
|
}
|
|
|
|
/* the errors in the next few statements can only happen when
|
|
* m is NULL, hence the NO_CREATION error. */
|
|
if (index_decode(&value->var, sub, iidx,
|
|
§ion, &seclen))
|
|
return (SNMP_ERR_NO_CREATION);
|
|
|
|
/* check the section name */
|
|
if (seclen > LM_SECTION_MAX || seclen == 0) {
|
|
free(section);
|
|
return (SNMP_ERR_NO_CREATION);
|
|
}
|
|
for (ptr = section; ptr < section + seclen; ptr++)
|
|
if (!isascii(*ptr) || !isalnum(*ptr)) {
|
|
free(section);
|
|
return (SNMP_ERR_NO_CREATION);
|
|
}
|
|
if (!isalpha(section[0])) {
|
|
free(section);
|
|
return (SNMP_ERR_NO_CREATION);
|
|
}
|
|
|
|
/* check the path */
|
|
for (ptr = value->v.octetstring.octets;
|
|
ptr < value->v.octetstring.octets + value->v.octetstring.len;
|
|
ptr++) {
|
|
if (*ptr == '\0') {
|
|
free(section);
|
|
return (SNMP_ERR_WRONG_VALUE);
|
|
}
|
|
}
|
|
|
|
if (m == NULL) {
|
|
if (value->v.octetstring.len == 0) {
|
|
free(section);
|
|
return (SNMP_ERR_INCONS_VALUE);
|
|
}
|
|
} else {
|
|
if (value->v.octetstring.len != 0) {
|
|
free(section);
|
|
return (SNMP_ERR_INCONS_VALUE);
|
|
}
|
|
}
|
|
|
|
asn_slice_oid(&idx, &value->var, sub, value->var.len);
|
|
|
|
/* so far, so good */
|
|
mdep = (struct module_dep *)(void *)snmp_dep_lookup(ctx,
|
|
&oid_begemotSnmpdModuleTable, &idx,
|
|
sizeof(*mdep), dep_modules);
|
|
if (mdep == NULL) {
|
|
free(section);
|
|
return (SNMP_ERR_RES_UNAVAIL);
|
|
}
|
|
|
|
if (mdep->section[0] != '\0') {
|
|
/* two writes to the same entry - bad */
|
|
free(section);
|
|
return (SNMP_ERR_INCONS_VALUE);
|
|
}
|
|
|
|
strncpy(mdep->section, section, seclen);
|
|
mdep->section[seclen] = '\0';
|
|
free(section);
|
|
|
|
if (value->v.octetstring.len == 0)
|
|
mdep->path = NULL;
|
|
else {
|
|
if ((mdep->path = malloc(value->v.octetstring.len + 1)) == NULL)
|
|
return (SNMP_ERR_RES_UNAVAIL);
|
|
strncpy(mdep->path, value->v.octetstring.octets,
|
|
value->v.octetstring.len);
|
|
mdep->path[value->v.octetstring.len] = '\0';
|
|
}
|
|
ctx->scratch->ptr1 = mdep;
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
/* must be module path */
|
|
free(ctx->scratch->ptr1);
|
|
case SNMP_OP_COMMIT:
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
switch (which) {
|
|
|
|
case LEAF_begemotSnmpdModulePath:
|
|
return (string_get(value, m->path, -1));
|
|
|
|
case LEAF_begemotSnmpdModuleComment:
|
|
return (string_get(value, m->config->comment, -1));
|
|
}
|
|
abort();
|
|
}
|
|
|
|
int
|
|
op_snmp_set(struct snmp_context *ctx __unused, struct snmp_value *value,
|
|
u_int sub, u_int iidx __unused, enum snmp_op op)
|
|
{
|
|
switch (op) {
|
|
|
|
case SNMP_OP_GETNEXT:
|
|
abort();
|
|
|
|
case SNMP_OP_GET:
|
|
switch (value->var.subs[sub - 1]) {
|
|
|
|
case LEAF_snmpSetSerialNo:
|
|
value->v.integer = snmp_serial_no;
|
|
break;
|
|
|
|
default:
|
|
abort();
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_SET:
|
|
switch (value->var.subs[sub - 1]) {
|
|
|
|
case LEAF_snmpSetSerialNo:
|
|
if (value->v.integer != snmp_serial_no)
|
|
return (SNMP_ERR_INCONS_VALUE);
|
|
break;
|
|
|
|
default:
|
|
abort();
|
|
}
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_ROLLBACK:
|
|
return (SNMP_ERR_NOERROR);
|
|
|
|
case SNMP_OP_COMMIT:
|
|
if (snmp_serial_no++ == 2147483647)
|
|
snmp_serial_no = 0;
|
|
return (SNMP_ERR_NOERROR);
|
|
}
|
|
abort();
|
|
}
|