freebsd-dev/contrib/bsnmp/snmpd/action.c
2003-11-10 08:53:38 +00:00

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,
&section, &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();
}