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