summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsnmpd
diff options
context:
space:
mode:
authorsyrinx <syrinx@FreeBSD.org>2010-12-08 14:30:25 +0000
committersyrinx <syrinx@FreeBSD.org>2010-12-08 14:30:25 +0000
commit9ef714f2e2dd9ccafd17fc4781a095ec9b0265ba (patch)
treedb02060c17839f69576a5f76a958ec282d4a8240 /usr.sbin/bsnmpd
parented79f703fb1803e10222fccd98100334741138ff (diff)
downloadFreeBSD-src-9ef714f2e2dd9ccafd17fc4781a095ec9b0265ba.zip
FreeBSD-src-9ef714f2e2dd9ccafd17fc4781a095ec9b0265ba.tar.gz
Add bsnmpd(1)'s SNMP client tools (including SNMPv3 support) to the base system.
Sponsored by: The FreeBSD Foundation (the SNMPv3 bits), Google Summer of Code 2005 Reviewed by: philip@ (mostly), bz@ (earlier version based on p4 ch124545) Approved by: philip@
Diffstat (limited to 'usr.sbin/bsnmpd')
-rw-r--r--usr.sbin/bsnmpd/Makefile3
-rw-r--r--usr.sbin/bsnmpd/tools/Makefile7
-rw-r--r--usr.sbin/bsnmpd/tools/Makefile.inc13
-rw-r--r--usr.sbin/bsnmpd/tools/bsnmptools/Makefile28
-rw-r--r--usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1401
-rw-r--r--usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c1275
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/Makefile14
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c971
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpmap.c1018
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c1287
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.h95
-rwxr-xr-xusr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c2121
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h331
13 files changed, 7563 insertions, 1 deletions
diff --git a/usr.sbin/bsnmpd/Makefile b/usr.sbin/bsnmpd/Makefile
index c948108..632753d 100644
--- a/usr.sbin/bsnmpd/Makefile
+++ b/usr.sbin/bsnmpd/Makefile
@@ -2,6 +2,7 @@
SUBDIR= gensnmptree \
bsnmpd \
- modules
+ modules \
+ tools
.include <bsd.subdir.mk>
diff --git a/usr.sbin/bsnmpd/tools/Makefile b/usr.sbin/bsnmpd/tools/Makefile
new file mode 100644
index 0000000..3ffc01e
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+# Author: Shteryana Shopova <syrinx@FreeBSD.org>
+
+SUBDIR= libbsnmptools \
+ bsnmptools
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/bsnmpd/tools/Makefile.inc b/usr.sbin/bsnmpd/tools/Makefile.inc
new file mode 100644
index 0000000..e08fe26
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/Makefile.inc
@@ -0,0 +1,13 @@
+# $FreeBSD$
+# Author: Shteryana Shopova <syrinx@FreeBSD.org>
+
+BINDIR?= /usr/bin
+
+CFLAGS+= -I. -I${.CURDIR}
+
+.if exists(${.OBJDIR}/../libbsnmptools)
+LIBBSNMPTOOLSDIR= ${.OBJDIR}/../libbsnmptools
+.else
+LIBBSNMPTOOLSDIR= ${.CURDIR}/../libbsnmptools
+.endif
+LIBBSNMPTOOLS= ${LIBBSNMPTOOLSDIR}/libbsnmptools.a
diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/Makefile b/usr.sbin/bsnmpd/tools/bsnmptools/Makefile
new file mode 100644
index 0000000..311b1a9
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/bsnmptools/Makefile
@@ -0,0 +1,28 @@
+# $FreeBSD$
+# Author: Shteryana Shopova <syrinx@FreeBSD.org>
+
+.include <bsd.own.mk>
+
+.PATH: ${.CURDIR}
+
+PROG= bsnmpget
+
+DPADD+= ${LIBBSNMP} ${LIBBSNMPTOOLS}
+LDADD+= -lbsnmp -lbsnmptools
+CFLAGS+= -I${.CURDIR}/../libbsnmptools
+LDFLAGS+= -L${LIBBSNMPTOOLSDIR}
+
+.if ${MK_OPENSSL} != "no"
+DPADD+= ${LIBCRYPTO}
+LDADD+= -lcrypto
+.endif
+
+LINKS= ${DESTDIR}/usr/bin/bsnmpget ${DESTDIR}/usr/bin/bsnmpwalk
+LINKS+= ${DESTDIR}/usr/bin/bsnmpget ${DESTDIR}/usr/bin/bsnmpset
+
+MAN= bsnmpget.1
+
+MLINKS= bsnmpget.1 bsnmpwalk.1
+MLINKS+= bsnmpget.1 bsnmpset.1
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1 b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1
new file mode 100644
index 0000000..aa3f911
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.1
@@ -0,0 +1,401 @@
+.\"
+.\" Copyright (c) 2010 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" Portions of this documentation were written by Shteryana Sotirova Shopova
+.\" under sponsorship from the FreeBSD Foundation.
+.\"
+.\" Copyright (c) 2005-2007 The FreeBSD Project.
+.\" All rights reserved.
+.\"
+.\" Author: Shteryana Shopova <syrinx@FreeBSD.org>
+.\"
+.\" Redistribution 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 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND 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 AUTHOR OR 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 17, 2007
+.Dt BSNMPGET 1
+.Os
+.Sh NAME
+.Nm bsnmpget ,
+.Nm bsnmpwalk ,
+.Nm bsnmpset
+.Nd "simple tools for querying SNMP agents"
+.Sh SYNOPSIS
+.Nm
+.Op Fl aDdehnK
+.Op Fl A Ar options
+.Op Fl b Ar buffersize
+.Op Fl C Ar options
+.Op Fl I Ar options
+.Op Fl i Ar filelist
+.Op Fl l Ar filename
+.Op Fl M Ar max-repetitions
+.Op Fl N Ar non-repeaters
+.Op Fl o Ar output
+.Op Fl P Ar options
+.Op Fl p Ar pdu
+.Op Fl r Ar retries
+.Op Fl s Ar [trans::][community@][server][:port]
+.Op Fl t Ar timeout
+.Op Fl U Ar options
+.Op Fl v Ar version
+.Op Ar OID ...
+.Pp
+.Nm bsnmpwalk
+.Op Fl dhnK
+.Op Fl A Ar options
+.Op Fl b Ar buffersize
+.Op Fl C Ar options
+.Op Fl I Ar options
+.Op Fl i Ar filelist
+.Op Fl l Ar filename
+.Op Fl o Ar output
+.Op Fl P Ar options
+.Op Fl r Ar retries
+.Op Fl s Ar [trans::][community@][server][:port]
+.Op Fl t Ar timeout
+.Op Fl U Ar options
+.Op Fl v Ar version
+.Op Ar OID ...
+.Pp
+.Nm bsnmpset
+.Op Fl adehnK
+.Op Fl A Ar options
+.Op Fl b Ar buffersize
+.Op Fl C Ar options
+.Op Fl I Ar options
+.Op Fl i Ar filelist
+.Op Fl l Ar filename
+.Op Fl o Ar output
+.Op Fl P Ar options
+.Op Fl r Ar retries
+.Op Fl s Ar [trans::][community@][server][:port]
+.Op Fl t Ar timeout
+.Op Fl U Ar options
+.Op Fl v Ar version
+.Ar OID Ns = Ar syntax Ns : Ns Ar value
+.Op Ar OID Ns = Ar syntax Ns : Ns Ar value ...
+.Sh DESCRIPTION
+.Nm ,
+.Nm bsnmpwalk
+and
+.Nm bsnmpset
+are simple tools for retrieving management information from and setting
+management information to a Simple Network Managment Protocol (SNMP) agent.
+.Pp
+Depending on the options
+.Nm bsnmpget
+constructs either a SMNP GetRequest, GetNextRequest
+or a GetBulkRequest packet, fills in the object identifiers (OIDs) of the
+objects whose values will be retrived, waits for a response and prints it if
+received successfully.
+.Pp
+.Nm Bsnmpwalk
+queries an agent with SMNP GetNextRequest packets,
+asking for values of OID instances that are a part of the object subtree
+rooted at the provided OIDs.
+.Pp
+.Nm Bsnmpset
+constructs a SMNP SetRequest packet, fills in the OIDs (object identifiers),
+syntaxes and values of the objects whose values are to be set and waits for a
+responce from server.
+.Sh OPTIONS
+.Pp
+The options are as follows (not all apply to all three programs):
+.Bl -tag -width ".It Fl D Ar options"
+.It Fl A Ar options
+Authentication options to use with SNMPv3 PDUs
+.Bl -tag -width
+.It Cm proto=[md5|sha]
+The protocol to use when calculating the PDU message digest.
+.It Cm key=authkey
+A binary localized authentication key to use when calculating the PDU message
+digest.
+.El
+.Pp
+By default SNMPv3 PDUs are sent unauthenticated.
+.It Fl a
+Skip any sanity checks when adding OIDs to a Protocol Data Unit (PDU):
+ingore syntax/access type, allow adding of non-leaf objects for GetPdu and
+read-only objects to a SetPDU.
+.It Fl b Ar buffersize
+Tune the size of buffers used to send and receive packets.
+The default size is 10000 bytes which should be enough unless an agent sends
+a really large octetstring.
+The maximum allowed length is 65535 according to the Structure of Management
+Information (SMIv2).
+.It Fl C Ar options
+The context to query with SNMPv3 PDUs.
+.Bl -tag -width
+.It Cm context=name
+The context name. Default is "" (empty).
+.It Cm context-engine=engine-id
+The SNMP Engine ID of the context to query with SNMPv3 PDUs, represented as
+binary octet string. By default, this is set to the Engine ID of the SNMP agent.
+.El
+.It Fl D
+Perform SNMP USM Engine Discovery, rather than sending a request for the value
+of a specific object.
+.It Fl d
+Turn on debugging.
+This option will cause the packets sent and received to be dumped to the
+terminal.
+.It Fl e
+Retry on error.
+If an error is returned in the response PDU, resend the request removing the
+variable that caused the error until a valid response is received.
+This is only usefull for a GetRequest- and a GetNextRequest-PDU.
+.It Fl h
+Print a short help text with default values for various options.
+.It Fl I Ar options
+Load each MIB description file from the given list to translate symbolic
+object names to their numerical representation and vice versa.
+Use the other options to obtain a non-default behaviour:
+.Bl -tag -width
+.It Cm cut=OID
+Specifies the initial OID that was cut by
+.Xr gensnmpdef 1
+when producing the MIB description file.
+The default value is .iso(1).org(3).dod(6) which is what should have been
+used for all the files installed under /usr/share/snmp/defs/ .
+Use this only if you generated your own files, providing a '-c' option to
+.Xr gensnmpdef 1 .
+.It Cm path=filedir
+The directory where files in the list will be searched.
+The default is
+.Pa /usr/share/snmp/defs/ .
+.It Cm file=filelist
+A comma separated list of files to which the two options above will apply.
+.El
+.Pp
+The file suboption has to come after the other suboptions so that their
+non-default values will be applied to the list of files.
+The order of the other suboptions before each file suboption can be random.
+Suboptions may be separated either by commas or by spaces.
+If using spaces make sure the entire option string is one argument, for
+example using quotes.
+.It Fl i Ar filelist
+List of MIB description files produced by
+.Xr gensnmpdef 1 which
+.Nm bsnmpget ,
+.Nm bsnmpwalk
+or
+.Nm bsnmpset
+will search to translate numerical OIDs to their symbolic object names.
+Multiple files can be provided either giving this option multiple times
+or a comma separated list of file names.
+If a filename begins with a letter the default directory,
+/usr/share/snmp/defs/ ,
+will be searched.
+.It Fl K
+Calculate and display the localized authentication and privacy keys
+corresponding to a plain text password. The password is obtain via the
+environment. Additionally, if one or more OIDs are specified, the calculated
+keys are used when processing the SNMPv3 requests.
+.It Fl l Ar filename
+The path of the posix local (unix domain) socket if local
+transport is used.
+.It Fl M Ar max-repetitions
+The value for the max-repetitions field in a GetBulk PDU.
+Default is 1.
+.It Fl N Ar non-repeaters
+The value for the non-repeaters field in a GetBulk PDU.
+Default is 0.
+.It Fl n
+Only use numerical representations for input and output OIDs and do not
+try to resolve symbolic object names.
+Note that
+.Nm bsnmpget ,
+.Nm bsnmpwalk
+and
+.Nm bsnmpset
+will print numerical OIDs anyway if the corresponding string representation
+is not found in the MIB description files.
+.It Fl o Ar [quiet|short|verbose]
+The format used to print the received response.
+Quiet only prints values, short (default) prints an abbreviated OID
+representation and the value.
+In addition to the short output verbose prints the type before the value.
+.It Fl P Ar options
+Privacy options to use with SNMPv3 PDUs
+.Bl -tag -width
+.It Cm proto=[aes|des]
+The protocol to use when encypting/decrypting SNMPv3 PDU data.
+.It Cm key=privkey
+A binary localized privacy key to use when encypting/decrypting SNMPv3 PDU data.
+.El
+.Pp
+By default plain text SNMPv3 PDUs are sent.
+.It Fl p Ar [get|getnext|getbulk]
+The PDU type to send by
+.Nm bsmpget .
+Default is get.
+.It Fl r Ar retries
+Number of resends of request packets before giving up if the agent does
+not respond after the first try.
+Default is 3.
+.It Fl s Ar [trans::] Ns Ar [community@] Ns Ar [server] Ns Ar [:port]
+Each of the server specification components is optional but at least one
+has to be provided if '-s' option is used.
+The server specification is constructed in the following manner:
+.Bl -tag -width
+.It Cm trans::
+Transport type may be one of udp, stream or dgram.
+If this option is not provided an udp inet/inet6 socket will be used, which
+is the most common.
+Stream stands for a posix local stream socket and a posix local datagram
+socket will be used if dgram is specified.
+.It Cm community@
+Specify an SNMP community string to be used when sending packets.
+If the option is skipped the default "public" will be used for
+.Nm
+and
+.Nm bsnmpwalk
+and the default "private" community string will be used for
+.Nm bsnmpset .
+.It Cm server
+This might be either the IP address or the hostname where the agent is
+listening.
+The default is 'localhost'.
+.It Cm port
+The destination port to send the requests to.
+This is useful if the SNMP agent listens on a non-default port.
+Default is given by the 'snmp' entry in /etc/services, port 161.
+.El
+.It Fl t Ar timeout
+Number of seconds before resending a request packet if the agent does
+not respond.
+The default value is 3 seconds.
+.It Fl U Ar options
+User credentials when sending SNMPv3 PDUs.
+.Bl -tag -width
+.It Cm engine=id
+The Engine ID of the SNMP agent represented as a binary octet string.
+.It Cm engine-boots=value
+The value of the snmpEngineBoots of the SNMP agent.
+.It Cm engine-time=value
+The value of the snmpEngineTime of the SNMP agent.
+.Pp
+If any of the above is not specified, SNMP USM Engine Discovery is attempted.
+This is also the default behavior.
+.It Cm name=username
+The USM user name to include in the SNMPv3 PDUs. By default, the user name is
+obtain via the environment
+.El
+.It Fl v Ar version
+The SNMP protocol version to use when sending requests. SNMP versions 1, 2 and
+3 are supported.
+If no version option is provided
+.Nm bsnmpget ,
+.Nm bsnmpwalk
+and
+.Nm bsnmpset
+will use version 2.
+Note that GetBulkRequest-PDUs were introduced in SNMPv2 thus setting the
+version to 1 is incompatiable with sending a GetBulk PDU.
+.It OID
+The object identifier whose value to retrive.
+At least one OID should be provided for
+.Nm bsnmpget
+to be able to send a request.
+.Pp
+For
+.Nm bsnmpwalk
+this is the root object identifier of the subtree whose values are to be
+retrived.
+If no OID is provided
+.Nm bsnmpwalk
+will walk the mib2 subtree rooted
+at .iso(1).org(3).dod(6).internet(1).mgmt(2).mib2(1) .
+.Pp
+Any of the formats used to print a single variable
+is valid as input OID:
+.Bl -tag -width
+.It 1.3.6.1.2.1.25.1.1.0
+.It sysDescr
+.It ifPhysAddress.1
+.It ifRcvAddressStatus.2.6.255.255.255.255.255.255
+.It ifRcvAddressType[2,ff:ff:ff:ff:ff:ff]
+.It ifRcvAddressStatus[Integer:1,OctetString:ff:ff:ff:ff:ff:ff]
+(requires '-o verbose' option)
+.El
+.Pp
+Square brackets are used to denote an entry's indexes.
+When used in an input OID, the square brackets may have to be
+escaped or the OID has to be quoted to protect it from the shell.
+Note there is no difference between ifName.1 and "ifName[1]".
+.It OID Ns = Ns Ar [syntax Ns :] Ns Ar value
+The object identifier with its syntax type and value that is to be set.
+At least one such string OID=[syntax:]value should be provided to
+.Nm bsnmpset
+to be able to send a request.
+.Bl -tag -width
+.It Cm OID
+OID may be input as a string, a string followed by a random number of integers
+(suboids) separated by dots, a sequence of integers separated by dots - that is
+if '-n' options is used - and in such case a syntax is required for every value,
+or a string followed by square brackets (used to denote an entry's indexes) and
+corresponding indexes.
+Any of formats used to print a single variable by
+.Nm bsnmpset is
+valid for inpit OID as well:
+.Bl -tag -width
+.It 1.3.6.1.2.1.25.1.1.0=TimeTicks:537615486
+.It sysLocation=OctetString:"@ Home" (with '-o verbose' option)
+.It sysLocation.0="@ Home"
+.It 1.3.6.1.2.1.2.2.1.6.1=OctetString:ffffffffffff
+.It ifPhysAddress.1="00:02:b3:1d:1c:a3"
+.It ifRcvAddressStatus.1.6.255.255.255.255.255.255=1
+.It "ifRcvAddressStatus[Integer:1,OctetString:ff:ff:ff:ff:ff:ff]=Integer:1"
+(with '-o verbose' option)
+.El
+.It Cm syntax
+where syntax string is one of :
+Integer, OctetString, OID, IpAddress, Counter32, Gauge, TimeTicks, Counter64.
+.It Cm value
+The value to be set - IP address in form of u.u.u.u - for example
+1.3.1.6.1.2.0=IpAddress:192.168.0.1, strings require inverted-commas if they
+contain any special characters or spaces, all other numeric types don't.
+.El
+.Sh ENVIRONMENT
+.Nm ,
+.Nm bsnmpwalk
+and
+.Nm bsnmpset
+use the following environment variables:
+.Bl -tag -width SNMPAUTH
+.It Ev SNMPAUTH
+Specifies a default SNMP USM authentication protocol.
+.It Ev SNMPPRIV
+Specifies a default SNMP USM privacy protocol.
+.It Ev SNMPUSER
+Specifies a default SNMP USM user name.
+.It Ev SNMPPASSWD
+Specifies the SNMP USM plain text password to use when calculating localized
+authentication and privacy keys. If this variable exists in the environment,
+SMNPv3 is the default version to use for outgoing requests.
+.Sh SEE ALSO
+.Xr gensnmpdef 1
+.Sh AUTHORS
+.An Shteryana Shopova Aq syrinx@FreeBSD.org
diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
new file mode 100644
index 0000000..c05a05a
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
@@ -0,0 +1,1275 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND 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 THE AUTHOR OR 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.
+ *
+ * Bsnmpget and bsnmpwalk are simple tools for querying SNMP agents,
+ * bsnmpset can be used to set MIB objects in an agent.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+#include <bsnmp/snmpclient.h>
+#include "bsnmptc.h"
+#include "bsnmptools.h"
+
+static const char *program_name = NULL;
+static enum program_e {
+ BSNMPGET,
+ BSNMPWALK,
+ BSNMPSET
+} program;
+
+/* *****************************************************************************
+ * Common bsnmptools functions.
+ */
+static void
+usage(void)
+{
+ fprintf(stderr,
+"Usage:\n"
+"%s %s [-A options] [-b buffersize] [-C options] [-I options]\n"
+"\t[-i filelist] [-l filename]%s [-o output] [-P options]\n"
+"\t%s[-r retries] [-s [trans::][community@][server][:port]]\n"
+"\t[-t timeout] [-U options] [-v version]%s\n",
+ program_name,
+ (program == BSNMPGET) ? "[-aDdehnK]" :
+ (program == BSNMPWALK) ? "[-dhnK]" :
+ (program == BSNMPSET) ? "[-adehnK]" :
+ "",
+ (program == BSNMPGET) ? " [-M max-repetitions] [-N non-repeaters]" : "",
+ (program == BSNMPGET) ? "[-p pdu] " : "",
+ (program == BSNMPGET) ? " OID [OID ...]" :
+ (program == BSNMPWALK || program == BSNMPSET) ? " [OID ...]" :
+ ""
+ );
+}
+
+static int32_t
+parse_max_repetitions(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ uint32_t v;
+
+ assert(opt_arg != NULL);
+
+ v = strtoul(opt_arg, (void *) NULL, 10);
+
+ if (v > SNMP_MAX_BINDINGS) {
+ warnx("Max repetitions value greater than %d maximum allowed.",
+ SNMP_MAX_BINDINGS);
+ return (-1);
+ }
+
+ SET_MAXREP(snmptoolctx, v);
+ return (2);
+}
+
+static int32_t
+parse_non_repeaters(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ uint32_t v;
+
+ assert(opt_arg != NULL);
+
+ v = strtoul(opt_arg, (void *) NULL, 10);
+
+ if (v > SNMP_MAX_BINDINGS) {
+ warnx("Non repeaters value greater than %d maximum allowed.",
+ SNMP_MAX_BINDINGS);
+ return (-1);
+ }
+
+ SET_NONREP(snmptoolctx, v);
+ return (2);
+}
+
+static int32_t
+parse_pdu_type(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ assert(opt_arg != NULL);
+
+ if (strcasecmp(opt_arg, "getbulk") == 0)
+ SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETBULK);
+ else if (strcasecmp(opt_arg, "getnext") == 0)
+ SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETNEXT);
+ else if (strcasecmp(opt_arg, "get") == 0)
+ SET_PDUTYPE(snmptoolctx, SNMP_PDU_GET);
+ else {
+ warnx("PDU type '%s' not supported.", opt_arg);
+ return (-1);
+ }
+
+ return (2);
+}
+
+static int32_t
+snmptool_parse_options(struct snmp_toolinfo *snmptoolctx, int argc, char **argv)
+{
+ int32_t count, optnum = 0;
+ int ch;
+ const char *opts;
+
+ switch (program) {
+ case BSNMPWALK:
+ opts = "dhnKA:b:C:I:i:l:o:P:r:s:t:U:v:";
+ break;
+ case BSNMPGET:
+ opts = "aDdehnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:";
+ break;
+ case BSNMPSET:
+ opts = "adehnKA:b:C:I:i:l:o:P:r:s:t:U:v:";
+ break;
+ default:
+ return (-1);
+ }
+
+ while ((ch = getopt(argc, argv, opts)) != EOF) {
+ switch (ch) {
+ case 'A':
+ count = parse_authentication(snmptoolctx, optarg);
+ break;
+ case 'a':
+ count = parse_skip_access(snmptoolctx);
+ break;
+ case 'b':
+ count = parse_buflen(optarg);
+ break;
+ case 'D':
+ count = parse_discovery(snmptoolctx);
+ break;
+ case 'd':
+ count = parse_debug();
+ break;
+ case 'e':
+ count = parse_errors(snmptoolctx);
+ break;
+ case 'h':
+ usage();
+ return (-2);
+ case 'C':
+ count = parse_context(snmptoolctx, optarg);
+ break;
+ case 'I':
+ count = parse_include(snmptoolctx, optarg);
+ break;
+ case 'i':
+ count = parse_file(snmptoolctx, optarg);
+ break;
+ case 'K':
+ count = parse_local_key(snmptoolctx);
+ break;
+ case 'l':
+ count = parse_local_path(optarg);
+ break;
+ case 'M':
+ count = parse_max_repetitions(snmptoolctx, optarg);
+ break;
+ case 'N':
+ count = parse_non_repeaters(snmptoolctx, optarg);
+ break;
+ case 'n':
+ count = parse_num_oids(snmptoolctx);
+ break;
+ case 'o':
+ count = parse_output(snmptoolctx, optarg);
+ break;
+ case 'P':
+ count = parse_privacy(snmptoolctx, optarg);
+ break;
+ case 'p':
+ count = parse_pdu_type(snmptoolctx, optarg);
+ break;
+ case 'r':
+ count = parse_retry(optarg);
+ break;
+ case 's':
+ count = parse_server(optarg);
+ break;
+ case 't':
+ count = parse_timeout(optarg);
+ break;
+ case 'U':
+ count = parse_user_security(snmptoolctx, optarg);
+ break;
+ case 'v':
+ count = parse_version(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ return (-1);
+ }
+ if (count < 0)
+ return (-1);
+ optnum += count;
+ }
+
+ return (optnum);
+}
+
+/*
+ * Read user input OID - one of following formats:
+ * 1) 1.2.1.1.2.1.0 - that is if option numeric was giveni;
+ * 2) string - in such case append .0 to the asn_oid subs;
+ * 3) string.1 - no additional proccessing required in such case.
+ */
+static char *
+snmptools_parse_stroid(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_object *obj, char *argv)
+{
+ char string[MAXSTR], *str;
+ int32_t i = 0;
+ struct asn_oid in_oid;
+
+ str = argv;
+
+ if (*str == '.')
+ str++;
+
+ while (isalpha(*str) || *str == '_' || (i != 0 && isdigit(*str))) {
+ str++;
+ i++;
+ }
+
+ if (i <= 0 || i >= MAXSTR)
+ return (NULL);
+
+ memset(&in_oid, 0, sizeof(struct asn_oid));
+ if ((str = snmp_parse_suboid((argv + i), &in_oid)) == NULL) {
+ warnx("Invalid OID - %s", argv);
+ return (NULL);
+ }
+
+ strlcpy(string, argv, i + 1);
+ if (snmp_lookup_oidall(snmptoolctx, obj, string) < 0) {
+ warnx("No entry for %s in mapping lists", string);
+ return (NULL);
+ }
+
+ /* If OID given on command line append it. */
+ if (in_oid.len > 0)
+ asn_append_oid(&(obj->val.var), &in_oid);
+ else if (*str == '[') {
+ if ((str = snmp_parse_index(snmptoolctx, str + 1, obj)) == NULL)
+ return (NULL);
+ } else if (obj->val.syntax > 0 && GET_PDUTYPE(snmptoolctx) ==
+ SNMP_PDU_GET) {
+ if (snmp_suboid_append(&(obj->val.var), (asn_subid_t) 0) < 0)
+ return (NULL);
+ }
+
+ return (str);
+}
+
+static int32_t
+snmptools_parse_oid(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_object *obj, char *argv)
+{
+ if (argv == NULL)
+ return (-1);
+
+ if (ISSET_NUMERIC(snmptoolctx)) {
+ if (snmp_parse_numoid(argv, &(obj->val.var)) < 0)
+ return (-1);
+ } else {
+ if (snmptools_parse_stroid(snmptoolctx, obj, argv) == NULL &&
+ snmp_parse_numoid(argv, &(obj->val.var)) < 0)
+ return (-1);
+ }
+
+ return (1);
+}
+
+static int32_t
+snmptool_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)
+{
+ if (obj->error > 0)
+ return (0);
+
+ asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));
+ pdu->nbindings++;
+
+ return (pdu->nbindings);
+}
+
+/* *****************************************************************************
+ * bsnmpget private functions.
+ */
+static int32_t
+snmpget_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
+ struct snmp_object *obj)
+{
+ if (pdu->version == SNMP_V1 && obj->val.syntax ==
+ SNMP_SYNTAX_COUNTER64) {
+ warnx("64-bit counters are not supported in SNMPv1 PDU");
+ return (-1);
+ }
+
+ if (ISSET_NUMERIC(snmptoolctx) || pdu->type == SNMP_PDU_GETNEXT ||
+ pdu->type == SNMP_PDU_GETBULK)
+ return (1);
+
+ if (pdu->type == SNMP_PDU_GET && obj->val.syntax == SNMP_SYNTAX_NULL) {
+ warnx("Only leaf object values can be added to GET PDU");
+ return (-1);
+ }
+
+ return (1);
+}
+
+/*
+ * In case of a getbulk PDU, the error_status and error_index fields are used by
+ * libbsnmp to hold the values of the non-repeaters and max-repetitions fields
+ * that are present only in the getbulk - so before sending the PDU make sure
+ * these have correct values as well.
+ */
+static void
+snmpget_fix_getbulk(struct snmp_pdu *pdu, uint32_t max_rep, uint32_t non_rep)
+{
+ assert(pdu != NULL);
+
+ if (pdu->nbindings < non_rep)
+ pdu->error_status = pdu->nbindings;
+ else
+ pdu->error_status = non_rep;
+
+ if (max_rep > 0)
+ pdu->error_index = max_rep;
+ else
+ pdu->error_index = 1;
+}
+
+static int
+snmptool_get(struct snmp_toolinfo *snmptoolctx)
+{
+ struct snmp_pdu req, resp;
+
+ snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));
+
+ while ((snmp_pdu_add_bindings(snmptoolctx, snmpget_verify_vbind,
+ snmptool_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {
+
+ if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK)
+ snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
+ GET_NONREP(snmptoolctx));
+
+ if (snmp_dialog(&req, &resp) == -1) {
+ warnx("Snmp dialog - %s", strerror(errno));
+ break;
+ }
+
+ if (snmp_parse_resp(&resp, &req) >= 0) {
+ snmp_output_resp(snmptoolctx, &resp);
+ break;
+ }
+
+ snmp_output_err_resp(snmptoolctx, &resp);
+ if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK ||
+ !ISSET_RETRY(snmptoolctx))
+ break;
+
+ /*
+ * Loop through the object list and set object->error to the
+ * varbinding that caused the error.
+ */
+ if (snmp_object_seterror(snmptoolctx,
+ &(resp.bindings[resp.error_index - 1]),
+ resp.error_status) <= 0)
+ break;
+
+ fprintf(stderr, "Retrying...\n");
+ snmp_pdu_free(&resp);
+ snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));
+ }
+
+ snmp_pdu_free(&resp);
+
+ return (0);
+}
+
+
+/* *****************************************************************************
+ * bsnmpwalk private functions.
+ */
+/* The default tree to walk. */
+static const struct asn_oid snmp_mibII_OID = {
+ 6 , { 1, 3, 6, 1, 2, 1 }
+};
+
+static int32_t
+snmpwalk_add_default(struct snmp_toolinfo *snmptoolctx __unused,
+ struct snmp_object *obj, char *string __unused)
+{
+ asn_append_oid(&(obj->val.var), &snmp_mibII_OID);
+ return (1);
+}
+
+/*
+ * Prepare the next GetNext/Get PDU to send.
+ */
+static void
+snmpwalk_nextpdu_create(uint32_t op, struct asn_oid *var, struct snmp_pdu *pdu)
+{
+ snmp_pdu_create(pdu, op);
+ asn_append_oid(&(pdu->bindings[0].var), var);
+ pdu->nbindings = 1;
+}
+
+static int
+snmptool_walk(struct snmp_toolinfo *snmptoolctx)
+{
+ struct snmp_pdu req, resp;
+ struct asn_oid root; /* Keep the inital oid. */
+ int32_t outputs, rc;
+
+ snmp_pdu_create(&req, SNMP_PDU_GETNEXT);
+
+ while ((rc = snmp_pdu_add_bindings(snmptoolctx, NULL,
+ snmptool_add_vbind, &req, 1)) > 0) {
+
+ /* Remember the root where the walk started from. */
+ memset(&root, 0, sizeof(struct asn_oid));
+ asn_append_oid(&root, &(req.bindings[0].var));
+
+ outputs = 0;
+ while (snmp_dialog(&req, &resp) >= 0) {
+ if ((snmp_parse_resp(&resp, &req)) < 0) {
+ snmp_output_err_resp(snmptoolctx, &resp);
+ snmp_pdu_free(&resp);
+ outputs = -1;
+ break;
+ }
+
+ if (!(asn_is_suboid(&root, &(resp.bindings[0].var)))) {
+ snmp_pdu_free(&resp);
+ break;
+ }
+
+ if (snmp_output_resp(snmptoolctx, &resp)!= 0) {
+ snmp_pdu_free(&resp);
+ outputs = -1;
+ break;
+ }
+ outputs++;
+ snmp_pdu_free(&resp);
+
+ snmpwalk_nextpdu_create(SNMP_PDU_GETNEXT,
+ &(resp.bindings[0].var), &req);
+ }
+
+ /* Just in case our root was a leaf. */
+ if (outputs == 0) {
+ snmpwalk_nextpdu_create(SNMP_PDU_GET, &root, &req);
+ if (snmp_dialog(&req, &resp) == SNMP_CODE_OK) {
+ if (snmp_parse_resp(&resp,&req) < 0)
+ snmp_output_err_resp(snmptoolctx, &resp);
+ else
+ snmp_output_resp(snmptoolctx, &(resp));
+
+ snmp_pdu_free(&resp);
+ } else
+ warnx("Snmp dialog - %s", strerror(errno));
+ }
+
+ if (snmp_object_remove(snmptoolctx, &root) < 0) {
+ warnx("snmp_object_remove");
+ break;
+ }
+
+ snmp_pdu_create(&req, SNMP_PDU_GETNEXT);
+ }
+
+ if (rc == 0)
+ return (0);
+ else
+ return (1);
+}
+
+/* *****************************************************************************
+ * bsnmpset private functions.
+ */
+
+static int32_t
+parse_oid_numeric(struct snmp_value *value, char *val)
+{
+ char *endptr;
+ int32_t saved_errno;
+ asn_subid_t suboid;
+
+ do {
+ saved_errno = errno;
+ errno = 0;
+ suboid = strtoul(val, &endptr, 10);
+ if (errno != 0) {
+ warnx("Value %s not supported - %s", val,
+ strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+ errno = saved_errno;
+ if ((asn_subid_t) suboid > ASN_MAXID) {
+ warnx("Suboid %u > ASN_MAXID", suboid);
+ return (-1);
+ }
+ if (snmp_suboid_append(&(value->v.oid), suboid) < 0)
+ return (-1);
+ val = endptr + 1;
+ } while (*endptr == '.');
+
+ if (*endptr != '\0')
+ warnx("OID value %s not supported", val);
+
+ value->syntax = SNMP_SYNTAX_OID;
+ return (0);
+}
+
+/*
+ * Allow OID leaf in both forms:
+ * 1) 1.3.6.1.2... -> in such case call directly the function reading raw OIDs;
+ * 2) begemotSnmpdAgentFreeBSD -> lookup the ASN OID corresponding to that.
+ */
+static int32_t
+parse_oid_string(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_value *value, char *string)
+{
+ struct snmp_object obj;
+
+ if (isdigit(string[0]))
+ return (parse_oid_numeric(value, string));
+
+ memset(&obj, 0, sizeof(struct snmp_object));
+ if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {
+ warnx("Unknown OID enum string - %s", string);
+ return (-1);
+ }
+
+ asn_append_oid(&(value->v.oid), &(obj.val.var));
+ return (1);
+}
+
+static int32_t
+parse_ip(struct snmp_value * value, char * val)
+{
+ uint32_t v;
+ int32_t i;
+ char *endptr, *str;
+
+ str = val;
+ for (i = 0; i < 4; i++) {
+ v = strtoul(str, &endptr, 10);
+ if (v > 0xff)
+ return (-1);
+ if (*endptr != '.' && *endptr != '\0' && i != 3)
+ break;
+ str = endptr + 1;
+ value->v.ipaddress[i] = (uint8_t) v;
+ }
+
+ value->syntax = SNMP_SYNTAX_IPADDRESS;
+ return (0);
+}
+
+static int32_t
+parse_int(struct snmp_value *value, char *val)
+{
+ char *endptr;
+ int32_t v, saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtol(val, &endptr, 10);
+
+ if (errno != 0) {
+ warnx("Value %s not supported - %s", val, strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ value->syntax = SNMP_SYNTAX_INTEGER;
+ value->v.integer = v;
+ errno = saved_errno;
+
+ return (0);
+}
+
+static int32_t
+parse_int_string(struct snmp_object *object, char *val)
+{
+ int32_t v;
+
+ if (isdigit(val[0]))
+ return ((parse_int(&(object->val), val)));
+
+ if (object->info == NULL) {
+ warnx("Unknown enumerated integer type - %s", val);
+ return (-1);
+ }
+ if ((v = enum_number_lookup(object->info->snmp_enum, val)) < 0)
+ warnx("Unknown enumerated integer type - %s", val);
+
+ object->val.v.integer = v;
+ return (1);
+}
+
+/*
+ * Here syntax may be one of SNMP_SYNTAX_COUNTER, SNMP_SYNTAX_GAUGE,
+ * SNMP_SYNTAX_TIMETICKS.
+ */
+static int32_t
+parse_uint(struct snmp_value *value, char *val)
+{
+ char *endptr;
+ uint32_t v = 0;
+ int32_t saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoul(val, &endptr, 10);
+
+ if (errno != 0) {
+ warnx("Value %s not supported - %s", val, strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ value->v.uint32 = v;
+ errno = saved_errno;
+
+ return (0);
+}
+
+static int32_t
+parse_ticks(struct snmp_value *value, char *val)
+{
+ if (parse_uint(value, val) < 0)
+ return (-1);
+
+ value->syntax = SNMP_SYNTAX_TIMETICKS;
+ return (0);
+}
+
+static int32_t
+parse_gauge(struct snmp_value *value, char *val)
+{
+ if (parse_uint(value, val) < 0)
+ return (-1);
+
+ value->syntax = SNMP_SYNTAX_GAUGE;
+ return (0);
+}
+
+static int32_t
+parse_counter(struct snmp_value *value, char *val)
+{
+ if (parse_uint(value, val) < 0)
+ return (-1);
+
+ value->syntax = SNMP_SYNTAX_COUNTER;
+ return (0);
+}
+
+static int32_t
+parse_uint64(struct snmp_value *value, char *val)
+{
+ char *endptr;
+ int32_t saved_errno;
+ uint64_t v;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoull(val, &endptr, 10);
+
+ if (errno != 0) {
+ warnx("Value %s not supported - %s", val, strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ value->syntax = SNMP_SYNTAX_COUNTER64;
+ value->v.counter64 = v;
+ errno = saved_errno;
+
+ return (0);
+}
+
+static int32_t
+parse_syntax_val(struct snmp_value *value, enum snmp_syntax syntax, char *val)
+{
+ switch (syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ return (parse_int(value, val));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (parse_ip(value, val));
+ case SNMP_SYNTAX_COUNTER:
+ return (parse_counter(value, val));
+ case SNMP_SYNTAX_GAUGE:
+ return (parse_gauge(value, val));
+ case SNMP_SYNTAX_TIMETICKS:
+ return (parse_ticks(value, val));
+ case SNMP_SYNTAX_COUNTER64:
+ return (parse_uint64(value, val));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_tc2oct(SNMP_STRING, value, val));
+ case SNMP_SYNTAX_OID:
+ return (parse_oid_numeric(value, val));
+ default:
+ /* NOTREACHED */
+ break;
+ }
+
+ return (-1);
+}
+
+/*
+ * Parse a command line argument of type OID=syntax:value and fill in whatever
+ * fields can be derived from the input into snmp_value structure. Reads numeric
+ * OIDs.
+ */
+static int32_t
+parse_pair_numoid_val(char *str, struct snmp_value *snmp_val)
+{
+ int32_t cnt;
+ char *ptr;
+ enum snmp_syntax syntax;
+ char oid_str[ASN_OIDSTRLEN];
+
+ ptr = str;
+ for (cnt = 0; cnt < ASN_OIDSTRLEN; cnt++)
+ if (ptr[cnt] == '=')
+ break;
+
+ if (cnt >= ASN_OIDSTRLEN) {
+ warnx("OID too long - %s", str);
+ return (-1);
+ }
+ strlcpy(oid_str, ptr, (size_t) (cnt + 1));
+
+ ptr = str + cnt + 1;
+ for (cnt = 0; cnt < MAX_CMD_SYNTAX_LEN; cnt++)
+ if(ptr[cnt] == ':')
+ break;
+
+ if (cnt >= MAX_CMD_SYNTAX_LEN) {
+ warnx("Unknown syntax in OID - %s", str);
+ return (-1);
+ }
+
+ if ((syntax = parse_syntax(ptr)) <= SNMP_SYNTAX_NULL) {
+ warnx("Unknown syntax in OID - %s", ptr);
+ return (-1);
+ }
+
+ ptr = ptr + cnt + 1;
+ for (cnt = 0; cnt < MAX_OCTSTRING_LEN; cnt++)
+ if (ptr[cnt] == '\0')
+ break;
+
+ if (ptr[cnt] != '\0') {
+ warnx("Value string too long - %s",ptr);
+ return (-1);
+ }
+
+ /*
+ * Here try parsing the OIDs and syntaxes and then check values - have
+ * to know syntax to check value boundaries.
+ */
+ if (snmp_parse_numoid(oid_str, &(snmp_val->var)) < 0) {
+ warnx("Error parsing OID %s",oid_str);
+ return (-1);
+ }
+
+ if (parse_syntax_val(snmp_val, syntax, ptr) < 0)
+ return (-1);
+
+ return (1);
+}
+
+/* XXX-BZ aruments should be swapped. */
+static int32_t
+parse_syntax_strval(struct snmp_toolinfo *snmptoolctx, char *str,
+ struct snmp_object *object)
+{
+ uint32_t len;
+ enum snmp_syntax syn;
+
+ /*
+ * Syntax string here not required - still may be present.
+ */
+
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {
+ for (len = 0 ; *(str + len) != ':'; len++) {
+ if (*(str + len) == '\0') {
+ warnx("Syntax missing in value - %s", str);
+ return (-1);
+ }
+ }
+ if ((syn = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {
+ warnx("Unknown syntax in - %s", str);
+ return (-1);
+ }
+ if (syn != object->val.syntax) {
+ if (!ISSET_ERRIGNORE(snmptoolctx)) {
+ warnx("Bad syntax in - %s", str);
+ return (-1);
+ } else
+ object->val.syntax = syn;
+ }
+ len++;
+ } else
+ len = 0;
+
+ switch (object->val.syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ return (parse_int_string(object, str + len));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (parse_ip(&(object->val), str + len));
+ case SNMP_SYNTAX_COUNTER:
+ return (parse_counter(&(object->val), str + len));
+ case SNMP_SYNTAX_GAUGE:
+ return (parse_gauge(&(object->val), str + len));
+ case SNMP_SYNTAX_TIMETICKS:
+ return (parse_ticks(&(object->val), str + len));
+ case SNMP_SYNTAX_COUNTER64:
+ return (parse_uint64(&(object->val), str + len));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_tc2oct(object->info->tc, &(object->val),
+ str + len));
+ case SNMP_SYNTAX_OID:
+ return (parse_oid_string(snmptoolctx, &(object->val),
+ str + len));
+ default:
+ /* NOTREACHED */
+ break;
+ }
+
+ return (-1);
+}
+
+static int32_t
+parse_pair_stroid_val(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_object *obj, char *argv)
+{
+ char *ptr;
+
+ if ((ptr = snmptools_parse_stroid(snmptoolctx, obj, argv)) == NULL)
+ return (-1);
+
+ if (*ptr != '=') {
+ warnx("Value to set expected after OID");
+ return (-1);
+ }
+
+ if (parse_syntax_strval(snmptoolctx, ptr + 1, obj) < 0)
+ return (-1);
+
+ return (1);
+}
+
+
+static int32_t
+snmpset_parse_oid(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_object *obj, char *argv)
+{
+ if (argv == NULL)
+ return (-1);
+
+ if (ISSET_NUMERIC(snmptoolctx)) {
+ if (parse_pair_numoid_val(argv, &(obj->val)) < 0)
+ return (-1);
+ } else {
+ if (parse_pair_stroid_val(snmptoolctx, obj, argv) < 0)
+ return (-1);
+ }
+
+ return (1);
+}
+
+static int32_t
+add_ip_syntax(struct snmp_value *dst, struct snmp_value *src)
+{
+ int8_t i;
+
+ dst->syntax = SNMP_SYNTAX_IPADDRESS;
+ for (i = 0; i < 4; i++)
+ dst->v.ipaddress[i] = src->v.ipaddress[i];
+
+ return (1);
+}
+
+static int32_t
+add_octstring_syntax(struct snmp_value *dst, struct snmp_value *src)
+{
+ if (src->v.octetstring.len > ASN_MAXOCTETSTRING) {
+ warnx("OctetString len too big - %u",src->v.octetstring.len);
+ return (-1);
+ }
+
+ if ((dst->v.octetstring.octets = malloc(src->v.octetstring.len)) ==
+ NULL) {
+ syslog(LOG_ERR, "malloc() failed - %s", strerror(errno));
+ return (-1);
+ }
+
+ memcpy(dst->v.octetstring.octets, src->v.octetstring.octets,
+ src->v.octetstring.len);
+ dst->syntax = SNMP_SYNTAX_OCTETSTRING;
+ dst->v.octetstring.len = src->v.octetstring.len;
+
+ return(0);
+}
+
+static int32_t
+add_oid_syntax(struct snmp_value *dst, struct snmp_value *src)
+{
+ asn_append_oid(&(dst->v.oid), &(src->v.oid));
+ dst->syntax = SNMP_SYNTAX_OID;
+ return (0);
+}
+
+/*
+ * Check syntax - if one of SNMP_SYNTAX_NULL, SNMP_SYNTAX_NOSUCHOBJECT,
+ * SNMP_SYNTAX_NOSUCHINSTANCE, SNMP_SYNTAX_ENDOFMIBVIEW or anything not known -
+ * return error.
+ */
+static int32_t
+snmpset_add_value(struct snmp_value *dst, struct snmp_value *src)
+{
+ if (dst == NULL || src == NULL)
+ return (-1);
+
+ switch (src->syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ dst->v.integer = src->v.integer;
+ dst->syntax = SNMP_SYNTAX_INTEGER;
+ break;
+ case SNMP_SYNTAX_TIMETICKS:
+ dst->v.uint32 = src->v.uint32;
+ dst->syntax = SNMP_SYNTAX_TIMETICKS;
+ break;
+ case SNMP_SYNTAX_GAUGE:
+ dst->v.uint32 = src->v.uint32;
+ dst->syntax = SNMP_SYNTAX_GAUGE;
+ break;
+ case SNMP_SYNTAX_COUNTER:
+ dst->v.uint32 = src->v.uint32;
+ dst->syntax = SNMP_SYNTAX_COUNTER;
+ break;
+ case SNMP_SYNTAX_COUNTER64:
+ dst->v.counter64 = src->v.counter64;
+ dst->syntax = SNMP_SYNTAX_COUNTER64;
+ break;
+ case SNMP_SYNTAX_IPADDRESS:
+ add_ip_syntax(dst, src);
+ break;
+ case SNMP_SYNTAX_OCTETSTRING:
+ add_octstring_syntax(dst, src);
+ break;
+ case SNMP_SYNTAX_OID:
+ add_oid_syntax(dst, src);
+ break;
+ default:
+ warnx("Unknown syntax %d", src->syntax);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int32_t
+snmpset_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
+ struct snmp_object *obj)
+{
+ if (pdu->version == SNMP_V1 && obj->val.syntax ==
+ SNMP_SYNTAX_COUNTER64) {
+ warnx("64-bit counters are not supported in SNMPv1 PDU");
+ return (-1);
+ }
+
+ if (ISSET_NUMERIC(snmptoolctx) || ISSET_ERRIGNORE(snmptoolctx))
+ return (1);
+
+ if (obj->info->access < SNMP_ACCESS_SET) {
+ warnx("Object %s not accessible for set - try 'bsnmpset -a'",
+ obj->info->string);
+ return (-1);
+ }
+
+ return (1);
+}
+
+static int32_t
+snmpset_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)
+{
+ if (pdu->nbindings > SNMP_MAX_BINDINGS) {
+ warnx("Too many OIDs for one PDU");
+ return (-1);
+ }
+
+ if (obj->error > 0)
+ return (0);
+
+ if (snmpset_add_value(&(pdu->bindings[pdu->nbindings]), &(obj->val))
+ < 0)
+ return (-1);
+
+ asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));
+ pdu->nbindings++;
+
+ return (pdu->nbindings);
+}
+
+static int
+snmptool_set(struct snmp_toolinfo *snmptoolctx)
+{
+ struct snmp_pdu req, resp;
+
+ snmp_pdu_create(&req, SNMP_PDU_SET);
+
+ while ((snmp_pdu_add_bindings(snmptoolctx, snmpset_verify_vbind,
+ snmpset_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {
+ if (snmp_dialog(&req, &resp)) {
+ warnx("Snmp dialog - %s", strerror(errno));
+ break;
+ }
+
+ if (snmp_pdu_check(&req, &resp) > 0) {
+ if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)
+ snmp_output_resp(snmptoolctx, &resp);
+ break;
+ }
+
+ snmp_output_err_resp(snmptoolctx, &resp);
+ if (!ISSET_RETRY(snmptoolctx))
+ break;
+
+ if (snmp_object_seterror(snmptoolctx,
+ &(resp.bindings[resp.error_index - 1]),
+ resp.error_status) <= 0)
+ break;
+
+ fprintf(stderr, "Retrying...\n");
+ snmp_pdu_free(&req);
+ snmp_pdu_free(&resp);
+ snmp_pdu_create(&req, SNMP_PDU_SET);
+ }
+
+ snmp_pdu_free(&resp);
+
+ return (0);
+}
+
+/* *****************************************************************************
+ * main
+ */
+/*
+ * According to command line options prepare SNMP Get | GetNext | GetBulk PDU.
+ * Wait for a responce and print it.
+ */
+/*
+ * Do a 'snmp walk' - according to command line options request for values
+ * lexicographically subsequent and subrooted at a common node. Send a GetNext
+ * PDU requesting the value for each next variable and print the responce. Stop
+ * when a Responce PDU is received that contains the value of a variable not
+ * subrooted at the variable the walk started.
+ */
+int
+main(int argc, char ** argv)
+{
+ struct snmp_toolinfo snmptoolctx;
+ int32_t oid_cnt, last_oid, opt_num;
+ int rc = 0;
+
+ /* Make sure program_name is set and valid. */
+ if (*argv == NULL)
+ program_name = "snmptool";
+ else {
+ program_name = strrchr(*argv, '/');
+ if (program_name != NULL)
+ program_name++;
+ else
+ program_name = *argv;
+ }
+
+ if (program_name == NULL) {
+ fprintf(stderr, "Error: No program name?\n");
+ exit (1);
+ } else if (strcmp(program_name, "bsnmpget") == 0)
+ program = BSNMPGET;
+ else if (strcmp(program_name, "bsnmpwalk") == 0)
+ program = BSNMPWALK;
+ else if (strcmp(program_name, "bsnmpset") == 0)
+ program = BSNMPSET;
+ else {
+ fprintf(stderr, "Unknown snmp tool name '%s'.\n", program_name);
+ exit (1);
+ }
+
+ /* Initialize. */
+ if (snmptool_init(&snmptoolctx) < 0)
+ exit (1);
+
+ if ((opt_num = snmptool_parse_options(&snmptoolctx, argc, argv)) < 0) {
+ snmp_tool_freeall(&snmptoolctx);
+ /* On -h (help) exit without error. */
+ if (opt_num == -2)
+ exit(0);
+ else
+ exit(1);
+ }
+
+ oid_cnt = argc - opt_num - 1;
+ if (oid_cnt == 0) {
+ switch (program) {
+ case BSNMPGET:
+ if (!ISSET_EDISCOVER(&snmptoolctx) &&
+ !ISSET_LOCALKEY(&snmptoolctx)) {
+ fprintf(stderr, "No OID given.\n");
+ usage();
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+ break;
+
+ case BSNMPWALK:
+ if (snmp_object_add(&snmptoolctx, snmpwalk_add_default,
+ NULL) < 0) {
+ fprintf(stderr,
+ "Error setting default subtree.\n");
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+ break;
+
+ case BSNMPSET:
+ fprintf(stderr, "No OID given.\n");
+ usage();
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+ }
+
+ if (snmp_import_all(&snmptoolctx) < 0) {
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+
+ /* A simple sanity check - can not send GETBULK when using SNMPv1. */
+ if (program == BSNMPGET && snmp_client.version == SNMP_V1 &&
+ GET_PDUTYPE(&snmptoolctx) == SNMP_PDU_GETBULK) {
+ fprintf(stderr, "Cannot send GETBULK PDU with SNMPv1.\n");
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+
+ for (last_oid = argc - 1; oid_cnt > 0; last_oid--, oid_cnt--) {
+ if ((snmp_object_add(&snmptoolctx, (program == BSNMPSET) ?
+ snmpset_parse_oid : snmptools_parse_oid,
+ argv[last_oid])) < 0) {
+ fprintf(stderr, "Error parsing OID string '%s'.\n",
+ argv[last_oid]);
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+ }
+
+ if (snmp_open(NULL, NULL, NULL, NULL)) {
+ warnx("Failed to open snmp session: %s.", strerror(errno));
+ snmp_tool_freeall(&snmptoolctx);
+ exit(1);
+ }
+
+ if (snmp_client.version == SNMP_V3 && snmp_client.engine.engine_len == 0)
+ SET_EDISCOVER(&snmptoolctx);
+
+ if (ISSET_EDISCOVER(&snmptoolctx) &&
+ snmp_discover_engine(snmptoolctx.passwd) < 0) {
+ warnx("Unknown SNMP Engine ID: %s.", strerror(errno));
+ rc = 1;
+ goto cleanup;
+ }
+
+ if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||
+ ISSET_EDISCOVER(&snmptoolctx))
+ snmp_output_engine();
+
+ if (snmp_client.version == SNMP_V3 && ISSET_LOCALKEY(&snmptoolctx) &&
+ !ISSET_EDISCOVER(&snmptoolctx)) {
+ if (snmp_passwd_to_keys(&snmp_client.user,
+ snmptoolctx.passwd) != SNMP_CODE_OK ||
+ snmp_get_local_keys(&snmp_client.user,
+ snmp_client.engine.engine_id,
+ snmp_client.engine.engine_len) != SNMP_CODE_OK) {
+ warnx("Failed to get keys: %s.", strerror(errno));
+ rc = 1;
+ goto cleanup;
+ }
+ }
+
+ if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||
+ ISSET_EDISCOVER(&snmptoolctx))
+ snmp_output_keys();
+
+ if (ISSET_EDISCOVER(&snmptoolctx) && snmptoolctx.objects == 0)
+ goto cleanup;
+
+ switch (program) {
+ case BSNMPGET:
+ rc = snmptool_get(&snmptoolctx);
+ break;
+ case BSNMPWALK:
+ rc = snmptool_walk(&snmptoolctx);
+ break;
+ case BSNMPSET:
+ rc = snmptool_set(&snmptoolctx);
+ break;
+ }
+
+
+cleanup:
+ snmp_tool_freeall(&snmptoolctx);
+ snmp_close();
+
+ exit(rc);
+}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/Makefile b/usr.sbin/bsnmpd/tools/libbsnmptools/Makefile
new file mode 100644
index 0000000..f2b71b6
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/Makefile
@@ -0,0 +1,14 @@
+#
+# $FreeBSD$
+#
+
+.PATH: ${.CURDIR}
+
+LIB= bsnmptools
+#INTERNALLIB=
+SRCS= bsnmpimport.c bsnmpmap.c bsnmptools.c bsnmptc.c
+CFLAGS+= -g -Wall -Werror
+
+SHLIB_MAJOR= 0
+
+.include <bsd.lib.mk>
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c
new file mode 100644
index 0000000..b92532f
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c
@@ -0,0 +1,971 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND 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 THE AUTHOR OR 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Read file containing table description - reuse magic from gensnmptree.c.
+ * Hopefully one day most of the code here will be part of libbsnmp and
+ * this duplication won't be necessary.
+ *
+ * Syntax is:
+ * ---------
+ * file := top | top file
+ *
+ * top := tree | typedef | include
+ *
+ * tree := head elements ')'
+ *
+ * entry := head ':' index STRING elements ')'
+ *
+ * leaf := head type STRING ACCESS ')'
+ *
+ * column := head type ACCESS ')'
+ *
+ * type := BASETYPE | BASETYPE '|' subtype | enum | bits
+ *
+ * subtype := STRING
+ *
+ * enum := ENUM '(' value ')'
+ *
+ * bits := BITS '(' value ')'
+ *
+ * value := INT STRING | INT STRING value
+ *
+ * head := '(' INT STRING
+ *
+ * elements := EMPTY | elements element
+ *
+ * element := tree | leaf | column
+ *
+ * index := type | index type
+ *
+ * typedef := 'typedef' STRING type
+ *
+ * include := 'include' filespec
+ *
+ * filespec := '"' STRING '"' | '<' STRING '>'
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+#include <bsnmp/snmpagent.h> /* SNMP_INDEXES_MAX */
+#include "bsnmptc.h"
+#include "bsnmptools.h"
+
+enum snmp_tbl_entry {
+ ENTRY_NONE = 0,
+ ENTRY_INDEX,
+ ENTRY_DATA
+};
+
+enum {
+ FL_GET = 0x01,
+ FL_SET = 0x02,
+};
+
+/************************************************************
+ *
+ * Allocate memory and panic just in the case...
+ */
+static void *
+xalloc(size_t size)
+{
+ void *ptr;
+
+ if ((ptr = malloc(size)) == NULL)
+ err(1, "allocing %zu bytes", size);
+
+ return (ptr);
+}
+
+static char *
+savestr(const char *s)
+{
+ if (s == NULL)
+ return (NULL);
+
+ return (strcpy(xalloc(strlen(s) + 1), s));
+}
+
+/************************************************************
+ *
+ * Input stack
+ */
+struct input {
+ FILE *fp;
+ uint32_t lno;
+ char *fname;
+ char *path;
+ LIST_ENTRY(input) link;
+};
+
+LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
+struct input *input = NULL;
+int32_t pbchar = -1;
+
+#define MAX_PATHS 100
+
+static const char *paths[MAX_PATHS + 1] = {
+ "/usr/share/snmp/defs",
+ "/usr/local/share/snmp/defs",
+ NULL
+};
+
+static void
+input_new(FILE *fp, const char *path, const char *fname)
+{
+ struct input *ip;
+
+ ip = xalloc(sizeof(*ip));
+ ip->fp = fp;
+ ip->lno = 1;
+ ip->fname = savestr(fname);
+ ip->path = savestr(path);
+ LIST_INSERT_HEAD(&inputs, ip, link);
+
+ input = ip;
+}
+
+static void
+input_close(void)
+{
+ if (input == NULL)
+ return;
+
+ fclose(input->fp);
+ free(input->fname);
+ free(input->path);
+ LIST_REMOVE(input, link);
+ free(input);
+
+ input = LIST_FIRST(&inputs);
+}
+
+static FILE *
+tryopen(const char *path, const char *fname)
+{
+ char *fn;
+ FILE *fp;
+
+ if (path == NULL)
+ fn = savestr(fname);
+ else {
+ fn = xalloc(strlen(path) + strlen(fname) + 2);
+ sprintf(fn, "%s/%s", path, fname);
+ }
+ fp = fopen(fn, "r");
+ free(fn);
+ return (fp);
+}
+
+static int32_t
+input_fopen(const char *fname)
+{
+ FILE *fp;
+ u_int p;
+
+ if (fname[0] == '/' || fname[0] == '.' || fname[0] == '~') {
+ if ((fp = tryopen(NULL, fname)) != NULL) {
+ input_new(fp, NULL, fname);
+ return (0);
+ }
+
+ } else {
+
+ for (p = 0; paths[p] != NULL; p++)
+ if ((fp = tryopen(paths[p], fname)) != NULL) {
+ input_new(fp, paths[p], fname);
+ return (0);
+ }
+ }
+
+ warnx("cannot open '%s'", fname);
+ return (-1);
+}
+
+static int32_t
+tgetc(void)
+{
+ int c;
+
+ if (pbchar != -1) {
+ c = pbchar;
+ pbchar = -1;
+ return (c);
+ }
+
+ for (;;) {
+ if (input == NULL)
+ return (EOF);
+
+ if ((c = getc(input->fp)) != EOF)
+ return (c);
+
+ input_close();
+ }
+}
+
+static int32_t
+tungetc(int c)
+{
+
+ if (pbchar != -1)
+ return (-1);
+
+ pbchar = c;
+ return (1);
+}
+
+/************************************************************
+ *
+ * Parsing input
+ */
+enum tok {
+ TOK_EOF = 0200, /* end-of-file seen */
+ TOK_NUM, /* number */
+ TOK_STR, /* string */
+ TOK_ACCESS, /* access operator */
+ TOK_TYPE, /* type operator */
+ TOK_ENUM, /* enum token (kind of a type) */
+ TOK_TYPEDEF, /* typedef directive */
+ TOK_DEFTYPE, /* defined type */
+ TOK_INCLUDE, /* include directive */
+ TOK_FILENAME, /* filename ("foo.bar" or <foo.bar>) */
+ TOK_BITS, /* bits token (kind of a type) */
+ TOK_ERR /* unexpected char - exit */
+};
+
+static const struct {
+ const char *str;
+ enum tok tok;
+ uint32_t val;
+} keywords[] = {
+ { "GET", TOK_ACCESS, FL_GET },
+ { "SET", TOK_ACCESS, FL_SET },
+ { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL },
+ { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER },
+ { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER },
+ { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE },
+ { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING },
+ { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS },
+ { "OID", TOK_TYPE, SNMP_SYNTAX_OID },
+ { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS },
+ { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER },
+ { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE },
+ { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 },
+ { "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER },
+ { "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING },
+ { "typedef", TOK_TYPEDEF, 0 },
+ { "include", TOK_INCLUDE, 0 },
+ { NULL, 0, 0 }
+};
+
+struct {
+ /* Current OID type, regarding table membership. */
+ enum snmp_tbl_entry tbl_type;
+ /* A pointer to a structure in table list to add to its members. */
+ struct snmp_index_entry *table_idx;
+} table_data;
+
+struct asn_oid current_oid;
+char nexttok[MAXSTR];
+u_long val; /* integer values */
+int32_t all_cond; /* all conditions are true */
+int32_t saved_token = -1;
+
+/* Prepare the global data before parsing a new file. */
+static void
+snmp_import_init(struct asn_oid *append)
+{
+ memset(&table_data, 0, sizeof(table_data));
+ memset(&current_oid, 0, sizeof(struct asn_oid));
+ memset(nexttok, 0, MAXSTR);
+
+ if (append != NULL)
+ asn_append_oid(&current_oid, append);
+
+ all_cond = 0;
+ val = 0;
+ saved_token = -1;
+}
+
+static int32_t
+gettoken(struct snmp_toolinfo *snmptoolctx)
+{
+ int c;
+ struct enum_type *t;
+
+ if (saved_token != -1) {
+ c = saved_token;
+ saved_token = -1;
+ return (c);
+ }
+
+ again:
+ /*
+ * Skip any whitespace before the next token.
+ */
+ while ((c = tgetc()) != EOF) {
+ if (c == '\n')
+ input->lno++;
+ if (!isspace(c))
+ break;
+ }
+ if (c == EOF)
+ return (TOK_EOF);
+
+ if (!isascii(c)) {
+ warnx("unexpected character %#2x", (u_int) c);
+ return (TOK_ERR);
+ }
+
+ /*
+ * Skip comments.
+ */
+ if (c == '#') {
+ while ((c = tgetc()) != EOF) {
+ if (c == '\n') {
+ input->lno++;
+ goto again;
+ }
+ }
+ warnx("unexpected EOF in comment");
+ return (TOK_ERR);
+ }
+
+ /*
+ * Single character tokens.
+ */
+ if (strchr("():|", c) != NULL)
+ return (c);
+
+ if (c == '"' || c == '<') {
+ int32_t end = c;
+ size_t n = 0;
+
+ val = 1;
+ if (c == '<') {
+ val = 0;
+ end = '>';
+ }
+
+ while ((c = tgetc()) != EOF) {
+ if (c == end)
+ break;
+ if (n == sizeof(nexttok) - 1) {
+ nexttok[n++] = '\0';
+ warnx("filename too long '%s...'", nexttok);
+ return (TOK_ERR);
+ }
+ nexttok[n++] = c;
+ }
+ nexttok[n++] = '\0';
+ return (TOK_FILENAME);
+ }
+
+ /*
+ * Sort out numbers.
+ */
+ if (isdigit(c)) {
+ size_t n = 0;
+ nexttok[n++] = c;
+ while ((c = tgetc()) != EOF) {
+ if (!isdigit(c)) {
+ if (tungetc(c) < 0)
+ return (TOK_ERR);
+ break;
+ }
+ if (n == sizeof(nexttok) - 1) {
+ nexttok[n++] = '\0';
+ warnx("number too long '%s...'", nexttok);
+ return (TOK_ERR);
+ }
+ nexttok[n++] = c;
+ }
+ nexttok[n++] = '\0';
+ sscanf(nexttok, "%lu", &val);
+ return (TOK_NUM);
+ }
+
+ /*
+ * So that has to be a string.
+ */
+ if (isalpha(c) || c == '_' || c == '-') {
+ size_t n = 0;
+ nexttok[n++] = c;
+ while ((c = tgetc()) != EOF) {
+ if (!isalnum(c) && c != '_' && c != '-') {
+ if (tungetc (c) < 0)
+ return (TOK_ERR);
+ break;
+ }
+ if (n == sizeof(nexttok) - 1) {
+ nexttok[n++] = '\0';
+ warnx("string too long '%s...'", nexttok);
+ return (TOK_ERR);
+ }
+ nexttok[n++] = c;
+ }
+ nexttok[n++] = '\0';
+
+ /*
+ * Keywords.
+ */
+ for (c = 0; keywords[c].str != NULL; c++)
+ if (strcmp(keywords[c].str, nexttok) == 0) {
+ val = keywords[c].val;
+ return (keywords[c].tok);
+ }
+
+ if ((t = snmp_enumtc_lookup(snmptoolctx, nexttok)) != NULL) {
+ val = t->syntax;
+ return (TOK_DEFTYPE);
+ }
+
+ return (TOK_STR);
+ }
+
+ if (isprint(c))
+ warnx("%u: unexpected character '%c'", input->lno, c);
+ else
+ warnx("%u: unexpected character 0x%02x", input->lno, (u_int) c);
+
+ return (TOK_ERR);
+}
+
+/*
+ * Update table information.
+ */
+static struct snmp_index_entry *
+snmp_import_update_table(enum snmp_tbl_entry te, struct snmp_index_entry *tbl)
+{
+ switch (te) {
+ case ENTRY_NONE:
+ if (table_data.tbl_type == ENTRY_NONE)
+ return (NULL);
+ if (table_data.tbl_type == ENTRY_INDEX)
+ table_data.table_idx = NULL;
+ table_data.tbl_type--;
+ return (NULL);
+
+ case ENTRY_INDEX:
+ if (tbl == NULL)
+ warnx("No table_index to add!!!");
+ table_data.table_idx = tbl;
+ table_data.tbl_type = ENTRY_INDEX;
+ return (tbl);
+
+ case ENTRY_DATA:
+ if (table_data.tbl_type == ENTRY_INDEX) {
+ table_data.tbl_type = ENTRY_DATA;
+ return (table_data.table_idx);
+ }
+ return (NULL);
+
+ default:
+ /* NOTREACHED */
+ warnx("Unknown table entry type!!!");
+ break;
+ }
+
+ return (NULL);
+}
+
+static int32_t
+parse_enum(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
+ struct enum_pairs *enums)
+{
+ while ((*tok = gettoken(snmptoolctx)) == TOK_STR) {
+ if (enum_pair_insert(enums, val, nexttok) < 0)
+ return (-1);
+ if ((*tok = gettoken(snmptoolctx)) != TOK_NUM)
+ break;
+ }
+
+ if (*tok != ')') {
+ warnx("')' at end of enums");
+ return (-1);
+ }
+
+ return (1);
+}
+
+static int32_t
+parse_subtype(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
+ enum snmp_tc *tc)
+{
+ if ((*tok = gettoken(snmptoolctx)) != TOK_STR) {
+ warnx("subtype expected after '|'");
+ return (-1);
+ }
+
+ *tc = snmp_get_tc(nexttok);
+ *tok = gettoken(snmptoolctx);
+
+ return (1);
+}
+
+static int32_t
+parse_type(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
+ enum snmp_tc *tc, struct enum_pairs **snmp_enum)
+{
+ int32_t syntax, mem;
+
+ syntax = val;
+ *tc = 0;
+
+ if (*tok == TOK_ENUM || *tok == TOK_BITS) {
+ if (*snmp_enum == NULL) {
+ if ((*snmp_enum = enum_pairs_init()) == NULL)
+ return (-1);
+ mem = 1;
+ *tc = SNMP_TC_OWN;
+ } else
+ mem = 0;
+
+ if (gettoken(snmptoolctx) != '(') {
+ warnx("'(' expected after ENUM/BITS");
+ return (-1);
+ }
+
+ if ((*tok = gettoken(snmptoolctx)) != TOK_NUM) {
+ warnx("need value for ENUM//BITS");
+ if (mem == 1) {
+ free(*snmp_enum);
+ *snmp_enum = NULL;
+ }
+ return (-1);
+ }
+
+ if (parse_enum(snmptoolctx, tok, *snmp_enum) < 0) {
+ enum_pairs_free(*snmp_enum);
+ *snmp_enum = NULL;
+ return (-1);
+ }
+
+ *tok = gettoken(snmptoolctx);
+
+ } else if (*tok == TOK_DEFTYPE) {
+ struct enum_type *t;
+
+ *tc = 0;
+ t = snmp_enumtc_lookup(snmptoolctx, nexttok);
+ if (t != NULL)
+ *snmp_enum = t->snmp_enum;
+
+ *tok = gettoken(snmptoolctx);
+
+ } else {
+ if ((*tok = gettoken(snmptoolctx)) == '|') {
+ if (parse_subtype(snmptoolctx, tok, tc) < 0)
+ return (-1);
+ }
+ }
+
+ return (syntax);
+}
+
+static int32_t
+snmp_import_head(struct snmp_toolinfo *snmptoolctx)
+{
+ enum tok tok;
+
+ if ((tok = gettoken(snmptoolctx)) == '(')
+ tok = gettoken(snmptoolctx);
+
+ if (tok != TOK_NUM || val > ASN_MAXID ) {
+ warnx("Suboid expected - line %d", input->lno);
+ return (-1);
+ }
+
+ if (gettoken(snmptoolctx) != TOK_STR) {
+ warnx("Node name expected at line %d", input->lno);
+ return (-1);
+ }
+
+ return (1);
+}
+
+static int32_t
+snmp_import_table(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *obj)
+{
+ int32_t i;
+ enum snmp_tc tc;
+ enum tok tok;
+ struct snmp_index_entry *entry;
+
+ if ((entry = malloc(sizeof(struct snmp_index_entry))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ memset(entry, 0, sizeof(struct snmp_index_entry));
+ STAILQ_INIT(&(entry->index_list));
+
+ for (i = 0, tok = gettoken(snmptoolctx); i < SNMP_INDEXES_MAX; i++) {
+ int32_t syntax;
+ struct enum_pairs *enums = NULL;
+
+ if (tok != TOK_TYPE && tok != TOK_DEFTYPE && tok != TOK_ENUM &&
+ tok != TOK_BITS)
+ break;
+
+ if ((syntax = parse_type(snmptoolctx, &tok, &tc, &enums)) < 0) {
+ enum_pairs_free(enums);
+ snmp_index_listfree(&(entry->index_list));
+ free(entry);
+ return (-1);
+ }
+
+ if (snmp_syntax_insert(&(entry->index_list), enums, syntax,
+ tc) < 0) {
+ snmp_index_listfree(&(entry->index_list));
+ enum_pairs_free(enums);
+ free(entry);
+ return (-1);
+ }
+ }
+
+ if (i == 0 || i > SNMP_INDEXES_MAX) {
+ warnx("Bad number of indexes at line %d", input->lno);
+ snmp_index_listfree(&(entry->index_list));
+ free(entry);
+ return (-1);
+ }
+
+ if (tok != TOK_STR) {
+ warnx("String expected after indexes at line %d", input->lno);
+ snmp_index_listfree(&(entry->index_list));
+ free(entry);
+ return (-1);
+ }
+
+ entry->string = obj->string;
+ entry->strlen = obj->strlen;
+ asn_append_oid(&(entry->var), &(obj->var));
+
+ if ((i = snmp_table_insert(snmptoolctx, entry)) < 0) {
+ snmp_index_listfree(&(entry->index_list));
+ free(entry);
+ return (-1);
+ } else if (i == 0) {
+ /* Same entry already present in lists. */
+ free(entry->string);
+ free(entry);
+ }
+
+ (void) snmp_import_update_table(ENTRY_INDEX, entry);
+
+ return (1);
+}
+
+/*
+ * Read everything after the syntax type that is certainly a leaf OID info.
+ */
+static int32_t
+snmp_import_leaf(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
+ struct snmp_oid2str *oid2str)
+{
+ int32_t i, syntax;
+
+ if ((syntax = parse_type(snmptoolctx, tok, &(oid2str->tc), &(oid2str->snmp_enum)))
+ < 0)
+ return(-1);
+
+ oid2str->syntax = syntax;
+ /*
+ * That is the name of the function, corresponding to the entry.
+ * It is used by bsnmpd, but is not interesting for us.
+ */
+ if (*tok == TOK_STR)
+ *tok = gettoken(snmptoolctx);
+
+ for (i = 0; i < SNMP_ACCESS_GETSET && *tok == TOK_ACCESS; i++) {
+ oid2str->access |= (uint32_t) val;
+ *tok = gettoken(snmptoolctx);
+ }
+
+ if (*tok != ')') {
+ warnx("')' expected at end of line %d", input->lno);
+ return (-1);
+ }
+
+ oid2str->table_idx = snmp_import_update_table(ENTRY_DATA, NULL);
+
+ if ((i = snmp_leaf_insert(snmptoolctx, oid2str)) < 0) {
+ warnx("Error adding leaf %s to list", oid2str->string);
+ return (-1);
+ }
+
+ /*
+ * Same entry is already present in the mapping lists and
+ * the new one was not inserted.
+ */
+ if (i == 0) {
+ free(oid2str->string);
+ free(oid2str);
+ }
+
+ (void) snmp_import_update_table(ENTRY_NONE, NULL);
+
+ return (1);
+}
+
+static int32_t
+snmp_import_object(struct snmp_toolinfo *snmptoolctx)
+{
+ char *string;
+ int i;
+ enum tok tok;
+ struct snmp_oid2str *oid2str;
+
+ if (snmp_import_head(snmptoolctx) < 0)
+ return (-1);
+
+ if ((oid2str = malloc(sizeof(struct snmp_oid2str))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ if ((string = malloc(strlen(nexttok) + 1)) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ free(oid2str);
+ return (-1);
+ }
+
+ memset(oid2str, 0, sizeof(struct snmp_oid2str));
+ strlcpy(string, nexttok, strlen(nexttok) + 1);
+ oid2str->string = string;
+ oid2str->strlen = strlen(nexttok);
+
+ asn_append_oid(&(oid2str->var), &(current_oid));
+ if (snmp_suboid_append(&(oid2str->var), (asn_subid_t) val) < 0)
+ goto error;
+
+ /*
+ * Prepared the entry - now figure out where to insert it.
+ * After the object we have following options:
+ * 1) new line, blank, ) - then it is an enum oid -> snmp_enumlist;
+ * 2) new line , ( - nonleaf oid -> snmp_nodelist;
+ * 2) ':' - table entry - a variable length SYNTAX_TYPE (one or more)
+ * may follow and second string must end line -> snmp_tablelist;
+ * 3) OID , string ) - this is a trap entry or a leaf -> snmp_oidlist;
+ * 4) SYNTAX_TYPE, string (not always), get/set modifier - always last
+ * and )- this is definitely a leaf.
+ */
+
+ switch (tok = gettoken(snmptoolctx)) {
+ case ')':
+ if ((i = snmp_enum_insert(snmptoolctx, oid2str)) < 0)
+ goto error;
+ if (i == 0) {
+ free(oid2str->string);
+ free(oid2str);
+ }
+ return (1);
+
+ case '(':
+ if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
+ goto error;
+
+ /*
+ * Ignore the error for nodes since the .def files currently
+ * contain different strings for 1.3.6.1.2.1 - mibII. Only make
+ * sure the memory is freed and don't complain.
+ */
+ if ((i = snmp_node_insert(snmptoolctx, oid2str)) <= 0) {
+ free(string);
+ free(oid2str);
+ }
+ return (snmp_import_object(snmptoolctx));
+
+ case ':':
+ if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
+ goto error;
+ if (snmp_import_table(snmptoolctx, oid2str) < 0)
+ goto error;
+ /*
+ * A different table entry type was malloced and the data is
+ * contained there.
+ */
+ free(oid2str);
+ return (1);
+
+ case TOK_TYPE:
+ /* FALLTHROUGH */
+ case TOK_DEFTYPE:
+ /* FALLTHROUGH */
+ case TOK_ENUM:
+ /* FALLTHROUGH */
+ case TOK_BITS:
+ if (snmp_import_leaf(snmptoolctx, &tok, oid2str) < 0)
+ goto error;
+ return (1);
+
+ default:
+ warnx("Unexpected token at line %d - %s", input->lno,
+ input->fname);
+ break;
+ }
+
+error:
+ snmp_mapping_entryfree(oid2str);
+
+ return (-1);
+}
+
+static int32_t
+snmp_import_tree(struct snmp_toolinfo *snmptoolctx, enum tok *tok)
+{
+ while (*tok != TOK_EOF) {
+ switch (*tok) {
+ case TOK_ERR:
+ return (-1);
+ case '(':
+ if (snmp_import_object(snmptoolctx) < 0)
+ return (-1);
+ break;
+ case ')':
+ if (snmp_suboid_pop(&current_oid) < 0)
+ return (-1);
+ (void) snmp_import_update_table(ENTRY_NONE, NULL);
+ break;
+ default:
+ /* Anything else here would be illegal. */
+ return (-1);
+ }
+ *tok = gettoken(snmptoolctx);
+ }
+
+ return (0);
+}
+
+static int32_t
+snmp_import_top(struct snmp_toolinfo *snmptoolctx, enum tok *tok)
+{
+ enum snmp_tc tc;
+ struct enum_type *t;
+
+ if (*tok == '(')
+ return (snmp_import_tree(snmptoolctx, tok));
+
+ if (*tok == TOK_TYPEDEF) {
+ if ((*tok = gettoken(snmptoolctx)) != TOK_STR) {
+ warnx("type name expected after typedef - %s",
+ input->fname);
+ return (-1);
+ }
+
+ t = snmp_enumtc_init(nexttok);
+
+ *tok = gettoken(snmptoolctx);
+ t->is_enum = (*tok == TOK_ENUM);
+ t->is_bits = (*tok == TOK_BITS);
+ t->syntax = parse_type(snmptoolctx, tok, &tc, &(t->snmp_enum));
+ snmp_enumtc_insert(snmptoolctx, t);
+
+ return (1);
+ }
+
+ if (*tok == TOK_INCLUDE) {
+ int i;
+
+ *tok = gettoken(snmptoolctx);
+ if (*tok != TOK_FILENAME) {
+ warnx("filename expected in include directive - %s",
+ nexttok);
+ return (-1);
+ }
+
+ if (( i = add_filename(snmptoolctx, nexttok, NULL, 1)) == 0) {
+ *tok = gettoken(snmptoolctx);
+ return (1);
+ }
+
+ if (i == -1)
+ return (-1);
+
+ input_fopen(nexttok);
+ *tok = gettoken(snmptoolctx);
+ return (1);
+ }
+
+ warnx("'(' or 'typedef' expected - %s", nexttok);
+ return (-1);
+}
+
+static int32_t
+snmp_import(struct snmp_toolinfo *snmptoolctx)
+{
+ int i;
+ enum tok tok;
+
+ tok = gettoken(snmptoolctx);
+
+ do
+ i = snmp_import_top(snmptoolctx, &tok);
+ while (i > 0);
+
+ return (i);
+}
+
+/*
+ * Read a .def file and import oid<->string mapping.
+ * Mappings are inserted into a global structure containing list for each OID
+ * syntax type.
+ */
+int32_t
+snmp_import_file(struct snmp_toolinfo *snmptoolctx, struct fname *file)
+{
+ int idx;
+
+ snmp_import_init(&(file->cut));
+ input_fopen(file->name);
+ if ((idx = snmp_import(snmptoolctx)) < 0)
+ warnx("Failed to read mappings from file %s", file->name);
+
+ input_close();
+
+ return (idx);
+}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpmap.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpmap.c
new file mode 100644
index 0000000..a6d14a2
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpmap.c
@@ -0,0 +1,1018 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND 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 THE AUTHOR OR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+#include "bsnmptc.h"
+#include "bsnmptools.h"
+
+extern int _bsnmptools_debug;
+#define DEBUG if (_bsnmptools_debug) fprintf
+
+/* Allocate memory and initialize list. */
+struct snmp_mappings *
+snmp_mapping_init(void)
+{
+ struct snmp_mappings *m;
+
+ if ((m = malloc(sizeof(struct snmp_mappings))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (NULL);
+ }
+
+ memset(m, 0, sizeof(struct snmp_mappings));
+ return (m);
+}
+
+#define snmp_nodelist mappings->nodelist
+#define snmp_intlist mappings->intlist
+#define snmp_octlist mappings->octlist
+#define snmp_oidlist mappings->oidlist
+#define snmp_iplist mappings->iplist
+#define snmp_ticklist mappings->ticklist
+#define snmp_cntlist mappings->cntlist
+#define snmp_gaugelist mappings->gaugelist
+#define snmp_cnt64list mappings->cnt64list
+#define snmp_enumlist mappings->enumlist
+#define snmp_tablelist mappings->tablelist
+#define snmp_tclist mappings->tclist
+
+void
+enum_pairs_free(struct enum_pairs *headp)
+{
+ struct enum_pair *e;
+
+ if (headp == NULL)
+ return;
+
+ while ((e = STAILQ_FIRST(headp)) != NULL) {
+ STAILQ_REMOVE_HEAD(headp, link);
+
+ if (e->enum_str)
+ free(e->enum_str);
+ free(e);
+ }
+
+ free(headp);
+}
+
+void
+snmp_mapping_entryfree(struct snmp_oid2str *entry)
+{
+ if (entry->string)
+ free(entry->string);
+
+ if (entry->tc == SNMP_TC_OWN)
+ enum_pairs_free(entry->snmp_enum);
+
+ free(entry);
+}
+
+static void
+snmp_mapping_listfree(struct snmp_mapping *headp)
+{
+ struct snmp_oid2str *p;
+
+ while ((p = SLIST_FIRST(headp)) != NULL) {
+ SLIST_REMOVE_HEAD(headp, link);
+
+ if (p->string)
+ free(p->string);
+
+ if (p->tc == SNMP_TC_OWN)
+ enum_pairs_free(p->snmp_enum);
+ free(p);
+ }
+
+ SLIST_INIT(headp);
+}
+
+void
+snmp_index_listfree(struct snmp_idxlist *headp)
+{
+ struct index *i;
+
+ while ((i = STAILQ_FIRST(headp)) != NULL) {
+ STAILQ_REMOVE_HEAD(headp, link);
+ if (i->tc == SNMP_TC_OWN)
+ enum_pairs_free(i->snmp_enum);
+ free(i);
+ }
+
+ STAILQ_INIT(headp);
+}
+
+static void
+snmp_mapping_table_listfree(struct snmp_table_index *headp)
+{
+ struct snmp_index_entry *t;
+
+ while ((t = SLIST_FIRST(headp)) != NULL) {
+ SLIST_REMOVE_HEAD(headp, link);
+
+ if (t->string)
+ free(t->string);
+
+ snmp_index_listfree(&(t->index_list));
+ free(t);
+ }
+}
+
+static void
+snmp_enumtc_listfree(struct snmp_enum_tc *headp)
+{
+ struct enum_type *t;
+
+ while ((t = SLIST_FIRST(headp)) != NULL) {
+ SLIST_REMOVE_HEAD(headp, link);
+
+ if (t->name)
+ free(t->name);
+ enum_pairs_free(t->snmp_enum);
+ free(t);
+ }
+}
+
+int
+snmp_mapping_free(struct snmp_toolinfo *snmptoolctx)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL)
+ return (-1);
+
+ snmp_mapping_listfree(&snmptoolctx->snmp_nodelist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_intlist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_octlist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_oidlist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_iplist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_ticklist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_cntlist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_gaugelist);
+ snmp_mapping_listfree(&snmptoolctx->snmp_cnt64list);
+ snmp_mapping_listfree(&snmptoolctx->snmp_enumlist);
+ snmp_mapping_table_listfree(&snmptoolctx->snmp_tablelist);
+ snmp_enumtc_listfree(&snmptoolctx->snmp_tclist);
+ free(snmptoolctx->mappings);
+
+ return (0);
+}
+
+static void
+snmp_dump_enumpairs(struct enum_pairs *headp)
+{
+ struct enum_pair *entry;
+
+ if (headp == NULL)
+ return;
+
+ fprintf(stderr,"enums: ");
+ STAILQ_FOREACH(entry, headp, link)
+ fprintf(stderr,"%d - %s, ", entry->enum_val,
+ (entry->enum_str == NULL)?"NULL":entry->enum_str);
+
+ fprintf(stderr,"; ");
+}
+
+void
+snmp_dump_oid2str(struct snmp_oid2str *entry)
+{
+ char buf[ASN_OIDSTRLEN];
+
+ if (entry != NULL) {
+ memset(buf, 0, sizeof(buf));
+ asn_oid2str_r(&(entry->var), buf);
+ DEBUG(stderr, "%s - %s - %d - %d - %d", buf, entry->string,
+ entry->syntax, entry->access, entry->strlen);
+ snmp_dump_enumpairs(entry->snmp_enum);
+ DEBUG(stderr,"%s \n", (entry->table_idx == NULL)?"No table":
+ entry->table_idx->string);
+ }
+}
+
+static void
+snmp_dump_indexlist(struct snmp_idxlist *headp)
+{
+ struct index *entry;
+
+ if (headp == NULL)
+ return;
+
+ STAILQ_FOREACH(entry, headp, link) {
+ fprintf(stderr,"%d, ", entry->syntax);
+ snmp_dump_enumpairs(entry->snmp_enum);
+ }
+
+ fprintf(stderr,"\n");
+}
+
+/* Initialize the enum pairs list of a oid2str entry. */
+struct enum_pairs *
+enum_pairs_init(void)
+{
+ struct enum_pairs *snmp_enum;
+
+ if ((snmp_enum = malloc(sizeof(struct enum_pairs))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (NULL);
+ }
+
+ STAILQ_INIT(snmp_enum);
+ return (snmp_enum);
+}
+
+/*
+ * Given a number and string, allocate memory for a (int, string) pair and add
+ * it to the given oid2str mapping entry's enum pairs list.
+ */
+int32_t
+enum_pair_insert(struct enum_pairs *headp, int32_t enum_val, char *enum_str)
+{
+ struct enum_pair *e_new;
+
+ if ((e_new = malloc(sizeof(struct enum_pair))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ memset(e_new, 0, sizeof(struct enum_pair));
+
+ if ((e_new->enum_str = malloc(strlen(enum_str) + 1)) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ free(e_new);
+ return (-1);
+ }
+
+ e_new->enum_val = enum_val;
+ strlcpy(e_new->enum_str, enum_str, strlen(enum_str) + 1);
+ STAILQ_INSERT_TAIL(headp, e_new, link);
+
+ return (1);
+
+}
+
+/*
+ * Insert an entry in a list - entries are lexicographicaly order by asn_oid.
+ * Returns 1 on success, -1 if list is not initialized, 0 if a matching oid already
+ * exists. Error cheking is left to calling function.
+ */
+static int
+snmp_mapping_insert(struct snmp_mapping *headp, struct snmp_oid2str *entry)
+{
+ int32_t rc;
+ struct snmp_oid2str *temp, *prev;
+
+ if (entry == NULL)
+ return(-1);
+
+ if ((prev = SLIST_FIRST(headp)) == NULL ||
+ asn_compare_oid(&(entry->var), &(prev->var)) < 0) {
+ SLIST_INSERT_HEAD(headp, entry, link);
+ return (1);
+ } else
+ rc = -1; /* Make the compiler happy. */
+
+ SLIST_FOREACH(temp, headp, link) {
+ if ((rc = asn_compare_oid(&(entry->var), &(temp->var))) <= 0)
+ break;
+ prev = temp;
+ rc = -1;
+ }
+
+ switch (rc) {
+ case 0:
+ /* Ops, matching OIDs - hope the rest info also matches. */
+ if (strncmp(temp->string, entry->string, entry->strlen)) {
+ syslog(LOG_INFO, "Matching OIDs with different string "
+ "mappings: old - %s, new - %s", temp->string,
+ entry->string);
+ return (-1);
+ }
+ /*
+ * Ok, we have that already.
+ * As long as the strings match - don't complain.
+ */
+ return (0);
+
+ case 1:
+ SLIST_INSERT_AFTER(temp, entry, link);
+ break;
+
+ case -1:
+ SLIST_INSERT_AFTER(prev, entry, link);
+ break;
+
+ default:
+ /* NOTREACHED */
+ return (-1);
+ }
+
+ return (1);
+}
+
+int32_t
+snmp_node_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_nodelist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_int_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_intlist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_oct_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_octlist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_oid_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_oidlist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_ip_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_iplist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_tick_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_ticklist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_cnt_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_cntlist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_gauge_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_gaugelist,entry));
+
+ return (-1);
+}
+
+static int32_t
+snmp_cnt64_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_cnt64list,entry));
+
+ return (-1);
+}
+
+int32_t
+snmp_enum_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ if (snmptoolctx != NULL && snmptoolctx->mappings)
+ return (snmp_mapping_insert(&snmptoolctx->snmp_enumlist,entry));
+
+ return (-1);
+}
+
+int32_t
+snmp_leaf_insert(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *entry)
+{
+ switch (entry->syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ return (snmp_int_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_oct_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_OID:
+ return (snmp_oid_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (snmp_ip_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_COUNTER:
+ return (snmp_cnt_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_GAUGE:
+ return (snmp_gauge_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_TIMETICKS:
+ return (snmp_tick_insert(snmptoolctx, entry));
+ case SNMP_SYNTAX_COUNTER64:
+ return (snmp_cnt64_insert(snmptoolctx, entry));
+ default:
+ break;
+ }
+
+ return (-1);
+}
+
+static int32_t
+snmp_index_insert(struct snmp_idxlist *headp, struct index *idx)
+{
+ if (headp == NULL || index == NULL)
+ return (-1);
+
+ STAILQ_INSERT_TAIL(headp, idx, link);
+ return (1);
+}
+
+int32_t
+snmp_syntax_insert(struct snmp_idxlist *headp, struct enum_pairs *enums,
+ enum snmp_syntax syntax, enum snmp_tc tc)
+{
+ struct index *idx;
+
+ if ((idx = malloc(sizeof(struct index))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ memset(idx, 0, sizeof(struct index));
+
+ if (snmp_index_insert(headp, idx) < 0) {
+ free(idx);
+ return (-1);
+ }
+
+ idx->syntax = syntax;
+ idx->snmp_enum = enums;
+ idx->tc = tc;
+
+ return (1);
+}
+
+int32_t
+snmp_table_insert(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_index_entry *entry)
+{
+ int32_t rc;
+ struct snmp_index_entry *temp, *prev;
+
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL ||
+ entry == NULL)
+ return(-1);
+
+ if ((prev = SLIST_FIRST(&snmptoolctx->snmp_tablelist)) == NULL ||
+ asn_compare_oid(&(entry->var), &(prev->var)) < 0) {
+ SLIST_INSERT_HEAD(&snmptoolctx->snmp_tablelist, entry, link);
+ return (1);
+ } else
+ rc = -1; /* Make the compiler happy. */
+
+ SLIST_FOREACH(temp, &snmptoolctx->snmp_tablelist, link) {
+ if ((rc = asn_compare_oid(&(entry->var), &(temp->var))) <= 0)
+ break;
+ prev = temp;
+ rc = -1;
+ }
+
+ switch (rc) {
+ case 0:
+ /* Ops, matching OIDs - hope the rest info also matches. */
+ if (strncmp(temp->string, entry->string, entry->strlen)) {
+ syslog(LOG_INFO, "Matching OIDs with different string "
+ "mapping - old - %s, new - %s", temp->string,
+ entry->string);
+ return (-1);
+ }
+ return(0);
+
+ case 1:
+ SLIST_INSERT_AFTER(temp, entry, link);
+ break;
+
+ case -1:
+ SLIST_INSERT_AFTER(prev, entry, link);
+ break;
+
+ default:
+ /* NOTREACHED */
+ return (-1);
+ }
+
+ return (1);
+}
+
+struct enum_type *
+snmp_enumtc_init(char *name)
+{
+ struct enum_type *enum_tc;
+
+ if ((enum_tc = malloc(sizeof(struct enum_type))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (NULL);
+ }
+
+ memset(enum_tc, 0, sizeof(struct enum_type));
+ if ((enum_tc->name = malloc(strlen(name) + 1)) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ free(enum_tc);
+ return (NULL);
+ }
+ strlcpy(enum_tc->name, name, strlen(name) + 1);
+
+ return (enum_tc);
+}
+
+void
+snmp_enumtc_free(struct enum_type *tc)
+{
+ if (tc->name)
+ free(tc->name);
+ if (tc->snmp_enum)
+ enum_pairs_free(tc->snmp_enum);
+ free(tc);
+}
+
+void
+snmp_enumtc_insert(struct snmp_toolinfo *snmptoolctx, struct enum_type *entry)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL)
+ return; /* XXX no error handling? */
+
+ SLIST_INSERT_HEAD(&snmptoolctx->snmp_tclist, entry, link);
+}
+
+struct enum_type *
+snmp_enumtc_lookup(struct snmp_toolinfo *snmptoolctx, char *name)
+{
+ struct enum_type *temp;
+
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL)
+ return (NULL);
+
+ SLIST_FOREACH(temp, &snmptoolctx->snmp_tclist, link) {
+ if (strcmp(temp->name, name) == 0)
+ return (temp);
+ }
+ return (NULL);
+}
+
+static void
+snmp_mapping_dumplist(struct snmp_mapping *headp)
+{
+ char buf[ASN_OIDSTRLEN];
+ struct snmp_oid2str *entry;
+
+ if (headp == NULL)
+ return;
+
+ SLIST_FOREACH(entry,headp,link) {
+ memset(buf, 0, sizeof(buf));
+ asn_oid2str_r(&(entry->var), buf);
+ fprintf(stderr, "%s - %s - %d - %d - %d", buf, entry->string,
+ entry->syntax, entry->access ,entry->strlen);
+ fprintf(stderr," - %s \n", (entry->table_idx == NULL)?
+ "No table":entry->table_idx->string);
+ }
+}
+
+static void
+snmp_mapping_dumptable(struct snmp_table_index *headp)
+{
+ char buf[ASN_OIDSTRLEN];
+ struct snmp_index_entry *entry;
+
+ if (headp == NULL)
+ return;
+
+ SLIST_FOREACH(entry, headp, link) {
+ memset(buf, 0, sizeof(buf));
+ asn_oid2str_r(&(entry->var), buf);
+ fprintf(stderr,"%s - %s - %d - ", buf, entry->string,
+ entry->strlen);
+ snmp_dump_indexlist(&(entry->index_list));
+ }
+}
+
+void
+snmp_mapping_dump(struct snmp_toolinfo *snmptoolctx /* int bits */)
+{
+ if (!_bsnmptools_debug)
+ return;
+
+ if (snmptoolctx == NULL) {
+ fprintf(stderr,"No snmptool context!\n");
+ return;
+ }
+
+ if (snmptoolctx->mappings == NULL) {
+ fprintf(stderr,"No mappings!\n");
+ return;
+ }
+
+ fprintf(stderr,"snmp_nodelist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_nodelist);
+
+ fprintf(stderr,"snmp_intlist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_intlist);
+
+ fprintf(stderr,"snmp_octlist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_octlist);
+
+ fprintf(stderr,"snmp_oidlist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_oidlist);
+
+ fprintf(stderr,"snmp_iplist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_iplist);
+
+ fprintf(stderr,"snmp_ticklist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_ticklist);
+
+ fprintf(stderr,"snmp_cntlist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_cntlist);
+
+ fprintf(stderr,"snmp_gaugelist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_gaugelist);
+
+ fprintf(stderr,"snmp_cnt64list:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_cnt64list);
+
+ fprintf(stderr,"snmp_enumlist:\n");
+ snmp_mapping_dumplist(&snmptoolctx->snmp_enumlist);
+
+ fprintf(stderr,"snmp_tablelist:\n");
+ snmp_mapping_dumptable(&snmptoolctx->snmp_tablelist);
+}
+
+char *
+enum_string_lookup(struct enum_pairs *headp, int32_t enum_val)
+{
+ struct enum_pair *temp;
+
+ if (headp == NULL)
+ return (NULL);
+
+ STAILQ_FOREACH(temp, headp, link) {
+ if (temp->enum_val == enum_val)
+ return (temp->enum_str);
+ }
+
+ return (NULL);
+}
+
+int32_t
+enum_number_lookup(struct enum_pairs *headp, char *e_str)
+{
+ struct enum_pair *tmp;
+
+ if (headp == NULL)
+ return (-1);
+
+ STAILQ_FOREACH(tmp, headp, link)
+ if (strncmp(tmp->enum_str, e_str, strlen(tmp->enum_str)) == 0)
+ return (tmp->enum_val);
+
+ return (-1);
+}
+
+static int32_t
+snmp_lookuplist_string(struct snmp_mapping *headp, struct snmp_object *s)
+{
+ struct snmp_oid2str *temp;
+
+ if (headp == NULL)
+ return (-1);
+
+ SLIST_FOREACH(temp, headp, link)
+ if (asn_compare_oid(&(temp->var), &(s->val.var)) == 0)
+ break;
+
+ if ((s->info = temp) == NULL)
+ return (-1);
+
+ return (1);
+}
+
+/* provided an asn_oid find the corresponding string for it */
+static int32_t
+snmp_lookup_leaf(struct snmp_mapping *headp, struct snmp_object *s)
+{
+ struct snmp_oid2str *temp;
+
+ if (headp == NULL)
+ return (-1);
+
+ SLIST_FOREACH(temp,headp,link) {
+ if ((asn_compare_oid(&(temp->var), &(s->val.var)) == 0) ||
+ (asn_is_suboid(&(temp->var), &(s->val.var)))) {
+ s->info = temp;
+ return (1);
+ }
+ }
+
+ return (-1);
+}
+
+int32_t
+snmp_lookup_leafstring(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL || s == NULL)
+ return (-1);
+
+ switch (s->val.syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ return (snmp_lookup_leaf(&snmptoolctx->snmp_intlist, s));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_lookup_leaf(&snmptoolctx->snmp_octlist, s));
+ case SNMP_SYNTAX_OID:
+ return (snmp_lookup_leaf(&snmptoolctx->snmp_oidlist, s));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (snmp_lookup_leaf(&snmptoolctx->snmp_iplist, s));
+ case SNMP_SYNTAX_COUNTER:
+ return (snmp_lookup_leaf(&snmptoolctx->snmp_cntlist, s));
+ case SNMP_SYNTAX_GAUGE:
+ return (snmp_lookup_leaf(
+ &snmptoolctx->snmp_gaugelist, s));
+ case SNMP_SYNTAX_TIMETICKS:
+ return (snmp_lookup_leaf(
+ &snmptoolctx->snmp_ticklist, s));
+ case SNMP_SYNTAX_COUNTER64:
+ return (snmp_lookup_leaf(
+ &snmptoolctx->snmp_cnt64list, s));
+ case SNMP_SYNTAX_NOSUCHOBJECT:
+ /* FALLTHROUGH */
+ case SNMP_SYNTAX_NOSUCHINSTANCE:
+ /* FALLTHROUGH */
+ case SNMP_SYNTAX_ENDOFMIBVIEW:
+ return (snmp_lookup_allstring(snmptoolctx, s));
+ default:
+ warnx("Unknown syntax - %d", s->val.syntax);
+ break;
+ }
+
+ return (-1);
+}
+
+int32_t
+snmp_lookup_enumstring(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL || s == NULL)
+ return (-1);
+
+ return (snmp_lookuplist_string(&snmptoolctx->snmp_enumlist, s));
+}
+
+int32_t
+snmp_lookup_oidstring(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL || s == NULL)
+ return (-1);
+
+ return (snmp_lookuplist_string(&snmptoolctx->snmp_oidlist, s));
+}
+
+int32_t
+snmp_lookup_nodestring(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL || s == NULL)
+ return (-1);
+
+ return (snmp_lookuplist_string(&snmptoolctx->snmp_nodelist, s));
+}
+
+int32_t
+snmp_lookup_allstring(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s)
+{
+ if (snmptoolctx == NULL || snmptoolctx->mappings == NULL)
+ return (-1);
+
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_intlist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_octlist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_oidlist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_iplist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_cntlist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_gaugelist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_ticklist, s) > 0)
+ return (1);
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_cnt64list, s) > 0)
+ return (1);
+ if (snmp_lookuplist_string(&snmptoolctx->snmp_enumlist, s) > 0)
+ return (1);
+ if (snmp_lookuplist_string(&snmptoolctx->snmp_nodelist, s) > 0)
+ return (1);
+
+ return (-1);
+}
+
+int32_t
+snmp_lookup_nonleaf_string(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_object *s)
+{
+ if (snmptoolctx == NULL)
+ return (-1);
+
+ if (snmp_lookuplist_string(&snmptoolctx->snmp_nodelist, s) > 0)
+ return (1);
+ if (snmp_lookuplist_string(&snmptoolctx->snmp_enumlist, s) > 0)
+ return (1);
+
+ return (-1);
+}
+
+static int32_t
+snmp_lookup_oidlist(struct snmp_mapping *hp, struct snmp_object *s, char *oid)
+{
+ struct snmp_oid2str *temp;
+
+ if (hp == NULL)
+ return (-1);
+
+ SLIST_FOREACH(temp, hp, link) {
+ if (temp->strlen != strlen(oid))
+ continue;
+
+ if (strncmp(temp->string, oid, temp->strlen))
+ continue;
+
+ s->val.syntax = temp->syntax;
+ s->info = temp;
+ asn_append_oid(&(s->val.var), &(temp->var));
+ return (1);
+ }
+
+ return (-1);
+}
+
+static int32_t
+snmp_lookup_tablelist(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_table_index *headp, struct snmp_object *s, char *oid)
+{
+ struct snmp_index_entry *temp;
+
+ if (snmptoolctx == NULL || headp == NULL)
+ return (-1);
+
+ SLIST_FOREACH(temp, headp, link) {
+ if (temp->strlen != strlen(oid))
+ continue;
+
+ if (strncmp(temp->string, oid, temp->strlen))
+ continue;
+
+ /*
+ * Another hack here - if we were given a table name
+ * return the corresponding pointer to it's entry.
+ * That should not change the reponce we'll get.
+ */
+ s->val.syntax = SNMP_SYNTAX_NULL;
+ asn_append_oid(&(s->val.var), &(temp->var));
+ if (snmp_lookup_leaf(&snmptoolctx->snmp_nodelist, s) > 0)
+ return (1);
+ else
+ return (-1);
+ }
+
+ return (-1);
+}
+
+int32_t
+snmp_lookup_oidall(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s,
+ char *oid)
+{
+ if (snmptoolctx == NULL || s == NULL || oid == NULL)
+ return (-1);
+
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_intlist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_octlist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_oidlist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_iplist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_ticklist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_cntlist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_gaugelist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_cnt64list, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_oidlist(&snmptoolctx->snmp_nodelist, s, oid) > 0)
+ return (1);
+ if (snmp_lookup_tablelist(snmptoolctx, &snmptoolctx->snmp_tablelist,
+ s, oid) > 0)
+ return (1);
+
+ return (-1);
+}
+
+int32_t
+snmp_lookup_enumoid(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s,
+ char *oid)
+{
+ if (snmptoolctx == NULL || s == NULL)
+ return (-1);
+
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_enumlist, s, oid));
+}
+
+int32_t
+snmp_lookup_oid(struct snmp_toolinfo *snmptoolctx, struct snmp_object *s,
+ char *oid)
+{
+ if (snmptoolctx == NULL || s == NULL)
+ return (-1);
+
+ switch (s->val.syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_intlist,
+ s, oid));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_octlist,
+ s, oid));
+ case SNMP_SYNTAX_OID:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_oidlist,
+ s, oid));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_iplist,
+ s, oid));
+ case SNMP_SYNTAX_COUNTER:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_cntlist,
+ s, oid));
+ case SNMP_SYNTAX_GAUGE:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_gaugelist,
+ s, oid));
+ case SNMP_SYNTAX_TIMETICKS:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_ticklist,
+ s, oid));
+ case SNMP_SYNTAX_COUNTER64:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_cnt64list,
+ s, oid));
+ case SNMP_SYNTAX_NULL:
+ return (snmp_lookup_oidlist(&snmptoolctx->snmp_nodelist,
+ s, oid));
+ default:
+ warnx("Unknown syntax - %d", s->val.syntax);
+ break;
+ }
+
+ return (-1);
+}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c
new file mode 100644
index 0000000..dc22c69
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.c
@@ -0,0 +1,1287 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND 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 THE AUTHOR OR 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.
+ *
+ * Textual conventions for OctetStrings
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+#include "bsnmptc.h"
+#include "bsnmptools.h"
+
+/* OctetString, DisplayString */
+static char *snmp_oct2str(uint32_t, char *, char *);
+static char *snmp_str2asn_oid(char *, struct asn_oid *);
+static int parse_octetstring(struct snmp_value *, char *);
+
+/* DateAndTime */
+static char *snmp_octstr2date(uint32_t, char *, char *);
+static char *snmp_date2asn_oid(char * , struct asn_oid *);
+static int parse_dateandtime(struct snmp_value *, char *);
+
+/* PhysAddress */
+static char *snmp_oct2physAddr(uint32_t, char *, char *);
+static char *snmp_addr2asn_oid(char *, struct asn_oid *);
+static int parse_physaddress(struct snmp_value *, char *);
+
+/* NTPTimeStamp */
+static char *snmp_oct2ntp_ts(uint32_t, char *, char *);
+static char *snmp_ntp_ts2asn_oid(char *, struct asn_oid *);
+static int parse_ntp_ts(struct snmp_value *, char *);
+
+/* BridgeId */
+static char *snmp_oct2bridgeid(uint32_t, char *, char *);
+static char *snmp_bridgeid2oct(char *, struct asn_oid *);
+static int parse_bridge_id(struct snmp_value *, char *);
+
+/* BridgePortId */
+static char *snmp_oct2bport_id(uint32_t, char *, char *);
+static char *snmp_bport_id2oct(char *, struct asn_oid *);
+static int parse_bport_id(struct snmp_value *, char *);
+
+/* InetAddress */
+static char *snmp_oct2inetaddr(uint32_t len, char *octets, char *buf);
+static char *snmp_inetaddr2oct(char *str, struct asn_oid *oid);
+static int32_t parse_inetaddr(struct snmp_value *value, char *string);
+
+static char *snmp_oct2bits(uint32_t len, char *octets, char *buf);
+static char *snmp_bits2oct(char *str, struct asn_oid *oid);
+static int32_t parse_bits(struct snmp_value *value, char *string);
+
+struct snmp_text_conv {
+ enum snmp_tc tc;
+ const char *tc_str;
+ int32_t len;
+ snmp_oct2tc_f oct2tc;
+ snmp_tc2oid_f tc2oid;
+ snmp_tc2oct_f tc2oct;
+} text_convs[] = {
+ { SNMP_STRING, "OctetString", SNMP_VAR_STRSZ,
+ snmp_oct2str, snmp_str2asn_oid, parse_octetstring },
+
+ { SNMP_DISPLAYSTRING, "DisplayString" , SNMP_VAR_STRSZ,
+ snmp_oct2str, snmp_str2asn_oid, parse_octetstring },
+
+ { SNMP_DATEANDTIME, "DateAndTime", SNMP_DATETIME_STRSZ,
+ snmp_octstr2date, snmp_date2asn_oid, parse_dateandtime },
+
+ { SNMP_PHYSADDR, "PhysAddress", SNMP_PHYSADDR_STRSZ,
+ snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
+
+ { SNMP_ATMESI, "AtmESI", SNMP_PHYSADDR_STRSZ,
+ snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
+
+ { SNMP_NTP_TIMESTAMP, "NTPTimeStamp", SNMP_NTP_TS_STRSZ,
+ snmp_oct2ntp_ts, snmp_ntp_ts2asn_oid, parse_ntp_ts },
+
+ { SNMP_MACADDRESS, "MacAddress", SNMP_PHYSADDR_STRSZ,
+ snmp_oct2physAddr, snmp_addr2asn_oid, parse_physaddress },
+
+ { SNMP_BRIDGE_ID, "BridgeId", SNMP_BRIDGEID_STRSZ,
+ snmp_oct2bridgeid, snmp_bridgeid2oct, parse_bridge_id },
+
+ { SNMP_BPORT_ID, "BridgePortId", SNMP_BPORT_STRSZ,
+ snmp_oct2bport_id, snmp_bport_id2oct, parse_bport_id },
+
+ { SNMP_INETADDRESS, "InetAddress", SNMP_INADDRS_STRSZ,
+ snmp_oct2inetaddr, snmp_inetaddr2oct, parse_inetaddr },
+
+ { SNMP_TC_OWN, "BITS", SNMP_VAR_STRSZ,
+ snmp_oct2bits, snmp_bits2oct, parse_bits },
+
+ { SNMP_UNKNOWN, "Unknown", SNMP_VAR_STRSZ, snmp_oct2str,
+ snmp_str2asn_oid, parse_octetstring } /* keep last */
+};
+
+/* Common API */
+enum snmp_tc
+snmp_get_tc(char *str)
+{
+ int i;
+ for (i = 0; i < SNMP_UNKNOWN; i++) {
+ if (!strncmp(text_convs[i].tc_str, str,
+ strlen(text_convs[i].tc_str)))
+ return (text_convs[i].tc);
+ }
+
+ return (SNMP_STRING);
+}
+
+char *
+snmp_oct2tc(enum snmp_tc tc, uint32_t len, char *octets)
+{
+ uint32_t tc_len;
+ char * buf;
+
+ if (tc < 0 || tc > SNMP_UNKNOWN)
+ tc = SNMP_UNKNOWN;
+
+ if (text_convs[tc].len > 0)
+ tc_len = text_convs[tc].len;
+ else
+ tc_len = 2 * len + 3;
+
+ if ((buf = malloc(tc_len)) == NULL ) {
+ syslog(LOG_ERR, "malloc failed - %s", strerror(errno));
+ return (NULL);
+ }
+
+ memset(buf, 0, tc_len);
+ if (text_convs[tc].oct2tc(len, octets, buf) == NULL) {
+ free(buf);
+ return (NULL);
+ }
+
+ return (buf);
+}
+
+char *
+snmp_tc2oid(enum snmp_tc tc, char *str, struct asn_oid *oid)
+{
+ if (tc < 0 || tc > SNMP_UNKNOWN)
+ tc = SNMP_UNKNOWN;
+
+ return (text_convs[tc].tc2oid(str, oid));
+}
+
+int32_t
+snmp_tc2oct(enum snmp_tc tc, struct snmp_value *value, char *string)
+{
+ if (tc < 0 || tc > SNMP_UNKNOWN)
+ tc = SNMP_UNKNOWN;
+
+ return (text_convs[tc].tc2oct(value, string));
+}
+
+/*****************************************************
+* Basic OctetString type.
+*/
+static char *
+snmp_oct2str(uint32_t len, char *octets, char *buf)
+{
+ uint8_t binary = 0;
+ uint32_t i;
+ char *ptr;
+
+ if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
+ return (NULL);
+
+ for (ptr = buf, i = 0; i < len; i++)
+ if (!isprint(octets[i])) {
+ binary = 1;
+ buf += sprintf(buf, "0x");
+ break;
+ }
+
+ for (ptr = buf, i = 0; i < len; i++)
+ if (!binary)
+ ptr += sprintf(ptr, "%c", octets[i]);
+ else
+ ptr += sprintf(ptr, "%2.2x", (u_char)octets[i]);
+
+ return (buf);
+}
+
+static char *
+snmp_str2asn_oid(char *str, struct asn_oid *oid)
+{
+ uint32_t i, len = 0;
+
+ /*
+ * OctetStrings are allowed max length of ASN_MAXOCTETSTRING,
+ * but trying to index an entry with such a long OctetString
+ * will fail anyway.
+ */
+ for (len = 0; len < ASN_MAXOIDLEN; len++) {
+ if (strchr(",]", *(str + len)) != NULL)
+ break;
+ }
+
+ if (len >= ASN_MAXOIDLEN)
+ return (NULL);
+
+ if (snmp_suboid_append(oid, (asn_subid_t) len) < 0)
+ return (NULL);
+
+ for (i = 0; i < len; i++)
+ if (snmp_suboid_append(oid, (asn_subid_t) *(str + i)) < 0)
+ return (NULL);
+
+ return (str + len);
+}
+
+static int32_t
+parse_octetstring(struct snmp_value *value, char *val)
+{
+ size_t len;
+
+ if ((len = strlen(val)) >= MAX_OCTSTRING_LEN) {
+ warnx("Octetstring too long - %d is max allowed",
+ MAX_OCTSTRING_LEN - 1);
+ return (-1);
+ }
+
+ value->v.octetstring.len = len;
+
+ if((value->v.octetstring.octets = malloc(len)) == NULL) {
+ syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ memcpy(value->v.octetstring.octets, val, len);
+ value->syntax = SNMP_SYNTAX_OCTETSTRING;
+
+ return (0);
+}
+
+/*************************************************************
+ * DateAndTime
+ *************************************************************
+ * rfc 2579 specification:
+ * DateAndTime ::= TEXTUAL-CONVENTION
+ * DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
+ * STATUS current
+ * DESCRIPTION
+ * "A date-time specification.
+ *
+ * field octets contents range
+ * ----- ------ -------- -----
+ * 1 1-2 year* 0..65536
+ * 2 3 month 1..12
+ * 3 4 day 1..31
+ * 4 5 hour 0..23
+ * 5 6 minutes 0..59
+ * 6 7 seconds 0..60
+ * (use 60 for leap-second)
+ * 7 8 deci-seconds 0..9
+ * 8 9 direction from UTC '+' / '-'
+ * 9 10 hours from UTC* 0..13
+ * 10 11 minutes from UTC 0..59
+ *
+ * * Notes:
+ * - the value of year is in network-byte order
+ * - daylight saving time in New Zealand is +13
+ *
+ * For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
+ * displayed as:
+ *
+ * 1992-5-26,13:30:15.0,-4:0
+ */
+static char *
+snmp_octstr2date(uint32_t len, char *octets, char *buf)
+{
+ int year;
+ char *ptr;
+
+ if (len != SNMP_DATETIME_OCTETS || octets == NULL || buf == NULL)
+ return (NULL);
+
+ buf[0]= '\0';
+ year = (octets[0] << 8);
+ year += (octets[1]);
+
+ ptr = buf;
+ ptr += sprintf(ptr, "%4.4d-%.2d-%.2d, ", year, octets[2],octets[3]);
+ ptr += sprintf(ptr, "%2.2d:%2.2d:%2.2d.%.2d, ", octets[4],octets[5],
+ octets[6],octets[7]);
+ ptr += sprintf(ptr, "%c%.2d:%.2d", octets[8],octets[9],octets[10]);
+
+ return (buf);
+}
+
+static char *
+snmp_date2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr, *ptr;
+ uint32_t v;
+ int32_t saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) SNMP_DATETIME_OCTETS) < 0)
+ return (NULL);
+
+ /* Read 'YYYY-' and write it in two subs. */
+ ptr = str;
+ saved_errno = errno;
+ errno = 0;
+ v = strtoul(ptr, &endptr, 10);
+ if (v > 0xffff)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != '-')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) ((v & 0xff00) >> 8)) < 0)
+ return (NULL);
+ if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
+ return (NULL);
+
+ /* 'MM-' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != '-')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'DD,' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != '-')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'HH:' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != ':')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'MM:' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != ':')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'SS.' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != '.')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'M(mseconds),' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != ',')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'UTC' - optional */
+ ptr = endptr + 1;
+ if (*ptr == 'U' && *(ptr + 1) == 'T' && *(ptr + 1) == 'C')
+ ptr += 3;
+
+ /* '+/-' */
+ if (*ptr == '-' || *ptr == '+') {
+ if (snmp_suboid_append(oid, (asn_subid_t) (*ptr)) < 0)
+ return (NULL);
+ } else
+ goto error1;
+
+ /* 'HH:' */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (*endptr != ':')
+ goto error1;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ /* 'MM' - last one - ignore endptr here. */
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0)
+ goto error;
+ else
+ errno = saved_errno;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+
+ error:
+ errno = saved_errno;
+ error1:
+ warnx("Date value %s not supported", str);
+ return (NULL);
+}
+
+/* Read a DateAndTime string eg. 1992-5-26,13:30:15.0,-4:0. */
+static int32_t
+parse_dateandtime(struct snmp_value *sv, char *val)
+{
+ char *endptr;
+ uint32_t v;
+ uint8_t date[SNMP_DATETIME_OCTETS];
+
+ /* 'YYYY-' */
+ v = strtoul(val, &endptr, 10);
+ if (v > 0xffff || *endptr != '-')
+ goto error;
+ date[0] = ((v & 0xff00) >> 8);
+ date[1] = (v & 0xff);
+ val = endptr + 1;
+
+ /* 'MM-' */
+ v = strtoul(val, &endptr, 10);
+ if (v == 0 || v > 12 || *endptr != '-')
+ goto error;
+ date[2] = v;
+ val = endptr + 1;
+
+ /* 'DD,' */
+ v = strtoul(val, &endptr, 10);
+ if (v == 0 || v > 31 || *endptr != ',')
+ goto error;
+ date[3] = v;
+ val = endptr + 1;
+
+ /* 'HH:' */
+ v = strtoul(val, &endptr, 10);
+ if (v > 23 || *endptr != ':')
+ goto error;
+ date[4] = v;
+ val = endptr + 1;
+
+ /* 'MM:' */
+ v = strtoul(val, &endptr, 10);
+ if (v > 59 || *endptr != ':')
+ goto error;
+ date[5] = v;
+ val = endptr + 1;
+
+ /* 'SS.' */
+ v = strtoul(val, &endptr, 10);
+ if (v > 60 || *endptr != '.')
+ goto error;
+ date[6] = v;
+ val = endptr + 1;
+
+ /* '(deci-)s,' */
+ v = strtoul(val, &endptr, 10);
+ if (v > 9 || *endptr != ',')
+ goto error;
+ date[7] = v;
+ val = endptr + 1;
+
+ /* offset - '+/-' */
+ if (*val != '-' && *val != '+')
+ goto error;
+ date[8] = (uint8_t) *val;
+ val = endptr + 1;
+
+ /* 'HH:' - offset from UTC */
+ v = strtoul(val, &endptr, 10);
+ if (v > 13 || *endptr != ':')
+ goto error;
+ date[9] = v;
+ val = endptr + 1;
+
+ /* 'MM'\0'' offset from UTC */
+ v = strtoul(val, &endptr, 10);
+ if (v > 59 || *endptr != '\0')
+ goto error;
+ date[10] = v;
+
+ if ((sv->v.octetstring.octets = malloc(SNMP_DATETIME_OCTETS)) == NULL) {
+ warnx("malloc() failed - %s", strerror(errno));
+ return (-1);
+ }
+
+ sv->v.octetstring.len = SNMP_DATETIME_OCTETS;
+ memcpy(sv->v.octetstring.octets, date, SNMP_DATETIME_OCTETS);
+ sv->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+
+ error:
+ warnx("Date value %s not supported", val);
+ return (-1);
+}
+
+/**************************************************************
+ * PhysAddress
+ */
+static char *
+snmp_oct2physAddr(uint32_t len, char *octets, char *buf)
+{
+ char *ptr;
+ uint32_t i;
+
+ if (len != SNMP_PHYSADDR_OCTETS || octets == NULL || buf == NULL)
+ return (NULL);
+
+ buf[0]= '\0';
+
+ ptr = buf;
+ ptr += sprintf(ptr, "%2.2x", octets[0]);
+ for (i = 1; i < 6; i++)
+ ptr += sprintf(ptr, ":%2.2x", octets[i]);
+
+ return (buf);
+}
+
+static char *
+snmp_addr2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr, *ptr;
+ uint32_t v, i;
+ int saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) SNMP_PHYSADDR_OCTETS) < 0)
+ return (NULL);
+
+ ptr = str;
+ for (i = 0; i < 5; i++) {
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 16);
+ errno = saved_errno;
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", str);
+ return (NULL);
+ }
+ if (*endptr != ':') {
+ warnx("Failed adding oid - %s",str);
+ return (NULL);
+ }
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+ ptr = endptr + 1;
+ }
+
+ /* The last one - don't check the ending char here. */
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 16);
+ errno = saved_errno;
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", str);
+ return (NULL);
+ }
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+static int32_t
+parse_physaddress(struct snmp_value *sv, char *val)
+{
+ char *endptr;
+ int32_t i;
+ uint32_t v;
+ uint8_t phys_addr[SNMP_PHYSADDR_OCTETS];
+
+ for (i = 0; i < 5; i++) {
+ v = strtoul(val, &endptr, 16);
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", val);
+ return (-1);
+ }
+ if(*endptr != ':') {
+ warnx("Failed reading octet - %s", val);
+ return (-1);
+ }
+ phys_addr[i] = v;
+ val = endptr + 1;
+ }
+
+ /* The last one - don't check the ending char here. */
+ v = strtoul(val, &endptr, 16);
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", val);
+ return (-1);
+ }
+ phys_addr[5] = v;
+
+ if ((sv->v.octetstring.octets = malloc(SNMP_PHYSADDR_OCTETS)) == NULL) {
+ syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ sv->v.octetstring.len = SNMP_PHYSADDR_OCTETS;
+ memcpy(sv->v.octetstring.octets, phys_addr, SNMP_PHYSADDR_OCTETS);
+ sv->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+}
+
+/**************************************************************
+ * NTPTimeStamp
+ **************************************************************
+ * NTP MIB, Revision 0.2, 7/25/97:
+ * NTPTimeStamp ::= TEXTUAL-CONVENTION
+ * DISPLAY-HINT "4x.4x"
+ * STATUS current
+ * DESCRIPTION
+ * ""
+ * SYNTAX OCTET STRING (SIZE(8))
+ */
+static char *
+snmp_oct2ntp_ts(uint32_t len, char *octets, char *buf)
+{
+ char *ptr;
+ uint32_t i;
+
+ if (len != SNMP_NTP_TS_OCTETS || octets == NULL || buf == NULL)
+ return (NULL);
+
+ buf[0]= '\0';
+
+ ptr = buf;
+ i = octets[0] * 1000 + octets[1] * 100 + octets[2] * 10 + octets[3];
+ ptr += sprintf(ptr, "%4.4d", i);
+ i = octets[4] * 1000 + octets[5] * 100 + octets[6] * 10 + octets[7];
+ ptr += sprintf(ptr, ".%4.4d", i);
+
+ return (buf);
+}
+
+static char *
+snmp_ntp_ts2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr, *ptr;
+ uint32_t v, i, d;
+ struct asn_oid suboid;
+ int saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) SNMP_NTP_TS_OCTETS) < 0)
+ return (NULL);
+
+ ptr = str;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0 || (v / 1000) > 9) {
+ warnx("Integer value %s not supported", str);
+ errno = saved_errno;
+ return (NULL);
+ } else
+ errno = saved_errno;
+
+ if (*endptr != '.') {
+ warnx("Failed adding oid - %s",str);
+ return (NULL);
+ }
+
+ memset(&suboid, 0, sizeof(struct asn_oid));
+ suboid.len = SNMP_NTP_TS_OCTETS;
+
+ for (i = 0, d = 1000; i < 4; i++) {
+ suboid.subs[i] = v / d;
+ v = v % d;
+ d = d / 10;
+ }
+
+ ptr = endptr + 1;
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ if (errno != 0 || (v / 1000) > 9) {
+ warnx("Integer value %s not supported", str);
+ errno = saved_errno;
+ return (NULL);
+ } else
+ errno = saved_errno;
+
+ for (i = 0, d = 1000; i < 4; i++) {
+ suboid.subs[i + 4] = v / d;
+ v = v % d;
+ d = d / 10;
+ }
+
+ asn_append_oid(oid, &suboid);
+ return (endptr);
+}
+
+static int32_t
+parse_ntp_ts(struct snmp_value *sv, char *val)
+{
+ char *endptr;
+ int32_t i, d, saved_errno;
+ uint32_t v;
+ uint8_t ntp_ts[SNMP_NTP_TS_OCTETS];
+
+ saved_errno = errno;
+ v = strtoul(val, &endptr, 10);
+ if (errno != 0 || (v / 1000) > 9) {
+ saved_errno = errno;
+ warnx("Integer value %s not supported", val);
+ return (-1);
+ } else
+ saved_errno = errno;
+
+ if (*endptr != '.') {
+ warnx("Failed reading octet - %s", val);
+ return (-1);
+ }
+
+ for (i = 0, d = 1000; i < 4; i++) {
+ ntp_ts[i] = v / d;
+ v = v % d;
+ d = d / 10;
+ }
+ val = endptr + 1;
+
+ saved_errno = errno;
+ v = strtoul(val, &endptr, 10);
+ if (errno != 0 || (v / 1000) > 9) {
+ saved_errno = errno;
+ warnx("Integer value %s not supported", val);
+ return (-1);
+ } else
+ saved_errno = errno;
+
+ for (i = 0, d = 1000; i < 4; i++) {
+ ntp_ts[i + 4] = v / d;
+ v = v % d;
+ d = d / 10;
+ }
+
+ if ((sv->v.octetstring.octets = malloc(SNMP_NTP_TS_OCTETS)) == NULL) {
+ syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ sv->v.octetstring.len = SNMP_NTP_TS_OCTETS;
+ memcpy(sv->v.octetstring.octets, ntp_ts, SNMP_NTP_TS_OCTETS);
+ sv->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+}
+
+/**************************************************************
+ * BridgeId
+ **************************************************************
+ * BRIDGE-MIB, REVISION "200509190000Z"
+ * BridgeId ::= TEXTUAL-CONVENTION
+ * STATUS current
+ * DESCRIPTION
+ * "The Bridge-Identifier, as used in the Spanning Tree
+ * Protocol, to uniquely identify a bridge. Its first two
+ * octets (in network byte order) contain a priority value,
+ * and its last 6 octets contain the MAC address used to
+ * refer to a bridge in a unique fashion (typically, the
+ * numerically smallest MAC address of all ports on the
+ * bridge)."
+ * SYNTAX OCTET STRING (SIZE (8))
+ */
+static char *
+snmp_oct2bridgeid(uint32_t len, char *octets, char *buf)
+{
+ char *ptr;
+ uint32_t i, priority;
+
+ if (len != SNMP_BRIDGEID_OCTETS || octets == NULL || buf == NULL)
+ return (NULL);
+
+ buf[0]= '\0';
+ ptr = buf;
+
+ priority = octets[0] << 8;
+ priority += octets[1];
+ if (priority > SNMP_MAX_BRIDGE_PRIORITY) {
+ warnx("Invalid bridge priority %d", priority);
+ return (NULL);
+ } else
+ ptr += sprintf(ptr, "%d.", octets[0]);
+
+ ptr += sprintf(ptr, "%2.2x", octets[2]);
+
+ for (i = 1; i < 6; i++)
+ ptr += sprintf(ptr, ":%2.2x", octets[i + 2]);
+
+ return (buf);
+}
+
+static char *
+snmp_bridgeid2oct(char *str, struct asn_oid *oid)
+{
+ char *endptr, *ptr;
+ uint32_t v, i;
+ int32_t saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BRIDGEID_OCTETS) < 0)
+ return (NULL);
+
+ ptr = str;
+ /* Read the priority. */
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ errno = 0;
+
+ if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
+ errno = saved_errno;
+ warnx("Bad bridge priority value %d", v);
+ return (NULL);
+ }
+
+ if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff00)) < 0)
+ return (NULL);
+
+ if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xff)) < 0)
+ return (NULL);
+
+ ptr = endptr + 1;
+ for (i = 0; i < 5; i++) {
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 16);
+ errno = saved_errno;
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", str);
+ return (NULL);
+ }
+ if (*endptr != ':') {
+ warnx("Failed adding oid - %s",str);
+ return (NULL);
+ }
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+ ptr = endptr + 1;
+ }
+
+ /* The last one - don't check the ending char here. */
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 16);
+ errno = saved_errno;
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", str);
+ return (NULL);
+ }
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+static int32_t
+parse_bridge_id(struct snmp_value *sv, char *string)
+{
+ char *ptr, *endptr;
+ int32_t i, saved_errno;
+ uint32_t v;
+ uint8_t bridge_id[SNMP_BRIDGEID_OCTETS];
+
+ ptr = string;
+ /* Read the priority. */
+ saved_errno = errno;
+ errno = 0;
+ v = strtoul(string, &endptr, 10);
+ errno = saved_errno;
+
+ if (v > SNMP_MAX_BRIDGE_PRIORITY || errno != 0 || *endptr != '.') {
+ errno = saved_errno;
+ warnx("Bad bridge priority value %d", v);
+ return (-1);
+ }
+
+ bridge_id[0] = (v & 0xff00);
+ bridge_id[1] = (v & 0xff);
+
+ string = endptr + 1;
+
+ for (i = 0; i < 5; i++) {
+ v = strtoul(string, &endptr, 16);
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", string);
+ return (-1);
+ }
+ if(*endptr != ':') {
+ warnx("Failed reading octet - %s", string);
+ return (-1);
+ }
+ bridge_id[i + 2] = v;
+ string = endptr + 1;
+ }
+
+ /* The last one - don't check the ending char here. */
+ v = strtoul(string, &endptr, 16);
+ if (v > 0xff) {
+ warnx("Integer value %s not supported", string);
+ return (-1);
+ }
+ bridge_id[7] = v;
+
+ if ((sv->v.octetstring.octets = malloc(SNMP_BRIDGEID_OCTETS)) == NULL) {
+ syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ sv->v.octetstring.len = SNMP_BRIDGEID_OCTETS;
+ memcpy(sv->v.octetstring.octets, bridge_id, SNMP_BRIDGEID_OCTETS);
+ sv->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+}
+
+/**************************************************************
+ * BridgePortId
+ **************************************************************
+ * BEGEMOT-BRIDGE-MIB, LAST-UPDATED "200608100000Z"
+ * BridgePortId ::= TEXTUAL-CONVENTION
+ * DISPLAY-HINT "1x.1x"
+ * STATUS current
+ * DESCRIPTION
+ * "A port identifier that contains a bridge port's STP priority
+ * in the first octet and the port number in the second octet."
+ * SYNTAX OCTET STRING (SIZE(2))
+ */
+static char *
+snmp_oct2bport_id(uint32_t len, char *octets, char *buf)
+{
+ char *ptr;
+
+ if (len != SNMP_BPORT_OCTETS || octets == NULL || buf == NULL)
+ return (NULL);
+
+ buf[0]= '\0';
+ ptr = buf;
+
+ ptr += sprintf(ptr, "%d.", octets[0]);
+ ptr += sprintf(ptr, "%d", octets[1]);
+
+ return (buf);
+}
+
+static char *
+snmp_bport_id2oct(char *str, struct asn_oid *oid)
+{
+ char *endptr, *ptr;
+ uint32_t v;
+ int saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) SNMP_BPORT_OCTETS) < 0)
+ return (NULL);
+
+ ptr = str;
+ /* Read the priority. */
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 10);
+ errno = 0;
+
+ if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
+ errno = saved_errno;
+ warnx("Bad bridge port priority value %d", v);
+ return (NULL);
+ }
+
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ saved_errno = errno;
+ v = strtoul(ptr, &endptr, 16);
+ errno = saved_errno;
+
+ if (v > 0xff) {
+ warnx("Bad port number - %d", v);
+ return (NULL);
+ }
+
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+static int32_t
+parse_bport_id(struct snmp_value *value, char *string)
+{
+ char *ptr, *endptr;
+ int saved_errno;
+ uint32_t v;
+ uint8_t bport_id[SNMP_BPORT_OCTETS];
+
+ ptr = string;
+ /* Read the priority. */
+ saved_errno = errno;
+ errno = 0;
+ v = strtoul(string, &endptr, 10);
+ errno = saved_errno;
+
+ if (v > SNMP_MAX_BPORT_PRIORITY || errno != 0 || *endptr != '.') {
+ errno = saved_errno;
+ warnx("Bad bridge port priority value %d", v);
+ return (-1);
+ }
+
+ bport_id[0] = v;
+
+ string = endptr + 1;
+ v = strtoul(string, &endptr, 16);
+ if (v > 0xff) {
+ warnx("Bad port number - %d", v);
+ return (-1);
+ }
+
+ bport_id[1] = v;
+
+ if ((value->v.octetstring.octets = malloc(SNMP_BPORT_OCTETS)) == NULL) {
+ syslog(LOG_ERR,"malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ value->v.octetstring.len = SNMP_BPORT_OCTETS;
+ memcpy(value->v.octetstring.octets, bport_id, SNMP_BPORT_OCTETS);
+ value->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+}
+/**************************************************************
+ * InetAddress
+ **************************************************************
+ * INET-ADDRESS-MIB, REVISION "200502040000Z"
+ * InetAddress ::= TEXTUAL-CONVENTION
+ * STATUS current
+ * DESCRIPTION
+ * "Denotes a generic Internet address.
+ *
+ * An InetAddress value is always interpreted within the context
+ * of an InetAddressType value. Every usage of the InetAddress
+ * textual convention is required to specify the InetAddressType
+ * object that provides the context. It is suggested that the
+ * InetAddressType object be logically registered before the
+ * object(s) that use the InetAddress textual convention, if
+ * they appear in the same logical row.
+ *
+ * The value of an InetAddress object must always be
+ * consistent with the value of the associated InetAddressType
+ * object. Attempts to set an InetAddress object to a value
+ * inconsistent with the associated InetAddressType
+ * must fail with an inconsistentValue error.
+ *
+ * When this textual convention is used as the syntax of an
+ * index object, there may be issues with the limit of 128
+ * sub-identifiers specified in SMIv2, STD 58. In this case,
+ * the object definition MUST include a 'SIZE' clause to
+ * limit the number of potential instance sub-identifiers;
+ * otherwise the applicable constraints MUST be stated in
+ * the appropriate conceptual row DESCRIPTION clauses, or
+ * in the surrounding documentation if there is no single
+ * DESCRIPTION clause that is appropriate."
+ * SYNTAX OCTET STRING (SIZE (0..255))
+ **************************************************************
+ * TODO: FIXME!!! syrinx: Since we do not support checking the
+ * consistency of a varbinding based on the value of a previous
+ * one, try to guess the type of address based on the
+ * OctetString SIZE - 4 for IPv4, 16 for IPv6, others currently
+ * not supported.
+ */
+static char *
+snmp_oct2inetaddr(uint32_t len, char *octets, char *buf)
+{
+ int af;
+ void *ip;
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+
+ if (len > MAX_OCTSTRING_LEN || octets == NULL || buf == NULL)
+ return (NULL);
+
+ switch (len) {
+ /* XXX: FIXME - IPv4*/
+ case 4:
+ memcpy(&ipv4.s_addr, octets, sizeof(ipv4.s_addr));
+ af = AF_INET;
+ ip = &ipv4;
+ break;
+
+ /* XXX: FIXME - IPv4*/
+ case 16:
+ memcpy(ipv6.s6_addr, octets, sizeof(ipv6.s6_addr));
+ af = AF_INET6;
+ ip = &ipv6;
+ break;
+
+ default:
+ return (NULL);
+ }
+
+ if (inet_ntop(af, ip, buf, SNMP_INADDRS_STRSZ) == NULL) {
+ warnx("inet_ntop failed - %s", strerror(errno));
+ return (NULL);
+ }
+
+ return (buf);
+}
+
+static char *
+snmp_inetaddr2oct(char *str, struct asn_oid *oid)
+{
+ return (NULL);
+}
+
+static int32_t
+parse_inetaddr(struct snmp_value *value, char *string)
+{
+ return (-1);
+}
+
+/**************************************************************
+ * SNMP BITS type - XXX: FIXME
+ **************************************************************/
+static char *
+snmp_oct2bits(uint32_t len, char *octets, char *buf)
+{
+ int i, bits;
+ uint64_t value;
+
+ if (len > sizeof(value) || octets == NULL || buf == NULL)
+ return (NULL);
+
+ for (i = len, value = 0, bits = 0; i > 0; i--, bits += 8)
+ value += octets[i] << bits;
+
+ buf[0]= '\0';
+ sprintf(buf, "0x%llx.",(long long unsigned) value);
+
+ return (buf);
+}
+
+static char *
+snmp_bits2oct(char *str, struct asn_oid *oid)
+{
+ char *endptr;
+ int i, size, bits, saved_errno;
+ uint64_t v, mask = 0xFF00000000000000;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoull(str, &endptr, 16);
+ if (errno != 0) {
+ warnx("Bad BITS value %s - %s", str, strerror(errno));
+ errno = saved_errno;
+ return (NULL);
+ }
+
+ bits = 8;
+ /* Determine length - up to 8 octets supported so far. */
+ for (size = sizeof(v); size > 0; size--) {
+ if ((v & mask) != 0)
+ break;
+ mask = mask >> bits;
+ }
+
+ if (size == 0)
+ size = 1;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) size) < 0)
+ return (NULL);
+
+ for (i = 0, bits = 0; i < size; i++, bits += 8)
+ if (snmp_suboid_append(oid,
+ (asn_subid_t)((v & mask) >> bits)) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+static int32_t
+parse_bits(struct snmp_value *value, char *string)
+{
+ char *endptr;
+ int i, size, bits, saved_errno;
+ uint64_t v, mask = 0xFF00000000000000;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoull(string, &endptr, 16);
+
+ if (errno != 0) {
+ warnx("Bad BITS value %s - %s", string, strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ bits = 8;
+ /* Determine length - up to 8 octets supported so far. */
+ for (size = sizeof(v); size > 0; size--) {
+ if ((v & mask) != 0)
+ break;
+ mask = mask >> bits;
+ }
+
+ if (size == 0)
+ size = 1;
+
+ if ((value->v.octetstring.octets = malloc(size)) == NULL) {
+ syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ value->v.octetstring.len = size;
+ for (i = 0, bits = 0; i < size; i++, bits += 8)
+ value->v.octetstring.octets[i] = (v & mask) >> bits;
+ value->syntax = SNMP_SYNTAX_OCTETSTRING;
+ return (1);
+}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.h b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.h
new file mode 100644
index 0000000..fd06676
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptc.h
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND 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 THE AUTHOR OR 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.
+ *
+ * Textual conventions for snmp
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BSNMP_TEXT_CONV_H_
+#define _BSNMP_TEXT_CONV_H_
+
+/* Variable display length string. */
+#define SNMP_VAR_STRSZ -1
+
+/*
+ * 11 bytes - octets that represent DateAndTime Textual convention
+ * and the size of string used to diplay that.
+ */
+#define SNMP_DATETIME_OCTETS 11
+#define SNMP_DATETIME_STRSZ 32
+
+/*
+ * 6 bytes - octets that represent PhysAddress Textual convention
+ * and the size of string used to diplay that.
+ */
+#define SNMP_PHYSADDR_OCTETS 6
+#define SNMP_PHYSADDR_STRSZ 19
+
+/* NTPTimeStamp. */
+#define SNMP_NTP_TS_OCTETS 8
+#define SNMP_NTP_TS_STRSZ 10
+
+/* BridgeId. */
+#define SNMP_BRIDGEID_OCTETS 8
+#define SNMP_BRIDGEID_STRSZ 25
+#define SNMP_MAX_BRIDGE_PRIORITY 65535
+
+/* BridgePortId. */
+#define SNMP_BPORT_OCTETS 2
+#define SNMP_BPORT_STRSZ 7
+#define SNMP_MAX_BPORT_PRIORITY 255
+
+/* InetAddress. */
+#define SNMP_INADDRS_STRSZ INET6_ADDRSTRLEN
+
+enum snmp_tc {
+ SNMP_STRING = 0,
+ SNMP_DISPLAYSTRING = 1,
+ SNMP_DATEANDTIME = 2,
+ SNMP_PHYSADDR = 3,
+ SNMP_ATMESI = 4,
+ SNMP_NTP_TIMESTAMP = 5,
+ SNMP_MACADDRESS = 6,
+ SNMP_BRIDGE_ID = 7,
+ SNMP_BPORT_ID = 8,
+ SNMP_INETADDRESS = 9,
+ SNMP_TC_OWN = 10,
+ SNMP_UNKNOWN, /* keep last */
+};
+
+typedef char * (*snmp_oct2tc_f) (uint32_t len, char *octs, char *buf);
+typedef char * (*snmp_tc2oid_f) (char *str, struct asn_oid *oid);
+typedef int32_t (*snmp_tc2oct_f) (struct snmp_value *value, char *string);
+
+enum snmp_tc snmp_get_tc(char *str);
+char *snmp_oct2tc(enum snmp_tc tc, uint32_t len, char *octets);
+char *snmp_tc2oid(enum snmp_tc tc, char *str, struct asn_oid *oid);
+int32_t snmp_tc2oct(enum snmp_tc tc, struct snmp_value *value, char *string);
+
+#endif /* _BSNMP_TEXT_CONV_H_ */
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
new file mode 100755
index 0000000..dbaac5b
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
@@ -0,0 +1,2121 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND 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 THE AUTHOR OR 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.
+ *
+ * Helper functions for snmp client tools
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <bsnmp/asn1.h>
+#include <bsnmp/snmp.h>
+#include <bsnmp/snmpclient.h>
+#include "bsnmptc.h"
+#include "bsnmptools.h"
+
+/* Internal varibale to turn on library debugging for testing and to
+ * find bugs. It is not exported via the header file.
+ * XXX should we cover it by some #ifdef BSNMPTOOLS_DEBUG? */
+int _bsnmptools_debug = 0;
+
+/* Default files to import mapping from if none explicitly provided. */
+#define bsnmpd_defs "/usr/share/snmp/defs/tree.def"
+#define mibII_defs "/usr/share/snmp/defs/mibII_tree.def"
+
+/*
+ * The .iso.org.dod oid that has to be prepended to every OID when requesting
+ * a value.
+ */
+const struct asn_oid IsoOrgDod_OID = {
+ 3, { 1, 3, 6 }
+};
+
+
+#define SNMP_ERR_UNKNOWN 0
+
+/*
+ * An array of error strings corresponding to error definitions from libbsnmp.
+ */
+static const struct {
+ const char *str;
+ int32_t error;
+} error_strings[] = {
+ { "Unknown", SNMP_ERR_UNKNOWN },
+ { "Too big ", SNMP_ERR_TOOBIG },
+ { "No such Name", SNMP_ERR_NOSUCHNAME },
+ { "Bad Value", SNMP_ERR_BADVALUE },
+ { "Readonly", SNMP_ERR_READONLY },
+ { "General error", SNMP_ERR_GENERR },
+ { "No access", SNMP_ERR_NO_ACCESS },
+ { "Wrong type", SNMP_ERR_WRONG_TYPE },
+ { "Wrong lenght", SNMP_ERR_WRONG_LENGTH },
+ { "Wrong encoding", SNMP_ERR_WRONG_ENCODING },
+ { "Wrong value", SNMP_ERR_WRONG_VALUE },
+ { "No creation", SNMP_ERR_NO_CREATION },
+ { "Inconsistent value", SNMP_ERR_INCONS_VALUE },
+ { "Resource unavailable", SNMP_ERR_RES_UNAVAIL },
+ { "Commit failed", SNMP_ERR_COMMIT_FAILED },
+ { "Undo failed", SNMP_ERR_UNDO_FAILED },
+ { "Authorization error", SNMP_ERR_AUTH_ERR },
+ { "Not writable", SNMP_ERR_NOT_WRITEABLE },
+ { "Inconsistent name", SNMP_ERR_INCONS_NAME },
+ { NULL, 0 }
+};
+
+/* This one and any following are exceptions. */
+#define SNMP_SYNTAX_UNKNOWN SNMP_SYNTAX_NOSUCHOBJECT
+
+static const struct {
+ const char *str;
+ enum snmp_syntax stx;
+} syntax_strings[] = {
+ { "Null", SNMP_SYNTAX_NULL },
+ { "Integer", SNMP_SYNTAX_INTEGER },
+ { "OctetString", SNMP_SYNTAX_OCTETSTRING },
+ { "OID", SNMP_SYNTAX_OID },
+ { "IpAddress", SNMP_SYNTAX_IPADDRESS },
+ { "Counter32", SNMP_SYNTAX_COUNTER },
+ { "Gauge", SNMP_SYNTAX_GAUGE },
+ { "TimeTicks", SNMP_SYNTAX_TIMETICKS },
+ { "Counter64", SNMP_SYNTAX_COUNTER64 },
+ { "Unknown", SNMP_SYNTAX_UNKNOWN },
+};
+
+int
+snmptool_init(struct snmp_toolinfo *snmptoolctx)
+{
+ char *str;
+ size_t slen;
+
+ memset(snmptoolctx, 0, sizeof(struct snmp_toolinfo));
+ snmptoolctx->objects = 0;
+ snmptoolctx->mappings = NULL;
+ snmptoolctx->flags = SNMP_PDU_GET; /* XXX */
+ SLIST_INIT(&snmptoolctx->filelist);
+ snmp_client_init(&snmp_client);
+
+ if (add_filename(snmptoolctx, bsnmpd_defs, &IsoOrgDod_OID, 0) < 0)
+ warnx("Error adding file %s to list", bsnmpd_defs);
+
+ if (add_filename(snmptoolctx, mibII_defs, &IsoOrgDod_OID, 0) < 0)
+ warnx("Error adding file %s to list", mibII_defs);
+
+ /* Read the environment */
+ if ((str = getenv("SNMPAUTH")) != NULL) {
+ slen = strlen(str);
+ if (slen == strlen("md5") && strcasecmp(str, "md5") == 0)
+ snmp_client.user.auth_proto = SNMP_AUTH_HMAC_MD5;
+ else if (slen == strlen("sha")&& strcasecmp(str, "sha") == 0)
+ snmp_client.user.auth_proto = SNMP_AUTH_HMAC_SHA;
+ else if (slen != 0)
+ warnx("Bad authentication type - %s in SNMPAUTH", str);
+ }
+
+ if ((str = getenv("SNMPPRIV")) != NULL) {
+ slen = strlen(str);
+ if (slen == strlen("des") && strcasecmp(str, "des") == 0)
+ snmp_client.user.priv_proto = SNMP_PRIV_DES;
+ else if (slen == strlen("aes")&& strcasecmp(str, "aes") == 0)
+ snmp_client.user.priv_proto = SNMP_PRIV_AES;
+ else if (slen != 0)
+ warnx("Bad privacy type - %s in SNMPPRIV", str);
+ }
+
+ if ((str = getenv("SNMPUSER")) != NULL) {
+ if ((slen = strlen(str)) > sizeof(snmp_client.user.sec_name)) {
+ warnx("Username too long - %s in SNMPUSER", str);
+ return (-1);
+ }
+ if (slen > 0) {
+ strlcpy(snmp_client.user.sec_name, str,
+ sizeof(snmp_client.user.sec_name));
+ snmp_client.version = SNMP_V3;
+ }
+ }
+
+ if ((str = getenv("SNMPPASSWD")) != NULL) {
+ if ((slen = strlen(str)) > MAXSTR)
+ slen = MAXSTR - 1;
+ if ((snmptoolctx->passwd = malloc(slen + 1)) == NULL) {
+ warnx("malloc() failed - %s", strerror(errno));
+ return (-1);
+ }
+ if (slen > 0)
+ strlcpy(snmptoolctx->passwd, str, slen + 1);
+ }
+
+ return (0);
+}
+
+#define OBJECT_IDX_LIST(o) o->info->table_idx->index_list
+
+/*
+ * Walk through the file list and import string<->oid mappings from each file.
+ */
+int32_t
+snmp_import_all(struct snmp_toolinfo *snmptoolctx)
+{
+ int32_t fc;
+ struct fname *tmp;
+
+ if (snmptoolctx == NULL)
+ return (-1);
+
+ if (ISSET_NUMERIC(snmptoolctx))
+ return (0);
+
+ if ((snmptoolctx->mappings = snmp_mapping_init()) == NULL)
+ return (-1);
+
+ fc = 0;
+ if (SLIST_EMPTY(&snmptoolctx->filelist)) {
+ warnx("No files to read OID <-> string conversions from");
+ return (-1);
+ } else {
+ SLIST_FOREACH(tmp, &snmptoolctx->filelist, link) {
+ if (tmp->done)
+ continue;
+ if (snmp_import_file(snmptoolctx, tmp) < 0) {
+ fc = -1;
+ break;
+ }
+ fc++;
+ }
+ }
+
+ snmp_mapping_dump(snmptoolctx);
+ return (fc);
+}
+
+/*
+ * Add a filename to the file list - the initail idea of keeping a list with all
+ * files to read OIDs from was that an application might want to have loaded in
+ * memory the OIDs from a single file only and when done with them read the OIDs
+ * from another file. This is not used yet but might be a good idea at some
+ * point. Size argument is number of bytes in string including trailing '\0',
+ * not string lenght.
+ */
+int32_t
+add_filename(struct snmp_toolinfo *snmptoolctx, const char *filename,
+ const struct asn_oid *cut, int32_t done)
+{
+ char *fstring;
+ struct fname *entry;
+
+ if (snmptoolctx == NULL)
+ return (-1);
+
+ /* Make sure file was not in list. */
+ SLIST_FOREACH(entry, &snmptoolctx->filelist, link) {
+ if (strncmp(entry->name, filename, strlen(entry->name)) == 0)
+ return (0);
+ }
+
+ if ((fstring = malloc(strlen(filename) + 1)) == NULL) {
+ warnx("malloc() failed - %s", strerror(errno));
+ return (-1);
+ }
+
+ if ((entry = malloc(sizeof(struct fname))) == NULL) {
+ warnx("malloc() failed - %s", strerror(errno));
+ free(fstring);
+ return (-1);
+ }
+
+ memset(entry, 0, sizeof(struct fname));
+
+ if (cut != NULL)
+ asn_append_oid(&(entry->cut), cut);
+ strlcpy(fstring, filename, strlen(filename) + 1);
+ entry->name = fstring;
+ entry->done = done;
+ SLIST_INSERT_HEAD(&snmptoolctx->filelist, entry, link);
+
+ return (1);
+}
+
+void
+free_filelist(struct snmp_toolinfo *snmptoolctx)
+{
+ struct fname *f;
+
+ if (snmptoolctx == NULL)
+ return; /* XXX error handling */
+
+ while ((f = SLIST_FIRST(&snmptoolctx->filelist)) != NULL) {
+ SLIST_REMOVE_HEAD(&snmptoolctx->filelist, link);
+ if (f->name)
+ free(f->name);
+ free(f);
+ }
+}
+
+static char
+isvalid_fchar(char c, int pos)
+{
+ if (isalpha(c)|| c == '/'|| c == '_' || c == '.' || c == '~' ||
+ (pos != 0 && isdigit(c))){
+ return (c);
+ }
+
+ if (c == '\0')
+ return (0);
+
+ if (!isascii(c) || !isprint(c))
+ warnx("Unexpected character %#2x", (u_int) c);
+ else
+ warnx("Illegal character '%c'", c);
+
+ return (-1);
+}
+
+/*
+ * Re-implement getsubopt from scratch, because the second argument is broken
+ * and will not compile with WARNS=5.
+ * Copied from src/contrib/bsnmp/snmpd/main.c.
+ */
+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(*optp, *options) == 0)
+ return (i);
+ return (-1);
+}
+
+static int32_t
+parse_path(char *value)
+{
+ int32_t i, len;
+
+ if (value == NULL)
+ return (-1);
+
+ for (len = 0; len < MAXPATHLEN; len++) {
+ i = isvalid_fchar(*(value + len), len) ;
+
+ if (i == 0)
+ break;
+ else if (i < 0)
+ return (-1);
+ }
+
+ if (len >= MAXPATHLEN || value[len] != '\0') {
+ warnx("Bad pathname - '%s'", value);
+ return (-1);
+ }
+
+ return (len);
+}
+
+static int32_t
+parse_flist(struct snmp_toolinfo *snmptoolctx, char *value, char *path,
+ const struct asn_oid *cut)
+{
+ int32_t namelen;
+ char filename[MAXPATHLEN + 1];
+
+ if (value == NULL)
+ return (-1);
+
+ do {
+ memset(filename, 0, MAXPATHLEN + 1);
+
+ if (isalpha(*value) && (path == NULL || path[0] == '\0')) {
+ strlcpy(filename, SNMP_DEFS_DIR, MAXPATHLEN + 1);
+ namelen = strlen(SNMP_DEFS_DIR);
+ } else if (path != NULL){
+ strlcpy(filename, path, MAXPATHLEN + 1);
+ namelen = strlen(path);
+ } else
+ namelen = 0;
+
+ for ( ; namelen < MAXPATHLEN; value++) {
+ if (isvalid_fchar(*value, namelen) > 0) {
+ filename[namelen++] = *value;
+ continue;
+ }
+
+ if (*value == ',' )
+ value++;
+ else if (*value == '\0')
+ ;
+ else {
+ if (!isascii(*value) || !isprint(*value))
+ warnx("Unexpected character %#2x in"
+ " filename", (u_int) *value);
+ else
+ warnx("Illegal character '%c' in"
+ " filename", *value);
+ return (-1);
+ }
+
+ filename[namelen]='\0';
+ break;
+ }
+
+ if ((namelen == MAXPATHLEN) && (filename[MAXPATHLEN] != '\0')) {
+ warnx("Filename %s too long", filename);
+ return (-1);
+ }
+
+ if (add_filename(snmptoolctx, filename, cut, 0) < 0) {
+ warnx("Error adding file %s to list", filename);
+ return (-1);
+ }
+ } while (*value != '\0');
+
+ return(1);
+}
+
+static int32_t
+parse_ascii(char *ascii, uint8_t *binstr, size_t binlen)
+{
+ int32_t alen, count, saved_errno, i;
+ uint32_t val;
+ char dptr[3];
+
+ /* Filter 0x at the beggining */
+ if ((alen = strlen(ascii)) > 2 && ascii[0] == '0' && ascii[1] == 'x')
+ i = 2;
+ else
+ i = 0;
+
+ saved_errno = errno;
+ errno = 0;
+ for (count = 0; i < alen; i += 2) {
+ /* XXX: consider strlen(ascii) % 2 != 0 */
+ dptr[0] = ascii[i];
+ dptr[1] = ascii[i + 1];
+ dptr[2] = '\0';
+ if ((val = strtoul(dptr, NULL, 16)) > 0xFF || errno != 0) {
+ errno = saved_errno;
+ return (-1);
+ }
+ binstr[count] = (uint8_t) val;
+ if (++count >= binlen) {
+ warnx("Key %s too long - truncating to %zu octest",
+ ascii, binlen);
+ break;
+ }
+ }
+
+ return (count);
+}
+
+/*
+ * Functions to parse common input options for client tools and fill in the
+ * snmp_client structure.
+ */
+int32_t
+parse_authentication(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ int32_t count, subopt;
+ char *val, *option;
+ const char *const subopts[] = {
+ "proto",
+ "key",
+ NULL
+ };
+
+ assert(opt_arg != NULL);
+ count = 1;
+ while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
+ switch (subopt) {
+ case 0:
+ if (val == NULL) {
+ warnx("Suboption 'proto' requires an argument");
+ return (-1);
+ }
+ if (strlen(val) != 3) {
+ warnx("Unknown auth protocol - %s", val);
+ return (-1);
+ }
+ if (strncasecmp("md5", val, strlen("md5")) == 0)
+ snmp_client.user.auth_proto =
+ SNMP_AUTH_HMAC_MD5;
+ else if (strncasecmp("sha", val, strlen("sha")) == 0)
+ snmp_client.user.auth_proto =
+ SNMP_AUTH_HMAC_SHA;
+ else {
+ warnx("Unknown auth protocol - %s", val);
+ return (-1);
+ }
+ break;
+ case 1:
+ if (val == NULL) {
+ warnx("Suboption 'key' requires an argument");
+ return (-1);
+ }
+ if (parse_ascii(val, snmp_client.user.auth_key,
+ SNMP_AUTH_KEY_SIZ) < 0) {
+ warnx("Bad authentication key- %s", val);
+ return (-1);
+ }
+ break;
+ default:
+ warnx("Unknown suboption - '%s'", suboptarg);
+ return (-1);
+ }
+ count += 1;
+ }
+ return (2/* count */);
+}
+
+int32_t
+parse_privacy(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ int32_t count, subopt;
+ char *val, *option;
+ const char *const subopts[] = {
+ "proto",
+ "key",
+ NULL
+ };
+
+ assert(opt_arg != NULL);
+ count = 1;
+ while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
+ switch (subopt) {
+ case 0:
+ if (val == NULL) {
+ warnx("Suboption 'proto' requires an argument");
+ return (-1);
+ }
+ if (strlen(val) != 3) {
+ warnx("Unknown privacy protocol - %s", val);
+ return (-1);
+ }
+ if (strncasecmp("aes", val, strlen("aes")) == 0)
+ snmp_client.user.priv_proto = SNMP_PRIV_AES;
+ else if (strncasecmp("des", val, strlen("des")) == 0)
+ snmp_client.user.priv_proto = SNMP_PRIV_DES;
+ else {
+ warnx("Unknown privacy protocol - %s", val);
+ return (-1);
+ }
+ break;
+ case 1:
+ if (val == NULL) {
+ warnx("Suboption 'key' requires an argument");
+ return (-1);
+ }
+ if (parse_ascii(val, snmp_client.user.priv_key,
+ SNMP_PRIV_KEY_SIZ) < 0) {
+ warnx("Bad privacy key- %s", val);
+ return (-1);
+ }
+ break;
+ default:
+ warnx("Unknown suboption - '%s'", suboptarg);
+ return (-1);
+ }
+ count += 1;
+ }
+ return (2/* count */);
+}
+
+int32_t
+parse_context(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ int32_t count, subopt;
+ char *val, *option;
+ const char *const subopts[] = {
+ "context",
+ "context-engine",
+ NULL
+ };
+
+ assert(opt_arg != NULL);
+ count = 1;
+ while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
+ switch (subopt) {
+ case 0:
+ if (val == NULL) {
+ warnx("Suboption 'context' - no argument");
+ return (-1);
+ }
+ strlcpy(snmp_client.cname, val, SNMP_CONTEXT_NAME_SIZ);
+ break;
+ case 1:
+ if (val == NULL) {
+ warnx("Suboption 'context-engine' - no argument");
+ return (-1);
+ }
+ if ((snmp_client.clen = parse_ascii(val,
+ snmp_client.cengine, SNMP_ENGINE_ID_SIZ)) < 0) {
+ warnx("Bad EngineID - %s", val);
+ return (-1);
+ }
+ break;
+ default:
+ warnx("Unknown suboption - '%s'", suboptarg);
+ return (-1);
+ }
+ count += 1;
+ }
+ return (2/* count */);
+}
+
+int32_t
+parse_user_security(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ int32_t count, subopt, saved_errno;
+ char *val, *option;
+ const char *const subopts[] = {
+ "engine",
+ "engine-boots",
+ "engine-time",
+ "name",
+ NULL
+ };
+
+ assert(opt_arg != NULL);
+ count = 1;
+ while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
+ switch (subopt) {
+ case 0:
+ if (val == NULL) {
+ warnx("Suboption 'engine' - no argument");
+ return (-1);
+ }
+ snmp_client.engine.engine_len = parse_ascii(val,
+ snmp_client.engine.engine_id, SNMP_ENGINE_ID_SIZ);
+ if (snmp_client.engine.engine_len < 0) {
+ warnx("Bad EngineID - %s", val);
+ return (-1);
+ }
+ break;
+ case 1:
+ if (val == NULL) {
+ warnx("Suboption 'engine-boots' - no argument");
+ return (-1);
+ }
+ saved_errno = errno;
+ errno = 0;
+ snmp_client.engine.engine_boots = strtoul(val, NULL, 10);
+ if (errno != 0) {
+ warnx("Bad 'engine-boots' value %s - %s", val,
+ strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+ errno = saved_errno;
+ break;
+ case 2:
+ if (val == NULL) {
+ warnx("Suboption 'engine-time' - no argument");
+ return (-1);
+ }
+ saved_errno = errno;
+ errno = 0;
+ snmp_client.engine.engine_time = strtoul(val, NULL, 10);
+ if (errno != 0) {
+ warnx("Bad 'engine-time' value %s - %s", val,
+ strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+ errno = saved_errno;
+ break;
+ case 3:
+ strlcpy(snmp_client.user.sec_name, val,
+ SNMP_ADM_STR32_SIZ);
+ break;
+ default:
+ warnx("Unknown suboption - '%s'", suboptarg);
+ return (-1);
+ }
+ count += 1;
+ }
+ return (2/* count */);
+}
+
+int32_t
+parse_file(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ assert(opt_arg != NULL);
+
+ if (parse_flist(snmptoolctx, opt_arg, NULL, &IsoOrgDod_OID) < 0)
+ return (-1);
+
+ return (2);
+}
+
+int32_t
+parse_include(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ char path[MAXPATHLEN + 1];
+ int32_t cut_dflt, len, subopt;
+ struct asn_oid cut;
+ char *val, *option;
+ const char *const subopts[] = {
+ "cut",
+ "path",
+ "file",
+ NULL
+ };
+
+#define INC_CUT 0
+#define INC_PATH 1
+#define INC_LIST 2
+
+ assert(opt_arg != NULL);
+
+ /* if (opt == 'i')
+ free_filelist(snmptoolctx, ); */
+ /*
+ * This function should be called only after getopt(3) - otherwise if
+ * no previous validation of opt_arg strlen() may not return what is
+ * expected.
+ */
+
+ path[0] = '\0';
+ memset(&cut, 0, sizeof(struct asn_oid));
+ cut_dflt = -1;
+
+ while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
+ switch (subopt) {
+ case INC_CUT:
+ if (val == NULL) {
+ warnx("Suboption 'cut' requires an argument");
+ return (-1);
+ } else {
+ if (snmp_parse_numoid(val, &cut) < 0)
+ return (-1);
+ }
+ cut_dflt = 1;
+ break;
+
+ case INC_PATH:
+ if ((len = parse_path(val)) < 0)
+ return (-1);
+ strlcpy(path, val, len + 1);
+ break;
+
+ case INC_LIST:
+ if (val == NULL)
+ return (-1);
+ if (cut_dflt == -1)
+ len = parse_flist(snmptoolctx, val, path, &IsoOrgDod_OID);
+ else
+ len = parse_flist(snmptoolctx, val, path, &cut);
+ if (len < 0)
+ return (-1);
+ break;
+
+ default:
+ warnx("Unknown suboption - '%s'", suboptarg);
+ return (-1);
+ }
+ }
+
+ /* XXX: Fix me - returning two is wrong here */
+ return (2);
+}
+
+int32_t
+parse_server(char *opt_arg)
+{
+ assert(opt_arg != NULL);
+
+ if (snmp_parse_server(&snmp_client, opt_arg) < 0)
+ return (-1);
+
+ if (snmp_client.trans > SNMP_TRANS_UDP && snmp_client.chost == NULL) {
+ if ((snmp_client.chost = malloc(strlen(SNMP_DEFAULT_LOCAL + 1)))
+ == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+ strcpy(snmp_client.chost, SNMP_DEFAULT_LOCAL);
+ }
+
+ return (2);
+}
+
+int32_t
+parse_timeout(char *opt_arg)
+{
+ int32_t v, saved_errno;
+
+ assert(opt_arg != NULL);
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtol(opt_arg, NULL, 10);
+ if (errno != 0) {
+ warnx( "Error parsing timeout value - %s", strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ snmp_client.timeout.tv_sec = v;
+ errno = saved_errno;
+ return (2);
+}
+
+int32_t
+parse_retry(char *opt_arg)
+{
+ uint32_t v;
+ int32_t saved_errno;
+
+ assert(opt_arg != NULL);
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoul(opt_arg, NULL, 10);
+ if (errno != 0) {
+ warnx("Error parsing retries count - %s", strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ snmp_client.retries = v;
+ errno = saved_errno;
+ return (2);
+}
+
+int32_t
+parse_version(char *opt_arg)
+{
+ uint32_t v;
+ int32_t saved_errno;
+
+ assert(opt_arg != NULL);
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoul(opt_arg, NULL, 10);
+ if (errno != 0) {
+ warnx("Error parsing version - %s", strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ switch (v) {
+ case 1:
+ snmp_client.version = SNMP_V1;
+ break;
+ case 2:
+ snmp_client.version = SNMP_V2c;
+ break;
+ case 3:
+ snmp_client.version = SNMP_V3;
+ break;
+ default:
+ warnx("Unsupported SNMP version - %u", v);
+ errno = saved_errno;
+ return (-1);
+ }
+
+ errno = saved_errno;
+ return (2);
+}
+
+int32_t
+parse_local_path(char *opt_arg)
+{
+ assert(opt_arg != NULL);
+
+ if (sizeof(opt_arg) > sizeof(SNMP_LOCAL_PATH)) {
+ warnx("Filename too long - %s", opt_arg);
+ return (-1);
+ }
+
+ strlcpy(snmp_client.local_path, opt_arg, sizeof(SNMP_LOCAL_PATH));
+ return (2);
+}
+
+int32_t
+parse_buflen(char *opt_arg)
+{
+ uint32_t size;
+ int32_t saved_errno;
+
+ assert(opt_arg != NULL);
+
+ saved_errno = errno;
+ errno = 0;
+
+ size = strtoul(opt_arg, NULL, 10);
+ if (errno != 0) {
+ warnx("Error parsing buffer size - %s", strerror(errno));
+ errno = saved_errno;
+ return (-1);
+ }
+
+ if (size > MAX_BUFF_SIZE) {
+ warnx("Buffer size too big - %d max allowed", MAX_BUFF_SIZE);
+ errno = saved_errno;
+ return (-1);
+ }
+
+ snmp_client.txbuflen = snmp_client.rxbuflen = size;
+ errno = saved_errno;
+ return (2);
+}
+
+int32_t
+parse_debug(void)
+{
+ snmp_client.dump_pdus = 1;
+ return (1);
+}
+
+int32_t
+parse_discovery(struct snmp_toolinfo *snmptoolctx)
+{
+ SET_EDISCOVER(snmptoolctx);
+ snmp_client.version = SNMP_V3;
+ return (1);
+}
+
+int32_t
+parse_local_key(struct snmp_toolinfo *snmptoolctx)
+{
+ SET_LOCALKEY(snmptoolctx);
+ snmp_client.version = SNMP_V3;
+ return (1);
+}
+
+int32_t
+parse_num_oids(struct snmp_toolinfo *snmptoolctx)
+{
+ SET_NUMERIC(snmptoolctx);
+ return (1);
+}
+
+int32_t
+parse_output(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
+{
+ assert(opt_arg != NULL);
+
+ if (strlen(opt_arg) > strlen("verbose")) {
+ warnx( "Invalid output option - %s",opt_arg);
+ return (-1);
+ }
+
+ if (strncasecmp(opt_arg, "short", strlen(opt_arg)) == 0)
+ SET_OUTPUT(snmptoolctx, OUTPUT_SHORT);
+ else if (strncasecmp(opt_arg, "verbose", strlen(opt_arg)) == 0)
+ SET_OUTPUT(snmptoolctx, OUTPUT_VERBOSE);
+ else if (strncasecmp(opt_arg,"tabular", strlen(opt_arg)) == 0)
+ SET_OUTPUT(snmptoolctx, OUTPUT_TABULAR);
+ else if (strncasecmp(opt_arg, "quiet", strlen(opt_arg)) == 0)
+ SET_OUTPUT(snmptoolctx, OUTPUT_QUIET);
+ else {
+ warnx( "Invalid output option - %s", opt_arg);
+ return (-1);
+ }
+
+ return (2);
+}
+
+int32_t
+parse_errors(struct snmp_toolinfo *snmptoolctx)
+{
+ SET_RETRY(snmptoolctx);
+ return (1);
+}
+
+int32_t
+parse_skip_access(struct snmp_toolinfo *snmptoolctx)
+{
+ SET_ERRIGNORE(snmptoolctx);
+ return (1);
+}
+
+char *
+snmp_parse_suboid(char *str, struct asn_oid *oid)
+{
+ char *endptr;
+ asn_subid_t suboid;
+
+ if (*str == '.')
+ str++;
+
+ if (*str < '0' || *str > '9')
+ return (str);
+
+ do {
+ suboid = strtoul(str, &endptr, 10);
+ if ((asn_subid_t) suboid > ASN_MAXID) {
+ warnx("Suboid %u > ASN_MAXID", suboid);
+ return (NULL);
+ }
+ if (snmp_suboid_append(oid, suboid) < 0)
+ return (NULL);
+ str = endptr + 1;
+ } while (*endptr == '.');
+
+ return (endptr);
+}
+
+static char *
+snmp_int2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr;
+ int32_t v, saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtol(str, &endptr, 10);
+ if (errno != 0) {
+ warnx("Integer value %s not supported - %s", str,
+ strerror(errno));
+ errno = saved_errno;
+ return (NULL);
+ }
+ errno = saved_errno;
+
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+/* It is a bit weird to have a table indexed by OID but still... */
+static char *
+snmp_oid2asn_oid(struct snmp_toolinfo *snmptoolctx, char *str,
+ struct asn_oid *oid)
+{
+ int32_t i;
+ char string[MAXSTR], *endptr;
+ struct snmp_object obj;
+
+ for (i = 0; i < MAXSTR; i++)
+ if (isalpha (*(str + i)) == 0)
+ break;
+
+ endptr = str + i;
+ memset(&obj, 0, sizeof(struct snmp_object));
+ if (i == 0) {
+ if ((endptr = snmp_parse_suboid(str, &(obj.val.var))) == NULL)
+ return (NULL);
+ if (snmp_suboid_append(oid, (asn_subid_t) obj.val.var.len) < 0)
+ return (NULL);
+ } else {
+ strlcpy(string, str, i + 1);
+ string[i] = '\0';
+ if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {
+ warnx("Unknown string - %s",string);
+ return (NULL);
+ }
+ free(string);
+ }
+
+ asn_append_oid(oid, &(obj.val.var));
+ return (endptr);
+}
+
+static char *
+snmp_ip2asn_oid(char *str, struct asn_oid *oid)
+{
+ uint32_t v;
+ int32_t i;
+ char *endptr, *ptr;
+
+ ptr = str;
+ for (i = 0; i < 4; i++) {
+ v = strtoul(ptr, &endptr, 10);
+ if (v > 0xff)
+ return (NULL);
+ if (*endptr != '.' && strchr("],\0", *endptr) == NULL && i != 3)
+ return (NULL);
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+ ptr = endptr + 1;
+ }
+
+ return (endptr);
+}
+
+/* 32-bit counter, gauge, timeticks. */
+static char *
+snmp_uint2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr;
+ uint32_t v;
+ int32_t saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoul(str, &endptr, 10);
+ if (errno != 0) {
+ warnx("Integer value %s not supported - %s\n", str,
+ strerror(errno));
+ errno = saved_errno;
+ return (NULL);
+ }
+ errno = saved_errno;
+ if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+static char *
+snmp_cnt64_2asn_oid(char *str, struct asn_oid *oid)
+{
+ char *endptr;
+ uint64_t v;
+ int32_t saved_errno;
+
+ saved_errno = errno;
+ errno = 0;
+
+ v = strtoull(str, &endptr, 10);
+
+ if (errno != 0) {
+ warnx("Integer value %s not supported - %s", str,
+ strerror(errno));
+ errno = saved_errno;
+ return (NULL);
+ }
+ errno = saved_errno;
+ if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xffffffff)) < 0)
+ return (NULL);
+
+ if (snmp_suboid_append(oid, (asn_subid_t) (v >> 32)) < 0)
+ return (NULL);
+
+ return (endptr);
+}
+
+enum snmp_syntax
+parse_syntax(char *str)
+{
+ int32_t i;
+
+ for (i = 0; i < SNMP_SYNTAX_UNKNOWN; i++) {
+ if (strncmp(syntax_strings[i].str, str,
+ strlen(syntax_strings[i].str)) == 0)
+ return (syntax_strings[i].stx);
+ }
+
+ return (SNMP_SYNTAX_NULL);
+}
+
+static char *
+snmp_parse_subindex(struct snmp_toolinfo *snmptoolctx, char *str,
+ struct index *idx, struct snmp_object *object)
+{
+ char *ptr;
+ int32_t i;
+ enum snmp_syntax stx;
+ char syntax[MAX_CMD_SYNTAX_LEN];
+
+ ptr = str;
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {
+ for (i = 0; i < MAX_CMD_SYNTAX_LEN ; i++) {
+ if (*(ptr + i) == ':')
+ break;
+ }
+
+ if (i >= MAX_CMD_SYNTAX_LEN) {
+ warnx("Unknown syntax in OID - %s", str);
+ return (NULL);
+ }
+ /* Expect a syntax string here. */
+ if ((stx = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {
+ warnx("Invalid syntax - %s",syntax);
+ return (NULL);
+ }
+
+ if (stx != idx->syntax && !ISSET_ERRIGNORE(snmptoolctx)) {
+ warnx("Syntax mismatch - %d expected, %d given",
+ idx->syntax, stx);
+ return (NULL);
+ }
+ /*
+ * That is where the suboid started + the syntax length + one
+ * character for ':'.
+ */
+ ptr = str + i + 1;
+ } else
+ stx = idx->syntax;
+
+ switch (stx) {
+ case SNMP_SYNTAX_INTEGER:
+ return (snmp_int2asn_oid(ptr, &(object->val.var)));
+ case SNMP_SYNTAX_OID:
+ return (snmp_oid2asn_oid(snmptoolctx, ptr,
+ &(object->val.var)));
+ case SNMP_SYNTAX_IPADDRESS:
+ return (snmp_ip2asn_oid(ptr, &(object->val.var)));
+ case SNMP_SYNTAX_COUNTER:
+ /* FALLTHROUGH */
+ case SNMP_SYNTAX_GAUGE:
+ /* FALLTHROUGH */
+ case SNMP_SYNTAX_TIMETICKS:
+ return (snmp_uint2asn_oid(ptr, &(object->val.var)));
+ case SNMP_SYNTAX_COUNTER64:
+ return (snmp_cnt64_2asn_oid(ptr, &(object->val.var)));
+ case SNMP_SYNTAX_OCTETSTRING:
+ return (snmp_tc2oid(idx->tc, ptr, &(object->val.var)));
+ default:
+ /* NOTREACHED */
+ break;
+ }
+
+ return (NULL);
+}
+
+char *
+snmp_parse_index(struct snmp_toolinfo *snmptoolctx, char *str,
+ struct snmp_object *object)
+{
+ char *ptr;
+ struct index *temp;
+
+ if (object->info->table_idx == NULL)
+ return (NULL);
+
+ ptr = NULL;
+ STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(object)), link) {
+ if ((ptr = snmp_parse_subindex(snmptoolctx, str, temp, object))
+ == NULL)
+ return (NULL);
+
+ if (*ptr != ',' && *ptr != ']')
+ return (NULL);
+ str = ptr + 1;
+ }
+
+ if (ptr == NULL || *ptr != ']') {
+ warnx("Mismatching index - %s", str);
+ return (NULL);
+ }
+
+ return (ptr + 1);
+}
+
+/*
+ * Fill in the struct asn_oid member of snmp_value with suboids from input.
+ * If an error occurs - print message on stderr and return (-1).
+ * If all is ok - return the length of the oid.
+ */
+int32_t
+snmp_parse_numoid(char *argv, struct asn_oid *var)
+{
+ char *endptr, *str;
+ asn_subid_t suboid;
+
+ str = argv;
+
+ if (*str == '.')
+ str++;
+
+ do {
+ if (var->len == ASN_MAXOIDLEN) {
+ warnx("Oid too long - %u", var->len);
+ return (-1);
+ }
+
+ suboid = strtoul(str, &endptr, 10);
+ if (suboid > ASN_MAXID) {
+ warnx("Oid too long - %u", var->len);
+ return (-1);
+ }
+
+ var->subs[var->len++] = suboid;
+ str = endptr + 1;
+ } while ( *endptr == '.');
+
+ if (*endptr != '\0') {
+ warnx("Invalid oid string - %s", argv);
+ return (-1);
+ }
+
+ return (var->len);
+}
+
+/* Append a length 1 suboid to an asn_oid structure. */
+int32_t
+snmp_suboid_append(struct asn_oid *var, asn_subid_t suboid)
+{
+ if (var == NULL)
+ return (-1);
+
+ if (var->len >= ASN_MAXOIDLEN) {
+ warnx("Oid too long - %u", var->len);
+ return (-1);
+ }
+
+ var->subs[var->len++] = suboid;
+
+ return (1);
+}
+
+/* Pop the last suboid from an asn_oid structure. */
+int32_t
+snmp_suboid_pop(struct asn_oid *var)
+{
+ asn_subid_t suboid;
+
+ if (var == NULL)
+ return (-1);
+
+ if (var->len < 1)
+ return (-1);
+
+ suboid = var->subs[--(var->len)];
+ var->subs[var->len] = 0;
+
+ return (suboid);
+}
+
+/*
+ * Parse the command-line provided string into an OID - alocate memory for a new
+ * snmp object, fill in its fields and insert it in the object list. A
+ * (snmp_verify_inoid_f) function must be provided to validate the input string.
+ */
+int32_t
+snmp_object_add(struct snmp_toolinfo *snmptoolctx, snmp_verify_inoid_f func,
+ char *string)
+{
+ struct snmp_object *obj;
+
+ if (snmptoolctx == NULL)
+ return (-1);
+
+ /* XXX-BZ does that chack make sense? */
+ if (snmptoolctx->objects >= SNMP_MAX_BINDINGS) {
+ warnx("Too many bindings in PDU - %u", snmptoolctx->objects + 1);
+ return (-1);
+ }
+
+ if ((obj = malloc(sizeof(struct snmp_object))) == NULL) {
+ syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
+ return (-1);
+ }
+
+ memset(obj, 0, sizeof(struct snmp_object));
+ if (func(snmptoolctx, obj, string) < 0) {
+ warnx("Invalid OID - %s", string);
+ free(obj);
+ return (-1);
+ }
+
+ snmptoolctx->objects++;
+ SLIST_INSERT_HEAD(&snmptoolctx->snmp_objectlist, obj, link);
+
+ return (1);
+}
+
+/* Given an OID, find it in the object list and remove it. */
+int32_t
+snmp_object_remove(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
+{
+ struct snmp_object *temp;
+
+ if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist)) {
+ warnx("Object list already empty");
+ return (-1);
+ }
+
+
+ SLIST_FOREACH(temp, &snmptoolctx->snmp_objectlist, link)
+ if (asn_compare_oid(&(temp->val.var), oid) == 0)
+ break;
+
+ if (temp == NULL) {
+ warnx("No such object in list");
+ return (-1);
+ }
+
+ SLIST_REMOVE(&snmptoolctx->snmp_objectlist, temp, snmp_object, link);
+ if (temp->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
+ temp->val.v.octetstring.octets != NULL)
+ free(temp->val.v.octetstring.octets);
+ free(temp);
+
+ return (1);
+}
+
+static void
+snmp_object_freeall(struct snmp_toolinfo *snmptoolctx)
+{
+ struct snmp_object *o;
+
+ while ((o = SLIST_FIRST(&snmptoolctx->snmp_objectlist)) != NULL) {
+ SLIST_REMOVE_HEAD(&snmptoolctx->snmp_objectlist, link);
+
+ if (o->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
+ o->val.v.octetstring.octets != NULL)
+ free(o->val.v.octetstring.octets);
+ free(o);
+ }
+}
+
+/* Do all possible memory release before exit. */
+void
+snmp_tool_freeall(struct snmp_toolinfo *snmptoolctx)
+{
+ if (snmp_client.chost != NULL) {
+ free(snmp_client.chost);
+ snmp_client.chost = NULL;
+ }
+
+ if (snmp_client.cport != NULL) {
+ free(snmp_client.cport);
+ snmp_client.cport = NULL;
+ }
+
+ snmp_mapping_free(snmptoolctx);
+ free_filelist(snmptoolctx);
+ snmp_object_freeall(snmptoolctx);
+
+ if (snmptoolctx->passwd != NULL) {
+ free(snmptoolctx->passwd);
+ snmptoolctx->passwd = NULL;
+ }
+}
+
+/*
+ * Fill all variables from the object list into a PDU. (snmp_verify_vbind_f)
+ * function should check whether the variable is consistent in this PDU
+ * (e.g do not add non-leaf OIDs to a GET PDU, or OIDs with read access only to
+ * a SET PDU) - might be NULL though. (snmp_add_vbind_f) function is the
+ * function actually adds the variable to the PDU and must not be NULL.
+ */
+int32_t
+snmp_pdu_add_bindings(struct snmp_toolinfo *snmptoolctx,
+ snmp_verify_vbind_f vfunc, snmp_add_vbind_f afunc,
+ struct snmp_pdu *pdu, int32_t maxcount)
+{
+ int32_t nbindings, abind;
+ struct snmp_object *obj;
+
+ if (pdu == NULL || afunc == NULL)
+ return (-1);
+
+ /* Return 0 in case of no more work todo. */
+ if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist))
+ return (0);
+
+ if (maxcount < 0 || maxcount > SNMP_MAX_BINDINGS) {
+ warnx("maxcount out of range: <0 || >SNMP_MAX_BINDINGS");
+ return (-1);
+ }
+
+ nbindings = 0;
+ SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link) {
+ if ((vfunc != NULL) && (vfunc(snmptoolctx, pdu, obj) < 0)) {
+ nbindings = -1;
+ break;
+ }
+ if ((abind = afunc(pdu, obj)) < 0) {
+ nbindings = -1;
+ break;
+ }
+
+ if (abind > 0) {
+ /* Do not put more varbindings than requested. */
+ if (++nbindings >= maxcount)
+ break;
+ }
+ }
+
+ return (nbindings);
+}
+
+/*
+ * Locate an object in the object list and set a corresponding error status.
+ */
+int32_t
+snmp_object_seterror(struct snmp_toolinfo *snmptoolctx,
+ struct snmp_value *err_value, int32_t error_status)
+{
+ struct snmp_object *obj;
+
+ if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist) || err_value == NULL)
+ return (-1);
+
+ SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link)
+ if (asn_compare_oid(&(err_value->var), &(obj->val.var)) == 0) {
+ obj->error = error_status;
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Check a PDU received in responce to a SNMP_PDU_GET/SNMP_PDU_GETBULK request
+ * but don't compare syntaxes - when sending a request PDU they must be null.
+ * This is a (almost) complete copy of snmp_pdu_check() - with matching syntaxes
+ * checks and some other checks skiped.
+ */
+int32_t
+snmp_parse_get_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
+{
+ uint32_t i;
+
+ for (i = 0; i < req->nbindings; i++) {
+ if (asn_compare_oid(&req->bindings[i].var,
+ &resp->bindings[i].var) != 0) {
+ warnx("Bad OID in response");
+ return (-1);
+ }
+
+ if (snmp_client.version != SNMP_V1 && (resp->bindings[i].syntax
+ == SNMP_SYNTAX_NOSUCHOBJECT || resp->bindings[i].syntax ==
+ SNMP_SYNTAX_NOSUCHINSTANCE))
+ return (0);
+ }
+
+ return (1);
+}
+
+int32_t
+snmp_parse_getbulk_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
+{
+ int32_t N, R, M, r;
+
+ if (req->error_status > (int32_t) resp->nbindings) {
+ warnx("Bad number of bindings in response");
+ return (-1);
+ }
+
+ for (N = 0; N < req->error_status; N++) {
+ if (asn_is_suboid(&req->bindings[N].var,
+ &resp->bindings[N].var) == 0)
+ return (0);
+ if (resp->bindings[N].syntax == SNMP_SYNTAX_ENDOFMIBVIEW)
+ return (0);
+ }
+
+ for (R = N , r = N; R < (int32_t) req->nbindings; R++) {
+ for (M = 0; M < req->error_index && (r + M) <
+ (int32_t) resp->nbindings; M++) {
+ if (asn_is_suboid(&req->bindings[R].var,
+ &resp->bindings[r + M].var) == 0)
+ return (0);
+
+ if (resp->bindings[r + M].syntax ==
+ SNMP_SYNTAX_ENDOFMIBVIEW) {
+ M++;
+ break;
+ }
+ }
+ r += M;
+ }
+
+ return (0);
+}
+
+int32_t
+snmp_parse_getnext_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
+{
+ uint32_t i;
+
+ for (i = 0; i < req->nbindings; i++) {
+ if (asn_is_suboid(&req->bindings[i].var, &resp->bindings[i].var)
+ == 0)
+ return (0);
+
+ if (resp->version != SNMP_V1 && resp->bindings[i].syntax ==
+ SNMP_SYNTAX_ENDOFMIBVIEW)
+ return (0);
+ }
+
+ return (1);
+}
+
+/*
+ * Should be called to check a responce to get/getnext/getbulk.
+ */
+int32_t
+snmp_parse_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
+{
+ if (resp == NULL || req == NULL)
+ return (-2);
+
+ if (resp->version != req->version) {
+ warnx("Response has wrong version");
+ return (-1);
+ }
+
+ if (resp->error_status == SNMP_ERR_NOSUCHNAME) {
+ warnx("Error - No Such Name");
+ return (0);
+ }
+
+ if (resp->error_status != SNMP_ERR_NOERROR) {
+ warnx("Error %d in responce", resp->error_status);
+ return (-1);
+ }
+
+ if (resp->nbindings != req->nbindings && req->type != SNMP_PDU_GETBULK){
+ warnx("Bad number of bindings in response");
+ return (-1);
+ }
+
+ switch (req->type) {
+ case SNMP_PDU_GET:
+ return (snmp_parse_get_resp(resp,req));
+ case SNMP_PDU_GETBULK:
+ return (snmp_parse_getbulk_resp(resp,req));
+ case SNMP_PDU_GETNEXT:
+ return (snmp_parse_getnext_resp(resp,req));
+ default:
+ /* NOTREACHED */
+ break;
+ }
+
+ return (-2);
+}
+
+static void
+snmp_output_octetstring(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
+ uint32_t len, uint8_t *octets)
+{
+ char *buf;
+
+ if (len == 0 || octets == NULL)
+ return;
+
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_OCTETSTRING].str);
+
+ if ((buf = snmp_oct2tc(tc, len, (char *) octets)) != NULL) {
+ fprintf(stdout, "%s", buf);
+ free(buf);
+ }
+}
+
+static void
+snmp_output_octetindex(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
+ struct asn_oid *oid)
+{
+ uint32_t i;
+ uint8_t *s;
+
+ if ((s = malloc(oid->subs[0] + 1)) == NULL)
+ syslog(LOG_ERR, "malloc failed - %s", strerror(errno));
+ else {
+ for (i = 0; i < oid->subs[0]; i++)
+ s[i] = (u_char) (oid->subs[i + 1]);
+
+ snmp_output_octetstring(snmptoolctx, tc, oid->subs[0], s);
+ free(s);
+ }
+}
+
+/*
+ * Check and output syntax type and value.
+ */
+static void
+snmp_output_oid_value(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
+{
+ char oid_string[ASN_OIDSTRLEN];
+ struct snmp_object obj;
+
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_OID].str);
+
+ if(!ISSET_NUMERIC(snmptoolctx)) {
+ memset(&obj, 0, sizeof(struct snmp_object));
+ asn_append_oid(&(obj.val.var), oid);
+
+ if (snmp_lookup_enumstring(snmptoolctx, &obj) > 0)
+ fprintf(stdout, "%s" , obj.info->string);
+ else if (snmp_lookup_oidstring(snmptoolctx, &obj) > 0)
+ fprintf(stdout, "%s" , obj.info->string);
+ else if (snmp_lookup_nodestring(snmptoolctx, &obj) > 0)
+ fprintf(stdout, "%s" , obj.info->string);
+ else {
+ (void) asn_oid2str_r(oid, oid_string);
+ fprintf(stdout, "%s", oid_string);
+ }
+ } else {
+ (void) asn_oid2str_r(oid, oid_string);
+ fprintf(stdout, "%s", oid_string);
+ }
+}
+
+static void
+snmp_output_int(struct snmp_toolinfo *snmptoolctx, struct enum_pairs *enums,
+ int32_t int_val)
+{
+ char *string;
+
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_INTEGER].str);
+
+ if (enums != NULL && (string = enum_string_lookup(enums, int_val))
+ != NULL)
+ fprintf(stdout, "%s", string);
+ else
+ fprintf(stdout, "%d", int_val);
+}
+
+static void
+snmp_output_ipaddress(struct snmp_toolinfo *snmptoolctx, uint8_t *ip)
+{
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_IPADDRESS].str);
+
+ fprintf(stdout, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
+}
+
+static void
+snmp_output_counter(struct snmp_toolinfo *snmptoolctx, uint32_t counter)
+{
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_COUNTER].str);
+
+ fprintf(stdout, "%u", counter);
+}
+
+static void
+snmp_output_gauge(struct snmp_toolinfo *snmptoolctx, uint32_t gauge)
+{
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_GAUGE].str);
+
+ fprintf(stdout, "%u", gauge);
+}
+
+static void
+snmp_output_ticks(struct snmp_toolinfo *snmptoolctx, uint32_t ticks)
+{
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_TIMETICKS].str);
+
+ fprintf(stdout, "%u", ticks);
+}
+
+static void
+snmp_output_counter64(struct snmp_toolinfo *snmptoolctx, uint64_t counter64)
+{
+ if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
+ fprintf(stdout, "%s : ",
+ syntax_strings[SNMP_SYNTAX_COUNTER64].str);
+
+ fprintf(stdout,"%ju", counter64);
+}
+
+int32_t
+snmp_output_numval(struct snmp_toolinfo *snmptoolctx, struct snmp_value *val,
+ struct snmp_oid2str *entry)
+{
+ if (val == NULL)
+ return (-1);
+
+ if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)
+ fprintf(stdout, " = ");
+
+ switch (val->syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ if (entry != NULL)
+ snmp_output_int(snmptoolctx, entry->snmp_enum,
+ val->v.integer);
+ else
+ snmp_output_int(snmptoolctx, NULL, val->v.integer);
+ break;
+
+ case SNMP_SYNTAX_OCTETSTRING:
+ if (entry != NULL)
+ snmp_output_octetstring(snmptoolctx, entry->tc,
+ val->v.octetstring.len, val->v.octetstring.octets);
+ else
+ snmp_output_octetstring(snmptoolctx, SNMP_STRING,
+ val->v.octetstring.len, val->v.octetstring.octets);
+ break;
+
+ case SNMP_SYNTAX_OID:
+ snmp_output_oid_value(snmptoolctx, &(val->v.oid));
+ break;
+
+ case SNMP_SYNTAX_IPADDRESS:
+ snmp_output_ipaddress(snmptoolctx, val->v.ipaddress);
+ break;
+
+ case SNMP_SYNTAX_COUNTER:
+ snmp_output_counter(snmptoolctx, val->v.uint32);
+ break;
+
+ case SNMP_SYNTAX_GAUGE:
+ snmp_output_gauge(snmptoolctx, val->v.uint32);
+ break;
+
+ case SNMP_SYNTAX_TIMETICKS:
+ snmp_output_ticks(snmptoolctx, val->v.uint32);
+ break;
+
+ case SNMP_SYNTAX_COUNTER64:
+ snmp_output_counter64(snmptoolctx, val->v.counter64);
+ break;
+
+ case SNMP_SYNTAX_NOSUCHOBJECT:
+ fprintf(stdout, "No Such Object\n");
+ return (val->syntax);
+
+ case SNMP_SYNTAX_NOSUCHINSTANCE:
+ fprintf(stdout, "No Such Instance\n");
+ return (val->syntax);
+
+ case SNMP_SYNTAX_ENDOFMIBVIEW:
+ fprintf(stdout, "End of Mib View\n");
+ return (val->syntax);
+
+ case SNMP_SYNTAX_NULL:
+ /* NOTREACHED */
+ fprintf(stdout, "agent returned NULL Syntax\n");
+ return (val->syntax);
+
+ default:
+ /* NOTREACHED - If here - then all went completely wrong. */
+ fprintf(stdout, "agent returned unknown syntax\n");
+ return (-1);
+ }
+
+ fprintf(stdout, "\n");
+
+ return (0);
+}
+
+static int32_t
+snmp_fill_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *obj,
+ struct snmp_value *val)
+{
+ int32_t rc;
+ asn_subid_t suboid;
+
+ if (obj == NULL || val == NULL)
+ return (-1);
+
+ if ((suboid = snmp_suboid_pop(&(val->var))) > ASN_MAXID)
+ return (-1);
+
+ memset(obj, 0, sizeof(struct snmp_object));
+ asn_append_oid(&(obj->val.var), &(val->var));
+ obj->val.syntax = val->syntax;
+
+ if (obj->val.syntax > 0)
+ rc = snmp_lookup_leafstring(snmptoolctx, obj);
+ else
+ rc = snmp_lookup_nonleaf_string(snmptoolctx, obj);
+
+ (void) snmp_suboid_append(&(val->var), suboid);
+ (void) snmp_suboid_append(&(obj->val.var), suboid);
+
+ return (rc);
+}
+
+static int32_t
+snmp_output_index(struct snmp_toolinfo *snmptoolctx, struct index *stx,
+ struct asn_oid *oid)
+{
+ uint8_t ip[4];
+ uint32_t bytes = 1;
+ uint64_t cnt64;
+ struct asn_oid temp, out;
+
+ if (oid->len < bytes)
+ return (-1);
+
+ memset(&temp, 0, sizeof(struct asn_oid));
+ asn_append_oid(&temp, oid);
+
+ switch (stx->syntax) {
+ case SNMP_SYNTAX_INTEGER:
+ snmp_output_int(snmptoolctx, stx->snmp_enum, temp.subs[0]);
+ break;
+
+ case SNMP_SYNTAX_OCTETSTRING:
+ if ((temp.subs[0] > temp.len -1 ) || (temp.subs[0] >
+ ASN_MAXOCTETSTRING))
+ return (-1);
+ snmp_output_octetindex(snmptoolctx, stx->tc, &temp);
+ bytes += temp.subs[0];
+ break;
+
+ case SNMP_SYNTAX_OID:
+ if ((temp.subs[0] > temp.len -1) || (temp.subs[0] >
+ ASN_MAXOIDLEN))
+ return (-1);
+
+ bytes += temp.subs[0];
+ memset(&out, 0, sizeof(struct asn_oid));
+ asn_slice_oid(&out, &temp, 1, bytes);
+ snmp_output_oid_value(snmptoolctx, &out);
+ break;
+
+ case SNMP_SYNTAX_IPADDRESS:
+ if (temp.len < 4)
+ return (-1);
+ for (bytes = 0; bytes < 4; bytes++)
+ ip[bytes] = temp.subs[bytes];
+
+ snmp_output_ipaddress(snmptoolctx, ip);
+ bytes = 4;
+ break;
+
+ case SNMP_SYNTAX_COUNTER:
+ snmp_output_counter(snmptoolctx, temp.subs[0]);
+ break;
+
+ case SNMP_SYNTAX_GAUGE:
+ snmp_output_gauge(snmptoolctx, temp.subs[0]);
+ break;
+
+ case SNMP_SYNTAX_TIMETICKS:
+ snmp_output_ticks(snmptoolctx, temp.subs[0]);
+ break;
+
+ case SNMP_SYNTAX_COUNTER64:
+ if (oid->len < 2)
+ return (-1);
+ bytes = 2;
+ memcpy(&cnt64, temp.subs, bytes);
+ snmp_output_counter64(snmptoolctx, cnt64);
+ break;
+
+ default:
+ return (-1);
+ }
+
+ return (bytes);
+}
+
+static int32_t
+snmp_output_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *o)
+{
+ int32_t i, first, len;
+ struct asn_oid oid;
+ struct index *temp;
+
+ if (ISSET_NUMERIC(snmptoolctx))
+ return (-1);
+
+ if (o->info->table_idx == NULL) {
+ fprintf(stdout,"%s.%d", o->info->string,
+ o->val.var.subs[o->val.var.len - 1]);
+ return (1);
+ }
+
+ fprintf(stdout,"%s[", o->info->string);
+ memset(&oid, 0, sizeof(struct asn_oid));
+
+ len = 1;
+ asn_slice_oid(&oid, &(o->val.var), (o->info->table_idx->var.len + len),
+ o->val.var.len);
+
+ first = 1;
+ STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(o)), link) {
+ if(first)
+ first = 0;
+ else
+ fprintf(stdout, ", ");
+ if ((i = snmp_output_index(snmptoolctx, temp, &oid)) < 0)
+ break;
+ len += i;
+ memset(&oid, 0, sizeof(struct asn_oid));
+ asn_slice_oid(&oid, &(o->val.var),
+ (o->info->table_idx->var.len + len), o->val.var.len + 1);
+ }
+
+ fprintf(stdout,"]");
+ return (1);
+}
+
+void
+snmp_output_err_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu)
+{
+ char buf[ASN_OIDSTRLEN];
+ struct snmp_object object;
+
+ if (pdu == NULL || (pdu->error_index > (int32_t) pdu->nbindings)) {
+ fprintf(stdout,"Invalid error index in PDU\n");
+ return;
+ }
+
+ fprintf(stdout, "Agent %s:%s returned error \n", snmp_client.chost,
+ snmp_client.cport);
+
+ if (!ISSET_NUMERIC(snmptoolctx) && (snmp_fill_object(snmptoolctx, &object,
+ &(pdu->bindings[pdu->error_index - 1])) > 0))
+ snmp_output_object(snmptoolctx, &object);
+ else {
+ asn_oid2str_r(&(pdu->bindings[pdu->error_index - 1].var), buf);
+ fprintf(stdout,"%s", buf);
+ }
+
+ fprintf(stdout," caused error - ");
+ if ((pdu->error_status > 0) && (pdu->error_status <=
+ SNMP_ERR_INCONS_NAME))
+ fprintf(stdout, "%s\n", error_strings[pdu->error_status].str);
+ else
+ fprintf(stdout,"%s\n", error_strings[SNMP_ERR_UNKNOWN].str);
+}
+
+int32_t
+snmp_output_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu)
+{
+ int32_t error;
+ char p[ASN_OIDSTRLEN];
+ uint32_t i;
+ struct snmp_object object;
+
+ for (i = 0, error = 0; i < pdu->nbindings; i++) {
+ if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) {
+ if (!ISSET_NUMERIC(snmptoolctx) &&
+ (snmp_fill_object(snmptoolctx, &object,
+ &(pdu->bindings[i])) > 0))
+ snmp_output_object(snmptoolctx, &object);
+ else {
+ asn_oid2str_r(&(pdu->bindings[i].var), p);
+ fprintf(stdout, "%s", p);
+ }
+ }
+ error |= snmp_output_numval(snmptoolctx, &(pdu->bindings[i]), object.info);
+ }
+
+ return (error);
+}
+
+void
+snmp_output_engine(void)
+{
+ uint32_t i;
+ char *cptr, engine[2 * SNMP_ENGINE_ID_SIZ + 2];
+
+ cptr = engine;
+ for (i = 0; i < snmp_client.engine.engine_len; i++)
+ cptr += sprintf(cptr, "%.2x", snmp_client.engine.engine_id[i]);
+ *cptr++ = '\0';
+
+ fprintf(stdout, "Engine ID 0x%s\n", engine);
+ fprintf(stdout, "Boots : %u\t\tTime : %d\n",
+ snmp_client.engine.engine_boots,
+ snmp_client.engine.engine_time);
+}
+
+void
+snmp_output_keys(void)
+{
+ uint32_t i, keylen = 0;
+ char *cptr, extkey[2 * SNMP_AUTH_KEY_SIZ + 2];
+
+ fprintf(stdout, "Localized keys for %s\n", snmp_client.user.sec_name);
+ if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_MD5) {
+ fprintf(stdout, "MD5 : 0x");
+ keylen = SNMP_AUTH_HMACMD5_KEY_SIZ;
+ } else if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_SHA) {
+ fprintf(stdout, "SHA : 0x");
+ keylen = SNMP_AUTH_HMACSHA_KEY_SIZ;
+ }
+ if (snmp_client.user.auth_proto != SNMP_AUTH_NOAUTH) {
+ cptr = extkey;
+ for (i = 0; i < keylen; i++)
+ cptr += sprintf(cptr, "%.2x",
+ snmp_client.user.auth_key[i]);
+ *cptr++ = '\0';
+ fprintf(stdout, "%s\n", extkey);
+ }
+
+ if (snmp_client.user.priv_proto == SNMP_PRIV_DES) {
+ fprintf(stdout, "DES : 0x");
+ keylen = SNMP_PRIV_DES_KEY_SIZ;
+ } else if (snmp_client.user.priv_proto == SNMP_PRIV_AES) {
+ fprintf(stdout, "AES : 0x");
+ keylen = SNMP_PRIV_AES_KEY_SIZ;
+ }
+ if (snmp_client.user.priv_proto != SNMP_PRIV_NOPRIV) {
+ cptr = extkey;
+ for (i = 0; i < keylen; i++)
+ cptr += sprintf(cptr, "%.2x",
+ snmp_client.user.priv_key[i]);
+ *cptr++ = '\0';
+ fprintf(stdout, "%s\n", extkey);
+ }
+}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h
new file mode 100644
index 0000000..6e62186
--- /dev/null
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h
@@ -0,0 +1,331 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Shteryana Shopova <syrinx@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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND 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 THE AUTHOR OR 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.
+ *
+ * Helper functions common for all tools.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BSNMP_TOOLS_H_
+#define _BSNMP_TOOLS_H_
+
+/* From asn1.h + 1 byte for trailing zero. */
+#define MAX_OCTSTRING_LEN ASN_MAXOCTETSTRING + 1
+#define MAX_CMD_SYNTAX_LEN 12
+
+/* Arbitrary upper limit on node names and function names - gensnmptree.c. */
+#define MAXSTR 1000
+
+/* Should be enough to fetch the biggest allowed octet string. */
+#define MAX_BUFF_SIZE (ASN_MAXOCTETSTRING + 50)
+
+#define SNMP_DEFS_DIR "/usr/share/snmp/defs/"
+#define SNMP_DEFAULT_LOCAL "/var/run/snmpd.sock"
+
+enum snmp_access {
+ SNMP_ACCESS_NONE = 0,
+ SNMP_ACCESS_GET,
+ SNMP_ACCESS_SET,
+ SNMP_ACCESS_GETSET,
+};
+
+/* A structure for integer-string enumerations. */
+struct enum_pair {
+ int32_t enum_val;
+ char *enum_str;
+ STAILQ_ENTRY(enum_pair) link;
+};
+
+STAILQ_HEAD(enum_pairs, enum_pair);
+
+struct enum_type {
+ char *name;
+ uint32_t syntax;
+ int32_t is_enum;
+ int32_t is_bits;
+ struct enum_pairs *snmp_enum;
+ SLIST_ENTRY(enum_type) link;
+};
+
+SLIST_HEAD(snmp_enum_tc, enum_type);
+
+struct index {
+ enum snmp_tc tc;
+ enum snmp_syntax syntax;
+ struct enum_pairs *snmp_enum;
+ STAILQ_ENTRY(index) link;
+};
+
+STAILQ_HEAD(snmp_idxlist, index);
+
+struct snmp_index_entry {
+ char *string;
+ uint32_t strlen;
+ struct asn_oid var;
+ struct snmp_idxlist index_list;
+ SLIST_ENTRY(snmp_index_entry) link;
+};
+
+/* Information needed for oid to string conversion. */
+struct snmp_oid2str {
+ char *string;
+ uint32_t strlen;
+ enum snmp_tc tc;
+ enum snmp_syntax syntax;
+ enum snmp_access access;
+ struct asn_oid var;
+ /* A pointer to a entry from the table list - OK if NULL. */
+ struct snmp_index_entry *table_idx;
+ /*
+ * A singly-linked tail queue of all (int, string) pairs -
+ * for INTEGER syntax only.
+ */
+ struct enum_pairs *snmp_enum;
+ SLIST_ENTRY(snmp_oid2str) link;
+};
+
+/* A structure to hold each oid input by user. */
+struct snmp_object {
+ /* Flag - if set, the variable caused error in a previous request. */
+ int32_t error;
+ /*
+ * A pointer in the mapping lists - not used if OIDs are input as
+ * numericals.
+ */
+ struct snmp_oid2str *info;
+ /* A snmp value to hold the actual oid, syntax and value. */
+ struct snmp_value val;
+ SLIST_ENTRY(snmp_object) link;
+};
+
+struct fname {
+ char *name;
+ int32_t done;
+ struct asn_oid cut;
+ SLIST_ENTRY(fname) link;
+};
+
+SLIST_HEAD(snmp_mapping, snmp_oid2str);
+SLIST_HEAD(fname_list, fname);
+SLIST_HEAD(snmp_table_index, snmp_index_entry);
+
+/*
+ * Keep a list for every syntax type.
+ */
+struct snmp_mappings {
+ /* The list containing all non-leaf nodes. */
+ struct snmp_mapping nodelist;
+ /* INTEGER/INTEGER32 types. */
+ struct snmp_mapping intlist;
+ /* OCTETSTRING types. */
+ struct snmp_mapping octlist;
+ /* OID types. */
+ struct snmp_mapping oidlist;
+ /* IPADDRESS types. */
+ struct snmp_mapping iplist;
+ /* TIMETICKS types. */
+ struct snmp_mapping ticklist;
+ /* COUNTER types. */
+ struct snmp_mapping cntlist;
+ /* GAUGE types. */
+ struct snmp_mapping gaugelist;
+ /* COUNTER64 types. */
+ struct snmp_mapping cnt64list;
+ /* ENUM values for oid types. */
+ struct snmp_mapping enumlist;
+ /* Description of all table entry types. */
+ struct snmp_table_index tablelist;
+ /* Defined enumerated textual conventions. */
+ struct snmp_enum_tc tclist;
+};
+
+struct snmp_toolinfo {
+ uint32_t flags;
+ /* Number of initially input OIDs. */
+ int32_t objects;
+ /* List of all input OIDs. */
+ SLIST_HEAD(snmp_objectlist, snmp_object) snmp_objectlist;
+ /* All known OID to string mapping data. */
+ struct snmp_mappings *mappings;
+ /* A list of .defs filenames to search oid<->string mapping. */
+ struct fname_list filelist;
+ /* SNMPv3 USM user credentials */
+ char *passwd;
+};
+
+/* XXX we might want to get away with this and will need to touch
+ * XXX the MACROS then too */
+extern struct snmp_toolinfo snmptool;
+
+/* Definitions for some flags' bits. */
+#define OUTPUT_BITS 0x00000003 /* bits 0-1 for output type */
+#define NUMERIC_BIT 0x00000004 /* bit 2 for numeric oids */
+#define RETRY_BIT 0x00000008 /* bit 3 for retry on error responce */
+#define ERRIGNORE_BIT 0x00000010 /* bit 4 for skip sanity checking */
+#define ERRIGNORE_BIT 0x00000010 /* bit 4 for skip sanity checking */
+#define EDISCOVER_BIT 0x00000020 /* bit 5 for SNMP Engine Discovery */
+#define LOCALKEY_BIT 0x00000040 /* bit 6 for using localized key */
+ /* 0x00000080 */ /* bit 7 reserverd */
+#define PDUTYPE_BITS 0x00000f00 /* bits 8-11 for pdu type */
+ /* 0x0000f000 */ /* bit 12-15 reserverd */
+#define MAXREP_BITS 0x00ff0000 /* bits 16-23 for max-repetit. value */
+#define NONREP_BITS 0xff000000 /* bits 24-31 for non-repeaters value */
+
+#define OUTPUT_SHORT 0x0
+#define OUTPUT_VERBOSE 0x1
+#define OUTPUT_TABULAR 0x2
+#define OUTPUT_QUIET 0x3
+
+/* Macros for playing with flags' bits. */
+#define SET_OUTPUT(ctx, type) ((ctx)->flags |= ((type) & OUTPUT_BITS))
+#define GET_OUTPUT(ctx) ((ctx)->flags & OUTPUT_BITS)
+
+#define SET_NUMERIC(ctx) ((ctx)->flags |= NUMERIC_BIT)
+#define ISSET_NUMERIC(ctx) ((ctx)->flags & NUMERIC_BIT)
+
+#define SET_RETRY(ctx) ((ctx)->flags |= RETRY_BIT)
+#define ISSET_RETRY(ctx) ((ctx)->flags & RETRY_BIT)
+
+#define SET_ERRIGNORE(ctx) ((ctx)->flags |= ERRIGNORE_BIT)
+#define ISSET_ERRIGNORE(ctx) ((ctx)->flags & ERRIGNORE_BIT)
+
+#define SET_EDISCOVER(ctx) ((ctx)->flags |= EDISCOVER_BIT)
+#define ISSET_EDISCOVER(ctx) ((ctx)->flags & EDISCOVER_BIT)
+
+#define SET_LOCALKEY(ctx) ((ctx)->flags |= LOCALKEY_BIT)
+#define ISSET_LOCALKEY(ctx) ((ctx)->flags & LOCALKEY_BIT)
+
+#define SET_PDUTYPE(ctx, type) (((ctx)->flags |= (((type) & 0xf) << 8)))
+#define GET_PDUTYPE(ctx) (((ctx)->flags & PDUTYPE_BITS) >> 8)
+
+#define SET_MAXREP(ctx, i) (((ctx)->flags |= (((i) & 0xff) << 16)))
+#define GET_MAXREP(ctx) (((ctx)->flags & MAXREP_BITS) >> 16)
+
+#define SET_NONREP(ctx, i) (((ctx)->flags |= (((i) & 0xff) << 24)))
+#define GET_NONREP(ctx) (((ctx)->flags & NONREP_BITS) >> 24)
+
+
+extern const struct asn_oid IsoOrgDod_OID;
+
+int snmptool_init(struct snmp_toolinfo *);
+int32_t snmp_import_file(struct snmp_toolinfo *, struct fname *);
+int32_t snmp_import_all(struct snmp_toolinfo *);
+int32_t add_filename(struct snmp_toolinfo *, const char *,
+ const struct asn_oid *, int32_t);
+void free_filelist(struct snmp_toolinfo *);
+void snmp_tool_freeall(struct snmp_toolinfo *);
+void snmp_import_dump(int);
+
+/* bsnmpmap.c */
+struct snmp_mappings *snmp_mapping_init(void);
+int32_t snmp_mapping_free(struct snmp_toolinfo *);
+void snmp_index_listfree(struct snmp_idxlist *);
+void snmp_dump_oid2str(struct snmp_oid2str *);
+int32_t snmp_node_insert(struct snmp_toolinfo *, struct snmp_oid2str *);
+int32_t snmp_leaf_insert(struct snmp_toolinfo *, struct snmp_oid2str *);
+int32_t snmp_enum_insert(struct snmp_toolinfo *, struct snmp_oid2str *);
+struct enum_pairs *enum_pairs_init(void);
+void enum_pairs_free(struct enum_pairs *);
+void snmp_mapping_entryfree(struct snmp_oid2str *);
+int32_t enum_pair_insert(struct enum_pairs *, int32_t, char *);
+char *enum_string_lookup(struct enum_pairs *, int32_t);
+int32_t enum_number_lookup(struct enum_pairs *, char *);
+int32_t snmp_syntax_insert(struct snmp_idxlist *, struct enum_pairs *,
+ enum snmp_syntax, enum snmp_tc);
+int32_t snmp_table_insert(struct snmp_toolinfo *, struct snmp_index_entry *);
+
+struct enum_type *snmp_enumtc_init(char *);
+void snmp_enumtc_free(struct enum_type *);
+void snmp_enumtc_insert(struct snmp_toolinfo *, struct enum_type *);
+struct enum_type *snmp_enumtc_lookup(struct snmp_toolinfo *, char *);
+
+void snmp_mapping_dump(struct snmp_toolinfo *);
+int32_t snmp_lookup_leafstring(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_enumstring(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_oidstring(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_nonleaf_string(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_allstring(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_nodestring(struct snmp_toolinfo *, struct snmp_object *);
+int32_t snmp_lookup_oidall(struct snmp_toolinfo *, struct snmp_object *, char *);
+int32_t snmp_lookup_enumoid(struct snmp_toolinfo *, struct snmp_object *, char *);
+int32_t snmp_lookup_oid(struct snmp_toolinfo *, struct snmp_object *, char *);
+
+/* Functions parsing common options for all tools. */
+int32_t parse_server(char *);
+int32_t parse_timeout(char *);
+int32_t parse_retry(char *);
+int32_t parse_version(char *);
+int32_t parse_local_path(char *);
+int32_t parse_buflen(char *);
+int32_t parse_debug(void);
+int32_t parse_discovery(struct snmp_toolinfo *);
+int32_t parse_local_key(struct snmp_toolinfo *);
+int32_t parse_num_oids(struct snmp_toolinfo *);
+int32_t parse_file(struct snmp_toolinfo *, char *);
+int32_t parse_include(struct snmp_toolinfo *, char *);
+int32_t parse_output(struct snmp_toolinfo *, char *);
+int32_t parse_errors(struct snmp_toolinfo *);
+int32_t parse_skip_access(struct snmp_toolinfo *);
+int32_t parse_authentication(struct snmp_toolinfo *, char *);
+int32_t parse_privacy(struct snmp_toolinfo *, char *);
+int32_t parse_context(struct snmp_toolinfo *, char *);
+int32_t parse_user_security(struct snmp_toolinfo *, char *);
+
+typedef int32_t (*snmp_verify_inoid_f) (struct snmp_toolinfo *,
+ struct snmp_object *, char *);
+int32_t snmp_object_add(struct snmp_toolinfo *, snmp_verify_inoid_f, char *);
+int32_t snmp_object_remove(struct snmp_toolinfo *, struct asn_oid *oid);
+int32_t snmp_object_seterror(struct snmp_toolinfo *, struct snmp_value *,
+ int32_t);
+
+enum snmp_syntax parse_syntax(char *);
+char *snmp_parse_suboid(char *, struct asn_oid *);
+char *snmp_parse_index(struct snmp_toolinfo *, char *, struct snmp_object *);
+int32_t snmp_parse_numoid(char *, struct asn_oid *);
+int32_t snmp_suboid_append(struct asn_oid *, asn_subid_t);
+int32_t snmp_suboid_pop(struct asn_oid *);
+
+typedef int32_t (*snmp_verify_vbind_f) (struct snmp_toolinfo *,
+ struct snmp_pdu *, struct snmp_object *);
+typedef int32_t (*snmp_add_vbind_f) (struct snmp_pdu *, struct snmp_object *);
+int32_t snmp_pdu_add_bindings(struct snmp_toolinfo *, snmp_verify_vbind_f,
+ snmp_add_vbind_f, struct snmp_pdu *, int32_t);
+
+int32_t snmp_parse_get_resp(struct snmp_pdu *, struct snmp_pdu *);
+int32_t snmp_parse_getbulk_resp(struct snmp_pdu *, struct snmp_pdu *);
+int32_t snmp_parse_getnext_resp(struct snmp_pdu *, struct snmp_pdu *);
+int32_t snmp_parse_resp(struct snmp_pdu *, struct snmp_pdu *);
+int32_t snmp_output_numval(struct snmp_toolinfo *, struct snmp_value *,
+ struct snmp_oid2str *);
+void snmp_output_val(struct snmp_value *);
+int32_t snmp_output_resp(struct snmp_toolinfo *, struct snmp_pdu *);
+void snmp_output_err_resp(struct snmp_toolinfo *, struct snmp_pdu *);
+void snmp_output_engine(void);
+void snmp_output_keys(void);
+
+#endif /* _BSNMP_TOOLS_H_ */
OpenPOWER on IntegriCloud