summaryrefslogtreecommitdiff
path: root/contrib/bsnmp/snmpd/action.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bsnmp/snmpd/action.c')
-rw-r--r--contrib/bsnmp/snmpd/action.c1145
1 files changed, 1145 insertions, 0 deletions
diff --git a/contrib/bsnmp/snmpd/action.c b/contrib/bsnmp/snmpd/action.c
new file mode 100644
index 0000000000000..7c87beaf445e9
--- /dev/null
+++ b/contrib/bsnmp/snmpd/action.c
@@ -0,0 +1,1145 @@
+/*
+ * 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();
+}