diff options
Diffstat (limited to 'contrib/bsnmp/snmpd/action.c')
-rw-r--r-- | contrib/bsnmp/snmpd/action.c | 1145 |
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, + §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(); +} |