diff options
author | Hartmut Brandt <harti@FreeBSD.org> | 2003-11-10 08:53:38 +0000 |
---|---|---|
committer | Hartmut Brandt <harti@FreeBSD.org> | 2003-11-10 08:53:38 +0000 |
commit | f06ca4af1879f1cb903660d2a12ba7edcf152938 (patch) | |
tree | 150e45ef74a56ce93475bd8e0436d6da856d4a18 /contrib/bsnmp/snmpd | |
download | src-f06ca4af1879f1cb903660d2a12ba7edcf152938.tar.gz src-f06ca4af1879f1cb903660d2a12ba7edcf152938.zip |
Virgin import of bsnmp 1.4vendor/bsnmp/1.4
Notes
Notes:
svn path=/vendor/bsnmp/dist/; revision=122394
svn path=/vendor/bsnmp/1.4/; revision=122396; tag=vendor/bsnmp/1.4
Diffstat (limited to 'contrib/bsnmp/snmpd')
-rw-r--r-- | contrib/bsnmp/snmpd/.gdbinit | 2 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/BEGEMOT-MIB.txt | 63 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/BEGEMOT-SNMPD.txt | 482 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/FOKUS-MIB.txt | 61 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/action.c | 1145 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/bsnmpd.1 | 256 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/config.c | 1361 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/export.c | 378 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/main.c | 2038 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/snmpd.config | 92 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/snmpd.h | 277 | ||||
-rwxr-xr-x | contrib/bsnmp/snmpd/snmpd.sh | 89 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/snmpmod.3 | 861 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/snmpmod.h | 363 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/trap.c | 475 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/tree.def | 183 |
16 files changed, 8126 insertions, 0 deletions
diff --git a/contrib/bsnmp/snmpd/.gdbinit b/contrib/bsnmp/snmpd/.gdbinit new file mode 100644 index 000000000000..acfacec5d828 --- /dev/null +++ b/contrib/bsnmp/snmpd/.gdbinit @@ -0,0 +1,2 @@ +dir ../snmp_netgraph +dir ../snmp_mibII diff --git a/contrib/bsnmp/snmpd/BEGEMOT-MIB.txt b/contrib/bsnmp/snmpd/BEGEMOT-MIB.txt new file mode 100644 index 000000000000..f2822763777e --- /dev/null +++ b/contrib/bsnmp/snmpd/BEGEMOT-MIB.txt @@ -0,0 +1,63 @@ +-- +-- 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/BEGEMOT-MIB.txt,v 1.3 2002/02/06 12:43:51 hbb Exp $ +-- +-- Begemot private definitions and root. +-- +BEGEMOT-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY + FROM SNMPv2-SMI + fokus + FROM FOKUS-MIB; + +begemot MODULE-IDENTITY + LAST-UPDATED "200201300000Z" + ORGANIZATION "Fraunhofer FOKUS, CATS" + CONTACT-INFO + " Hartmut Brandt + + Postal: Fraunhofer Institute for Open Communication Systems + Kaiserin-Augusta-Allee 31 + 10589 Berlin + Germany + + Fax: +49 30 3463 7352 + + E-mail: harti@freebsd.org" + DESCRIPTION + "The root of the Begemot subtree of the fokus tree." + ::= { fokus 1 } + +END diff --git a/contrib/bsnmp/snmpd/BEGEMOT-SNMPD.txt b/contrib/bsnmp/snmpd/BEGEMOT-SNMPD.txt new file mode 100644 index 000000000000..8c0996b11562 --- /dev/null +++ b/contrib/bsnmp/snmpd/BEGEMOT-SNMPD.txt @@ -0,0 +1,482 @@ +-- +-- 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/BEGEMOT-SNMPD.txt,v 1.18 2002/12/11 15:54:07 hbb Exp $ +-- +-- Begemot Private SNMPd MIB. +-- +BEGEMOT-SNMPD-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, OBJECT-IDENTITY, Counter32, + Unsigned32 + FROM SNMPv2-SMI + TEXTUAL-CONVENTION, TruthValue, RowStatus + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP + FROM SNMPv2-CONF + begemot + FROM BEGEMOT-MIB; + +begemotSnmpd MODULE-IDENTITY + LAST-UPDATED "200212040000Z" + ORGANIZATION "Fraunhofer FOKUS, CATS" + CONTACT-INFO + " Hartmut Brandt + + Postal: Fraunhofer Institute for Open Communication Systems + Kaiserin-Augusta-Allee 31 + 10589 Berlin + Germany + + Fax: +49 30 3463 7352 + + E-mail: harti@freebsd.org" + DESCRIPTION + "The MIB module for the Begemot SNMP daemon." + ::= { begemot 1 } + +begemotSnmpdObjects OBJECT IDENTIFIER ::= { begemotSnmpd 1 } +begemotSnmpdDefs OBJECT IDENTIFIER ::= { begemotSnmpd 2 } + +-- -------------------------------------------------------------------------- + +SectionName ::= TEXTUAL-CONVENTION + DISPLAY-HINT "14a" + STATUS current + DESCRIPTION + "Name of a loadable module. Should consist of alphanumeric characers + only, the first character must be a letter." + SYNTAX OCTET STRING (SIZE(1..14)) + +-- -------------------------------------------------------------------------- +-- +-- Agent types +-- +begemotSnmpdAgent OBJECT IDENTIFIER ::= { begemotSnmpdDefs 1 } + +begemotSnmpdAgentFreeBSD OBJECT-IDENTITY + STATUS current + DESCRIPTION + "Identifies the agent as running on FreeBSD." + ::= { begemotSnmpdAgent 1 } + +-- -------------------------------------------------------------------------- +-- +-- The Config Group +-- +begemotSnmpdConfig OBJECT IDENTIFIER ::= { begemotSnmpdObjects 1 } + +begemotSnmpdTransmitBuffer OBJECT-TYPE + SYNTAX INTEGER (484..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The size of the receive buffer in bytes. Larger messages + are dropped by SNMPd." + DEFVAL { 2048 } + ::= { begemotSnmpdConfig 1 } + +begemotSnmpdReceiveBuffer OBJECT-TYPE + SYNTAX INTEGER (484..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The size of the transmit buffer in bytes. Larger messages + cannot be sent by the SNMPd." + DEFVAL { 2048 } + ::= { begemotSnmpdConfig 2 } + +begemotSnmpdCommunityDisable OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Disables all access to the CommunityTable from SNMP. Once + set it cannot be cleared." + DEFVAL { false } + ::= { begemotSnmpdConfig 3 } + +begemotSnmpdTrap1Addr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The trap sink for v1 traps." + ::= { begemotSnmpdConfig 4 } + +-- +-- Trap destinations +-- +begemotTrapSinkTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotTrapSinkEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table with destinations for standard traps." + INDEX { begemotTrapSinkAddr, begemotTrapSinkPort } + ::= { begemotSnmpdObjects 2 } + +begemotTrapSinkEntry OBJECT-TYPE + SYNTAX BegemotTrapSinkEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Entry describes one trap destination." + INDEX { begemotTrapSinkAddr, begemotTrapSinkPort } + ::= { begemotTrapSinkTable 1 } + +BegemotTrapSinkEntry ::= SEQUENCE { + begemotTrapSinkAddr IpAddress, + begemotTrapSinkPort INTEGER, + begemotTrapSinkStatus RowStatus +} + +begemotTrapSinkAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Destination IP address of the manager station where to send + traps." + ::= { begemotTrapSinkEntry 1 } + +begemotTrapSinkPort OBJECT-TYPE + SYNTAX INTEGER (1..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Destination UDP port of the manager station where to send + traps." + ::= { begemotTrapSinkEntry 2 } + +begemotTrapSinkStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Used to create/activate/destroy the entry." + ::= { begemotTrapSinkEntry 3 } + +-- +-- SNMP port table +-- +begemotSnmpdPortTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotSnmpdPortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table with descriptions of UDP ports to listen on + for SNMP messages." + ::= { begemotSnmpdObjects 4 } + +begemotSnmpdPortEntry OBJECT-TYPE + SYNTAX BegemotSnmpdPortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry in the table with descriptions of UDP ports to + listen on for SNMP messages." + INDEX { begemotSnmpdPortAddress, begemotSnmpdPortPort } + ::= { begemotSnmpdPortTable 1 } + +BegemotSnmpdPortEntry ::= SEQUENCE { + begemotSnmpdPortAddress IpAddress, + begemotSnmpdPortPort INTEGER, + begemotSnmpdPortStatus INTEGER +} + +begemotSnmpdPortAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The IP address to bind to." + ::= { begemotSnmpdPortEntry 1 } + +begemotSnmpdPortPort OBJECT-TYPE + SYNTAX INTEGER (1..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The UDP port to listen on for SNMP messages." + ::= { begemotSnmpdPortEntry 2 } + +begemotSnmpdPortStatus OBJECT-TYPE + SYNTAX INTEGER { valid(1), invalid(2) } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Set status to 1 to create entry, set it to 2 to delete it." + ::= { begemotSnmpdPortEntry 3 } + +--- +--- Community table +--- +begemotSnmpdCommunityTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotSnmpdCommunityEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table with the community strings for access control." + ::= { begemotSnmpdObjects 5 } + +begemotSnmpdCommunityEntry OBJECT-TYPE + SYNTAX BegemotSnmpdCommunityEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table with the community strings for access control. + When begemotSnmpdCommDisable is true, this table disappears." + INDEX { begemotSnmpdCommunityModule, begemotSnmpdCommunityIndex } + ::= { begemotSnmpdCommunityTable 1 } + +BegemotSnmpdCommunityEntry ::= SEQUENCE { + begemotSnmpdCommunityModule SectionName, + begemotSnmpdCommunityIndex Unsigned32, + begemotSnmpdCommunityString OCTET STRING, + begemotSnmpdCommunityDescr OCTET STRING +} + +begemotSnmpdCommunityModule OBJECT-TYPE + SYNTAX SectionName + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Index of the module that has registered this community. + For global communities this is the empty string." + ::= { begemotSnmpdCommunityEntry 1 } + +begemotSnmpdCommunityIndex OBJECT-TYPE + SYNTAX Unsigned32 (1..4294967295) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The numerical index of the community (private to the module)." + ::= { begemotSnmpdCommunityEntry 2 } + +begemotSnmpdCommunityString OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The string for access to SNMPd." + ::= { begemotSnmpdCommunityEntry 3 } + +begemotSnmpdCommunityDescr OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A description what this community is good for." + ::= { begemotSnmpdCommunityEntry 4 } + +-- +-- Module table +-- +begemotSnmpdModuleTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotSnmpdModuleEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table describing all the currently loaded dynamic modules. + Writing to this table loads and unloads modules." + ::= { begemotSnmpdObjects 6 } + +begemotSnmpdModuleEntry OBJECT-TYPE + SYNTAX BegemotSnmpdModuleEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table entry describing a loadable module." + INDEX { begemotSnmpdModuleSection } + ::= { begemotSnmpdModuleTable 1 } + +BegemotSnmpdModuleEntry ::= SEQUENCE { + begemotSnmpdModuleSection SectionName, + begemotSnmpdModulePath OCTET STRING, + begemotSnmpdModuleComment OCTET STRING +} + +begemotSnmpdModuleSection OBJECT-TYPE + SYNTAX SectionName + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The string used for matching configuration file sections + and indexes the module table." + ::= { begemotSnmpdModuleEntry 1 } + + +begemotSnmpdModulePath OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The path name of the module. Set to empty string + to unload a module. The path of an existing module + may not be changed." + ::= { begemotSnmpdModuleEntry 2 } + +begemotSnmpdModuleComment OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A comment describing this module." + ::= { begemotSnmpdModuleEntry 3 } + + +-- -------------------------------------------------------------------------- +-- +-- The STATISTICS Group +-- +begemotSnmpdStats OBJECT IDENTIFIER ::= { begemotSnmpdObjects 7 } + +begemotSnmpdStatsNoRxBufs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times a receive buffer could not be allocated + for a packet." + ::= { begemotSnmpdStats 1 } + +begemotSnmpdStatsNoTxBufs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times a transmit buffer could not be allocated + for a packet." + ::= { begemotSnmpdStats 2 } + +begemotSnmpdStatsInTooLongPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets received that were longer than the + receive buffer. These packets are dropped." + ::= { begemotSnmpdStats 3 } + +begemotSnmpdStatsInBadPduTypes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets received with a bad type field." + ::= { begemotSnmpdStats 4 } + +-- +-- The Debug Group +-- +begemotSnmpdDebug OBJECT IDENTIFIER ::= { begemotSnmpdObjects 8 } + +begemotSnmpdDebugDumpPdus OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Dump PDUs to log file if true." + DEFVAL { false } + ::= { begemotSnmpdDebug 1 } + +begemotSnmpdDebugSnmpTrace OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Tracing flags for the SNMP library. These flags have the + following meaning: + 0x00000001 trace GET operator + 0x00000002 trace GETNEXT operator + 0x00000004 trace SET operator + 0x00000008 trace dependency processing + 0x00000010 trace node finding + Individual values can be or-ed together." + DEFVAL { 0 } + ::= { begemotSnmpdDebug 2 } + +begemotSnmpdDebugSyslogPri OBJECT-TYPE + SYNTAX INTEGER (0..8) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Events with this or higher priority should not be logged." + DEFVAL { 7 } -- don't log debug messages + ::= { begemotSnmpdDebug 3 } + +-- +-- Local port table +-- +begemotSnmpdLocalPortTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotSnmpdLocalPortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table with descriptions of local (unix domain) ports to listen + on for SNMP messages." + ::= { begemotSnmpdObjects 9 } + +begemotSnmpdLocalPortEntry OBJECT-TYPE + SYNTAX BegemotSnmpdLocalPortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry in the table with descriptions of local ports to + listen on for SNMP messages." + INDEX { begemotSnmpdLocalPortPath } + ::= { begemotSnmpdLocalPortTable 1 } + +BegemotSnmpdLocalPortEntry ::= SEQUENCE { + begemotSnmpdLocalPortPath OCTET STRING, + begemotSnmpdLocalPortStatus INTEGER +} + +begemotSnmpdLocalPortPath OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(1..104)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The path name to create and listen on." + ::= { begemotSnmpdLocalPortEntry 1 } + +begemotSnmpdLocalPortStatus OBJECT-TYPE + SYNTAX INTEGER { valid(1), invalid(2) } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Set status to 1 to create entry, set it to 2 to delete it." + ::= { begemotSnmpdLocalPortEntry 2 } + +END diff --git a/contrib/bsnmp/snmpd/FOKUS-MIB.txt b/contrib/bsnmp/snmpd/FOKUS-MIB.txt new file mode 100644 index 000000000000..c0939babee88 --- /dev/null +++ b/contrib/bsnmp/snmpd/FOKUS-MIB.txt @@ -0,0 +1,61 @@ +-- +-- 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/FOKUS-MIB.txt,v 1.3 2002/02/06 12:43:51 hbb Exp $ +-- +-- Begemot private definitions and fokus root. +-- +FOKUS-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, enterprises + FROM SNMPv2-SMI; + +fokus MODULE-IDENTITY + LAST-UPDATED "200202050000Z" + ORGANIZATION "Fraunhofer FOKUS, CATS" + CONTACT-INFO + " Hartmut Brandt + + Postal: Fraunhofer Institute for Open Communication Systems + Kaiserin-Augusta-Allee 31 + 10589 Berlin + Germany + + Fax: +49 30 3463 7352 + + E-mail: harti@freebsd.org" + DESCRIPTION + "The root of the Fokus enterprises tree." + ::= { enterprises 12325 } + +END diff --git a/contrib/bsnmp/snmpd/action.c b/contrib/bsnmp/snmpd/action.c new file mode 100644 index 000000000000..7c87beaf445e --- /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(); +} diff --git a/contrib/bsnmp/snmpd/bsnmpd.1 b/contrib/bsnmp/snmpd/bsnmpd.1 new file mode 100644 index 000000000000..01c7a1c52e99 --- /dev/null +++ b/contrib/bsnmp/snmpd/bsnmpd.1 @@ -0,0 +1,256 @@ +.\" +.\" 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/snmpd.1,v 1.2 2002/08/15 13:27:47 hbb Exp $ +.\" +.Dd August 15, 2002 +.Dt SNMPD 1 +.Os +.Sh NAME +.Nm snmpd +.Nd "simple and extendable SNMP daemon" +.Sh SYNOPSIS +.Nm +.Op Fl dh +.Op Fl c Ar file +.Op Fl D Ar options +.Op Fl I Ar paths +.Op Fl l Ar prefix +.Op Fl m Ar variable Ns Op = Ns Ar value +.Op Fl p Ar file +.Sh DESCRIPTION +The +.Nm +daemon servers the internet SNMP (Simple Network Managment Protocol). +It is intended to server only the absolute basic MIBs and implement all other +MIBs through loadable modules. In this way the +.Nm +can be used in unexpected ways. +.Pp +The options are as follows: +.Bl -tag -width ".It Fl D Ar options" +.It Fl d +This option is used for debugging +.Nm +and causes it not to daemonize itself. +.It Fl h +This option prints a short usage message. +.It Fl c Ar file +Use +.Ar file +as configuration file instead of the standard one. +.It Fl D Ar options +Debugging options are specified with a +.Fl o +flag followed by a comma separated string of options. +The following options are available. +.Bl -tag -width ".It Cm trace Ns Cm = Ns Cm level" +.It Cm dump +This option causes all sent and received PDUs to be dumped to the terminal. +.It Cm events +This causes the debugging level of the event library (see +.Xr eventlib 3 ) +to be set to 10. +.It Cm trace Ns Cm = Ns Cm level +This option causes the snmp library trace flag to be set to the specified +value. The value can be specified in the usual C-syntax for numbers. +.El +.It Fl I Ar paths +This option specifies a colon separated list of directories to search for +configuration include files. The default is +.Pa /etc:/usr/etc/:/usr/local/etc . +These paths are only searched for include specified within <> parantheses. +.It Fl l Ar prefix +The +.Ar prefix +is used as the default basename for the pid and the configuration files. +.It Fl m Ar variable Ns Op = Ns Ar value +Define a configuration variable. +.It Fl p Ar file +Specify an alternate pid file instead of the default one. +.El +.Sh CONFIGURATION +The +.Nm +reads its configuration from either the default or the user specified +configuration file. The configuration file consists of the following types of +lines: +.Bl -bullet -offset indent +.It +variable assignments +.It +section separators +.It +include directives +.It +MIB variable assignments +.El +.Pp +If a line is too long it can be continued on the next line by ending it with +a backslash. Empty lines and lines who's first non-blank character is a +.Dq # +sign are ignored. +.Pp +All MIB variable assignments of the entire configuration (including nested +configuration files) are handled as one transaction, i.e. as if they arrived +in a single SET PDU. Any failure during the initial configuration read causes +.Nm +to exit. A failure during the configuration read caused by a module load +causes the loading of the module to fail. +.Pp +The configuration is red during initialisation of +.Nm , +when a module is loaded and when +.Nm +receives a SIGHUP. +.Ss VARIABLE ASSIGNMENTS +Variable assignments can take one of two forms: +.Bd -unfilled -offset indent +variable := string +variable ?= string +.Ed +.Pp +The string reaches from the first non-blank character after the +equal sign until the first new line or +.Dq # +character. In the first case +the string is assigned to the variable unconditionally, in the second case the +variable is only assigned if it does not exist yet. +.Pp +Variable names must begin with a letter or underscore and contain only letters, +digits or underscores. +.Ss SECTION SEPARATORS +The configuration consists of named sections. The MIB variable assignments in +the section named +.Dq snmpd +are executed only during initial setup or when +.Nm +receives a SIGHUP. All other sections are executed when either a module +with the same name as the section is loaded or +.Nm +receives a SIGHUP and that module is already loaded. The default section +at the start of the configuration is +.Dq snmpd . +One can switch to another section with the syntax +.Bd -unfilled -offset indent +%secname +.Ed +.Pp +Where +.Ar secname +is the name of the section. The same +.Ar secname +can be used in more than one place in the configuration. All of these parts are +collected into one section. +.Ss INCLUDE DIRECTIVES +Another configuration file can be included into the current one with the +include directive that takes one of two forms: +.Bd -unfilled -offset indent +\&.include "file" +\&.include <"file"> +.Ed +.Pp +The first form causes the file to be searched in the current directory, the +second form causes the file to be searched in the directories specified in +the system include path. Nesting depths is only restricted by available +memory. +.Ss MIB VARIABLE ASSIGNMENTS +A MIB variable is assigned with the syntax +.Bd -unfilled -offset indent +oid [ suboids ] = value +.Ed +.Pp +.Va oid +is the name of the variable to be set. Only the last component of the entire +name is used here. If the variable is a scalar, the index (.0) is automatically +appended and need not to be specified. If the variable is a table column, +the index ( +.Va suboids ) +must be specified. The index consist of elements each seperated from the +previous one by a dot. Elements may be either numbers, strings or hostnames +enclosed in [] brackets. If the element is a number it is appended +to the current oid. If the element is a string, its length and the +.Tn ASCII +code of each of its characters are appended to the current oid. If the +element is a hostname, the IP address of the host is looked up and the four +elements of the IP address are appended to the oid. +.Pp +For example a oid of +.Bd -unfilled -offset indent +myvariable.27.foooll.[localhost]."&^!" +.Ed +.Pp +results in the oid +.Bd -unfilled -offset indent +myvariable.27.6.102.111.111.111.108.108.127.0.0.1.38.94.33 +.Ed +.Pp +The value of the assignment may be either empty, a string or a number. +If a string starts with a letter or an underscore and consists only of +letters, digits, underscores and minus signs, it can be written without +quotes. In all other cases the string must be enclosed in double quotes. +.Sh SUBSTITUTIONS +A variable substitution is written as +.Bd -unfilled -offset indent +$(variable) +.Ed +.Pp +where +.Ar variable +is the name of the variable to substitute. Using an undefined variable is +considered an error. +.Sh FILES +.Bl -tag -width ".It Pa /var/run/ Ns Ao Ar prefix Ac Ns \&.pid" -compact +.It Pa /etc/ Ns Ao Ar prefix Ac Ns \&.config +Default configuration file, where the default +.Aq prefix +is +.Dq snmpd . +.It Pa /var/run/ Ns Ao Ar prefix Ac Ns \&.pid +Default pid file. +.It Pa /etc:/usr/etc/:/usr/local/etc +This is the default search path for system include files. +.It Pa /usr/local/share/snmp/mibs/FOKUS-MIB.txt +.It Pa /usr/local/share/snmp/mibs/BEGEMOT-MIB.txt +.It Pa /usr/local/share/snmp/mibs/BEGEMOT-SNMPD.txt +The definitions for the MIBs implemented in the daemon. +.El +.Sh SEE ALSO +.Xr gensnmptree 1 +.Sh STANDARDS +The +.Nm +conforms to the applicable IETF RFCs. +.Sh AUTHORS +.An Hartmut Brandt Aq brandt@fokus.gmd.de +.Sh BUGS +Sure. diff --git a/contrib/bsnmp/snmpd/config.c b/contrib/bsnmp/snmpd/config.c new file mode 100644 index 000000000000..e247797ff69e --- /dev/null +++ b/contrib/bsnmp/snmpd/config.c @@ -0,0 +1,1361 @@ +/* + * 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/config.c,v 1.18 2003/03/11 15:30:01 hbb Exp $ + * + * Parse configuration file. + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <ctype.h> +#include <errno.h> +#include <syslog.h> +#include <unistd.h> +#include <limits.h> +#include <netdb.h> +#include <setjmp.h> +#include <inttypes.h> + +#include "snmpmod.h" +#include "snmpd.h" +#include "tree.h" + +/* +#define DEBUGGING +*/ + +/* + * config_file: EMPTY | config_file line + * + * line: oid '=' value + * | '%' STRING + * | STRING := REST_OF_LINE + * | STRING ?= REST_OF_LINE + * | . INCLUDE STRING + * + * oid: STRING suboid + * + * suboid: EMPTY | suboid '.' subid + * + * subid: NUM | STRING | '[' STRING ']' + * + * value: EMPTY | STRING | NUM + */ + +/* + * Input context for macros and includes + */ +enum input_type { + INPUT_FILE = 1, + INPUT_STRING +}; +struct input { + enum input_type type; + union { + struct { + FILE *fp; + char *filename; + u_int lno; + } file; + struct { + char *macro; + char *str; + char *ptr; + size_t left; + } str; + } u; + LIST_ENTRY(input) link; +}; +static LIST_HEAD(, input) inputs; + +#define input_fp u.file.fp +#define input_filename u.file.filename +#define input_lno u.file.lno +#define input_macro u.str.macro +#define input_str u.str.str +#define input_ptr u.str.ptr +#define input_left u.str.left + +static int input_push; +static int input_buf[2]; + +/* + * Configuration data. The configuration file is handled as one single + * SNMP transaction. So we need to keep the assignment data for the + * commit or rollback pass. Note, that dependencies and finish functions + * are NOT allowed here. + */ +struct assign { + struct snmp_value value; + struct snmp_scratch scratch; + const char *node_name; + + TAILQ_ENTRY(assign) link; +}; +static TAILQ_HEAD(assigns, assign) assigns = TAILQ_HEAD_INITIALIZER(assigns); + + +static struct snmp_context *snmp_ctx; + +struct macro { + char *name; + char *value; + size_t length; + LIST_ENTRY(macro) link; + int perm; +}; +static LIST_HEAD(, macro) macros = LIST_HEAD_INITIALIZER(¯os); + +enum { + TOK_EOF = 0200, + TOK_EOL, + TOK_NUM, + TOK_STR, + TOK_HOST, + TOK_ASSIGN, + TOK_QASSIGN, +}; + +/* lexer values and last token */ +static uint64_t numval; +static char strval[_POSIX2_LINE_MAX]; +static size_t strvallen; +static int token; + +/* error return */ +static jmp_buf errjmp[4]; +static volatile int errstk; + +# define ERRPUSH() (setjmp(errjmp[errstk++])) +# define ERRPOP() ((void)(errstk--)) +# define ERRNEXT() (longjmp(errjmp[--errstk], 1)) +# define ERR() (longjmp(errjmp[--errstk], 1)) + +/* section context */ +static int ignore; + +/* + * Report an error and jump to the error label + */ +static void report(const char *fmt, ...) __dead2 __printflike(1, 2); + +static void +report(const char *fmt, ...) +{ + va_list ap; + const struct input *input; + + va_start(ap, fmt); + vsyslog(LOG_ERR, fmt, ap); + va_end(ap); + + LIST_FOREACH(input, &inputs, link) { + switch (input->type) { + + case INPUT_FILE: + syslog(LOG_ERR, " in file %s line %u", + input->input_filename, input->input_lno); + break; + + case INPUT_STRING: + syslog(LOG_ERR, " in macro %s pos %td", + input->input_macro, + input->input_ptr - input->input_str); + break; + } + } + ERR(); +} + +/* + * Open a file for input + */ +static int +input_open_file(const char *fname, int sysdir) +{ + struct input *input; + FILE *fp; + char path[PATH_MAX + 1]; + char *col; + const char *ptr; + + if (sysdir) { + ptr = syspath; + fp = NULL; + while (*ptr != '\0') { + if ((col = strchr(ptr, ':')) == NULL) + snprintf(path, sizeof(path), "%s/%s", + ptr, fname); + else if (col == ptr) + snprintf(path, sizeof(path), "./%s", fname); + else + snprintf(path, sizeof(path), "%.*s/%s", + (int)(col - ptr), ptr, fname); + if ((fp = fopen(path, "r")) != NULL) + break; + ptr = col + 1; + } + } else + fp = fopen(fname, "r"); + + if (fp == NULL) + report("%s: %m", fname); + + if ((input = malloc(sizeof(*input))) == NULL) { + fclose(fp); + return (-1); + } + if ((input->input_filename = malloc(strlen(fname) + 1)) == NULL) { + fclose(fp); + free(input); + return (-1); + } + strcpy(input->input_filename, fname); + input->input_fp = fp; + input->input_lno = 1; + input->type = INPUT_FILE; + LIST_INSERT_HEAD(&inputs, input, link); + return (0); +} + +/* + * Make a macro the next input + */ +static void +input_open_macro(struct macro *m) +{ + struct input *input; + + if ((input = malloc(sizeof(*input))) == NULL) + report("%m"); + input->type = INPUT_STRING; + input->input_macro = m->name; + if ((input->input_str = malloc(m->length)) == NULL) { + free(input); + report("%m"); + } + memcpy(input->input_str, m->value, m->length); + input->input_ptr = input->input_str; + input->input_left = m->length; + LIST_INSERT_HEAD(&inputs, input, link); +} + +/* + * Close top input source + */ +static void +input_close(void) +{ + struct input *input; + + if ((input = LIST_FIRST(&inputs)) == NULL) + abort(); + switch (input->type) { + + case INPUT_FILE: + fclose(input->input_fp); + free(input->input_filename); + break; + + case INPUT_STRING: + free(input->input_str); + break; + } + LIST_REMOVE(input, link); + free(input); +} + +/* + * Close all inputs + */ +static void +input_close_all(void) +{ + while (!LIST_EMPTY(&inputs)) + input_close(); +} + +/* + * Push back one character + */ +static void +input_ungetc(int c) +{ + if (c == EOF) + report("pushing EOF"); + if (input_push == 2) + report("pushing third char"); + input_buf[input_push++] = c; +} + + +/* + * Return next character from the input without preprocessing. + */ +static int +input_getc_raw(void) +{ + int c; + struct input *input; + + if (input_push != 0) { + c = input_buf[--input_push]; + goto ok; + } + while ((input = LIST_FIRST(&inputs)) != NULL) { + switch (input->type) { + + case INPUT_FILE: + if ((c = getc(input->input_fp)) == EOF) { + if (ferror(input->input_fp)) + report("read error: %m"); + input_close(); + break; + } + if (c == '\n') + input->input_lno++; + goto ok; + + case INPUT_STRING: + if (input->input_left-- == 0) { + input_close(); + break; + } + c = *input->input_ptr++; + goto ok; + } + } +# ifdef DEBUGGING + fprintf(stderr, "EOF"); +# endif + return (EOF); + + ok: +# ifdef DEBUGGING + if (!isascii(c) || !isprint(c)) + fprintf(stderr, "'%#2x'", c); + else + fprintf(stderr, "'%c'", c); +# endif + return (c); +} + +/* + * Get character with and \\n -> processing. + */ +static int +input_getc_plain(void) +{ + int c; + + again: + if ((c = input_getc_raw()) == '\\') { + if ((c = input_getc_raw()) == '\n') + goto again; + if (c != EOF) + input_ungetc(c); + return ('\\'); + } + return (c); +} + +/* + * Get next character with substitution of macros + */ +static int +input_getc(void) +{ + int c; + struct macro *m; + char name[_POSIX2_LINE_MAX]; + size_t namelen; + + again: + if ((c = input_getc_plain()) != '$') + return (c); + + if ((c = input_getc()) == EOF) + report("unexpected EOF"); + if (c != '(') + report("expecting '(' after '$'"); + + namelen = 0; + while ((c = input_getc()) != EOF && c != ')') { + if (isalpha(c) || c == '_' || (namelen != 0 && isdigit(c))) + name[namelen++] = c; + else + goto badchar; + } + if (c == EOF) + report("unexpected EOF"); + name[namelen++] = '\0'; + + LIST_FOREACH(m, ¯os, link) + if (strcmp(m->name, name) == 0) + break; + if (m == NULL) + report("undefined macro '%s'", name); + + input_open_macro(m); + goto again; + + badchar: + if (!isascii(c) || !isprint(c)) + report("unexpected character %#2x", (u_int)c); + else + report("bad character '%c'", c); +} + + +static void +input_getnum(u_int base, u_int flen) +{ + int c; + u_int cnt; + + cnt = 0; + numval = 0; + while (flen == 0 || cnt < flen) { + if ((c = input_getc()) == EOF) { + if (cnt == 0) + report("bad number"); + return; + } + if (isdigit(c)) { + if (base == 8 && (c == '8' || c == '9')) { + input_ungetc(c); + if (cnt == 0) + report("bad number"); + return; + } + numval = numval * base + (c - '0'); + } else if (base == 16 && isxdigit(c)) { + if (islower(c)) + numval = numval * base + (c - 'a' + 10); + else + numval = numval * base + (c - 'A' + 10); + } else { + input_ungetc(c); + if (cnt == 0) + report("bad number"); + return; + } + cnt++; + } +} + +static int +# ifdef DEBUGGING +_gettoken(void) +# else +gettoken(void) +# endif +{ + int c; + char *end; + static const char esc[] = "abfnrtv"; + static const char chr[] = "\a\b\f\n\r\t\v"; + + /* + * Skip any whitespace before the next token + */ + while ((c = input_getc()) != EOF) { + if (!isspace(c) || c == '\n') + break; + } + if (c == EOF) + return (token = TOK_EOF); + if (!isascii(c)) + goto badchar; + + /* + * Skip comments + */ + if (c == '#') { + while ((c = input_getc_plain()) != EOF) { + if (c == '\n') + return (token = TOK_EOL); + } + goto badeof; + } + + /* + * Single character tokens + */ + if (c == '\n') + return (token = TOK_EOL); + if (c == '.' || c == '%' || c == '=' || c == '<' || c == '>') + return (token = c); + if (c == ':') { + if ((c = input_getc()) == '=') + return (token = TOK_ASSIGN); + input_ungetc(c); + return (token = ':'); + } + if (c == '?') { + if ((c = input_getc()) == '=') + return (token = TOK_QASSIGN); + input_ungetc(c); + goto badchar; + } + + /* + * Sort out numbers + */ + if (isdigit(c)) { + if (c == '0') { + if ((c = input_getc()) == 'x' || c == 'X') { + input_getnum(16, 0); + } else if (isdigit(c)) { + input_ungetc(c); + input_getnum(8, 0); + } else { + if (c != EOF) + input_ungetc(c); + numval = 0; + c = 1; + } + } else { + input_ungetc(c); + input_getnum(10, 0); + } + return (token = TOK_NUM); + } + + /* + * Must be a string then + */ + strvallen = 0; + +# define GETC(C) do { \ + if ((c = input_getc()) == EOF) \ + goto badeof; \ + if (!isascii(c) || (!isprint(c) && c != '\t')) \ + goto badchar; \ +} while(0) + + if (c == '"') { + for(;;) { + GETC(c); + if (c == '"') { + strval[strvallen] = '\0'; + break; + } + if (c != '\\') { + strval[strvallen++] = c; + continue; + } + GETC(c); + if ((end = strchr(esc, c)) != NULL) { + strval[strvallen++] = chr[end - esc]; + continue; + } + if (c == 'x') { + input_getnum(16, 2); + c = numval; + } else if (c >= '0' && c <= '7') { + input_ungetc(c); + input_getnum(8, 3); + c = numval; + } + strval[strvallen++] = c; + } +# undef GETC + + } else if (c == '[') { + /* + * Skip leading space + */ + while ((c = input_getc()) != EOF && isspace(c)) + ; + if (c == EOF) + goto badeof; + while (c != ']' && !isspace(c)) { + if (!isalnum(c) && c != '.' && c != '-') + goto badchar; + strval[strvallen++] = c; + if ((c = input_getc()) == EOF) + goto badeof; + } + while (c != ']' && isspace(c)) { + if ((c = input_getc()) == EOF) + goto badeof; + } + if (c != ']') + goto badchar; + strval[strvallen] = '\0'; + return (token = TOK_HOST); + + } else if (!isalpha(c) && c != '_') { + goto badchar; + + } else { + for (;;) { + strval[strvallen++] = c; + if ((c = input_getc()) == EOF) + goto badeof; + if (!isalnum(c) && c != '_' && c != '-') { + input_ungetc(c); + strval[strvallen] = '\0'; + break; + } + } + } + + return (token = TOK_STR); + + badeof: + report("unexpected EOF"); + + badchar: + if (!isascii(c) || !isprint(c)) + report("unexpected character %#2x", (u_int)c); + else + report("bad character '%c'", c); +} + +# ifdef DEBUGGING +static int +gettoken() +{ + _gettoken(); + if (isascii(token) && isprint(token)) + printf("(%c)", token); + else { + switch (token) { + + case TOK_EOF: + printf("(EOF)"); + break; + case TOK_EOL: + printf("(EOL)"); + break; + case TOK_NUM: + printf("(NUM %llu)", numval); + break; + case TOK_STR: + printf("(STR %.*s)", (int)strvallen, strval); + break; + case TOK_HOST: + printf("(HOST %s)", strval); + break; + default: + printf("(%#2x)", token); + break; + } + } + return (token); +} +#endif + + +/* + * Try to execute the assignment. + */ +static void +handle_assignment(const struct snmp_node *node, struct asn_oid *vindex, + const struct snmp_value *value) +{ + u_int i; + int err; + struct assign *tp; + char nodename[100]; + + if (node->type == SNMP_NODE_LEAF) { + /* index must be one single zero or no index at all */ + if (vindex->len > 1 || (vindex->len == 1 && + vindex->subs[0] != 0)) + report("bad index on leaf node"); + vindex->len = 1; + vindex->subs[0] = 0; + } else { + /* resulting oid must not be too long */ + if (node->oid.len + vindex->len > ASN_MAXOIDLEN) + report("resulting OID too long"); + } + + /* + * Get the next assignment entry for the transaction. + */ + if ((tp = malloc(sizeof(*tp))) == NULL) + report("%m"); + + tp->value = *value; + tp->node_name = node->name; + + /* + * Build the OID + */ + tp->value.var = node->oid; + for (i = 0; i < vindex->len; i++) + tp->value.var.subs[tp->value.var.len++] = vindex->subs[i]; + + /* + * Puzzle together the variables for the call and call the + * set routine. The set routine may make our node pointer + * invalid (if we happend to call the module loader) so + * get a copy of the node name beforehands. + */ + snprintf(nodename, sizeof(nodename), "%s", node->name); + snmp_ctx->scratch = &tp->scratch; + snmp_ctx->var_index = 0; + err = (*node->op)(snmp_ctx, &tp->value, node->oid.len, node->index, + SNMP_OP_SET); + if (err != 0) { + free(tp); + report("assignment to %s.%s returns %d", nodename, + asn_oid2str(vindex), err); + } + + TAILQ_INSERT_TAIL(&assigns, tp, link); +} + + +/* + * Parse the section statement + */ +static void +parse_section(const struct lmodule *mod) +{ + if (token != TOK_STR) + report("expecting section name"); + + if (strcmp(strval, "snmpd") == 0) { + if (mod != NULL) + /* loading a module - ignore common stuff */ + ignore = 1; + else + /* global configuration - don't ignore */ + ignore = 0; + } else { + if (mod == NULL) { + /* global configuration - ignore module stuff */ + ignore = 1; + } else { + /* loading module - check if it's our section */ + ignore = (strcmp(strval, mod->section) != 0); + } + } + gettoken(); +} + +/* + * Convert a hostname to four u_chars + */ +static void +gethost(const char *host, u_char *ip) +{ + struct addrinfo hints, *res; + int error; + struct sockaddr_in *sain; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_PASSIVE; + error = getaddrinfo(host, NULL, &hints, &res); + if (error != 0) + report("%s: %s", host, gai_strerror(error)); + if (res == NULL) + report("%s: unknown hostname", host); + + sain = (struct sockaddr_in *)(void *)res->ai_addr; + sain->sin_addr.s_addr = ntohl(sain->sin_addr.s_addr); + ip[0] = sain->sin_addr.s_addr >> 24; + ip[1] = sain->sin_addr.s_addr >> 16; + ip[2] = sain->sin_addr.s_addr >> 8; + ip[3] = sain->sin_addr.s_addr >> 0; + + freeaddrinfo(res); +} + +/* + * Parse the left hand side of a config line. + */ +static const struct snmp_node * +parse_oid(const char *varname, struct asn_oid *oid) +{ + struct snmp_node *node; + u_int i; + u_char ip[4]; + + for (node = tree; node < &tree[tree_size]; node++) + if (strcmp(varname, node->name) == 0) + break; + if (node == &tree[tree_size]) + node = NULL; + + oid->len = 0; + while (token == '.') { + if (gettoken() == TOK_NUM) { + if (numval > ASN_MAXID) + report("subid too large %#"PRIx64, numval); + if (oid->len == ASN_MAXOIDLEN) + report("index too long"); + oid->subs[oid->len++] = numval; + + } else if (token == TOK_STR) { + if (strvallen + oid->len + 1 > ASN_MAXOIDLEN) + report("oid too long"); + oid->subs[oid->len++] = strvallen; + for (i = 0; i < strvallen; i++) + oid->subs[oid->len++] = strval[i]; + + } else if (token == TOK_HOST) { + gethost(strval, ip); + if (oid->len + 4 > ASN_MAXOIDLEN) + report("index too long"); + for (i = 0; i < 4; i++) + oid->subs[oid->len++] = ip[i]; + + } else + report("bad token in index"); + gettoken(); + } + + return (node); +} + +/* + * Parse the value for an assignment. + */ +static void +parse_syntax_null(struct snmp_value *value __unused) +{ + if (token != TOK_EOL) + report("bad NULL syntax"); +} + +static void +parse_syntax_integer(struct snmp_value *value) +{ + if (token != TOK_NUM) + report("bad INTEGER syntax"); + if (numval > 0x7fffffff) + report("INTEGER too large %"PRIu64, numval); + + value->v.integer = numval; + gettoken(); +} + +static void +parse_syntax_counter64(struct snmp_value *value) +{ + if (token != TOK_NUM) + report("bad COUNTER64 syntax"); + + value->v.counter64 = numval; + gettoken(); +} + +static void +parse_syntax_octetstring(struct snmp_value *value) +{ + u_long alloc; + u_char *noct; + + if (token == TOK_STR) { + value->v.octetstring.len = strvallen; + value->v.octetstring.octets = malloc(strvallen); + (void)memcpy(value->v.octetstring.octets, strval, strvallen); + gettoken(); + return; + } + + /* XX:XX:XX syntax */ + value->v.octetstring.octets = NULL; + value->v.octetstring.len = 0; + + if (token != TOK_NUM) + /* empty string is allowed */ + return; + + if (ERRPUSH()) { + free(value->v.octetstring.octets); + ERRNEXT(); + } + + alloc = 0; + for (;;) { + if (token != TOK_NUM) + report("bad OCTETSTRING syntax"); + if (numval > 0xff) + report("byte value too large"); + if (alloc == value->v.octetstring.len) { + alloc += 100; + noct = realloc(value->v.octetstring.octets, alloc); + if (noct == NULL) + report("%m"); + value->v.octetstring.octets = noct; + } + value->v.octetstring.octets[value->v.octetstring.len++] + = numval; + if (gettoken() != ':') + break; + gettoken(); + } + ERRPOP(); +} + +static void +parse_syntax_oid(struct snmp_value *value) +{ + value->v.oid.len = 0; + + if (token != TOK_NUM) + return; + + for (;;) { + if (token != TOK_NUM) + report("bad OID syntax"); + if (numval > ASN_MAXID) + report("subid too large"); + if (value->v.oid.len == ASN_MAXOIDLEN) + report("OID too long"); + value->v.oid.subs[value->v.oid.len++] = numval; + if (gettoken() != '.') + break; + gettoken(); + } +} + +static void +parse_syntax_ipaddress(struct snmp_value *value) +{ + int i; + u_char ip[4]; + + if (token == TOK_NUM) { + /* numerical address */ + i = 0; + for (;;) { + if (numval >= 256) + report("ip address part too large"); + value->v.ipaddress[i++] = numval; + if (i == 4) + break; + if (gettoken() != '.') + report("expecting '.' in ip address"); + } + gettoken(); + + } else if (token == TOK_HOST) { + /* host name */ + gethost(strval, ip); + for (i = 0; i < 4; i++) + value->v.ipaddress[i] = ip[i]; + gettoken(); + + } else + report("bad ip address syntax"); +} + +static void +parse_syntax_uint32(struct snmp_value *value) +{ + + if (token != TOK_NUM) + report("bad number syntax"); + if (numval > 0xffffffff) + report("number too large"); + value->v.uint32 = numval; + gettoken(); +} + +/* + * Parse an assignement line + */ +static void +parse_assign(const char *varname) +{ + struct snmp_value value; + struct asn_oid vindex; + const struct snmp_node *node; + + node = parse_oid(varname, &vindex); + if (token != '=') + report("'=' expected"); + gettoken(); + + if (ignore) { + /* skip rest of line */ + while (token != TOK_EOL && token != TOK_EOF) + gettoken(); + return; + } + if (node == NULL) + report("unknown variable"); + + switch (value.syntax = node->syntax) { + + case SNMP_SYNTAX_NULL: + parse_syntax_null(&value); + break; + + case SNMP_SYNTAX_INTEGER: + parse_syntax_integer(&value); + break; + + case SNMP_SYNTAX_COUNTER64: + parse_syntax_counter64(&value); + break; + + case SNMP_SYNTAX_OCTETSTRING: + parse_syntax_octetstring(&value); + break; + + case SNMP_SYNTAX_OID: + parse_syntax_oid(&value); + break; + + case SNMP_SYNTAX_IPADDRESS: + parse_syntax_ipaddress(&value); + break; + + case SNMP_SYNTAX_COUNTER: + case SNMP_SYNTAX_GAUGE: + case SNMP_SYNTAX_TIMETICKS: + parse_syntax_uint32(&value); + break; + + case SNMP_SYNTAX_NOSUCHOBJECT: + case SNMP_SYNTAX_NOSUCHINSTANCE: + case SNMP_SYNTAX_ENDOFMIBVIEW: + abort(); + } + + if (ERRPUSH()) { + snmp_value_free(&value); + ERRNEXT(); + } + + handle_assignment(node, &vindex, &value); + + ERRPOP(); +} + +/* + * Handle macro definition line + * We have already seen the := and the input now stands at the character + * after the =. Skip whitespace and then call the input routine directly to + * eat up characters. + */ +static void +parse_define(const char *varname) +{ + char *volatile string; + char *new; + volatile size_t alloc, length; + int c; + struct macro *m; + int t = token; + + alloc = 100; + length = 0; + if ((string = malloc(alloc)) == NULL) + report("%m"); + + if (ERRPUSH()) { + free(string); + ERRNEXT(); + } + + while ((c = input_getc_plain()) != EOF) { + if (c == '\n' || !isspace(c)) + break; + } + + while (c != EOF && c != '#' && c != '\n') { + if (alloc == length) { + alloc *= 2; + if ((new = realloc(string, alloc)) == NULL) + report("%m"); + string = new; + } + string[length++] = c; + c = input_getc_plain(); + } + if (c == '#') { + while ((c = input_getc_plain()) != EOF && c != '\n') + ; + } + if (c == EOF) + report("EOF in macro definition"); + + LIST_FOREACH(m, ¯os, link) + if (strcmp(m->name, varname) == 0) + break; + + if (m == NULL) { + if ((m = malloc(sizeof(*m))) == NULL) + report("%m"); + if ((m->name = malloc(strlen(varname) + 1)) == NULL) { + free(m); + report("%m"); + } + strcpy(m->name, varname); + m->perm = 0; + LIST_INSERT_HEAD(¯os, m, link); + + m->value = string; + m->length = length; + } else { + if (t != TOK_ASSIGN) { + free(m->value); + m->value = string; + m->length = length; + } + } + + token = TOK_EOL; + + ERRPOP(); +} + +/* + * Free all macros + */ +static void +macro_free_all(void) +{ + static struct macro *m, *m1; + + m = LIST_FIRST(¯os); + while (m != NULL) { + m1 = LIST_NEXT(m, link); + if (!m->perm) { + free(m->name); + free(m->value); + LIST_REMOVE(m, link); + free(m); + } + m = m1; + } +} + +/* + * Parse an include directive and switch to the new file + */ +static void +parse_include(void) +{ + int sysdir = 0; + char fname[_POSIX2_LINE_MAX]; + + if (gettoken() == '<') { + sysdir = 1; + if (gettoken() != TOK_STR) + report("expecting filename after in .include"); + } else if (token != TOK_STR) + report("expecting filename after in .include"); + + strcpy(fname, strval); + if (sysdir && gettoken() != '>') + report("expecting '>'"); + gettoken(); + if (input_open_file(fname, sysdir) == -1) + report("%s: %m", fname); +} + +/* + * Parse the configuration file + */ +static void +parse_file(const struct lmodule *mod) +{ + char varname[_POSIX2_LINE_MAX]; + + while (gettoken() != TOK_EOF) { + if (token == TOK_EOL) + /* empty line */ + continue; + if (token == '%') { + gettoken(); + parse_section(mod); + } else if (token == '.') { + if (gettoken() != TOK_STR) + report("keyword expected after '.'"); + if (strcmp(strval, "include") == 0) + parse_include(); + else + report("unknown keyword '%s'", strval); + } else if (token == TOK_STR) { + strcpy(varname, strval); + if (gettoken() == TOK_ASSIGN || token == TOK_QASSIGN) + parse_define(varname); + else + parse_assign(varname); + } + if (token != TOK_EOL) + report("eol expected"); + } +} + +/* + * Do rollback on errors + */ +static void +do_rollback(void) +{ + struct assign *tp; + struct snmp_node *node; + + while ((tp = TAILQ_LAST(&assigns, assigns)) != NULL) { + TAILQ_REMOVE(&assigns, tp, link); + for (node = tree; node < &tree[tree_size]; node++) + if (node->name == tp->node_name) { + snmp_ctx->scratch = &tp->scratch; + (void)(*node->op)(snmp_ctx, &tp->value, + node->oid.len, node->index, + SNMP_OP_ROLLBACK); + break; + } + if (node == &tree[tree_size]) + syslog(LOG_ERR, "failed to find node for " + "rollback"); + snmp_value_free(&tp->value); + free(tp); + } +} + +/* + * Do commit + */ +static void +do_commit(void) +{ + struct assign *tp; + struct snmp_node *node; + + while ((tp = TAILQ_FIRST(&assigns)) != NULL) { + TAILQ_REMOVE(&assigns, tp, link); + for (node = tree; node < &tree[tree_size]; node++) + if (node->name == tp->node_name) { + snmp_ctx->scratch = &tp->scratch; + (void)(*node->op)(snmp_ctx, &tp->value, + node->oid.len, node->index, SNMP_OP_COMMIT); + break; + } + if (node == &tree[tree_size]) + syslog(LOG_ERR, "failed to find node for commit"); + snmp_value_free(&tp->value); + free(tp); + } +} + +/* + * Read the configuration file. Handle the entire file as one transaction. + * + * If lodmod is NULL, the sections for 'snmpd' and all loaded modules are + * executed. If it is not NULL, only the sections for that module are handled. + */ +int +read_config(const char *fname, struct lmodule *lodmod) +{ + int err; + char objbuf[ASN_OIDSTRLEN]; + char idxbuf[ASN_OIDSTRLEN]; + + ignore = 0; + + input_push = 0; + if (input_open_file(fname, 0) == -1) { + syslog(LOG_ERR, "%s: %m", fname); + return (-1); + } + community = COMM_INITIALIZE; + + if ((snmp_ctx = snmp_init_context()) == NULL) { + syslog(LOG_ERR, "%m"); + return (-1); + } + + if (ERRPUSH()) { + do_rollback(); + input_close_all(); + macro_free_all(); + free(snmp_ctx); + return (-1); + } + parse_file(lodmod); + ERRPOP(); + + if ((err = snmp_dep_commit(snmp_ctx)) != SNMP_ERR_NOERROR) { + syslog(LOG_ERR, "init dep failed: %u %s %s", err, + asn_oid2str_r(&snmp_ctx->dep->obj, objbuf), + asn_oid2str_r(&snmp_ctx->dep->idx, idxbuf)); + snmp_dep_rollback(snmp_ctx); + do_rollback(); + input_close_all(); + macro_free_all(); + free(snmp_ctx); + return (-1); + } + + do_commit(); + macro_free_all(); + + free(snmp_ctx); + + return (0); +} + +/* + * Define a permanent macro + */ +int +define_macro(const char *name, const char *value) +{ + struct macro *m; + + if ((m = malloc(sizeof(*m))) == NULL) + return (-1); + if ((m->name = malloc(strlen(name) + 1)) == NULL) { + free(m); + return (-1); + } + strcpy(m->name, name); + if ((m->value = malloc(strlen(value) + 1)) == NULL) { + free(m->name); + free(m); + return (-1); + } + strcpy(m->value, value); + m->length = strlen(value); + return (0); +} diff --git a/contrib/bsnmp/snmpd/export.c b/contrib/bsnmp/snmpd/export.c new file mode 100644 index 000000000000..4cebdb330b10 --- /dev/null +++ b/contrib/bsnmp/snmpd/export.c @@ -0,0 +1,378 @@ +/* + * 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/export.c,v 1.5 2003/01/28 13:44:35 hbb Exp $ + * + * Support functions for modules. + */ +#include <sys/types.h> +#include <sys/un.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <stdarg.h> + +#include "snmpmod.h" +#include "snmpd.h" +#include "tree.h" + +/* + * Support functions + */ + +/* + * This is user for SET of string variables. If 'req' is not -1 then + * the arguments is checked to be of that length. The old value is saved + * in scratch->ptr1 and the new value is allocated and copied. + * If there is an old values it must have been allocated by malloc. + */ +int +string_save(struct snmp_value *value, struct snmp_context *ctx, + ssize_t req_size, u_char **valp) +{ + if (req_size != -1 && value->v.octetstring.len != (u_long)req_size) + return (SNMP_ERR_BADVALUE); + + ctx->scratch->ptr1 = *valp; + + if ((*valp = malloc(value->v.octetstring.len + 1)) == NULL) { + *valp = ctx->scratch->ptr1; + return (SNMP_ERR_RES_UNAVAIL); + } + + memcpy(*valp, value->v.octetstring.octets, value->v.octetstring.len); + (*valp)[value->v.octetstring.len] = '\0'; + + return (0); +} + +/* + * Commit a string. This is easy - free the old value. + */ +void +string_commit(struct snmp_context *ctx) +{ + free(ctx->scratch->ptr1); +} + +/* + * Rollback a string - free new value and copy back old one. + */ +void +string_rollback(struct snmp_context *ctx, u_char **valp) +{ + free(*valp); + *valp = ctx->scratch->ptr1; +} + +/* + * ROLLBACK or COMMIT fails because instance has disappeared. Free string. + */ +void +string_free(struct snmp_context *ctx) +{ + free(ctx->scratch->ptr1); +} + +/* + * Get a string value for a response packet + */ +int +string_get(struct snmp_value *value, const u_char *ptr, ssize_t len) +{ + if (ptr == NULL) { + value->v.octetstring.len = 0; + value->v.octetstring.octets = NULL; + return (SNMP_ERR_NOERROR); + } + if (len == -1) + len = strlen(ptr); + value->v.octetstring.len = (u_long)len; + if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + memcpy(value->v.octetstring.octets, ptr, (size_t)len); + return (SNMP_ERR_NOERROR); +} + +/* + * Support for IPADDRESS + * + * Save the old IP address in scratch->int1 and set the new one. + */ +int +ip_save(struct snmp_value *value, struct snmp_context *ctx, u_char *valp) +{ + ctx->scratch->int1 = (valp[0] << 24) | (valp[1] << 16) | (valp[2] << 8) + | valp[3]; + + valp[0] = value->v.ipaddress[0]; + valp[1] = value->v.ipaddress[1]; + valp[2] = value->v.ipaddress[2]; + valp[3] = value->v.ipaddress[3]; + + return (0); +} + +/* + * Rollback the address by copying back the old one + */ +void +ip_rollback(struct snmp_context *ctx, u_char *valp) +{ + valp[0] = ctx->scratch->int1 >> 24; + valp[1] = ctx->scratch->int1 >> 16; + valp[2] = ctx->scratch->int1 >> 8; + valp[3] = ctx->scratch->int1; +} + +/* + * Nothing to do for commit + */ +void +ip_commit(struct snmp_context *ctx __unused) +{ +} + +/* + * Retrieve an IP address + */ +int +ip_get(struct snmp_value *value, u_char *valp) +{ + value->v.ipaddress[0] = valp[0]; + value->v.ipaddress[1] = valp[1]; + value->v.ipaddress[2] = valp[2]; + value->v.ipaddress[3] = valp[3]; + return (SNMP_ERR_NOERROR); +} + +/* + * Object ID support + * + * Save the old value in a fresh allocated oid pointed to by scratch->ptr1. + */ +int +oid_save(struct snmp_value *value, struct snmp_context *ctx, + struct asn_oid *oid) +{ + if ((ctx->scratch->ptr1 = malloc(sizeof(struct asn_oid))) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + *(struct asn_oid *)ctx->scratch->ptr1 = *oid; + *oid = value->v.oid; + + return (0); +} + +void +oid_rollback(struct snmp_context *ctx, struct asn_oid *oid) +{ + *oid = *(struct asn_oid *)ctx->scratch->ptr1; + free(ctx->scratch->ptr1); +} + +void +oid_commit(struct snmp_context *ctx) +{ + free(ctx->scratch->ptr1); +} + +int +oid_get(struct snmp_value *value, const struct asn_oid *oid) +{ + value->v.oid = *oid; + return (SNMP_ERR_NOERROR); +} + +/* + * Decode an index + */ +int +index_decode(const struct asn_oid *oid, u_int sub, u_int code, ...) +{ + va_list ap; + u_int index_count; + void *octs[10]; + u_int nocts; + u_int idx; + + va_start(ap, code); + index_count = SNMP_INDEX_COUNT(code); + nocts = 0; + + for (idx = 0; idx < index_count; idx++) { + switch (SNMP_INDEX(code, idx)) { + + case SNMP_SYNTAX_NULL: + break; + + case SNMP_SYNTAX_INTEGER: + if (sub == oid->len) + goto err; + *va_arg(ap, int32_t *) = oid->subs[sub++]; + break; + + case SNMP_SYNTAX_COUNTER64: + if (sub == oid->len) + goto err; + *va_arg(ap, u_int64_t *) = oid->subs[sub++]; + break; + + case SNMP_SYNTAX_OCTETSTRING: + { + u_char **cval; + size_t *sval; + u_int i; + + /* only variable size supported */ + if (sub == oid->len) + goto err; + cval = va_arg(ap, u_char **); + sval = va_arg(ap, size_t *); + *sval = oid->subs[sub++]; + if (sub + *sval > oid->len) + goto err; + if ((*cval = malloc(*sval)) == NULL) { + syslog(LOG_ERR, "%s: %m", __func__); + goto err; + } + octs[nocts++] = *cval; + for (i = 0; i < *sval; i++) { + if (oid->subs[sub] > 0xff) + goto err; + (*cval)[i] = oid->subs[sub++]; + } + break; + } + + case SNMP_SYNTAX_OID: + { + struct asn_oid *aval; + u_int i; + + if (sub == oid->len) + goto err; + aval = va_arg(ap, struct asn_oid *); + aval->len = oid->subs[sub++]; + if (aval->len > ASN_MAXOIDLEN) + goto err; + for (i = 0; i < aval->len; i++) + aval->subs[i] = oid->subs[sub++]; + break; + } + + case SNMP_SYNTAX_IPADDRESS: + { + u_int8_t *pval; + u_int i; + + if (sub + 4 > oid->len) + goto err; + pval = va_arg(ap, u_int8_t *); + for (i = 0; i < 4; i++) { + if (oid->subs[sub] > 0xff) + goto err; + pval[i] = oid->subs[sub++]; + } + break; + } + + case SNMP_SYNTAX_COUNTER: + case SNMP_SYNTAX_GAUGE: + case SNMP_SYNTAX_TIMETICKS: + if (sub == oid->len) + goto err; + if (oid->subs[sub] > 0xffffffff) + goto err; + *va_arg(ap, u_int32_t *) = oid->subs[sub++]; + break; + } + } + + va_end(ap); + return (0); + + err: + va_end(ap); + while(nocts > 0) + free(octs[--nocts]); + return (-1); +} + +/* + * Compare the index part of an OID and an index. + */ +int +index_compare_off(const struct asn_oid *oid, u_int sub, + const struct asn_oid *idx, u_int off) +{ + u_int i; + + for (i = off; i < idx->len && i < oid->len - sub; i++) { + if (oid->subs[sub + i] < idx->subs[i]) + return (-1); + if (oid->subs[sub + i] > idx->subs[i]) + return (+1); + } + if (oid->len - sub < idx->len) + return (-1); + if (oid->len - sub > idx->len) + return (+1); + + return (0); +} + +int +index_compare(const struct asn_oid *oid, u_int sub, const struct asn_oid *idx) +{ + return (index_compare_off(oid, sub, idx, 0)); +} + +/* + * Append an index to an oid + */ +void +index_append_off(struct asn_oid *var, u_int sub, const struct asn_oid *idx, + u_int off) +{ + u_int i; + + var->len = sub + idx->len; + for (i = off; i < idx->len; i++) + var->subs[sub + i] = idx->subs[i]; +} +void +index_append(struct asn_oid *var, u_int sub, const struct asn_oid *idx) +{ + index_append_off(var, sub, idx, 0); +} + diff --git a/contrib/bsnmp/snmpd/main.c b/contrib/bsnmp/snmpd/main.c new file mode 100644 index 000000000000..1568b4b34c89 --- /dev/null +++ b/contrib/bsnmp/snmpd/main.c @@ -0,0 +1,2038 @@ +/* + * 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/main.c,v 1.76 2003/01/28 13:44:35 hbb Exp $ + * + * SNMPd main stuff. + */ +#include <sys/param.h> +#include <sys/un.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <stdarg.h> +#include <ctype.h> +#include <errno.h> +#include <syslog.h> +#include <unistd.h> +#include <signal.h> +#include <dlfcn.h> +#include <inttypes.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "snmpmod.h" +#include "snmpd.h" +#include "tree.h" +#include "oid.h" + +#define PATH_PID "/var/run/%s.pid" +#define PATH_CONFIG "/etc/%s.config" + +u_int32_t this_tick; /* start of processing of current packet */ +u_int32_t start_tick; /* start of processing */ + +struct systemg systemg = { + NULL, + { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, + NULL, NULL, NULL, + 64 + 8 + 4, + 0 +}; +struct debug debug = { + 0, /* dump_pdus */ + LOG_DEBUG, /* log_pri */ + 0, /* evdebug */ +}; + +struct snmpd snmpd = { + 2048, /* txbuf */ + 2048, /* rxbuf */ + 0, /* comm_dis */ + 0, /* auth_traps */ + {0, 0, 0, 0}, /* trap1addr */ +}; +struct snmpd_stats snmpd_stats; + +/* snmpSerialNo */ +int32_t snmp_serial_no; + +/* search path for config files */ +const char *syspath = PATH_SYSCONFIG; + +/* list of all loaded modules */ +struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); + +/* list of loaded modules during start-up in the order they were loaded */ +static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); + +/* list of all known communities */ +struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); + +/* list of all installed object resources */ +struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); + +/* community value generator */ +static u_int next_community_index = 1; + +/* list of all known ranges */ +struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); + +/* identifier generator */ +u_int next_idrange = 1; + +/* list of all current timers */ +struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); + +/* list of file descriptors */ +struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); + +/* program arguments */ +static char **progargs; +static int nprogargs; + +/* current community */ +u_int community; +static struct community *comm; + +/* list of all IP ports we are listening on */ +struct snmp_port_list snmp_port_list = + TAILQ_HEAD_INITIALIZER(snmp_port_list); + +/* list of all local ports we are listening on */ +struct local_port_list local_port_list = + TAILQ_HEAD_INITIALIZER(local_port_list); + +/* file names */ +static char config_file[MAXPATHLEN + 1]; +static char pid_file[MAXPATHLEN + 1]; + +/* event context */ +static evContext evctx; + +/* signal mask */ +static sigset_t blocked_sigs; + +/* signal handling */ +static int work; +#define WORK_DOINFO 0x0001 +#define WORK_RECONFIG 0x0002 + +/* oids */ +static const struct asn_oid + oid_snmpMIB = OIDX_snmpMIB, + oid_begemotSnmpd = OIDX_begemotSnmpd, + oid_coldStart = OIDX_coldStart, + oid_authenticationFailure = OIDX_authenticationFailure; + +const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; + +/* request id generator for traps */ +u_int trap_reqid; + +/* help text */ +static const char usgtxt[] = "\ +Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ +Open Communication Systems (FhG Fokus). All rights reserved.\n\ +usage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\ + [-m variable=value] [-p file]\n\ +options:\n\ + -d don't daemonize\n\ + -h print this info\n\ + -c file specify configuration file\n\ + -D options debugging options\n\ + -I path system include path\n\ + -l prefix default basename for pid and config file\n\ + -m var=val define variable\n\ + -p file specify pid file\n\ +"; + +/* forward declarations */ +static void snmp_printf_func(const char *fmt, ...); +static void snmp_error_func(const char *err, ...); +static void snmp_debug_func(const char *err, ...); +static void asn_error_func(const struct asn_buf *b, const char *err, ...); + +/* + * Allocate rx/tx buffer. We allocate one byte more for rx. + */ +void * +buf_alloc(int tx) +{ + void *buf; + + if ((buf = malloc(tx ? snmpd.txbuf : (snmpd.rxbuf + 1))) == NULL) { + syslog(LOG_CRIT, "cannot allocate buffer"); + if (tx) + snmpd_stats.noTxbuf++; + else + snmpd_stats.noRxbuf++; + return (NULL); + } + return (buf); +} + +/* + * Return the buffer size. (one more for RX). + */ +size_t +buf_size(int tx) +{ + return (tx ? snmpd.txbuf : (snmpd.rxbuf + 1)); +} + +/* + * Prepare a PDU for output + */ +void +snmp_output(struct snmp_v1_pdu *pdu, u_char *sndbuf, size_t *sndlen, + const char *dest) +{ + struct asn_buf resp_b; + + resp_b.asn_ptr = sndbuf; + resp_b.asn_len = snmpd.txbuf; + + if (snmp_pdu_encode(pdu, &resp_b) != 0) { + syslog(LOG_ERR, "cannot encode message"); + abort(); + } + if (debug.dump_pdus) { + snmp_printf("%s <- ", dest); + snmp_pdu_dump(pdu); + } + *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); +} + +/* + * Send a PDU to a given port + */ +void +snmp_send_port(const struct asn_oid *port, struct snmp_v1_pdu *pdu, + const struct sockaddr *addr, socklen_t addrlen) +{ + struct snmp_port *p; + u_char *sndbuf; + size_t sndlen; + ssize_t len; + + TAILQ_FOREACH(p, &snmp_port_list, link) + if (asn_compare_oid(port, &p->index) == 0) + break; + + if (p == 0) + return; + + if ((sndbuf = buf_alloc(1)) == NULL) + return; + + snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); + + if ((len = sendto(p->sock, sndbuf, sndlen, 0, addr, addrlen)) == -1) + syslog(LOG_ERR, "sendto: %m"); + else if ((size_t)len != sndlen) + syslog(LOG_ERR, "sendto: short write %zu/%zu", + sndlen, (size_t)len); + + free(sndbuf); +} + +/* + * SNMP input. Start: decode the PDU, find the community. + */ +enum snmpd_input_err +snmp_input_start(const u_char *buf, size_t len, const char *source, + struct snmp_v1_pdu *pdu, int32_t *ip) +{ + struct asn_buf b; + enum snmp_code code; + enum snmpd_input_err ret; + + snmpd_stats.inPkts++; + + b.asn_cptr = buf; + b.asn_len = len; + code = snmp_pdu_decode(&b, pdu, ip); + + ret = SNMPD_INPUT_OK; + switch (code) { + + case SNMP_CODE_FAILED: + snmpd_stats.inASNParseErrs++; + return (SNMPD_INPUT_FAILED); + + case SNMP_CODE_BADVERS: + snmpd_stats.inBadVersions++; + return (SNMPD_INPUT_FAILED); + + case SNMP_CODE_BADLEN: + if (pdu->type == SNMP_OP_SET) + ret = SNMPD_INPUT_VALBADLEN; + break; + + case SNMP_CODE_OORANGE: + if (pdu->type == SNMP_OP_SET) + ret = SNMPD_INPUT_VALRANGE; + break; + + case SNMP_CODE_BADENC: + if (pdu->type == SNMP_OP_SET) + ret = SNMPD_INPUT_VALBADENC; + break; + + case SNMP_CODE_OK: + break; + } + + if (debug.dump_pdus) { + snmp_printf("%s -> ", source); + snmp_pdu_dump(pdu); + } + + /* + * Look, whether we know the community + */ + TAILQ_FOREACH(comm, &community_list, link) + if (comm->string != NULL && + strcmp(comm->string, pdu->community) == 0) + break; + + if (comm == NULL) { + snmpd_stats.inBadCommunityNames++; + snmp_pdu_free(pdu); + if (snmpd.auth_traps) + snmp_send_trap(&oid_authenticationFailure, NULL); + return (SNMPD_INPUT_FAILED); + } + community = comm->value; + + /* update uptime */ + this_tick = get_ticks(); + + return (ret); +} + +/* + * Will return only _OK or _FAILED + */ +enum snmpd_input_err +snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, + u_char *sndbuf, size_t *sndlen, const char *source, + enum snmpd_input_err ierr, int32_t ivar, void *data) +{ + struct snmp_pdu resp; + struct asn_buf resp_b, pdu_b; + enum snmp_ret ret; + + resp_b.asn_ptr = sndbuf; + resp_b.asn_len = snmpd.txbuf; + + pdu_b.asn_cptr = rcvbuf; + pdu_b.asn_len = rcvlen; + + if (ierr != SNMPD_INPUT_OK) { + /* error decoding the input of a SET */ + if (pdu->version == SNMP_V1) + pdu->error_status = SNMP_ERR_BADVALUE; + else if (ierr == SNMPD_INPUT_VALBADLEN) + pdu->error_status = SNMP_ERR_WRONG_LENGTH; + else if (ierr == SNMPD_INPUT_VALRANGE) + pdu->error_status = SNMP_ERR_WRONG_VALUE; + else + pdu->error_status = SNMP_ERR_WRONG_ENCODING; + + pdu->error_index = ivar; + + if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { + syslog(LOG_WARNING, "could not encode error response"); + snmpd_stats.silentDrops++; + return (SNMPD_INPUT_FAILED); + } + + if (debug.dump_pdus) { + snmp_printf("%s <- ", source); + snmp_pdu_dump(pdu); + } + *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); + return (SNMPD_INPUT_OK); + } + + switch (pdu->type) { + + case SNMP_PDU_GET: + ret = snmp_get(pdu, &resp_b, &resp, data); + break; + + case SNMP_PDU_GETNEXT: + ret = snmp_getnext(pdu, &resp_b, &resp, data); + break; + + case SNMP_PDU_SET: + ret = snmp_set(pdu, &resp_b, &resp, data); + break; + + case SNMP_PDU_GETBULK: + ret = snmp_getbulk(pdu, &resp_b, &resp, data); + break; + + default: + ret = SNMP_RET_IGN; + break; + } + + switch (ret) { + + case SNMP_RET_OK: + /* normal return - send a response */ + if (debug.dump_pdus) { + snmp_printf("%s <- ", source); + snmp_pdu_dump(&resp); + } + *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); + snmp_pdu_free(&resp); + return (SNMPD_INPUT_OK); + + case SNMP_RET_IGN: + /* error - send nothing */ + snmpd_stats.silentDrops++; + return (SNMPD_INPUT_FAILED); + + case SNMP_RET_ERR: + /* error - send error response. The snmp routine has + * changed the error fields in the original message. */ + resp_b.asn_ptr = sndbuf; + resp_b.asn_len = snmpd.txbuf; + if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { + syslog(LOG_WARNING, "could not encode error response"); + snmpd_stats.silentDrops++; + return (SNMPD_INPUT_FAILED); + } else { + if (debug.dump_pdus) { + snmp_printf("%s <- ", source); + snmp_pdu_dump(pdu); + } + *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); + return (SNMPD_INPUT_OK); + } + } + abort(); +} + + + +/* + * File descriptor support + */ +static void +input(evContext ctx __unused, void *uap, int fd, int mask __unused) +{ + struct fdesc *f = uap; + + (*f->func)(fd, f->udata); +} + +void +fd_suspend(void *p) +{ + struct fdesc *f = p; + + if (evTestID(f->id)) { + (void)evDeselectFD(evctx, f->id); + evInitID(&f->id); + } +} + +int +fd_resume(void *p) +{ + struct fdesc *f = p; + int err; + + if (evTestID(f->id)) + return (0); + if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { + err = errno; + syslog(LOG_ERR, "select fd %d: %m", f->fd); + errno = err; + return (-1); + } + return (0); +} + +void * +fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) +{ + struct fdesc *f; + int err; + + if ((f = malloc(sizeof(struct fdesc))) == NULL) { + err = errno; + syslog(LOG_ERR, "fd_select: %m"); + errno = err; + return (NULL); + } + f->fd = fd; + f->func = func; + f->udata = udata; + f->owner = mod; + evInitID(&f->id); + + if (fd_resume(f)) { + err = errno; + free(f); + errno = err; + return (NULL); + } + + LIST_INSERT_HEAD(&fdesc_list, f, link); + + return (f); +} + +void +fd_deselect(void *p) +{ + struct fdesc *f = p; + + LIST_REMOVE(f, link); + fd_suspend(f); + free(f); +} + +static void +fd_flush(struct lmodule *mod) +{ + struct fdesc *t, *t1; + + t = LIST_FIRST(&fdesc_list); + while (t != NULL) { + t1 = LIST_NEXT(t, link); + if (t->owner == mod) + fd_deselect(t); + t = t1; + } + +} + + +/* + * Input from UDP socket + */ +static void +do_input(int fd, const struct asn_oid *port_index, + struct sockaddr *ret, socklen_t *retlen) +{ + u_char *resbuf, embuf[100]; + u_char *sndbuf; + size_t sndlen; + ssize_t len; + struct snmp_v1_pdu pdu; + enum snmpd_input_err ierr, ferr; + enum snmpd_proxy_err perr; + int32_t vi; + + if ((resbuf = buf_alloc(0)) == NULL) { + (void)recvfrom(fd, embuf, sizeof(embuf), 0, ret, retlen); + return; + } + if ((len = recvfrom(fd, resbuf, buf_size(0), 0, ret, retlen)) == -1) { + free(resbuf); + return; + } + if (len == 0) { + free(resbuf); + return; + } + if ((size_t)len == buf_size(0)) { + free(resbuf); + snmpd_stats.silentDrops++; + snmpd_stats.inTooLong++; + return; + } + + /* + * Handle input + */ + ierr = snmp_input_start(resbuf, (size_t)len, "SNMP", &pdu, &vi); + + /* can't check for bad SET pdus here, because a proxy may have to + * check the access first. We don't want to return an error response + * to a proxy PDU with a wrong community */ + if (ierr == SNMPD_INPUT_FAILED) { + free(resbuf); + return; + } + + /* + * If that is a module community and the module has a proxy function, + * the hand it over to the module. + */ + if (comm->owner != NULL && comm->owner->config->proxy != NULL) { + perr = (*comm->owner->config->proxy)(&pdu, port_index, + ret, *retlen, ierr, vi); + + switch (perr) { + + case SNMPD_PROXY_OK: + free(resbuf); + return; + + case SNMPD_PROXY_REJ: + break; + + case SNMPD_PROXY_DROP: + free(resbuf); + snmp_pdu_free(&pdu); + snmpd_stats.proxyDrops++; + return; + + case SNMPD_PROXY_BADCOMM: + free(resbuf); + snmp_pdu_free(&pdu); + snmpd_stats.inBadCommunityNames++; + if (snmpd.auth_traps) + snmp_send_trap(&oid_authenticationFailure, + NULL); + return; + + case SNMPD_PROXY_BADCOMMUSE: + free(resbuf); + snmp_pdu_free(&pdu); + snmpd_stats.inBadCommunityUses++; + if (snmpd.auth_traps) + snmp_send_trap(&oid_authenticationFailure, + NULL); + return; + } + } + + /* + * Check type + */ + if (pdu.type == SNMP_PDU_RESPONSE || + pdu.type == SNMP_PDU_TRAP || + pdu.type == SNMP_PDU_TRAP2) { + snmpd_stats.silentDrops++; + snmpd_stats.inBadPduTypes++; + snmp_pdu_free(&pdu); + free(resbuf); + return; + } + + /* + * Check community + */ + if (community != COMM_WRITE && + (pdu.type == SNMP_PDU_SET || community != COMM_READ)) { + snmpd_stats.inBadCommunityUses++; + snmp_pdu_free(&pdu); + free(resbuf); + if (snmpd.auth_traps) + snmp_send_trap(&oid_authenticationFailure, NULL); + return; + } + + /* + * Execute it. + */ + if ((sndbuf = buf_alloc(1)) == NULL) { + snmpd_stats.silentDrops++; + snmp_pdu_free(&pdu); + free(resbuf); + return; + } + ferr = snmp_input_finish(&pdu, resbuf, len, sndbuf, &sndlen, "SNMP", + ierr, vi, NULL); + + if (ferr == SNMPD_INPUT_OK) { + if ((len = sendto(fd, sndbuf, sndlen, 0, ret, *retlen)) == -1) + syslog(LOG_ERR, "sendto: %m"); + else if ((size_t)len != sndlen) + syslog(LOG_ERR, "sendto: short write %zu/%zu", + sndlen, (size_t)len); + } + snmp_pdu_free(&pdu); + free(sndbuf); + free(resbuf); +} + +static void +ssock_input(int fd, void *udata) +{ + struct snmp_port *p = udata; + + p->retlen = sizeof(p->ret); + do_input(fd, &p->index, (struct sockaddr *)&p->ret, &p->retlen); +} + +static void +lsock_input(int fd, void *udata) +{ + struct local_port *p = udata; + + p->retlen = sizeof(p->ret); + do_input(fd, &p->index, (struct sockaddr *)&p->ret, &p->retlen); +} + + +/* + * Create a UDP socket and bind it to the given port + */ +static int +init_snmp(struct snmp_port *p) +{ + struct sockaddr_in addr; + u_int32_t ip; + + if ((p->sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "creating UDP socket: %m"); + return (SNMP_ERR_RES_UNAVAIL); + } + ip = (p->addr[0] << 24) | (p->addr[1] << 16) | (p->addr[2] << 8) | + p->addr[3]; + memset(&addr, 0, sizeof(addr)); + addr.sin_addr.s_addr = htonl(ip); + addr.sin_port = htons(p->port); + addr.sin_family = AF_INET; + addr.sin_len = sizeof(addr); + if (bind(p->sock, (struct sockaddr *)&addr, sizeof(addr))) { + if (errno == EADDRNOTAVAIL) { + close(p->sock); + p->sock = -1; + return (SNMP_ERR_INCONS_NAME); + } + syslog(LOG_ERR, "bind: %s:%u %m", inet_ntoa(addr.sin_addr), + p->port); + close(p->sock); + p->sock = -1; + return (SNMP_ERR_GENERR); + } + if ((p->id = fd_select(p->sock, ssock_input, p, NULL)) == NULL) { + close(p->sock); + p->sock = -1; + return (SNMP_ERR_GENERR); + } + return (SNMP_ERR_NOERROR); +} + + +/* + * Create a new SNMP Port object and start it, if we are not + * in initialisation mode. The arguments are in host byte order. + */ +int +open_snmp_port(u_int8_t *addr, u_int32_t port, struct snmp_port **pp) +{ + struct snmp_port *snmp, *p; + int err; + + if (port > 0xffff) + return (SNMP_ERR_NO_CREATION); + if ((snmp = malloc(sizeof(*snmp))) == NULL) + return (SNMP_ERR_GENERR); + snmp->addr[0] = addr[0]; + snmp->addr[1] = addr[1]; + snmp->addr[2] = addr[2]; + snmp->addr[3] = addr[3]; + snmp->port = port; + snmp->sock = -1; + snmp->id = NULL; + snmp->index.len = 5; + snmp->index.subs[0] = addr[0]; + snmp->index.subs[1] = addr[1]; + snmp->index.subs[2] = addr[2]; + snmp->index.subs[3] = addr[3]; + snmp->index.subs[4] = port; + + /* + * Insert it into the right place + */ + TAILQ_FOREACH(p, &snmp_port_list, link) { + if (asn_compare_oid(&p->index, &snmp->index) > 0) { + TAILQ_INSERT_BEFORE(p, snmp, link); + break; + } + } + if (p == NULL) + TAILQ_INSERT_TAIL(&snmp_port_list, snmp, link); + + if (community != COMM_INITIALIZE && + (err = init_snmp(snmp)) != SNMP_ERR_NOERROR) { + TAILQ_REMOVE(&snmp_port_list, snmp, link); + free(snmp); + return (err); + } + *pp = snmp; + return (SNMP_ERR_NOERROR); +} + +/* + * Close an SNMP port + */ +void +close_snmp_port(struct snmp_port *snmp) +{ + if (snmp->id != NULL) + fd_deselect(snmp->id); + if (snmp->sock >= 0) + (void)close(snmp->sock); + + TAILQ_REMOVE(&snmp_port_list, snmp, link); + free(snmp); +} + +/* + * Create a local socket + */ +static int +init_local(struct local_port *p) +{ + struct sockaddr_un sa; + + if ((p->sock = socket(PF_LOCAL, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "creating local socket: %m"); + return (SNMP_ERR_RES_UNAVAIL); + } + strcpy(sa.sun_path, p->name); + sa.sun_family = AF_LOCAL; + sa.sun_len = strlen(p->name) + offsetof(struct sockaddr_un, sun_path); + + (void)remove(p->name); + + if (bind(p->sock, (struct sockaddr *)&sa, sizeof(sa))) { + if (errno == EADDRNOTAVAIL) { + close(p->sock); + p->sock = -1; + return (SNMP_ERR_INCONS_NAME); + } + syslog(LOG_ERR, "bind: %s %m", p->name); + close(p->sock); + p->sock = -1; + return (SNMP_ERR_GENERR); + } + if (chmod(p->name, 0666) == -1) + syslog(LOG_WARNING, "chmod(%s,0666): %m", p->name); + if ((p->id = fd_select(p->sock, lsock_input, p, NULL)) == NULL) { + (void)remove(p->name); + close(p->sock); + p->sock = -1; + return (SNMP_ERR_GENERR); + } + return (SNMP_ERR_NOERROR); +} + + +/* + * Open a local port + */ +int +open_local_port(u_char *name, size_t namelen, struct local_port **pp) +{ + struct local_port *port, *p; + size_t u; + int err; + struct sockaddr_un sa; + + if (namelen == 0 || namelen + 1 > sizeof(sa.sun_path)) { + free(name); + return (SNMP_ERR_BADVALUE); + } + if ((port = malloc(sizeof(*port))) == NULL) { + free(name); + return (SNMP_ERR_GENERR); + } + if ((port->name = malloc(namelen + 1)) == NULL) { + free(name); + free(port); + return (SNMP_ERR_GENERR); + } + strncpy(port->name, name, namelen); + port->name[namelen] = '\0'; + + port->sock = -1; + port->id = NULL; + port->index.len = namelen + 1; + port->index.subs[0] = namelen; + for (u = 0; u < namelen; u++) + port->index.subs[u + 1] = name[u]; + + /* + * Insert it into the right place + */ + TAILQ_FOREACH(p, &local_port_list, link) { + if (asn_compare_oid(&p->index, &port->index) > 0) { + TAILQ_INSERT_BEFORE(p, port, link); + break; + } + } + if (p == NULL) + TAILQ_INSERT_TAIL(&local_port_list, port, link); + + if (community != COMM_INITIALIZE && + (err = init_local(port)) != SNMP_ERR_NOERROR) { + TAILQ_REMOVE(&local_port_list, port, link); + free(port->name); + free(port); + return (err); + } + + *pp = p; + + return (SNMP_ERR_NOERROR); +} + +/* + * Close a local port + */ +void +close_local_port(struct local_port *port) +{ + if (port->id != NULL) + fd_deselect(port->id); + if (port->sock >= 0) + (void)close(port->sock); + (void)remove(port->name); + + TAILQ_REMOVE(&local_port_list, port, link); + free(port->name); + free(port); +} + +/* + * Dump internal state. + */ +static void +info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) +{ + struct lmodule *m; + u_int i; + char buf[10000]; + + syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); + for (i = 0; i < tree_size; i++) { + switch (tree[i].type) { + + case SNMP_NODE_LEAF: + sprintf(buf, "LEAF: %s %s", tree[i].name, + asn_oid2str(&tree[i].oid)); + break; + + case SNMP_NODE_COLUMN: + sprintf(buf, "COL: %s %s", tree[i].name, + asn_oid2str(&tree[i].oid)); + break; + } + syslog(LOG_DEBUG, "%s", buf); + } + + TAILQ_FOREACH(m, &lmodules, link) + if (m->config->dump) + (*m->config->dump)(); +} + +/* + * Re-read configuration + */ +static void +config_func(evContext ctx __unused, void *uap __unused, + const void *tag __unused) +{ + struct lmodule *m; + + if (read_config(config_file, NULL)) { + syslog(LOG_ERR, "error reading config file '%s'", config_file); + return; + } + TAILQ_FOREACH(m, &lmodules, link) + if (m->config->config) + (*m->config->config)(); +} + +/* + * On USR1 dump actual configuration. + */ +static void +onusr1(int s __unused) +{ + work |= WORK_DOINFO; +} +static void +onhup(int s __unused) +{ + work |= WORK_RECONFIG; +} + +static void +onterm(int s __unused) +{ + struct local_port *p; + + TAILQ_FOREACH(p, &local_port_list, link) + (void)remove(p->name); + + exit(0); +} + + +static void +init_sigs(void) +{ + struct sigaction sa; + + sa.sa_handler = onusr1; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGUSR1, &sa, NULL)) { + syslog(LOG_ERR, "sigaction: %m"); + exit(1); + } + + sa.sa_handler = onhup; + if (sigaction(SIGHUP, &sa, NULL)) { + syslog(LOG_ERR, "sigaction: %m"); + exit(1); + } + + sa.sa_handler = onterm; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGTERM, &sa, NULL)) { + syslog(LOG_ERR, "sigaction: %m"); + exit(1); + } + if (sigaction(SIGINT, &sa, NULL)) { + syslog(LOG_ERR, "sigaction: %m"); + exit(1); + } +} + +static void +block_sigs(void) +{ + sigset_t set; + + sigfillset(&set); + if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { + syslog(LOG_ERR, "SIG_BLOCK: %m"); + exit(1); + } +} +static void +unblock_sigs(void) +{ + if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { + syslog(LOG_ERR, "SIG_SETMASK: %m"); + exit(1); + } +} + +/* + * Shut down + */ +static void +term(void) +{ + (void)unlink(pid_file); +} + +/* + * Define a macro from the command line + */ +static void +do_macro(char *arg) +{ + char *eq; + int err; + + if ((eq = strchr(arg, '=')) == NULL) + err = define_macro(arg, ""); + else { + *eq++ = '\0'; + err = define_macro(arg, eq); + } + if (err == -1) { + syslog(LOG_ERR, "cannot save macro: %m"); + exit(1); + } +} + +/* + * Re-implement getsubopt from scratch, because the second argument is broken + * and will not compile with WARNS=5. + */ +static int +getsubopt1(char **arg, const char *const *options, char **valp, char **optp) +{ + static const char *const delim = ",\t "; + u_int i; + char *ptr; + + *optp = NULL; + + /* skip leading junk */ + for (ptr = *arg; *ptr != '\0'; ptr++) + if (strchr(delim, *ptr) == NULL) + break; + if (*ptr == '\0') { + *arg = ptr; + return (-1); + } + *optp = ptr; + + /* find the end of the option */ + while (*++ptr != '\0') + if (strchr(delim, *ptr) != NULL || *ptr == '=') + break; + + if (*ptr != '\0') { + if (*ptr == '=') { + *ptr++ = '\0'; + *valp = ptr; + while (*ptr != '\0' && strchr(delim, *ptr) == NULL) + ptr++; + if (*ptr != '\0') + *ptr++ = '\0'; + } else + *ptr++ = '\0'; + } + + *arg = ptr; + + for (i = 0; *options != NULL; options++, i++) + if (strcmp(suboptarg, *options) == 0) + return (i); + return (-1); +} + +int +main(int argc, char *argv[]) +{ + int opt; + FILE *fp; + int background = 1; + struct snmp_port *p; + struct local_port *pl; + const char *prefix = "snmpd"; + struct lmodule *m; + char *value, *option; + +#define DBG_DUMP 0 +#define DBG_EVENTS 1 +#define DBG_TRACE 2 + static const char *const debug_opts[] = { + "dump", + "events", + "trace", + NULL + }; + + snmp_printf = snmp_printf_func; + snmp_error = snmp_error_func; + snmp_debug = snmp_debug_func; + asn_error = asn_error_func; + + while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF) + switch (opt) { + + case 'c': + strlcpy(config_file, optarg, sizeof(config_file)); + break; + + case 'd': + background = 0; + break; + + case 'D': + while (*optarg) { + switch (getsubopt1(&optarg, debug_opts, + &value, &option)) { + + case DBG_DUMP: + debug.dump_pdus = 1; + break; + + case DBG_EVENTS: + debug.evdebug++; + break; + + case DBG_TRACE: + if (value == NULL) + syslog(LOG_ERR, + "no value for 'trace'"); + snmp_trace = strtoul(value, NULL, 0); + break; + + case -1: + if (suboptarg) + syslog(LOG_ERR, + "unknown debug flag '%s'", + option); + else + syslog(LOG_ERR, + "missing debug flag"); + break; + } + } + break; + + case 'h': + fprintf(stderr, "%s", usgtxt); + exit(0); + + case 'I': + syspath = optarg; + break; + + case 'l': + prefix = optarg; + break; + + case 'm': + do_macro(optarg); + break; + + case 'p': + strlcpy(pid_file, optarg, sizeof(pid_file)); + break; + } + + openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); + setlogmask(LOG_UPTO(debug.logpri - 1)); + + if (background && daemon(0, 0) < 0) { + syslog(LOG_ERR, "daemon: %m"); + exit(1); + } + + argc -= optind; + argv += optind; + + progargs = argv; + nprogargs = argc; + + srandomdev(); + + snmp_serial_no = random(); + + /* + * Initialize the tree. + */ + if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { + syslog(LOG_ERR, "%m"); + exit(1); + } + memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); + tree_size = CTREE_SIZE; + + /* + * Get standard communities + */ + (void)comm_define(1, "SNMP read", NULL, "public"); + (void)comm_define(2, "SNMP write", NULL, "public"); + community = COMM_INITIALIZE; + + trap_reqid = reqid_allocate(512, NULL); + + if (config_file[0] == '\0') + snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); + + init_actvals(); + if (read_config(config_file, NULL)) { + syslog(LOG_ERR, "error in config file"); + exit(1); + } + + if (evCreate(&evctx)) { + syslog(LOG_ERR, "evCreate: %m"); + exit(1); + } + if (debug.evdebug > 0) + evSetDebug(evctx, 10, stderr); + + TAILQ_FOREACH(p, &snmp_port_list, link) + (void)init_snmp(p); + TAILQ_FOREACH(pl, &local_port_list, link) + (void)init_local(pl); + + init_sigs(); + + if (pid_file[0] == '\0') + snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); + + if ((fp = fopen(pid_file, "w")) != NULL) { + fprintf(fp, "%u", getpid()); + fclose(fp); + atexit(term); + } + + start_tick = get_ticks(); + this_tick = get_ticks(); + + if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", + NULL) == 0) { + syslog(LOG_ERR, "cannot register SNMPv2 MIB"); + exit(1); + } + if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", + NULL) == 0) { + syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); + exit(1); + } + + snmp_send_trap(&oid_coldStart, NULL); + + while ((m = TAILQ_FIRST(&modules_start)) != NULL) { + m->flags &= ~LM_ONSTARTLIST; + TAILQ_REMOVE(&modules_start, m, start); + lm_start(m); + } + + for (;;) { + evEvent event; + struct lmodule *mod; + + TAILQ_FOREACH(mod, &lmodules, link) + if (mod->config->idle != NULL) + (*mod->config->idle)(); + + if (evGetNext(evctx, &event, EV_WAIT) == 0) { + if (evDispatch(evctx, event)) + syslog(LOG_ERR, "evDispatch: %m"); + } else if (errno != EINTR) { + syslog(LOG_ERR, "evGetNext: %m"); + exit(1); + } + + if (work != 0) { + block_sigs(); + if (work & WORK_DOINFO) { + if (evWaitFor(evctx, &work, info_func, + NULL, NULL) == -1) { + syslog(LOG_ERR, "evWaitFor: %m"); + exit(1); + } + } + if (work & WORK_RECONFIG) { + if (evWaitFor(evctx, &work, config_func, + NULL, NULL) == -1) { + syslog(LOG_ERR, "evWaitFor: %m"); + exit(1); + } + } + work = 0; + unblock_sigs(); + if (evDo(evctx, &work) == -1) { + syslog(LOG_ERR, "evDo: %m"); + exit(1); + } + } + } + + return (0); +} + + +u_int32_t +get_ticks() +{ + struct timeval tv; + u_int32_t ret; + + if (gettimeofday(&tv, NULL)) + abort(); + ret = tv.tv_sec * 100 + tv.tv_usec / 10000; + return (ret); +} +/* + * Timer support + */ +static void +tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, + struct timespec inter __unused) +{ + struct timer *tp = uap; + + LIST_REMOVE(tp, link); + tp->func(tp->udata); + free(tp); +} + +/* + * Start a timer + */ +void * +timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) +{ + struct timer *tp; + struct timespec due; + + if ((tp = malloc(sizeof(struct timer))) == NULL) { + syslog(LOG_CRIT, "out of memory for timer"); + exit(1); + } + due = evAddTime(evNowTime(), + evConsTime(ticks / 100, (ticks % 100) * 10000)); + + tp->udata = udata; + tp->owner = mod; + tp->func = func; + + LIST_INSERT_HEAD(&timer_list, tp, link); + + if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) + == -1) { + syslog(LOG_ERR, "cannot set timer: %m"); + exit(1); + } + return (tp); +} + +void +timer_stop(void *p) +{ + struct timer *tp = p; + + LIST_REMOVE(tp, link); + if (evClearTimer(evctx, tp->id) == -1) { + syslog(LOG_ERR, "cannot stop timer: %m"); + exit(1); + } + free(p); +} + +static void +timer_flush(struct lmodule *mod) +{ + struct timer *t, *t1; + + t = LIST_FIRST(&timer_list); + while (t != NULL) { + t1 = LIST_NEXT(t, link); + if (t->owner == mod) + timer_stop(t); + t = t1; + } +} + +static void +snmp_printf_func(const char *fmt, ...) +{ + va_list ap; + static char *pend = NULL; + char *ret, *new; + + va_start(ap, fmt); + vasprintf(&ret, fmt, ap); + va_end(ap); + + if (ret == NULL) + return; + if (pend != NULL) { + if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) + == NULL) { + free(ret); + return; + } + pend = new; + strcat(pend, ret); + free(ret); + } else + pend = ret; + + while ((ret = strchr(pend, '\n')) != NULL) { + *ret = '\0'; + syslog(LOG_DEBUG, "%s", pend); + if (strlen(ret + 1) == 0) { + free(pend); + pend = NULL; + break; + } + strcpy(pend, ret + 1); + } +} + +static void +snmp_error_func(const char *err, ...) +{ + char errbuf[1000]; + va_list ap; + + va_start(ap, err); + snprintf(errbuf, sizeof(errbuf), "SNMP: "); + vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), + err, ap); + va_end(ap); + + syslog(LOG_ERR, "%s", errbuf); +} + +static void +snmp_debug_func(const char *err, ...) +{ + char errbuf[1000]; + va_list ap; + + va_start(ap, err); + snprintf(errbuf, sizeof(errbuf), "SNMP: "); + vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), + err, ap); + va_end(ap); + + syslog(LOG_DEBUG, "%s", errbuf); +} + +static void +asn_error_func(const struct asn_buf *b, const char *err, ...) +{ + char errbuf[1000]; + va_list ap; + u_int i; + + va_start(ap, err); + snprintf(errbuf, sizeof(errbuf), "ASN.1: "); + vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), + err, ap); + va_end(ap); + + if (b != NULL) { + snprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), + " at"); + for (i = 0; b->asn_len > i; i++) + snprintf(errbuf+strlen(errbuf), + sizeof(errbuf)-strlen(errbuf), " %02x", b->asn_cptr[i]); + } + + syslog(LOG_ERR, "%s", errbuf); +} + +/* + * Create a new community + */ +u_int +comm_define(u_int priv, const char *descr, struct lmodule *owner, + const char *str) +{ + struct community *c, *p; + u_int ncomm; + + /* generate an identifier */ + do { + if ((ncomm = next_community_index++) == UINT_MAX) + next_community_index = 1; + TAILQ_FOREACH(c, &community_list, link) + if (c->value == ncomm) + break; + } while (c != NULL); + + if ((c = malloc(sizeof(struct community))) == NULL) { + syslog(LOG_ERR, "comm_define: %m"); + return (0); + } + c->owner = owner; + c->value = ncomm; + c->descr = descr; + c->string = NULL; + c->private = priv; + + if (str != NULL) { + if((c->string = malloc(strlen(str)+1)) == NULL) { + free(c); + return (0); + } + strcpy(c->string, str); + } + + /* make index */ + if (c->owner == NULL) { + c->index.len = 1; + c->index.subs[0] = 0; + } else { + c->index = c->owner->index; + } + c->index.subs[c->index.len++] = c->private; + + /* + * Insert ordered + */ + TAILQ_FOREACH(p, &community_list, link) { + if (asn_compare_oid(&p->index, &c->index) > 0) { + TAILQ_INSERT_BEFORE(p, c, link); + break; + } + } + if (p == NULL) + TAILQ_INSERT_TAIL(&community_list, c, link); + return (c->value); +} + +const char * +comm_string(u_int ncomm) +{ + struct community *p; + + TAILQ_FOREACH(p, &community_list, link) + if (p->value == ncomm) + return (p->string); + return (NULL); +} + +/* + * Delete all communities allocated by a module + */ +static void +comm_flush(struct lmodule *mod) +{ + struct community *p, *p1; + + p = TAILQ_FIRST(&community_list); + while (p != NULL) { + p1 = TAILQ_NEXT(p, link); + if (p->owner == mod) { + free(p->string); + TAILQ_REMOVE(&community_list, p, link); + free(p); + } + p = p1; + } +} + +/* + * Request ID handling. + * + * Allocate a new range of request ids. Use a first fit algorithm. + */ +u_int +reqid_allocate(int size, struct lmodule *mod) +{ + u_int type; + struct idrange *r, *r1; + + if (size <= 0 || size > INT32_MAX) { + syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); + return (0); + } + /* allocate a type id */ + do { + if ((type = next_idrange++) == UINT_MAX) + next_idrange = 1; + TAILQ_FOREACH(r, &idrange_list, link) + if (r->type == type) + break; + } while(r != NULL); + + /* find a range */ + if (TAILQ_EMPTY(&idrange_list)) + r = NULL; + else { + r = TAILQ_FIRST(&idrange_list); + if (r->base < size) { + while((r1 = TAILQ_NEXT(r, link)) != NULL) { + if (r1->base - (r->base + r->size) >= size) + break; + r = r1; + } + r = r1; + } + if (r == NULL) { + r1 = TAILQ_LAST(&idrange_list, idrange_list); + if (INT32_MAX - size + 1 < r1->base + r1->size) { + syslog(LOG_ERR, "out of id ranges (%u)", size); + return (0); + } + } + } + + /* allocate structure */ + if ((r1 = malloc(sizeof(struct idrange))) == NULL) { + syslog(LOG_ERR, "%s: %m", __FUNCTION__); + return (0); + } + + r1->type = type; + r1->size = size; + r1->owner = mod; + if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { + r1->base = 0; + TAILQ_INSERT_HEAD(&idrange_list, r1, link); + } else if (r == NULL) { + r = TAILQ_LAST(&idrange_list, idrange_list); + r1->base = r->base + r->size; + TAILQ_INSERT_TAIL(&idrange_list, r1, link); + } else { + r = TAILQ_PREV(r, idrange_list, link); + r1->base = r->base + r->size; + TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); + } + r1->next = r1->base; + + return (type); +} + +int32_t +reqid_next(u_int type) +{ + struct idrange *r; + int32_t id; + + TAILQ_FOREACH(r, &idrange_list, link) + if (r->type == type) + break; + if (r == NULL) { + syslog(LOG_CRIT, "wrong idrange type"); + abort(); + } + if ((id = r->next++) == r->base + (r->size - 1)) + r->next = r->base; + return (id); +} + +int32_t +reqid_base(u_int type) +{ + struct idrange *r; + + TAILQ_FOREACH(r, &idrange_list, link) + if (r->type == type) + return (r->base); + syslog(LOG_CRIT, "wrong idrange type"); + abort(); +} + +u_int +reqid_type(int32_t reqid) +{ + struct idrange *r; + + TAILQ_FOREACH(r, &idrange_list, link) + if (reqid >= r->base && reqid <= r->base + (r->size - 1)) + return (r->type); + return (0); +} + +int +reqid_istype(int32_t reqid, u_int type) +{ + return (reqid_type(reqid) == type); +} + +/* + * Delete all communities allocated by a module + */ +static void +reqid_flush(struct lmodule *mod) +{ + struct idrange *p, *p1; + + p = TAILQ_FIRST(&idrange_list); + while (p != NULL) { + p1 = TAILQ_NEXT(p, link); + if (p->owner == mod) { + TAILQ_REMOVE(&idrange_list, p, link); + free(p); + } + p = p1; + } +} + +/* + * Merge the given tree for the given module into the main tree. + */ +static int +compare_node(const void *v1, const void *v2) +{ + const struct snmp_node *n1 = v1; + const struct snmp_node *n2 = v2; + + return (asn_compare_oid(&n1->oid, &n2->oid)); +} +static int +tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) +{ + struct snmp_node *xtree; + u_int i; + + xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); + if (xtree == NULL) { + syslog(LOG_ERR, "lm_load: %m"); + return (-1); + } + tree = xtree; + memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); + + for (i = 0; i < nsize; i++) + tree[tree_size + i].data = mod; + + tree_size += nsize; + + qsort(tree, tree_size, sizeof(tree[0]), compare_node); + + return (0); +} + +/* + * Remove all nodes belonging to the loadable module + */ +static void +tree_unmerge(struct lmodule *mod) +{ + u_int s, d; + + for(s = d = 0; s < tree_size; s++) + if (tree[s].data != mod) { + if (s != d) + tree[d] = tree[s]; + d++; + } + tree_size = d; +} + +/* + * Loadable modules + */ +struct lmodule * +lm_load(const char *path, const char *section) +{ + struct lmodule *m; + int err; + int i; + char *av[MAX_MOD_ARGS + 1]; + int ac; + u_int u; + + if ((m = malloc(sizeof(*m))) == NULL) { + syslog(LOG_ERR, "lm_load: %m"); + return (NULL); + } + m->handle = NULL; + m->flags = 0; + strcpy(m->section, section); + + if ((m->path = malloc(strlen(path) + 1)) == NULL) { + syslog(LOG_ERR, "lm_load: %m"); + goto err; + } + strcpy(m->path, path); + + /* + * Make index + */ + m->index.subs[0] = strlen(section); + m->index.len = m->index.subs[0] + 1; + for (u = 0; u < m->index.subs[0]; u++) + m->index.subs[u + 1] = section[u]; + + /* + * Load the object file and locate the config structure + */ + if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { + syslog(LOG_ERR, "lm_load: open %s", dlerror()); + goto err; + } + + if ((m->config = dlsym(m->handle, "config")) == NULL) { + syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); + goto err; + } + + /* + * Insert it into the right place + */ + INSERT_OBJECT_OID(m, &lmodules); + + /* preserve order */ + if (community == COMM_INITIALIZE) { + m->flags |= LM_ONSTARTLIST; + TAILQ_INSERT_TAIL(&modules_start, m, start); + } + + /* + * make the argument vector. + */ + ac = 0; + for (i = 0; i < nprogargs; i++) { + if (strlen(progargs[i]) >= strlen(section) + 1 && + strncmp(progargs[i], section, strlen(section)) == 0 && + progargs[i][strlen(section)] == ':') { + if (ac == MAX_MOD_ARGS) { + syslog(LOG_WARNING, "too many arguments for " + "module '%s", section); + break; + } + av[ac++] = &progargs[i][strlen(section)+1]; + } + } + av[ac] = NULL; + + /* + * Run the initialisation function + */ + if ((err = (*m->config->init)(m, ac, av)) != 0) { + syslog(LOG_ERR, "lm_load: init failed: %d", err); + TAILQ_REMOVE(&lmodules, m, link); + goto err; + } + + return (m); + + err: + if (m->handle) + dlclose(m->handle); + free(m->path); + free(m); + return (NULL); +} + +/* + * Start a module + */ +void +lm_start(struct lmodule *mod) +{ + const struct lmodule *m; + + /* + * Merge tree. If this fails, unload the module. + */ + if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { + lm_unload(mod); + return; + } + + /* + * Read configuration + */ + if (read_config(config_file, mod)) { + syslog(LOG_ERR, "error in config file"); + lm_unload(mod); + return; + } + if (mod->config->start) + (*mod->config->start)(); + + mod->flags |= LM_STARTED; + + /* + * Inform other modules + */ + TAILQ_FOREACH(m, &lmodules, link) + if (m->config->loading) + (*m->config->loading)(mod, 1); +} + + +/* + * Unload a module. + */ +void +lm_unload(struct lmodule *m) +{ + int err; + const struct lmodule *mod; + + TAILQ_REMOVE(&lmodules, m, link); + if (m->flags & LM_ONSTARTLIST) + TAILQ_REMOVE(&modules_start, m, start); + tree_unmerge(m); + + if ((m->flags & LM_STARTED) && m->config->fini && + (err = (*m->config->fini)()) != 0) + syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); + + comm_flush(m); + reqid_flush(m); + timer_flush(m); + fd_flush(m); + + dlclose(m->handle); + free(m->path); + + /* + * Inform other modules + */ + TAILQ_FOREACH(mod, &lmodules, link) + if (mod->config->loading) + (*mod->config->loading)(m, 0); + + free(m); +} + +/* + * Register an object resource and return the index (or 0 on failures) + */ +u_int +or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) +{ + struct objres *objres, *or1; + u_int idx; + + /* find a free index */ + idx = 1; + for (objres = TAILQ_FIRST(&objres_list); + objres != NULL; + objres = TAILQ_NEXT(objres, link)) { + if ((or1 = TAILQ_NEXT(objres, link)) == NULL || + or1->index > objres->index + 1) { + idx = objres->index + 1; + break; + } + } + + if ((objres = malloc(sizeof(*objres))) == NULL) + return (0); + + objres->index = idx; + objres->oid = *or; + strlcpy(objres->descr, descr, sizeof(objres->descr)); + objres->uptime = get_ticks() - start_tick; + objres->module = mod; + + INSERT_OBJECT_INT(objres, &objres_list); + + systemg.or_last_change = objres->uptime; + + return (idx); +} + +void +or_unregister(u_int idx) +{ + struct objres *objres; + + TAILQ_FOREACH(objres, &objres_list, link) + if (objres->index == idx) { + TAILQ_REMOVE(&objres_list, objres, link); + free(objres); + return; + } +} diff --git a/contrib/bsnmp/snmpd/snmpd.config b/contrib/bsnmp/snmpd/snmpd.config new file mode 100644 index 000000000000..128b020132e7 --- /dev/null +++ b/contrib/bsnmp/snmpd/snmpd.config @@ -0,0 +1,92 @@ +# +# 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/snmpd.config,v 1.11 2002/12/11 15:54:08 hbb Exp $ +# +# Example configuration file. +# + +# +# Set some common variables +# +host := foo.bar.com +location := "Room 200" +contact := "sysmeister@bar.com" +system := 1 # FreeBSD +traphost := noc.bar.com +trapport := 162 + +read := "public" +write := "geheim" +trap := "mytrap" + +# +# Configuration +# +%snmpd +begemotSnmpdDebugDumpPdus = 2 +begemotSnmpdDebugSyslogPri = 7 + +begemotSnmpdCommunityString.0.1 = $(read) +begemotSnmpdCommunityString.0.2 = $(write) +begemotSnmpdCommunityDisable = 1 + +# open standard SNMP ports +begemotSnmpdPortStatus.[$(host)].161 = 1 +begemotSnmpdPortStatus.127.0.0.1.161 = 1 + +# open a unix domain socket +begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1 + +# send traps to the traphost +begemotTrapSinkStatus[$(traphost)].$(trapport) = 4 +begemotTrapSinkVersion[$(traphost)].$(trapport) = 2 +begemotTrapSinkComm[$(traphost)].$(trapport) = $(trap) + +sysContact = $(contact) +sysLocation = $(location) +sysObjectId = 1.3.6.1.4.1.12325.1.1.2.1.$(system) + +snmpEnableAuthenTraps = 2 + +# +# Load MIB-2 module +# +begemotSnmpdModulePath."mibII" = "/usr/local/lib/snmp_mibII.so" + +# +# Netgraph module +# +begemotSnmpdModulePath."netgraph" = "/usr/local/lib/snmp_netgraph.so" + +%netgraph +begemotNgControlNodeName = "snmpd" diff --git a/contrib/bsnmp/snmpd/snmpd.h b/contrib/bsnmp/snmpd/snmpd.h new file mode 100644 index 000000000000..5c8e78f4a459 --- /dev/null +++ b/contrib/bsnmp/snmpd/snmpd.h @@ -0,0 +1,277 @@ +/* + * 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/snmpd.h,v 1.17 2003/01/28 13:44:35 hbb Exp $ + * + * Private SNMPd data and functions. + */ +#include <sys/queue.h> +#include <isc/eventlib.h> + +#define PATH_SYSCONFIG "/etc:/usr/etc:/usr/local/etc" + +/************************************************************* + * + * Communities + */ +struct community { + struct lmodule *owner; /* who created the community */ + u_int private;/* private name for the module */ + u_int value; /* value of this community */ + u_char * string; /* the community string */ + const u_char * descr; /* description */ + TAILQ_ENTRY(community) link; + + struct asn_oid index; +}; +/* list of all known communities */ +extern TAILQ_HEAD(community_list, community) community_list; + +/************************************************************* + * + * Request IDs. + */ +struct idrange { + u_int type; /* type id */ + int32_t base; /* base of this range */ + int32_t size; /* size of this range */ + int32_t next; /* generator */ + struct lmodule *owner; /* owner module */ + TAILQ_ENTRY(idrange) link; +}; + +/* list of all known ranges */ +extern TAILQ_HEAD(idrange_list, idrange) idrange_list; + +/* identifier generator */ +extern u_int next_idrange; + +/* request id generator for traps */ +extern u_int trap_reqid; + +/************************************************************* + * + * Timers + */ +struct timer { + void (*func)(void *);/* user function */ + void *udata; /* user data */ + evTimerID id; /* timer id */ + struct lmodule *owner; /* owner of the timer */ + LIST_ENTRY(timer) link; +}; + +/* list of all current timers */ +extern LIST_HEAD(timer_list, timer) timer_list; + + +/************************************************************* + * + * File descriptors + */ +struct fdesc { + int fd; /* the file descriptor */ + void (*func)(int, void *);/* user function */ + void *udata; /* user data */ + evFileID id; /* file id */ + struct lmodule *owner; /* owner module of the file */ + LIST_ENTRY(fdesc) link; +}; + +/* list of all current selected files */ +extern LIST_HEAD(fdesc_list, fdesc) fdesc_list; + +/************************************************************* + * + * Loadable modules + */ +# define LM_SECTION_MAX 14 +struct lmodule { + char section[LM_SECTION_MAX + 1]; /* and index */ + char *path; + u_int flags; + void *handle; + const struct snmp_module *config; + + TAILQ_ENTRY(lmodule) link; + TAILQ_ENTRY(lmodule) start; + + struct asn_oid index; +}; +#define LM_STARTED 0x0001 +#define LM_ONSTARTLIST 0x0002 + +extern TAILQ_HEAD(lmodules, lmodule) lmodules; + +struct lmodule *lm_load(const char *, const char *); +void lm_unload(struct lmodule *); +void lm_start(struct lmodule *); + +/************************************************************* + * + * SNMP ports + */ +struct snmp_port { + u_int8_t addr[4];/* host byteorder */ + u_int16_t port; /* host byteorder */ + + int sock; /* the socket */ + void * id; /* evSelect handle */ + + struct sockaddr_in ret; /* the return address */ + socklen_t retlen; /* length of that address */ + + TAILQ_ENTRY(snmp_port) link; + + struct asn_oid index; +}; +TAILQ_HEAD(snmp_port_list, snmp_port); +extern struct snmp_port_list snmp_port_list; + +void close_snmp_port(struct snmp_port *); +int open_snmp_port(u_int8_t *, u_int32_t, struct snmp_port **); + +struct local_port { + char *name; /* unix path name */ + int sock; /* the socket */ + void *id; /* evSelect handle */ + + struct sockaddr_un ret; /* the return address */ + socklen_t retlen; /* length of that address */ + + TAILQ_ENTRY(local_port) link; + + struct asn_oid index; +}; +TAILQ_HEAD(local_port_list, local_port); +extern struct local_port_list local_port_list; + +void close_local_port(struct local_port *); +int open_local_port(u_char *, size_t, struct local_port **); + +/************************************************************* + * + * SNMPd scalar configuration. + */ +struct snmpd { + /* transmit buffer size */ + u_int32_t txbuf; + + /* receive buffer size */ + u_int32_t rxbuf; + + /* disable community table */ + int comm_dis; + + /* authentication traps */ + int auth_traps; + + /* source address for V1 traps */ + u_char trap1addr[4]; +}; +extern struct snmpd snmpd; + +/* + * The debug group + */ +struct debug { + u_int dump_pdus; + u_int logpri; + u_int evdebug; +}; +extern struct debug debug; + + +/* + * SNMPd statistics table + */ +struct snmpd_stats { + u_int32_t inPkts; /* total packets received */ + u_int32_t inBadVersions; /* unknown version number */ + u_int32_t inASNParseErrs; /* fatal parse errors */ + u_int32_t inBadCommunityNames; + u_int32_t inBadCommunityUses; + u_int32_t proxyDrops; /* dropped by proxy function */ + u_int32_t silentDrops; + + u_int32_t inBadPduTypes; + u_int32_t inTooLong; + u_int32_t noTxbuf; + u_int32_t noRxbuf; +}; +extern struct snmpd_stats snmpd_stats; + +/* + * OR Table + */ +struct objres { + TAILQ_ENTRY(objres) link; + u_int index; + struct asn_oid oid; /* the resource OID */ + char descr[256]; + u_int32_t uptime; + struct lmodule *module; +}; +TAILQ_HEAD(objres_list, objres); +extern struct objres_list objres_list; + +/* + * Trap Sink Table + */ +struct trapsink { + TAILQ_ENTRY(trapsink) link; + struct asn_oid index; + u_int status; + int socket; + u_char comm[SNMP_COMMUNITY_MAXLEN]; + int version; +}; +enum { + TRAPSINK_ACTIVE = 1, + TRAPSINK_NOT_IN_SERVICE = 2, + TRAPSINK_NOT_READY = 3, + TRAPSINK_DESTROY = 6, + + TRAPSINK_V1 = 1, + TRAPSINK_V2 = 2, +}; +TAILQ_HEAD(trapsink_list, trapsink); +extern struct trapsink_list trapsink_list; + +extern const char *syspath; + +/* snmpSerialNo */ +extern int32_t snmp_serial_no; + +int init_actvals(void); +int read_config(const char *, struct lmodule *); +int define_macro(const char *name, const char *value); diff --git a/contrib/bsnmp/snmpd/snmpd.sh b/contrib/bsnmp/snmpd/snmpd.sh new file mode 100755 index 000000000000..86ec962d0159 --- /dev/null +++ b/contrib/bsnmp/snmpd/snmpd.sh @@ -0,0 +1,89 @@ +#!/bin/sh +# +# 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/snmpd.sh,v 1.1 2002/12/04 11:15:23 hbb Exp $ +# +# SNMPd startup script +# +SNMPD=/usr/local/bin/bsnmpd +PID=/var/run/snmpd.pid +CONF=/etc/snmpd.conf + +case "$1" in + +start) + if [ -r ${PID} ] ; then + if kill -0 `cat ${PID}` ; then + echo "snmpd already running -- pid `cat ${PID}`" >/dev/stderr + exit 1 + fi + rm -f ${PID} + fi + if ${SNMPD} -c ${CONF} -p ${PID} ; then + echo "snmpd started" + fi + ;; + +stop) + if [ -r ${PID} ] ; then + if kill -0 `cat ${PID}` ; then + if kill -15 `cat ${PID}` ; then + echo "snmpd stopped" + exit 0 + fi + echo "cannot kill snmpd" >/dev/stderr + exit 1 + fi + echo "stale pid file -- removing" >/dev/stderr + rm -f ${PID} + exit 1 + fi + echo "snmpd not running" >/dev/stderr + ;; + +status) + if [ ! -r ${PID} ] ; then + echo "snmpd not running" + elif kill -0 `cat ${PID}` ; then + echo "snmpd pid `cat ${PID}`" + else + echo "stale pid file -- pid `cat ${PID}`" + fi + ;; + +*) + echo "usage: `basename $0` {start|stop|status}" + exit 1 +esac + +exit 0 diff --git a/contrib/bsnmp/snmpd/snmpmod.3 b/contrib/bsnmp/snmpd/snmpmod.3 new file mode 100644 index 000000000000..143d12d2fab8 --- /dev/null +++ b/contrib/bsnmp/snmpd/snmpmod.3 @@ -0,0 +1,861 @@ +.\" +.\" 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/snmpmod.3,v 1.3 2003/01/28 13:44:35 hbb Exp $ +.\" +.Dd August 16, 2002 +.Dt snmpmod 3 +.Os +.Sh NAME +.Nm INSERT_OBJECT_OID_LINK_INDEX , +.Nm INSERT_OBJECT_INT_LINK_INDEX , +.Nm FIND_OBJECT_OID_LINK_INDEX , +.Nm NEXT_OBJECT_OID_LINK_INDEX , +.Nm FIND_OBJECT_INT_LINK_INDEX , +.Nm NEXT_OBJECT_INT_LINK_INDEX , +.Nm INSERT_OBJECT_OID_LINK , +.Nm INSERT_OBJECT_INT_LINK , +.Nm FIND_OBJECT_OID_LINK , +.Nm NEXT_OBJECT_OID_LINK , +.Nm FIND_OBJECT_INT_LINK , +.Nm NEXT_OBJECT_INT_LINK , +.Nm INSERT_OBJECT_OID , +.Nm INSERT_OBJECT_INT , +.Nm FIND_OBJECT_OID , +.Nm FIND_OBJECT_INT , +.Nm NEXT_OBJECT_OID , +.Nm NEXT_OBJECT_INT , +.Nm this_tick , +.Nm start_tick , +.Nm get_ticks , +.Nm systemg , +.Nm comm_define , +.Nm community , +.Nm oid_zeroDotZero , +.Nm reqid_allocate , +.Nm reqid_next , +.Nm reqid_base , +.Nm reqid_istype , +.Nm reqid_type , +.Nm timer_start , +.Nm timer_stop , +.Nm fd_select , +.Nm fd_deselect , +.Nm fd_suspend , +.Nm fd_resume , +.Nm or_register , +.Nm or_unregister , +.Nm buf_alloc , +.Nm buf_size , +.Nm snmp_input_start , +.Nm snmp_input_finish , +.Nm snmp_output , +.Nm snmp_send_port , +.Nm snmp_send_trap , +.Nm string_save , +.Nm string_commit , +.Nm string_rollback , +.Nm string_get , +.Nm string_free , +.Nm ip_save , +.Nm ip_rollback , +.Nm ip_commit , +.Nm ip_get , +.Nm oid_save , +.Nm oid_rollback , +.Nm oid_commit , +.Nm oid_get , +.Nm index_decode , +.Nm index_compare , +.Nm index_compare_off , +.Nm index_append , +.Nm index_append_off +.Nd "SNMP daemon loadable module interface" +.Sh LIBRARY +Begemot SNMP library +.Pq libbsnmp, -lbsnmp +.Sh SYNOPSIS +.In bsnmp/snmpmod.h +.Fn INSERT_OBJECT_OID_LINK_INDEX "PTR" "LIST" "LINK" "INDEX" +.Fn INSERT_OBJECT_INT_LINK_INDEX "PTR" "LIST" "LINK" "INDEX" +.Fn FIND_OBJECT_OID_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX" +.Fn FIND_OBJECT_INT_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX" +.Fn NEXT_OBJECT_OID_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX" +.Fn NEXT_OBJECT_INT_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX" +.Fn INSERT_OBJECT_OID_LINK "PTR" "LIST" "LINK" +.Fn INSERT_OBJECT_INT_LINK "PTR" "LIST" "LINK" +.Fn FIND_OBJECT_OID_LINK "LIST" "OID" "SUB" "LINK" +.Fn FIND_OBJECT_INT_LINK "LIST" "OID" "SUB" "LINK" +.Fn NEXT_OBJECT_OID_LINK "LIST" "OID" "SUB" "LINK" +.Fn NEXT_OBJECT_INT_LINK "LIST" "OID" "SUB" "LINK" +.Fn INSERT_OBJECT_OID "PTR" "LIST" +.Fn INSERT_OBJECT_INT "PTR" "LIST" +.Fn FIND_OBJECT_OID "LIST" "OID" "SUB" +.Fn FIND_OBJECT_INT "LIST" "OID" "SUB" +.Fn NEXT_OBJECT_OID "LIST" "OID" "SUB" +.Fn NEXT_OBJECT_INT "LIST" "OID" "SUB" +.Vt extern u_int32_t this_tick ; +.Vt extern u_int32_t start_tick ; +.Ft u_int32_t +.Fn get_ticks "void" +.Vt extern struct systemg systemg ; +.Ft u_int +.Fn comm_define "u_int priv" "const char *descr" "struct lmodule *mod" "const char *str" +.Ft const char * +.Fn comm_string "u_int comm" +.Vt extern u_int community ; +.Vt extern const struct asn_oid oid_zeroDotZero ; +.Ft u_int +.Fn reqid_allocate "int size" "struct lmodule *mod" +.Ft int32_t +.Fn reqid_next "u_int type" +.Ft int32_t +.Fn reqid_base "u_int type" +.Ft int +.Fn reqid_istype "int32_t reqid" "u_int type" +.Ft u_int +.Fn reqid_type "int32_t reqid" +.Ft void * +.Fn timer_start "u_int ticks" "void (*func)(void *)" "void *uarg" "struct lmodule *mod" +.Ft void +.Fn timer_stop "void *timer_id" +.Ft void * +.Fn fd_select "int fd" "void (*func)(int, void *)" "void *uarg" "struct lmodule *mod" +.Ft void +.Fn fd_deselect "void *fd_id" +.Ft void +.Fn fd_suspend "void *fd_id" +.Ft int +.Fn fd_resume "void *fd_id" +.Ft u_int +.Fn or_register "const struct asn_oid *oid" "const char *descr" "struct lmodule *mod" +.Ft void +.Fn or_unregister "u_int or_id" +.Ft void * +.Fn buf_alloc "int tx" +.Ft size_t +.Fn buf_size "int tx" +.Ft enum snmpd_input_err +.Fn snmp_input_start "const u_char *buf" "size_t len" "const char *source" \ + "struct snmp_pdu *pdu" "int32_t *ip" +.Ft enum snmpd_input_err +.Fn snmp_input_finish "struct snmp_pdu *pdu" "const u_char *rcvbuf" \ + "size_t rcvlen" "u_char *sndbuf" "size_t *sndlen" "const char *source" \ + "enum snmpd_input_err ierr" "int32_t ip" "void *data" +.Ft void +.Fn snmp_output "struct snmp_pdu *pdu" "u_char *sndbuf" "size_t *sndlen" \ + "const char *dest" +.Ft void +.Fn snmp_send_port "const struct asn_oid *port" "struct snmp_pdu *pdu" \ + "const struct sockaddr *addr" "socklen_t addrlen" +.Ft void +.Fn snmp_send_trap "const struct asn_oid *oid" "..." +.Ft int +.Fn string_save "struct snmp_value *val" "struct snmp_context *ctx" "ssize_t req_size" "u_char **strp" +.Ft void +.Fn string_commit "struct snmp_context *ctx" +.Ft void +.Fn string_rollback "struct snmp_context *ctx" "u_char **strp" +.Ft int +.Fn string_get "struct snmp_value *val" "const u_char *str" "ssize_t len" +.Ft void +.Fn string_free "struct snmp_context *ctx" +.Ft int +.Fn ip_save "struct snmp_value *val" "struct snmp_context *ctx" "u_char *ipa" +.Ft void +.Fn ip_rollback "struct snmp_context *ctx" "u_char *ipa" +.Ft void +.Fn ip_commit "struct snmp_context *ctx" +.Ft int +.Fn ip_get "struct snmp_value *val" "u_char *ipa" +.Ft int +.Fn oid_save "struct snmp_value *val" "struct snmp_context *ctx" "struct asn_oid *oid" +.Ft void +.Fn oid_rollback "struct snmp_context *ctx" "struct asn_oid *oid" +.Ft void +.Fn oid_commit "struct snmp_context *ctx" +.Ft int +.Fn oid_get "struct snmp_value *val" "const struct asn_oid *oid" +.Ft int +.Fn index_decode "const struct asn_oid *oid" "u_int sub" "u_int code" "..." +.Ft int +.Fn index_compare "const struct asn_oid *oid1" "u_int sub" "const struct asn_oid *oid2" +.Ft int +.Fn index_compare_off "const struct asn_oid *oid1" "u_int sub" "const struct asn_oid *oid2" "u_int off" +.Ft void +.Fn index_append "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src" +.Ft void +.Fn index_append_off "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src" "u_int off" +.Sh DESCRIPTION +The +.Xr snmpd 1 +SNMP daemon implements a minimal MIB which consists of the system group, part +of the SNMP MIB, a private configuration MIB, a trap destination table, a +UDP port table, a community table, a module table, a statistics group and +a debugging group. All other MIBs are support through loadable modules. +This allows +.Xr snmpd 1 +to use for task, that are not the classical SNMP task. +.Ss MODULE LOADING AND UNLOADING +Modules are loaded by writing to the module table. This table is indexed by +a string, that identfies the module to the daemon. This identifier is used +to select the correct configuration section from the configuration files and +to identify resources allocated to this module. A row in the module table is +created by writing a string of non-zero length to the +.Va begemotSnmpdModulePath +column. This string must be the complete path to the file containing the module. +A module can be unloaded by writing a zero length string to the path column +of an existing row. +.Pp +Modules may depend on each other an hence must be loaded in the correct order. +The dependencies are listed in the corresponding manual pages. +.Pp +Upon loading a module the SNMP daemon expects the module file to a export +a global symbol +.Va config . +This symbol should be a variable of type +.Vt struct snmp_module : +.Bd -literal -offset indent +typedef enum snmpd_proxy_err (*proxy_err_f)(struct snmp_pdu *, + const struct asn_oid *, const struct sockaddr *, socklen_t, + enum snmpd_input_err, int32_t); + + +struct snmp_module { + const char *comment; + int (*init)(struct lmodule *, int argc, char *argv[]); + int (*fini)(void); + void (*idle)(void); + void (*dump)(void); + void (*config)(void); + void (*start)(void); + proxy_err_f proxy; + const struct snmp_node *tree; + u_int tree_size; + void (*loading)(const struct lmodule *, int); +}; +.Ed +.Pp +This structure must be statically initialized and its fields have the +following functions: +.Bl -tag -width ".It Va tree_size" +.It Va comment +This is a string that will be visible in the module table. It should give +some hint about the function of this module. +.It Va init +This function is called upon loading the module. The module pointer should +be stored by the module because it is needed in other calls and the +argument vector will contain the arguments to this module from the daemons +command line. This function should return 0 if everything is ok or an +UNIX error code (see +.Xr errno 3 ). +Once the function returns 0, the +.Va fini +function is called when the module is unloaded. +.It Va fini +The module is unloaded. This gives the module a chance to free resources that +are not automatically freed. Be sure to free all memory, because daemons tend +to run very long. This function pointer may be +.Li NULL +if it is not needed. +.It Va idle +If this function pointer is not +.Li NULL , +the function pointed to by it is called whenever the daemon is going +to wait for an event. Try to avoid using this feature. +.It Va dump +Whenever the daemon receives a +.Li SIGUSR1 +it dumps it internal state via +.Xr syslog 3 . +If the +.Va dump +field is not +.Li NULL +it is called by the daemon to dump the state of the module. +.It Va config +Whenever the daemon receives a +.Li SIGHUP +signal it re-reads its configuration file. +If the +.Va config +field is not +.Li NULL +it is called after reading the configuration file to give the module a chance +to adapt to the new configuration. +.It Va start +If not +.Li NULL +this function is called after successful loading and initializing the module +to start its actual operation. +.It Va proxy +If the daemon receives a PDU and that PDU has a community string who's +community was registered by this module and +.Va proxy +is not +.Li NULL +than this function is called to handle the PDU. +.It Va tree +This is a pointer to the node array for the MIB tree implemented by this module. +.It Va tree_size +This is the number of nodes in +.Va tree . +.It Va loading +If this pointer is not +.Li NULL +it is called whenever another module was loaded or unloaded. It gets a +pointer to that module and a flag that is 0 for unloading and 1 for loading. +.El +.Pp +When everything is ok, the daemon merges the module's MIB tree into its current +global tree, calls the modules +.Fn init +function. If this function returns an error, the modules MIB tree is removed from +the global one and the module is unloaded. If initialisation is successful, +the modules +.Fn start +function is called. +After it returns the +.Fn loaded +functions of all modules (including the loaded one) are called. +.Pp +When the module is unloaded, its MIB tree is removed from the global one, +the communities, request id ranges, running timers and selected file +descriptors are released, the +.Fn fini +function is called, the module file is unloaded and the +.Fn loaded +functions of all other modules are called. +.Ss IMPLEMENTING TABLES +There are a number of macros designed to help implementing SNMP tables. +A problem while implementing a table is the support for the GETNEXT operator. +The GETNEXT operation has to find out whether, given an arbitrary OID, the +lessest table row, that has an OID higher than the given OID. The easiest way +to do this is to keep the table as an ordered list of structures each one +of which contains an OID that is the index of the table row. This allows easy +removal, insertion and search. +.Pp +The helper macros assume, that the table is organized as a TAILQ (see +.Xr queue 3 +and each structure contains a +.Vt struct asn_oid +that is used as index. +For simple tables with only a integer or unsigned index, an alternate form +of the macros is available, that presume the existence of an integer or +unsigned field as index field. +.Pp +The macros have name of the form +.Bd -literal -offset indent +{INSERT,FIND,NEXT}_OBJECT_{OID,INT}[_LINK[_INDEX]] +.Ed +.Pp +The +.Fn INSERT_* +macros are used in the SET operation to insert a new table row into the table. +The +.Fn FIND_* +macros are used in the GET operation to find a specific row in the table. +The +.Fn NEXT_* +macros are used in the GETNEXT operation to find the next row in the table. +The last two macros return a pointer to the row structure if a row is found, +.Li NULL +otherwise. +The macros +.Fn *_OBJECT_OID_* +assume the existence of a +.Vt struct asn_oid +that is used as index, the macros +.Fn *_OBJECT_INT_* +assume the existance of an unsigned integer field that is used as index. +.Pp +The macros +.Fn *_INDEX +allow the explicit naming of the index field in the parameter +.Fa INDEX , +whereas the other macros assume that this field is named +.Va index . +The macros +.Fn *_LINK_* +allow the explicit naming of the link field of the tail queues, the others +assume that the link field is named +.Va link . +Explicitely naming the link field may be necessary if the same structures +are held in two or more different tables. +.Pp +The arguments to the macros are as follows: +.Bl -tag -width "INDEX" +.It Fa PTR +A pointer to the new structure to be inserted into the table. +.It Fa LIST +A pointer to the tail queue head. +.It Fa LINK +The name of the link field in the row structure. +.It Fa INDEX +The name of the index field in the row structure. +.It Fa OID +Must point to the +.Va var +field of the +.Fa value +argument to the node operation callback. This is the OID to search for. +.It Fa SUB +This is the index of the start of the table index in the OID pointed to +by +.Fa OID . +This is usually the same as the +.Fa sub +argument to the node operation callback. +.El +.Ss DAEMON TIMESTAMPS +The variable +.Va this_tick +contains the tick (there are 100 SNMP ticks in a second) when +the current PDU processing was started. +The variable +.Va start_tick +contains the tick when the daemon was started. +The function +.Fn get_ticks +returns the current tick. The number of ticks since the daemon was started +is +.Bd -literal -offset indent +get_ticks() - start_tick +.Ed +.Ss THE SYSTEM GROUP +The scalar fields of the system group are held in the global variable +.Va systemg : +.Bd -literal -offset indent +struct systemg { + u_char *descr; + struct asn_oid object_id; + u_char *contact; + u_char *name; + u_char *location; + u_int32_t services; + u_int32_t or_last_change; +}; +.Ed +.Ss COMMUNITIES +The SNMP daemon implements a community table. On recipte of a request message +the community string in that message is compared to each of the community +strings in that table, if a match is found, the global variable +.Va community +is set to the community identifier for that community. Community identifiers +are unsigned integers. For the three standard communities there are three +constants defined: +.Bd -literal -offset indent +#define COMM_INITIALIZE 0 +#define COMM_READ 1 +#define COMM_WRITE 2 +.Ed +.Pp +.Va community +is set to +.Li COMM_INITIALIZE +while the assignments in the configuration file are processed. To +.Li COMM_READ +or +.Li COMM_WRITE +when the community strings for the read-write or read-only community are found +in the incoming PDU. +.Pp +Modules can define additional communities. This may be necessary to provide +transport proxying (a PDU received on one communication link is proxied to +another link) or to implement non-UDP access points to SNMP. A new +community is defined with the function +.Fn comm_define . +It takes the following parameters: +.Bl -tag -width ".It Fa descr" +.It Fa priv +This is an integer identifying the community to the module. Each module has +its own namespace with regard to this parameter. The community table is +indexed with the module name and this identifier. +.It Fa descr +This is a string providing a human readable description of the community. +It is visible in the community table. +.It Fa mod +This is the module defining the community. +.It Fa str +This is the initial community string. +.El +.Pp +The function returns a globally unique community identifier. If a PDU is +received who's community string matches, this identifier is set into the global +.Va community . +.Pp +The function +.Fn comm_string +returns the current community string for the given community. +.Pp +All communities defined by a module are automatically released when the module +is unloaded. +.Ss WELL KNOWN OIDS +The global variable +.Va oid_zeroDotZero +contains the OID 0.0. +.Ss REQUEST ID RANGES +For modules that implement SNMP client functions besides SNMP agent functions +it may be necessary to identify SNMP requests by their identifier to allow +easier routing of responses to the correct sub-system. Request id ranges +provide a way to aquire globally non-overlapping sub-ranges of the entire +31-bit id range. +.Pp +A request id range is allocated with +.Fn reqid_allocate . +The arguments are: the size of the range and the module allocating the range. +For example, the call +.Bd -literal -offset indent +id = reqid_allocate(1000, module); +.Ed +.Pp +allocates a range of 1000 request ids. The function returns the request +id range identifier or 0 if there is not enough identifier space. +The function +.Fn reqid_base +returns the lowest request id in the given range. +.Pp +Request id are allocated starting at the lowest one linear throughout the range. +If the client application may have a lot of outstanding request the range +must be large enough so that an id is not reused until it is really expired. +.Fn reqid_next +returns the sequentially next id in the range. +.Pp +The function +.Fn reqid_istype +checks whether the request id +.Fa reqid +is withing the range identified by +.Fa type . +The function +.Fn reqid_type +returns the range identifier for the given +.Fa reqid +or 0 if the request id is in none of the ranges. +.Ss TIMERS +The SNMP daemon supports an arbitrary number of timers with SNMP tick granularity. +The function +.Fn timer_start +arranges for the callback +.Fa func +to be called with the argument +.Fa uarg +after +.Fa ticks +SNMP ticks have expired. +.Fa mod +is the module that starts the timer. Timers are one-shot, they are not +restarted. The function returns a timer identifier that can be used to +stop the timer via +.Fn timer_stop . +If a module is unloaded all timers started by the module that have not expired +yet are stopped. +.Ss FILE DESCRIPTOR SUPPORT +A module may need to get input from socket file descriptors without blocking +the daemon (for example to implement alternative SNMP transports). +.Pp +The function +.Fn fd_select +causes the callback function +.Fa func +to be called with the file descriptor +.Fa fd +and the user argument +.Fa uarg +whenever the file descriptor +.Fa fd +can be red or has a close condition. If the file descriptor is not in +non-blocking mode, it is set to non-blocking mode. If the callback is not +needed anymore, +.Fn fd_deselect +may be called with the value returned from +.Fn fd_select . +All file descriptors selected by a module are automatically deselected when +the module is unloaded. +.Pp +To temporarily suspend the file descriptor registration +.Fn fd_suspend +can be called. This also causes the file descriptor to be switched back to +blocking mode if it was blocking prior the call to +.Fn fd_select . +This is necessary to do synchronuous input on a selected socket. +The effect of +.Fn fd_suspend +can be undone with +.Fn fd_resume . +.Ss OBJECT RESOURCES +The system group contains an object resource table. A module may create +an entry in this table by calling +.Fn or_register +with the +.Fa oid +to be registered, a textual description in +.Fa str +and a pointer to the module +.Fa mod . +The registration can be removed with +.Fn or_unregister . +All registrations of a module are automatically removed if the module is +unloaded. +.Ss TRANSMIT AND RECEIVE BUFFERS +A buffer is allocated via +.Fn buf_alloc . +The argument must be 1 for transmit and 0 for receive buffers. The function +may return +.Li NULL +if there is no memory available. The current buffersize can be obtained with +.Fn buf_size . +.Sh PROCESSING PDUS +For modules that need to do their own PDU processing (for example for proxying) +the following functions are available: +.Pp +Function +.Fn snmp_input_start +decodes the PDU, searches the community, and sets the global +.Va this_tick . +It returns one of the following error codes: +.Bl -tag -width ".It Er SNMPD_INPUT_VALBADLEN" +.It Er SNMPD_INPUT_OK +Everything ok, continue with processing. +.It Er SNMPD_INPUT_FAILED +The PDU could not be decoded, has a wrong version or an unknown +community string. +.It Er SNMPD_INPUT_VALBADLEN +A SET PDU had a value field in a binding with a wrong length field in an +ASN.1 header. +.It Er SNMPD_INPUT_VALRANGE +A SET PDU had a value field in a binding with a value that is out of range +for the given ASN.1 type. +.It Er SNMPD_INPUT_VALBADENC +A SET PDU had a value field in a binding with wrong ASN.1 encoding. +.El +.Pp +The function +.Fn snmp_input_finish +does the other half of processing: if +.Fn snmp_input_start +did not return OK, tries to construct an error response. If the start was OK, +it calls the correct function from +.Xr bsnmpagent +to execute the request and depending on the outcome constructs a response or +error response PDU or ignores the request PDU. It returns either +.Er SNMPD_INPUT_OK +or +.Er SNMPD_INPUT_FAILED . +In the first case a response PDU was constructed and should be sent. +.Pp +The function +.Fn snmp_output +takes a PDU and encodes it. +.Pp +The function +.Fn snmp_send_port +takes a PDU, encodes it and sends it through the given port (identified by +the index in the port table) to the given address. +.Pp +The function +.Fn snmp_send_trap +sends a trap to all trap destinations. The arguments are the +.Fa oid +identifying the trap and a NULL-terminated list of +.Vt struct snmp_value +pointers that are to be inserted into the trap binding list. +.Ss SIMPLE ACTION SUPPORT +For simple scalar variables that need no dependencies a number of support +functions is available to handle the set, commit, rollback and get. +.Pp +The following functions are used for OCTET STRING scalars, either NUL terminated +or not: +.Bl -tag -width "XXXXXXXXX" +.It Fn string_save +should be called for SNMP_OP_SET. +.Fa value +and +.Fa ctx +are the resp\&. arguments to the node callback. +.Fa valp +is a pointer to the pointer that holds the current value and +.Fa req_size +should be -1 if any size of the string is acceptable or a number larger or +equal zero if the string must have a specific size. The function saves +the old value in the scratch area (note, that any initial value must have +been allocated by +.Xr malloc 3 ), +allocates a new string, copies over the new value, NUL-terminates it and +sets the new current value. +.It Fn string_commit +simply frees the saved old value in the scratch area. +.It Fn string_rollback +frees the new value, and puts back the old one. +.It Fn string_get +is used for GET or GETNEXT. If +.Fa len +is -1, the length is computed via +.Xr strlen 3 +from the current string value. If the current value is NULL, +a OCTET STRING of zero length is returned. +.It Fn string_free +must be called if either rollback or commit fails to free the saved old value. +.El +.Pp +The following functions are used to process scalars of type IP-address: +.Bl -tag -width "XXXXXXXXX" +.It Fn ip_save +Saves the current value in the scratch area and sets the new value from +.Fa valp . +.It Fn ip_commit +Does nothing. +.It Fn ip_rollback +Restores the old IP address from the scratch area. +.It Fn ip_get +Retrieves the IP current address. +.El +.Pp +The following functions handle OID-typed variables: +.Bl -tag -width "XXXXXXXXX" +.It Fn oid_save +Saves the current value in the scratch area by allocating a +.Vt struct asn_oid +with +.Xr malloc 3 +and sets the new value from +.Fa oid . +.It Fn oid_commit +Frees the old value in the scratch area. +.It Fn oid_rollback +Restores the old OID from the scratch area and frees the old OID. +.It Fn oid_get +Retrieves the OID +.El +.Ss TABLE INDEX HANDLING +The following functions help in handling table indexes: +.Bl -tag -width "XXXXXXXXX" +.It Fn index_decode +Decodes the index part of the OID. The parameter +.Fa oid +must be a pointer to the +.Va var +field of the +.Fa value +argument of the node callback. The +.Fa sub +argument must be the index of the start of the index in the OID (this is +the +.Fa sub +argument to the node callback). +.Fa code +is the index expression (parameter +.Fa idx +to the node callback). +These parameters are followed by parameters depending on the syntax of the index +elements as follows: +.Bl -tag -width ".It Li OCTET STRING" +.It Li INTEGER +.Vt int32_t * +expected as argument. +.It Li COUNTER64 +.Vt u_int64_t * +expected as argument. Note, that this syntax is illegal for indexes. +.It Li OCTET STRING +A +.Vt u_char ** +and a +.Vt size_t * +expected as arguments. A buffer is allocated to hold the decoded string. +.It Li OID +A +.Vt struct asn_oid * +is expected as argument. +.It Li IP ADDRESS +A +.Vt u_int8_t * +expected as argument that points to a buffer of at least four byte. +.It Li COUNTER, GAUGE, TIMETICKS +A +.Vt u_int32_t +expected. +.It Li NULL +No argument expected. +.El +.It Fn index_compare +compares the current variable with an OID. +.Fa oid1 +and +.Fa sub +come from the node callback arguments +.Fa value->var +and +.Fa sub +resp. +.Fa oid2 +is the OID to compare to. The function returns -1, 0, +1 when the +variable is lesser, equal, higher to the given OID. +.Fa oid2 +must contain only the index part of the table column. +.It Fn index_compare_off +is equivalent to +.Fn index_compare +except that it takes an additional parameter +.Fa off +that causes it to ignore the first +.Fa off +components of both indexes. +.It Fn index_append +appends OID +.Fa src +beginning at position +.Fa sub +to +.Fa dst . +.It Fn index_append_off +appends OID +.Fa src +beginning at position +.Fa off +to +.Fa dst +beginning at position +.Fa sub ++ +.Fa off . +.El +.Sh SEE ALSO +.Xr snmpd 1 , +.Xr gensnmptree 1 , +.Xr bsnmplib 3 +.Xr bsnmpclient 3 , +.Xr bsnmpagent 3 +.Sh STANDARDS +This implementation conforms to the applicable IETF RFCs and ITU-T +recommendations. +.Sh AUTHORS +.An Hartmut Brandt Aq brandt@fokus.gmd.de diff --git a/contrib/bsnmp/snmpd/snmpmod.h b/contrib/bsnmp/snmpd/snmpmod.h new file mode 100644 index 000000000000..5e4cbbd32838 --- /dev/null +++ b/contrib/bsnmp/snmpd/snmpmod.h @@ -0,0 +1,363 @@ +/* + * 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/snmpmod.h,v 1.23 2003/01/28 13:44:35 hbb Exp $ + * + * SNMP daemon data and functions exported to modules. + */ +#ifndef snmpmod_h_ +#define snmpmod_h_ + +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include "asn1.h" +#include "snmp.h" +#include "snmpagent.h" + +#define MAX_MOD_ARGS 16 + +/* + * These macros help to handle object lists for SNMP tables. They use + * tail queues to hold the objects in ascending order in the list. + * ordering can be done either on an integer/unsigned field or and asn_oid. + */ +#define INSERT_OBJECT_OID_LINK_INDEX(PTR, LIST, LINK, INDEX) do { \ + __typeof (PTR) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if (asn_compare_oid(&_lelem->INDEX, &(PTR)->INDEX) > 0) \ + break; \ + if (_lelem == NULL) \ + TAILQ_INSERT_TAIL((LIST), (PTR), LINK); \ + else \ + TAILQ_INSERT_BEFORE(_lelem, (PTR), LINK); \ + } while(0) + +#define INSERT_OBJECT_INT_LINK_INDEX(PTR, LIST, LINK, INDEX) do { \ + __typeof (PTR) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if ((asn_subid_t)_lelem->INDEX > (asn_subid_t)(PTR)->INDEX)\ + break; \ + if (_lelem == NULL) \ + TAILQ_INSERT_TAIL((LIST), (PTR), LINK); \ + else \ + TAILQ_INSERT_BEFORE(_lelem, (PTR), LINK); \ + } while(0) + +#define FIND_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, LINK, INDEX) ({ \ + __typeof (TAILQ_FIRST(LIST)) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if (index_compare(OID, SUB, &_lelem->INDEX) == 0) \ + break; \ + (_lelem); \ + }) + +#define NEXT_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, LINK, INDEX) ({ \ + __typeof (TAILQ_FIRST(LIST)) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if (index_compare(OID, SUB, &_lelem->INDEX) < 0) \ + break; \ + (_lelem); \ + }) + +#define FIND_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, LINK, INDEX) ({ \ + __typeof (TAILQ_FIRST(LIST)) _lelem; \ + \ + if ((OID)->len - SUB != 1) \ + _lelem = NULL; \ + else \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if ((OID)->subs[SUB] == (asn_subid_t)_lelem->INDEX)\ + break; \ + (_lelem); \ + }) + +#define NEXT_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, LINK, INDEX) ({ \ + __typeof (TAILQ_FIRST(LIST)) _lelem; \ + \ + if ((OID)->len - SUB == 0) \ + _lelem = TAILQ_FIRST(LIST); \ + else \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if ((OID)->subs[SUB] < (asn_subid_t)_lelem->INDEX)\ + break; \ + (_lelem); \ + }) + +/* + * Macros for the case where the index field is called 'index' + */ +#define INSERT_OBJECT_OID_LINK(PTR, LIST, LINK) \ + INSERT_OBJECT_OID_LINK_INDEX(PTR, LIST, LINK, index) + +#define INSERT_OBJECT_INT_LINK(PTR, LIST, LINK) do { \ + INSERT_OBJECT_INT_LINK_INDEX(PTR, LIST, LINK, index) + +#define FIND_OBJECT_OID_LINK(LIST, OID, SUB, LINK) \ + FIND_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, LINK, index) + +#define NEXT_OBJECT_OID_LINK(LIST, OID, SUB, LINK) \ + NEXT_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, LINK, index) + +#define FIND_OBJECT_INT_LINK(LIST, OID, SUB, LINK) \ + FIND_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, LINK, index) + +#define NEXT_OBJECT_INT_LINK(LIST, OID, SUB, LINK) \ + NEXT_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, LINK, index) + +/* + * Macros for the case where the index field is called 'index' and the + * link field 'link'. + */ +#define INSERT_OBJECT_OID(PTR, LIST) \ + INSERT_OBJECT_OID_LINK_INDEX(PTR, LIST, link, index) + +#define INSERT_OBJECT_INT(PTR, LIST) \ + INSERT_OBJECT_INT_LINK_INDEX(PTR, LIST, link, index) + +#define FIND_OBJECT_OID(LIST, OID, SUB) \ + FIND_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, link, index) + +#define FIND_OBJECT_INT(LIST, OID, SUB) \ + FIND_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, link, index) + +#define NEXT_OBJECT_OID(LIST, OID, SUB) \ + NEXT_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, link, index) + +#define NEXT_OBJECT_INT(LIST, OID, SUB) \ + NEXT_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, link, index) + +struct lmodule; + +/* ticks when program and current packet was started */ +extern u_int32_t this_tick; +extern u_int32_t start_tick; + +u_int32_t get_ticks(void); + +/* + * Return code for proxy function + */ +enum snmpd_proxy_err { + /* proxy code will process the PDU */ + SNMPD_PROXY_OK, + /* proxy code does not process PDU */ + SNMPD_PROXY_REJ, + /* drop this PDU */ + SNMPD_PROXY_DROP, + /* drop because of bad community */ + SNMPD_PROXY_BADCOMM, + /* drop because of bad community use */ + SNMPD_PROXY_BADCOMMUSE +}; + +/* + * Input handling + */ +enum snmpd_input_err { + /* proceed with packet */ + SNMPD_INPUT_OK, + /* fatal error in packet, ignore it */ + SNMPD_INPUT_FAILED, + /* value encoding has wrong length in a SET operation */ + SNMPD_INPUT_VALBADLEN, + /* value encoding is out of range */ + SNMPD_INPUT_VALRANGE, + /* value has bad encoding */ + SNMPD_INPUT_VALBADENC, +}; + +/* + * Every loadable module must have one of this structures with + * the external name 'config'. + */ +struct snmp_module { + /* a comment describing what this module implements */ + const char *comment; + + /* the initialisation function */ + int (*init)(struct lmodule *, int argc, char *argv[]); + + /* the finalisation function */ + int (*fini)(void); + + /* the idle function */ + void (*idle)(void); + + /* the dump function */ + void (*dump)(void); + + /* re-configuration function */ + void (*config)(void); + + /* start operation */ + void (*start)(void); + + /* proxy a PDU */ + enum snmpd_proxy_err (*proxy)(struct snmp_v1_pdu *, + const struct asn_oid *, const struct sockaddr *, socklen_t, + enum snmpd_input_err, int32_t); + + /* the tree this module is going to server */ + const struct snmp_node *tree; + u_int tree_size; + + /* function called, when another module was unloaded/loaded */ + void (*loading)(const struct lmodule *, int); +}; + +/* + * Stuff exported to modules + */ + +/* + * The system group. + */ +struct systemg { + u_char *descr; + struct asn_oid object_id; + u_char *contact; + u_char *name; + u_char *location; + u_int32_t services; + u_int32_t or_last_change; +}; +extern struct systemg systemg; + +/* + * Community support. + * + * We have 2 fixed communities for SNMP read and write access. Modules + * can create their communities dynamically. They are deleted automatically + * if the module is unloaded. + */ +#define COMM_INITIALIZE 0 +#define COMM_READ 1 +#define COMM_WRITE 2 + +u_int comm_define(u_int, const char *descr, struct lmodule *, const char *str); +const char * comm_string(u_int); + +/* community for current packet */ +extern u_int community; + +/* + * Well known OIDs + */ +extern const struct asn_oid oid_zeroDotZero; + +/* + * Request ID ranges. + * + * A module can request a range of request ids and associate them with a + * type field. All ranges are deleted if a module is unloaded. + */ +u_int reqid_allocate(int size, struct lmodule *); +int32_t reqid_next(u_int type); +int32_t reqid_base(u_int type); +int reqid_istype(int32_t reqid, u_int type); +u_int reqid_type(int32_t reqid); + +/* + * Timers. + */ +void *timer_start(u_int, void (*)(void *), void *, struct lmodule *); +void timer_stop(void *); + +/* + * File descriptors + */ +void *fd_select(int, void (*)(int, void *), void *, struct lmodule *); +void fd_deselect(void *); +void fd_suspend(void *); +int fd_resume(void *); + +/* + * Object resources + */ +u_int or_register(const struct asn_oid *, const char *, struct lmodule *); +void or_unregister(u_int); + +/* + * Buffers + */ +void *buf_alloc(int tx); +size_t buf_size(int tx); + +/* decode PDU and find community */ +enum snmpd_input_err snmp_input_start(const u_char *, size_t, const char *, + struct snmp_v1_pdu *, int32_t *); + +/* process the pdu. returns either _OK or _FAILED */ +enum snmpd_input_err snmp_input_finish(struct snmp_pdu *, const u_char *, + size_t, u_char *, size_t *, const char *, enum snmpd_input_err, int32_t, + void *); + +void snmp_output(struct snmp_v1_pdu *, u_char *, size_t *, const char *); +void snmp_send_port(const struct asn_oid *, struct snmp_v1_pdu *, + const struct sockaddr *, socklen_t); + +/* sending traps */ +void snmp_send_trap(const struct asn_oid *, ...); + +/* + * Action support + */ +int string_save(struct snmp_value *, struct snmp_context *, ssize_t, u_char **); +void string_commit(struct snmp_context *); +void string_rollback(struct snmp_context *, u_char **); +int string_get(struct snmp_value *, const u_char *, ssize_t); +void string_free(struct snmp_context *); + +int ip_save(struct snmp_value *, struct snmp_context *, u_char *); +void ip_rollback(struct snmp_context *, u_char *); +void ip_commit(struct snmp_context *); +int ip_get(struct snmp_value *, u_char *); + +int oid_save(struct snmp_value *, struct snmp_context *, struct asn_oid *); +void oid_rollback(struct snmp_context *, struct asn_oid *); +void oid_commit(struct snmp_context *); +int oid_get(struct snmp_value *, const struct asn_oid *); + +int index_decode(const struct asn_oid *oid, u_int sub, u_int code, ...); +int index_compare(const struct asn_oid *, u_int, const struct asn_oid *); +int index_compare_off(const struct asn_oid *, u_int, const struct asn_oid *, + u_int); +void index_append(struct asn_oid *, u_int, const struct asn_oid *); +void index_append_off(struct asn_oid *, u_int, const struct asn_oid *, u_int); + +#endif diff --git a/contrib/bsnmp/snmpd/trap.c b/contrib/bsnmp/snmpd/trap.c new file mode 100644 index 000000000000..4853ea9d2160 --- /dev/null +++ b/contrib/bsnmp/snmpd/trap.c @@ -0,0 +1,475 @@ +/* + * 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/trap.c,v 1.5 2003/01/28 13:44:35 hbb Exp $ + * + * TrapSinkTable + */ +#include <sys/types.h> +#include <sys/sysctl.h> +#include <sys/un.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <syslog.h> +#include <unistd.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "snmpmod.h" +#include "snmpd.h" +#include "tree.h" +#include "oid.h" + +struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list); + +static const struct asn_oid oid_begemotTrapSinkTable = + OIDX_begemotTrapSinkTable; +static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime; +static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID; + +struct trapsink_dep { + struct snmp_dependency dep; + u_int set; + u_int status; + u_char comm[SNMP_COMMUNITY_MAXLEN + 1]; + u_int version; + u_int rb; + u_int rb_status; + u_int rb_version; + u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1]; +}; +enum { + TDEP_STATUS = 0x0001, + TDEP_COMM = 0x0002, + TDEP_VERSION = 0x0004, + + TDEP_CREATE = 0x0001, + TDEP_MODIFY = 0x0002, + TDEP_DESTROY = 0x0004, +}; + +static int +trapsink_create(struct trapsink_dep *tdep) +{ + struct trapsink *t; + struct sockaddr_in sa; + + if ((t = malloc(sizeof(*t))) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + + t->index = tdep->dep.idx; + t->status = TRAPSINK_NOT_READY; + t->comm[0] = '\0'; + t->version = TRAPSINK_V2; + + if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "socket(UDP): %m"); + free(t); + return (SNMP_ERR_RES_UNAVAIL); + } + (void)shutdown(t->socket, SHUT_RD); + + sa.sin_len = sizeof(sa); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) | + (t->index.subs[1] << 16) | (t->index.subs[2] << 8) | + (t->index.subs[3] << 0)); + sa.sin_port = htons(t->index.subs[4]); + + if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { + syslog(LOG_ERR, "connect(%s,%u): %m", + inet_ntoa(sa.sin_addr), ntohl(sa.sin_port)); + (void)close(t->socket); + free(t); + return (SNMP_ERR_GENERR); + } + + if (tdep->set & TDEP_VERSION) + t->version = tdep->version; + if (tdep->set & TDEP_COMM) + strcpy(t->comm, tdep->comm); + + if (t->comm[0] != '\0') + t->status = TRAPSINK_NOT_IN_SERVICE; + + /* look whether we should activate */ + if (tdep->status == 4) { + if (t->status == TRAPSINK_NOT_READY) { + if (t->socket != -1) + (void)close(t->socket); + free(t); + return (SNMP_ERR_INCONS_VALUE); + } + t->status = TRAPSINK_ACTIVE; + } + + INSERT_OBJECT_OID(t, &trapsink_list); + + tdep->rb |= TDEP_CREATE; + + return (SNMP_ERR_NOERROR); +} + +static void +trapsink_free(struct trapsink *t) +{ + TAILQ_REMOVE(&trapsink_list, t, link); + if (t->socket != -1) + (void)close(t->socket); + free(t); +} + +static int +trapsink_modify(struct trapsink *t, struct trapsink_dep *tdep) +{ + tdep->rb_status = t->status; + tdep->rb_version = t->version; + strcpy(tdep->rb_comm, t->comm); + + if (tdep->set & TDEP_STATUS) { + /* if we are active and should move to not_in_service do + * this first */ + if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) { + t->status = TRAPSINK_NOT_IN_SERVICE; + tdep->rb |= TDEP_MODIFY; + } + } + + if (tdep->set & TDEP_VERSION) + t->version = tdep->version; + if (tdep->set & TDEP_COMM) + strcpy(t->comm, tdep->comm); + + if (tdep->set & TDEP_STATUS) { + /* if we were inactive and should go active - do this now */ + if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) { + if (t->comm[0] == '\0') { + t->status = tdep->rb_status; + t->version = tdep->rb_version; + strcpy(t->comm, tdep->rb_comm); + return (SNMP_ERR_INCONS_VALUE); + } + t->status = TRAPSINK_ACTIVE; + tdep->rb |= TDEP_MODIFY; + } + } + return (SNMP_ERR_NOERROR); +} + +static int +trapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep) +{ + if (tdep->set & TDEP_STATUS) + t->status = tdep->rb_status; + if (tdep->set & TDEP_VERSION) + t->version = tdep->rb_version; + if (tdep->set & TDEP_COMM) + strcpy(t->comm, tdep->rb_comm); + + return (SNMP_ERR_NOERROR); +} + +static void +trapsink_finish(struct snmp_context *ctx __unused, int fail, void *arg) +{ + struct trapsink *t = arg; + + if (!fail) + trapsink_free(t); +} + +static int +trapsink_destroy(struct snmp_context *ctx, struct trapsink *t, + struct trapsink_dep *tdep) +{ + if (snmp_set_atfinish(ctx, trapsink_finish, t)) + return (SNMP_ERR_RES_UNAVAIL); + t->status = TRAPSINK_DESTROY; + tdep->rb_status = t->status; + tdep->rb |= TDEP_DESTROY; + return (SNMP_ERR_NOERROR); +} + +static int +trapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep) +{ + t->status = tdep->rb_status; + return (SNMP_ERR_NOERROR); +} + +static int +trapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep, + enum snmp_depop op) +{ + struct trapsink_dep *tdep = (struct trapsink_dep *)dep; + struct trapsink *t; + + t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0); + + switch (op) { + + case SNMP_DEPOP_COMMIT: + if (tdep->set & TDEP_STATUS) { + switch (tdep->status) { + + case 1: + case 2: + if (t == NULL) + return (SNMP_ERR_INCONS_VALUE); + return (trapsink_modify(t, tdep)); + + case 4: + case 5: + if (t != NULL) + return (SNMP_ERR_INCONS_VALUE); + return (trapsink_create(tdep)); + + case 6: + if (t == NULL) + return (SNMP_ERR_NOERROR); + return (trapsink_destroy(ctx, t, tdep)); + } + } else if (tdep->set != 0) + return (trapsink_modify(t, tdep)); + + return (SNMP_ERR_NOERROR); + + case SNMP_DEPOP_ROLLBACK: + if (tdep->rb & TDEP_CREATE) { + trapsink_free(t); + return (SNMP_ERR_NOERROR); + } + if (tdep->rb & TDEP_MODIFY) + return (trapsink_unmodify(t, tdep)); + if(tdep->rb & TDEP_DESTROY) + return (trapsink_undestroy(t, tdep)); + return (SNMP_ERR_NOERROR); + } + abort(); +} + +int +op_trapsink(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + struct trapsink *t; + u_char ipa[4]; + int32_t port; + struct asn_oid idx; + struct trapsink_dep *tdep; + u_char *p; + + t = NULL; /* gcc */ + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &t->index); + break; + + case SNMP_OP_GET: + if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (index_decode(&value->var, sub, iidx, ipa, &port) || + port == 0 || port > 65535) + return (SNMP_ERR_NO_CREATION); + t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub); + + asn_slice_oid(&idx, &value->var, sub, value->var.len); + + tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx, + &oid_begemotTrapSinkTable, &idx, + sizeof(*tdep), trapsink_dep); + if (tdep == NULL) + return (SNMP_ERR_RES_UNAVAIL); + + switch (value->var.subs[sub - 1]) { + + case LEAF_begemotTrapSinkStatus: + if (tdep->set & TDEP_STATUS) + return (SNMP_ERR_INCONS_VALUE); + switch (value->v.integer) { + + case 1: + case 2: + if (t == NULL) + return (SNMP_ERR_INCONS_VALUE); + break; + + case 4: + case 5: + if (t != NULL) + return (SNMP_ERR_INCONS_VALUE); + break; + + case 6: + break; + + default: + return (SNMP_ERR_WRONG_VALUE); + } + tdep->status = value->v.integer; + tdep->set |= TDEP_STATUS; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotTrapSinkComm: + if (tdep->set & TDEP_COMM) + return (SNMP_ERR_INCONS_VALUE); + if (value->v.octetstring.len == 0 || + value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN) + return (SNMP_ERR_WRONG_VALUE); + for (p = value->v.octetstring.octets; + p < value->v.octetstring.octets + value->v.octetstring.len; + p++) { + if (!isascii(*p) || !isprint(*p)) + return (SNMP_ERR_WRONG_VALUE); + } + tdep->set |= TDEP_COMM; + strncpy(tdep->comm, value->v.octetstring.octets, + value->v.octetstring.len); + tdep->comm[value->v.octetstring.len] = '\0'; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotTrapSinkVersion: + if (tdep->set & TDEP_VERSION) + return (SNMP_ERR_INCONS_VALUE); + if (value->v.integer != TRAPSINK_V1 && + value->v.integer != TRAPSINK_V2) + return (SNMP_ERR_WRONG_VALUE); + tdep->version = value->v.integer; + tdep->set |= TDEP_VERSION; + return (SNMP_ERR_NOERROR); + } + if (t == NULL) + return (SNMP_ERR_INCONS_NAME); + else + return (SNMP_ERR_NOT_WRITEABLE); + + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_begemotTrapSinkStatus: + value->v.integer = t->status; + break; + + case LEAF_begemotTrapSinkComm: + return (string_get(value, t->comm, -1)); + + case LEAF_begemotTrapSinkVersion: + value->v.integer = t->version; + break; + + } + return (SNMP_ERR_NOERROR); +} + +void +snmp_send_trap(const struct asn_oid *trap_oid, ...) +{ + struct snmp_pdu pdu; + struct trapsink *t; + const struct snmp_value *v; + va_list ap; + u_char *sndbuf; + size_t sndlen; + ssize_t len; + + TAILQ_FOREACH(t, &trapsink_list, link) { + if (t->status != TRAPSINK_ACTIVE) + continue; + memset(&pdu, 0, sizeof(pdu)); + strcpy(pdu.community, t->comm); + if (t->version == TRAPSINK_V1) { + pdu.version = SNMP_V1; + pdu.type = SNMP_PDU_TRAP; + pdu.enterprise = systemg.object_id; + memcpy(pdu.agent_addr, snmpd.trap1addr, 4); + pdu.generic_trap = trap_oid->subs[trap_oid->len - 1] - 1; + pdu.specific_trap = 0; + pdu.time_stamp = get_ticks() - start_tick; + + pdu.nbindings = 0; + } else { + pdu.version = SNMP_V2c; + pdu.type = SNMP_PDU_TRAP2; + pdu.request_id = reqid_next(trap_reqid); + pdu.error_index = 0; + pdu.error_status = SNMP_ERR_NOERROR; + + pdu.bindings[0].var = oid_sysUpTime; + pdu.bindings[0].var.subs[pdu.bindings[0].var.len++] = 0; + pdu.bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; + pdu.bindings[0].v.uint32 = get_ticks() - start_tick; + + pdu.bindings[1].var = oid_snmpTrapOID; + pdu.bindings[1].var.subs[pdu.bindings[1].var.len++] = 0; + pdu.bindings[1].syntax = SNMP_SYNTAX_OID; + pdu.bindings[1].v.oid = *trap_oid; + + pdu.nbindings = 2; + } + + va_start(ap, trap_oid); + while ((v = va_arg(ap, const struct snmp_value *)) != NULL) + pdu.bindings[pdu.nbindings++] = *v; + va_end(ap); + + if ((sndbuf = buf_alloc(1)) == NULL) { + syslog(LOG_ERR, "trap send buffer: %m"); + return; + } + + snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); + + if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) + syslog(LOG_ERR, "send: %m"); + else if ((size_t)len != sndlen) + syslog(LOG_ERR, "send: short write %zu/%zu", + sndlen, (size_t)len); + + free(sndbuf); + } +} diff --git a/contrib/bsnmp/snmpd/tree.def b/contrib/bsnmp/snmpd/tree.def new file mode 100644 index 000000000000..355a5a006d37 --- /dev/null +++ b/contrib/bsnmp/snmpd/tree.def @@ -0,0 +1,183 @@ +# +# 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/tree.def,v 1.34 2002/12/11 15:54:08 hbb Exp $ +# +# System group and private Begemot SNMPd MIB. +# +(1 internet + (2 mgmt + (1 mibII + (1 system +# +# The standard System group +# + (1 sysDescr OCTETSTRING op_system_group GET) + (2 sysObjectId OID op_system_group GET) + (3 sysUpTime TIMETICKS op_system_group GET) + (4 sysContact OCTETSTRING op_system_group GET SET) + (5 sysName OCTETSTRING op_system_group GET SET) + (6 sysLocation OCTETSTRING op_system_group GET SET) + (7 sysServices INTEGER op_system_group GET) + (8 sysORLastChange TIMETICKS op_system_group GET) + (9 sysORTable + (1 sysOREntry : INTEGER op_or_table + (1 sysORIndex INTEGER) + (2 sysORID OID GET) + (3 sysORDescr OCTETSTRING GET) + (4 sysORUpTime TIMETICKS GET) + )) + ) + (11 snmp + (1 snmpInPkts COUNTER op_snmp GET) + (3 snmpInBadVersions COUNTER op_snmp GET) + (4 snmpInBadCommunityNames COUNTER op_snmp GET) + (5 snmpInBadCommunityUses COUNTER op_snmp GET) + (6 snmpInASNParseErrs COUNTER op_snmp GET) + (30 snmpEnableAuthenTraps INTEGER op_snmp GET SET) + (31 snmpSilentDrops COUNTER op_snmp GET) + (32 snmpProxyDrops COUNTER op_snmp GET) + ) + )) +# +# Private Begemot Stuff +# + (4 private + (1 enterprises + (12325 fokus + (1 begemot + +# +# Daemon infrastructure +# + (1 begemotSnmpd + (1 begemotSnmpdObjects + +# +# Configuration +# + (1 begemotSnmpdConfig + (1 begemotSnmpdTransmitBuffer INTEGER op_snmpd_config GET SET) + (2 begemotSnmpdReceiveBuffer INTEGER op_snmpd_config GET SET) + (3 begemotSnmpdCommunityDisable INTEGER op_snmpd_config GET SET) + (4 begemotSnmpdTrap1Addr IPADDRESS op_snmpd_config GET SET) + ) + (2 begemotTrapSinkTable + (1 begemotTrapSinkEntry : IPADDRESS INTEGER op_trapsink + (1 begemotTrapSinkAddr IPADDRESS) + (2 begemotTrapSinkPort INTEGER) + (3 begemotTrapSinkStatus INTEGER GET SET) + (4 begemotTrapSinkComm OCTETSTRING GET SET) + (5 begemotTrapSinkVersion INTEGER GET SET) + ) + ) +# +# Port table +# + (4 begemotSnmpdPortTable + (1 begemotSnmpdPortEntry : IPADDRESS INTEGER op_snmp_port + (1 begemotSnmpdPortAddress IPADDRESS) + (2 begemotSnmpdPortPort UNSIGNED32) + (3 begemotSnmpdPortStatus INTEGER GET SET) + )) +# +# Community table +# + (5 begemotSnmpdCommunityTable + (1 begemotSnmpdCommunityEntry : OCTETSTRING UNSIGNED32 op_community + (1 begemotSnmpdCommunityModule OCTETSTRING) + (2 begemotSnmpdCommunityIndex UNSIGNED32) + (3 begemotSnmpdCommunityString OCTETSTRING GET SET) + (4 begemotSnmpdCommunityDescr OCTETSTRING GET) + )) +# +# Module table +# + (6 begemotSnmpdModuleTable + (1 begemotSnmpdModuleEntry : OCTETSTRING op_modules + (1 begemotSnmpdModuleSection OCTETSTRING) + (2 begemotSnmpdModulePath OCTETSTRING GET SET) + (3 begemotSnmpdModuleComment OCTETSTRING GET) + )) +# +# Statistics +# + (7 begemotSnmpdStats + (1 begemotSnmpdStatsNoRxBufs COUNTER op_snmpd_stats GET) + (2 begemotSnmpdStatsNoTxBufs COUNTER op_snmpd_stats GET) + (3 begemotSnmpdStatsInTooLongPkts COUNTER op_snmpd_stats GET) + (4 begemotSnmpdStatsInBadPduTypes COUNTER op_snmpd_stats GET)) +# +# Debugging +# + (8 begemotSnmpdDebug + (1 begemotSnmpdDebugDumpPdus INTEGER op_debug GET SET) + (2 begemotSnmpdDebugSnmpTrace UNSIGNED32 op_debug GET SET) + (3 begemotSnmpdDebugSyslogPri INTEGER op_debug GET SET)) + +# +# Local (UNIX domain) port table +# + (9 begemotSnmpdLocalPortTable + (1 begemotSnmpdLocalPortEntry : OCTETSTRING op_local_port + (1 begemotSnmpdLocalPortPath OCTETSTRING) + (2 begemotSnmpdLocalPortStatus INTEGER GET SET) + )) + ) + (2 begemotSnmpdDefs + (1 begemotSnmpdAgent + (1 begemotSnmpdAgentFreeBSD OID op_dummy) + ) + ) + ) + )) + ) + ) + (6 snmpV2 + (3 snmpModules + (1 snmpMIB + (1 snmpMIBObjects + (4 snmpTrap + (1 snmpTrapOID OID op_snmp_trap) + ) + (5 snmpTraps + (1 coldStart OID op_snmp_trap) + (2 warmStart OID op_snmp_trap) + (5 authenticationFailure OID op_snmp_trap) + ) + (6 snmpSet + (1 snmpSetSerialNo INTEGER op_snmp_set GET SET) + ) + ) + ) + )) +) |