--- /dev/null
+SHELL = /bin/sh
+
+.PHONY: all clean
+
+all:
+ $(MAKE) $(MAKECMDGOALS) -C snmp++
+
+clean: all
--- /dev/null
+SHELL = /bin/sh
+DEFS += -D_USE_OPENSSL
+INCS += -Iinclude
+CXXFLAGS += -W -Wall -Wextra $(DEFS) $(INCS)
+PROG = libsnmp++.a
+
+SOURCES = src/address.cpp \
+ src/counter.cpp \
+ src/eventlistholder.cpp \
+ src/integer.cpp \
+ src/msec.cpp \
+ src/octet.cpp \
+ src/reentrant.cpp \
+ src/target.cpp \
+ src/uxsnmp.cpp \
+ src/asn1.cpp \
+ src/ctr64.cpp \
+ src/gauge.cpp \
+ src/IPv6Utility.cpp \
+ src/md5c.cpp \
+ src/msgqueue.cpp \
+ src/oid.cpp \
+ src/sha.cpp \
+ src/timetick.cpp \
+ src/v3.cpp \
+ src/auth_priv.cpp \
+ src/eventlist.cpp \
+ src/idea.cpp \
+ src/log.cpp \
+ src/mp_v3.cpp \
+ src/notifyqueue.cpp \
+ src/pdu.cpp \
+ src/snmpmsg.cpp \
+ src/usm_v3.cpp \
+ src/vb.cpp
+
+.PHONY: all clear
+
+all: $(PROG)
+
+$(PROG): $(subst .cpp,.o,$(SOURCES))
+ $(AR) rc $@ $^
+ ranlib $@
+
+clean:
+ rm -f src/*.o src/*.d $(PROG)
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+-include $(subst .cpp,.d,$(SOURCES))
+endif
+endif
+
+%.d: %.cpp
+ @$(CXX) -MM $(CXXFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\).o[ :]*,src\/\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
--- /dev/null
+/*_############################################################################
+ _##
+ _## IPv6Utility.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*===================================================================
+
+ SNMP++ IPV6Utility.h
+
+ DESCRIPTION:
+ This module contains the Utility functions for IPV6 support functions
+ required for WIN32 environment
+
+ Adapted and integrated into snmp++ by Ragavan Tetchinamourty
+
+=====================================================================*/
+// $Id: $
+
+#ifndef _IPV6UTILITY_H
+#define _IPV6UTILITY_H
+
+#include "snmp_pp/config_snmp_pp.h"
+
+//FIXME #if defined(_MSC_VER) && defined(SNMP_PP_IPv6)
+#if defined(WIN32) && defined(SNMP_PP_IPv6)
+
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define ENOSPC 28
+
+
+const char * inet_ntop(int af, const void *src, char *dst, size_t size);
+
+int inet_pton(int af, const char *src, void *dst);
+
+#endif // defined(WIN32) && defined(SNMP_PP_IPv6)
+
+#endif // IPV6UTILITY_H
+
--- /dev/null
+/*_############################################################################
+ _##
+ _## address.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ A D D R E S S . H
+
+ ADDRESS CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ Address class definition. Encapsulates various network
+ addresses into easy to use, safe and portable classes.
+
+=====================================================================*/
+// $Id: address.h 307 2007-09-14 20:01:45Z katz $
+
+#ifndef _ADDRESS
+#define _ADDRESS
+
+
+//----[ includes ]-----------------------------------------------------
+#include <string.h>
+
+#if defined (CPU) && CPU == PPC603
+#undef HASH1
+#undef HASH2
+#else
+#include <memory.h>
+#endif
+
+#include "snmp_pp/config_snmp_pp.h" // for _IPX_ADDRESS and _MAC_ADDRESS
+#include "snmp_pp/smival.h"
+#include "snmp_pp/collect.h"
+#include "snmp_pp/reentrant.h"
+
+// include sockets header files
+// for Windows16 and Windows32 include Winsock
+// otherwise assume UNIX
+#if defined (CPU) && CPU == PPC603
+#include <inetLib.h>
+#include <hostLib.h>
+#endif
+
+#ifdef __unix
+#if !defined(_AIX) && !defined(__QNX_NEUTRINO)
+#include <unistd.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#if defined _AIX
+#include <strings.h> // This is needed for FD_SET, bzero
+#endif
+
+#if !defined __CYGWIN32__ && !defined __hpux && !defined linux && !defined _AIX
+extern int h_errno; // defined in WinSock header, but not for UX?!
+#endif
+#endif // __unix
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//----[ macros ]-------------------------------------------------------
+#define ADDRBUF 50 // worst case of address lens
+#define OUTBUFF 80 // worst case of output lens
+
+#define IPLEN 4
+#define UDPIPLEN 6
+#define IP6LEN_NO_SCOPE 16
+#define IP6LEN_WITH_SCOPE 20
+#define UDPIP6LEN_NO_SCOPE 18
+#define UDPIP6LEN_WITH_SCOPE 22
+#define IS_IP6LEN(n) ((n==16) || (n==20))
+#define IS_UDPIP6LEN(n) ((n==18) || (n==22))
+#define IPXLEN 10
+#define IPXSOCKLEN 12
+#define MACLEN 6
+#define MAX_FRIENDLY_NAME 80
+#define HASH0 19
+#define HASH1 13
+#define HASH2 7
+
+//---[ forward declarations ]-----------------------------------------
+class GenAddress;
+
+//----[ Address class ]-----------------------------------------------
+
+/**
+ * Base class of all Address classes.
+ */
+class DLLOPT Address : public SnmpSyntax
+{
+ friend class GenAddress;
+
+ public:
+ //----[ enumerated types for address types ]---------------------------
+ /**
+ * Type returned by Address::get_type().
+ */
+ enum addr_type
+ {
+ type_ip, ///< IpAddress (IPv4 or IPv6)
+ type_ipx, ///< IpxAddress
+ type_udp, ///< UdpAddress (IPv4 or IPv6)
+ type_ipxsock, ///< IpxSockAddress
+ type_mac, ///< MacAddress
+ type_invalid ///< Used by GenAddress::get_type() if address is not valid
+ };
+
+ /**
+ * Type returned by IpAddress::get_ip_version() and
+ * UdpAddress::get_ip_version().
+ */
+ enum version_type
+ {
+ version_ipv4, ///< IPv4
+ version_ipv6 ///< IPv6
+ };
+
+ /**
+ * Default constructor, clears the buffer and sets valid flag to false.
+ */
+ Address();
+
+ /**
+ * Allow destruction of derived classes.
+ */
+ virtual ~Address() {};
+
+ /// overloaded equivlence operator, are two addresses equal?
+ DLLOPT friend int operator==(const Address &lhs,const Address &rhs);
+
+ /// overloaded not equivlence operator, are two addresses not equal?
+ DLLOPT friend int operator!=(const Address &lhs, const Address &rhs)
+ { return !(lhs == rhs); };
+
+ /// overloaded > operator, is a1 > a2
+ DLLOPT friend int operator>(const Address &lhs,const Address &rhs);
+
+ /// overloaded >= operator, is a1 >= a2
+ DLLOPT friend int operator>=(const Address &lhs,const Address &rhs)
+ { if ((lhs > rhs) || (lhs == rhs)) return true; return false; };
+
+ /// overloaded < operator, is a1 < a2
+ DLLOPT friend int operator<(const Address &lhs,const Address &rhs);
+
+ /// overloaded <= operator, is a1 <= a2
+ DLLOPT friend int operator<=(const Address &lhs, const Address &rhs)
+ { if ((lhs < rhs) || (lhs == rhs)) return true; return false; };
+
+ /// equivlence operator overloaded, are an address and a string equal?
+ DLLOPT friend int operator==(const Address &lhs,const char *rhs);
+
+ /// overloaded not equivlence operator, are an address and string not equal?
+ DLLOPT friend int operator!=(const Address &lhs,const char *rhs)
+ { return !(lhs == rhs); };
+
+ /// overloaded < , is an address greater than a string?
+ DLLOPT friend int operator>(const Address &lhs,const char *rhs);
+
+ /// overloaded >=, is an address greater than or equal to a string?
+ DLLOPT friend int operator>=(const Address &lhs,const char *rhs);
+
+ /// overloaded < , is an address less than a string?
+ DLLOPT friend int operator<(const Address &lhs,const char *rhs);
+
+ /// overloaded <=, is an address less than or equal to a string?
+ DLLOPT friend int operator<=(const Address &lhs,const char *rhs);
+
+ /**
+ * Overloaded operator for streaming output.
+ *
+ * @return String containing the numerical address
+ */
+ virtual operator const char *() const = 0;
+
+ /**
+ * Return if the object contains a valid address.
+ *
+ * @return true if the object is valid
+ */
+ virtual bool valid() const { return valid_flag; };
+
+ /**
+ * Return the space needed for serialization.
+ */
+ virtual int get_asn1_length() const = 0;
+
+ /**
+ * Access as an array (read and write).
+ * @note Only pass in values between 0 and get_length().
+ *
+ * @param position - pos to return
+ * @return reference to the byte at the given position
+ */
+ unsigned char& operator[](const int position)
+ { addr_changed = true; valid_flag = true;
+ return (position < ADDRBUF) ? address_buffer[position]
+ : address_buffer[0]; };
+
+ /**
+ * Access as an array (read only).
+ * @note Only pass in values between 0 and get_length().
+ *
+ * @param position - pos to return
+ * @return the byte at the given position
+ */
+ unsigned char operator[](const int position) const
+ { return (position < ADDRBUF) ? address_buffer[ position] : 0; }
+
+
+ /**
+ * Get the length of the binary address (accessible through operator[]).
+ */
+ virtual int get_length() const = 0;
+
+ /**
+ * Get the type of the address.
+ * @see Address::addr_type
+ */
+ virtual addr_type get_type() const = 0;
+
+ /**
+ * Overloaded assignment operator.
+ */
+ virtual SnmpSyntax& operator=(const SnmpSyntax &val) = 0;
+
+ // return a hash key
+ virtual unsigned int hashFunction() const { return 0;};
+
+ protected:
+ SNMP_PP_MUTABLE bool addr_changed;
+ bool valid_flag;
+ unsigned char address_buffer[ADDRBUF]; // internal representation
+
+ // parse the address string
+ // redefined for each specific address subclass
+ virtual bool parse_address(const char * inaddr) = 0;
+
+ // format the output
+ // redefined for each specific address subclass
+ virtual void format_output() const = 0;
+
+ /**
+ * Trim of whitespaces at the start and the end of the string.
+ *
+ * @param ptr - string to trim
+ */
+ void trim_white_space(char * ptr);
+
+ /**
+ * Is this a GenAddress object.
+ */
+ virtual bool is_gen_address() const { return false; };
+
+ /**
+ * Reset the object.
+ */
+ void clear();
+
+#if !defined HAVE_GETHOSTBYNAME_R || !defined HAVE_GETHOSTBYADDR_R || !defined HAVE_REENTRANT_GETHOSTBYNAME || !defined HAVE_REENTRANT_GETHOSTBYADDR
+#ifdef _THREADS
+ static SnmpSynchronized syscall_mutex;
+#endif
+#endif
+
+};
+
+
+//-----------------------------------------------------------------------
+//---------[ IP Address Class ]------------------------------------------
+//-----------------------------------------------------------------------
+class DLLOPT IpAddress : public Address
+{
+ public:
+ /**
+ * Construct an empty invalid IP address.
+ */
+ IpAddress();
+
+ /**
+ * Construct an IP address from a string.
+ *
+ * The following formats can be used:
+ * - hostname with or without domain ("www.agentpp.com", "printsrv")
+ * - Numerical IPv4 address ("192.168.17.1")
+ * - Numerical IPv6 address ("abcd:1234::a:b:1", "::abcd:1")
+ * - Numerical IPv6 address with scope ("abcd:1234::a:b:1%3", "::abcd:1%1")
+ *
+ * @param inaddr - Hostname or IP address
+ */
+ IpAddress(const char *inaddr);
+
+ /**
+ * Construct an IP address from another IP address.
+ *
+ * @param ipaddr - address to copy
+ */
+ IpAddress(const IpAddress &ipaddr);
+
+ /**
+ * Construct an IP address from a GenAddress.
+ *
+ * @param genaddr - address to copy
+ */
+ IpAddress(const GenAddress &genaddr);
+
+ /**
+ * Destructor (ensure that SnmpSyntax::~SnmpSyntax() is overridden).
+ */
+ ~IpAddress() {};
+
+ /**
+ * Map other SnmpSyntax objects to IpAddress.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ /**
+ * Overloaded assignment operator for other IP addresses.
+ */
+ IpAddress& operator=(const IpAddress &ipaddress);
+
+ /**
+ * Overloaded assignment operator for strings.
+ */
+ IpAddress& operator=(const char *inaddr);
+
+ /**
+ * Clone this object.
+ *
+ * @return Pointer to the newly created object (allocated through new).
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *) new IpAddress(*this); };
+
+ /**
+ * Return the friendly name. Does a reverse DNS lookup for the IP address.
+ *
+ * @param status - The errno value for the lookup
+ *
+ * @return the friendly name or a zero length string (no null pointer)
+ */
+ char *friendly_name(int &status);
+
+ /**
+ * Get a printable ASCII value of the address.
+ *
+ * @return String containing the numerical address
+ */
+ virtual const char *get_printable() const
+ { if (addr_changed) format_output(); return output_buffer; };
+
+ /**
+ * Overloaded operator for streaming output.
+ *
+ * @return String containing the numerical address
+ */
+ virtual operator const char *() const
+ { if (addr_changed) format_output(); return output_buffer; };
+
+ /**
+ * Logically AND the address with the param.
+ *
+ * @param ipaddr - address to use as mask
+ */
+ void mask(const IpAddress &ipaddr);
+
+
+ /**
+ * Get the count of matching bits from the left.
+ *
+ * @param match_ip - address to match with
+ */
+ int get_match_bits(const IpAddress match_ip) const;
+
+ /**
+ * Get the length of the binary address (accessible through operator[]).
+ */
+ virtual int get_length() const
+ { return (ip_version == version_ipv4) ? IPLEN :
+ (have_ipv6_scope ? IP6LEN_WITH_SCOPE : IP6LEN_NO_SCOPE); };
+
+ /**
+ * Return the type of the address.
+ * @see Address::addr_type
+ * @return Always Address:type_ip
+ */
+ virtual addr_type get_type() const { return type_ip; };
+
+ /**
+ * Return the syntax.
+ *
+ * @return This method always returns sNMP_SYNTAX_IPADDR.
+ */
+ virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_IPADDR; };
+
+ /**
+ * Return the space needed for serialization.
+ */
+ virtual int get_asn1_length() const
+ { return get_length() + 2; };
+
+ /**
+ * Return the IP version of the address.
+ *
+ * @return one of Address::version_type
+ */
+ virtual version_type get_ip_version() const { return ip_version; };
+
+ /**
+ * Map a IPv4 address to a IPv6 address.
+ *
+ * @return - TRUE if no error occured.
+ */
+ virtual int map_to_ipv6();
+
+ /**
+ * Get the IPv6 scope
+ */
+ virtual unsigned int get_scope() const;
+
+ /**
+ * Set the IPv6 scope
+ */
+ virtual bool set_scope(const unsigned int scope);
+
+ /**
+ * Reset the object.
+ */
+ void clear();
+
+ bool has_ipv6_scope() const
+ { return (ip_version == version_ipv6) && have_ipv6_scope; };
+
+ protected:
+ SNMP_PP_MUTABLE char output_buffer[OUTBUFF]; // output buffer
+
+ // friendly name storage
+ char iv_friendly_name[MAX_FRIENDLY_NAME];
+ int iv_friendly_name_status;
+
+ // redefined parse address
+ // specific to IP addresses
+ virtual bool parse_address(const char *inaddr);
+
+ // redefined format output
+ // specific to IP addresses
+ virtual void format_output() const;
+
+ // parse a dotted string
+ int parse_dotted_ipstring(const char *inaddr);
+
+ // parse a coloned string
+ int parse_coloned_ipstring(const char *inaddr);
+
+ // using the currently defined address, do a DNS
+ // and try to fill up the name
+ int addr_to_friendly();
+
+ // support both ipv4 and ipv6 addresses
+ version_type ip_version;
+
+ bool have_ipv6_scope;
+};
+
+//------------------------------------------------------------------------
+//---------[ UDP Address Class ]------------------------------------------
+//------------------------------------------------------------------------
+class DLLOPT UdpAddress : public IpAddress
+{
+ public:
+ /**
+ * Construct an empty invalid UDP address.
+ */
+ UdpAddress();
+
+ /**
+ * Construct an UDP address from a string.
+ *
+ * The following formats can be used additional to those recognized by
+ * IpAdress:
+ * - Port added to IPv4 address with '/' or ':'
+ * ("192.168.17.1:161", "192.168.17.1/161", "printsrv/161")
+ * - Port added to IPv6 address with '/' or using '[...]:'
+ * ("::1/162", "[::1]/162", "[::1]:162")
+ *
+ * @param inaddr - Hostname or IP address
+ */
+ UdpAddress(const char *inaddr);
+
+ /**
+ * Construct an UDP address from another UDP address.
+ *
+ * @param udpaddr - address to copy
+ */
+ UdpAddress(const UdpAddress &udpaddr);
+
+ /**
+ * Construct an UDP address from a GenAddress.
+ *
+ * @param genaddr - address to copy
+ */
+ UdpAddress(const GenAddress &genaddr);
+
+ /**
+ * Construct an UDP address from a IP address.
+ * The port will be set to 0.
+ *
+ * @param ipaddr - address to copy
+ */
+ UdpAddress(const IpAddress &ipaddr);
+
+ /**
+ * Destructor (ensure that SnmpSyntax::~SnmpSyntax() is overridden).
+ */
+ ~UdpAddress() {};
+
+ /**
+ * Map other SnmpSyntax objects to UdpAddress.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ /**
+ * Overloaded assignment operator for UdpAddress.
+ */
+ UdpAddress& operator=(const UdpAddress &udpaddr);
+
+ /**
+ * Overloaded assignment operator for IpAddress.
+ */
+ UdpAddress& operator=(const IpAddress &ipaddr);
+
+ /**
+ * Overloaded assignment operator for strings.
+ */
+ UdpAddress& operator=(const char *inaddr);
+
+ /**
+ * Return the syntax.
+ *
+ * @return This method always returns sNMP_SYNTAX_OCTETS.
+ */
+ SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OCTETS; };
+
+ /**
+ * Return the space needed for serialization.
+ */
+ virtual int get_asn1_length() const
+ { return get_length() + 2; };
+
+ /**
+ * Clone this object.
+ *
+ * @return Pointer to the newly created object (allocated through new).
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *) new UdpAddress(*this); };
+
+ /**
+ * Get a printable ASCII value of the address.
+ *
+ * @return String containing the numerical address
+ */
+ virtual const char *get_printable() const
+ { if (addr_changed) format_output(); return output_buffer; };
+
+ /**
+ * Overloaded operator for streaming output.
+ *
+ * @return String containing the numerical address
+ */
+ virtual operator const char *() const
+ { if (addr_changed) format_output(); return output_buffer; };
+
+ /**
+ * Set the port number.
+ *
+ * @note If the object is not valid(), the port may not be set.
+ */
+ void set_port(const unsigned short p);
+
+ /**
+ * Get the port number.
+ *
+ * @return The port number, or 0 is the object is not valid.
+ */
+ unsigned short get_port() const;
+
+ /**
+ * Get the length of the binary address (accessible through operator[]).
+ */
+ virtual int get_length() const
+ { return (ip_version == version_ipv4) ? UDPIPLEN :
+ (have_ipv6_scope ? UDPIP6LEN_WITH_SCOPE : UDPIP6LEN_NO_SCOPE);};
+
+ /**
+ * Return the type of the address.
+ * @see Address::addr_type
+ * @return Always Address:type_udp
+ */
+ virtual addr_type get_type() const { return type_udp; };
+
+ /**
+ * Map a IPv4 UDP address to a IPv6 UDP address.
+ *
+ * @return - TRUE if no error occured.
+ */
+ virtual int map_to_ipv6();
+
+ /**
+ * Reset the object.
+ */
+ void clear()
+ { Address::clear(); memset(output_buffer, 0, sizeof(output_buffer)); };
+
+ /**
+ * Set the IPv6 scope
+ */
+ virtual bool set_scope(const unsigned int scope);
+
+ protected:
+ SNMP_PP_MUTABLE char output_buffer[OUTBUFF]; // output buffer
+ char sep; // separator
+
+ // redefined parse address
+ // specific to IP addresses
+ virtual bool parse_address(const char *inaddr);
+
+ // redefined format output
+ // specific to IP addresses
+ virtual void format_output() const;
+};
+
+#ifdef _MAC_ADDRESS
+//-------------------------------------------------------------------------
+//---------[ 802.3 MAC Address Class ]-------------------------------------
+//-------------------------------------------------------------------------
+class DLLOPT MacAddress : public Address {
+
+public:
+ // constructor, no arguments
+ MacAddress();
+
+ // constructor with a string argument
+ MacAddress(const char *inaddr);
+
+ // constructor with another MAC object
+ MacAddress(const MacAddress &macaddr);
+
+ // construct a MacAddress with a GenAddress
+ MacAddress(const GenAddress &genaddr);
+
+ // destructor
+ ~MacAddress() {};
+
+ /**
+ * Return the syntax.
+ *
+ * @return This method always returns sNMP_SYNTAX_OCTETS.
+ */
+ SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OCTETS; };
+
+ /**
+ * Return the space needed for serialization.
+ */
+ virtual int get_asn1_length() const { return MACLEN + 2; };
+
+ /**
+ * Map other SnmpSyntax objects to MacAddress.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ // assignment to another IpAddress object overloaded
+ MacAddress& operator=(const MacAddress &macaddress);
+
+ /**
+ * Clone this object.
+ *
+ * @return Pointer to the newly created object (allocated through new).
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *) new MacAddress(*this); };
+
+ /**
+ * Get a printable ASCII value of the address.
+ *
+ * @return String containing the numerical address
+ */
+ virtual const char *get_printable() const
+ { if (addr_changed) format_output(); return output_buffer; };
+
+ /**
+ * Overloaded operator for streaming output.
+ *
+ * @return String containing the numerical address
+ */
+ virtual operator const char *() const
+ { if (addr_changed) format_output(); return output_buffer; };
+
+ /**
+ * Get the length of the binary address (accessible through operator[]).
+ */
+ virtual int get_length() const { return MACLEN; };
+
+ /**
+ * Return the type of the address.
+ * @see Address::addr_type
+ * @return Always Address:type_mac
+ */
+ virtual addr_type get_type() const { return type_mac; };
+
+ // return a hash key
+ unsigned int hashFunction() const;
+
+ /**
+ * Reset the object.
+ */
+ void clear()
+ { Address::clear(); memset(output_buffer, 0, sizeof(output_buffer)); };
+
+ protected:
+ SNMP_PP_MUTABLE char output_buffer[OUTBUFF]; // output buffer
+
+ // redefined parse address for macs
+ virtual bool parse_address(const char *inaddr);
+
+ // redefined format output for MACs
+ virtual void format_output() const;
+};
+#endif // _MAC_ADDRESS
+
+#ifdef _IPX_ADDRESS
+//------------------------------------------------------------------------
+//---------[ IPX Address Class ]------------------------------------------
+//------------------------------------------------------------------------
+class DLLOPT IpxAddress : public Address {
+
+public:
+ // constructor no args
+ IpxAddress();
+
+ // constructor with a string arg
+ IpxAddress(const char *inaddr);
+
+ // constructor with another ipx object
+ IpxAddress(const IpxAddress &ipxaddr);
+
+ // construct with a GenAddress
+ IpxAddress(const GenAddress &genaddr);
+
+ // destructor
+ ~IpxAddress() {};
+
+ /**
+ * Return the syntax.
+ *
+ * @return This method always returns sNMP_SYNTAX_OCTETS.
+ */
+ virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OCTETS; };
+
+ /**
+ * Return the space needed for serialization.
+ */
+ virtual int get_asn1_length() const { return IPXLEN + 2; };
+
+ /**
+ * Map other SnmpSyntax objects to IpxAddress.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ // assignment to another IpAddress object overloaded
+ IpxAddress& operator=(const IpxAddress &ipxaddress);
+
+#ifdef _MAC_ADDRESS
+ // get the host id portion of an ipx address
+ int get_hostid(MacAddress& mac) const;
+#endif
+
+ /**
+ * Clone this object.
+ *
+ * @return Pointer to the newly created object (allocated through new).
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *) new IpxAddress(*this); };
+
+ /**
+ * Get a printable ASCII value of the address.
+ *
+ * @return String containing the numerical address
+ */
+ virtual const char *get_printable() const
+ { if (addr_changed) format_output(); return output_buffer; };
+
+ /**
+ * Overloaded operator for streaming output.
+ *
+ * @return String containing the numerical address
+ */
+ virtual operator const char *() const
+ { if (addr_changed) format_output(); return output_buffer; };
+
+ /**
+ * Get the length of the binary address (accessible through operator[]).
+ */
+ virtual int get_length() const { return IPXLEN; };
+
+ /**
+ * Return the type of the address.
+ * @see Address::addr_type
+ * @return Always Address:type_ipx
+ */
+ virtual addr_type get_type() const { return type_ipx; };
+
+ /**
+ * Reset the object.
+ */
+ void clear()
+ { Address::clear(); memset(output_buffer, 0, sizeof(output_buffer)); };
+
+ protected:
+ // ipx format separator
+ char separator;
+ SNMP_PP_MUTABLE char output_buffer[OUTBUFF]; // output buffer
+
+ // redefined parse address for ipx strings
+ virtual bool parse_address(const char *inaddr);
+
+ // redefined format output for ipx strings
+ // uses same separator as when constructed
+ virtual void format_output() const;
+
+};
+
+
+
+//------------------------------------------------------------------------
+//---------[ IpxSock Address Class ]--------------------------------------
+//------------------------------------------------------------------------
+class DLLOPT IpxSockAddress : public IpxAddress {
+
+public:
+ // constructor, no args
+ IpxSockAddress();
+
+ // constructor with a dotted string
+ IpxSockAddress(const char *inaddr);
+
+ // construct an Udp address with another Udp address
+ IpxSockAddress(const IpxSockAddress &ipxaddr);
+
+ //constructor with a GenAddress
+ IpxSockAddress(const GenAddress &genaddr);
+
+ //constructor with a IpxAddress
+ // default socket # is 0
+ IpxSockAddress(const IpxAddress &ipxaddr);
+
+ // destructor
+ ~IpxSockAddress() {};
+
+ // syntax type
+ //virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OCTETS; };
+
+ /**
+ * Return the space needed for serialization.
+ */
+ virtual int get_asn1_length() const { return IPXSOCKLEN + 2; };
+
+ /**
+ * Map other SnmpSyntax objects to IpxSockAddress.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ // assignment to another IpAddress object overloaded
+ IpxSockAddress& operator=(const IpxSockAddress &ipxaddr);
+
+ /**
+ * Clone this object.
+ *
+ * @return Pointer to the newly created object (allocated through new).
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *)new IpxSockAddress(*this); };
+
+ // set the socket number
+ void set_socket(const unsigned short s);
+
+ // get the socket number
+ unsigned short get_socket() const;
+
+ /**
+ * Get a printable ASCII value of the address.
+ *
+ * @return String containing the numerical address
+ */
+ virtual const char *get_printable() const
+ { if (addr_changed) format_output(); return output_buffer; };
+
+ /**
+ * Overloaded operator for streaming output.
+ *
+ * @return String containing the numerical address
+ */
+ virtual operator const char *() const
+ { if (addr_changed) format_output(); return output_buffer; };
+
+ /**
+ * Get the length of the binary address (accessible through operator[]).
+ */
+ virtual int get_length() const { return IPXSOCKLEN; };
+
+ /**
+ * Return the type of the address.
+ * @see Address::addr_type
+ * @return Always Address:type_ipxsock
+ */
+ virtual addr_type get_type() const { return type_ipxsock; };
+
+ /**
+ * Reset the object.
+ */
+ void clear()
+ { Address::clear(); memset(output_buffer, 0, sizeof(output_buffer)); };
+
+ protected:
+ SNMP_PP_MUTABLE char output_buffer[OUTBUFF]; // output buffer
+
+ // redefined parse address for ipx strings
+ virtual bool parse_address(const char *inaddr);
+
+ // redefined format output
+ // specific to IP addresses
+ virtual void format_output() const;
+};
+#endif // _IPX_ADDRESS
+
+
+
+
+//-------------------------------------------------------------------------
+//--------[ Generic Address ]----------------------------------------------
+//-------------------------------------------------------------------------
+class DLLOPT GenAddress : public Address
+{
+ public:
+ /**
+ * Construct an empty invalid generic address object.
+ */
+ GenAddress();
+
+ /**
+ * Construct a generic address from a string.
+ *
+ * To optimize the speed of the parsing method, use_type can be used
+ * to indicate that the address string is of the specified type.
+ *
+ * @param addr - address string
+ * @param use_type - if this value is set, the input string is only
+ * parsed for the given type
+ */
+ GenAddress(const char *addr,
+ const Address::addr_type use_type = Address::type_invalid);
+
+ /**
+ * Construct a generic address from an Address object.
+ *
+ * @param addr - Any address object
+ */
+ GenAddress(const Address &addr);
+
+ /**
+ * Construct a generic address from another generic address object.
+ *
+ * @param addr - Generic address object to copy
+ */
+ GenAddress(const GenAddress &addr);
+
+ /**
+ * Destructor, free memory.
+ */
+ ~GenAddress() { if (address) delete address; };
+
+ /**
+ * Return the syntax.
+ *
+ * @return This method returns sNMP_SYNTAX_IPADDR, sNMP_SYNTAX_OCTETS
+ * or sNMP_SYNTAX_NULL if the generic address does not have
+ * an address object.
+ */
+ SmiUINT32 get_syntax() const
+ { return address ? address->get_syntax() : sNMP_SYNTAX_NULL; };
+
+ /**
+ * Return the space needed for serialization.
+ */
+ virtual int get_asn1_length() const
+ { return address ? address->get_asn1_length() : 2; };
+
+ /**
+ * Clone this object.
+ *
+ * @return Pointer to the newly created object (allocated through new).
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *)new GenAddress(*this); };
+
+ /**
+ * Overloaded assignment operator for a GenAddress.
+ */
+ GenAddress& operator=(const GenAddress &addr);
+
+ /**
+ * Overloaded assignment operator for a Address.
+ */
+ GenAddress& operator=(const Address &addr);
+
+ /**
+ * Map other SnmpSyntax objects to GenAddress.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ /**
+ * Get a printable ASCII value of the address.
+ *
+ * @return String containing the numerical address
+ */
+ virtual const char *get_printable() const
+ { return (address) ? address->get_printable() : output_buffer; };
+
+ /**
+ * Overloaded operator for streaming output.
+ *
+ * @return String containing the numerical address
+ */
+ virtual operator const char *() const
+ { return address ? (const char *)*address : output_buffer; };
+
+ /**
+ * Get the length of the binary address (accessible through operator[]).
+ */
+ virtual int get_length() const
+ { return (address) ? address->get_length() : 0; };
+
+ /**
+ * Reset the object.
+ */
+ void clear() { if (address) address->clear(); };
+
+ /**
+ * Return the type of the address.
+ * @see Address::addr_type
+ * @return Type of the contained address object or Address::type_invalid
+ * if it is not valid().
+ */
+ virtual addr_type get_type() const
+ { return (valid()) ? address->get_type() : type_invalid; };
+
+ /**
+ * Access the protected address.
+ * The caller must make sure that this GenAddress object ist valid()
+ * and is of the right type (get_type()).
+ */
+ const IpAddress &cast_ipaddress() const { return (IpAddress& )*address; };
+
+ /**
+ * Access the protected address.
+ * The caller must make sure that this GenAddress object ist valid()
+ * and is of the right type (get_type()).
+ */
+ const UdpAddress &cast_udpaddress() const { return (UdpAddress&)*address; };
+
+#ifdef _MAC_ADDRESS
+ /**
+ * Access the protected address.
+ * The caller must make sure that this GenAddress object ist valid()
+ * and is of the right type (get_type()).
+ */
+ const MacAddress &cast_macaddress() const { return (MacAddress&)*address; };
+#endif
+
+#ifdef _IPX_ADDRESS
+ /**
+ * Access the protected address.
+ * The caller must make sure that this GenAddress object ist valid()
+ * and is of the right type (get_type()).
+ */
+ const IpxAddress &cast_ipxaddress() const { return (IpxAddress&)*address; };
+
+ /**
+ * Access the protected address.
+ * The caller must make sure that this GenAddress object ist valid()
+ * and is of the right type (get_type()).
+ */
+ const IpxSockAddress &cast_ipxsockaddress() const
+ { return (IpxSockAddress&)*address; };
+#endif
+
+protected:
+ // pointer to a concrete address
+ Address *address;
+ char output_buffer[1]; // output buffer
+
+ // redefined parse address for generic address
+ virtual bool parse_address(const char *addr)
+ { return parse_address(addr, Address::type_invalid); };
+
+ virtual bool parse_address(const char *addr,
+ const Address::addr_type use_type);
+
+ // format output for a generic address
+ virtual void format_output() const {};
+
+ /**
+ * Is this a GenAddress object.
+ */
+ virtual bool is_gen_address() const { return true; };
+};
+
+// create AddressCollection type
+typedef SnmpCollection <GenAddress> AddressCollection;
+typedef SnmpCollection <UdpAddress> UdpAddressCollection;
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif //_ADDRESS
--- /dev/null
+/*_############################################################################
+ _##
+ _## asn1.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+// $Id: asn1.h 1554 2009-06-28 19:50:17Z katz $
+
+#ifndef _ASN1
+#define _ASN1
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/target.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifndef EIGHTBIT_SUBIDS
+typedef unsigned long oid;
+#define MAX_SUBID 0xFFFFFFFF
+#else
+typedef unsigned char oid;
+#define MAX_SUBID 0xFF
+#endif
+
+#define MAX_OID_LEN 128 /* max subid's in an oid */
+
+// asn.1 values
+#define ASN_BOOLEAN (0x01)
+#ifndef ASN_INTEGER
+#define ASN_INTEGER (0x02)
+#endif
+#define ASN_BIT_STR (0x03)
+#define ASN_OCTET_STR (0x04)
+#ifndef ASN_NULL
+#define ASN_NULL (0x05)
+#endif
+#define ASN_OBJECT_ID (0x06)
+#ifndef ASN_SEQUENCE
+#define ASN_SEQUENCE (0x10)
+#endif
+#define ASN_SET (0x11)
+#ifndef ASN_UNIVERSAL
+#define ASN_UNIVERSAL (0x00)
+#endif
+#ifndef ASN_APPLICATION
+#define ASN_APPLICATION (0x40)
+#endif
+#ifndef ASN_CONTEXT
+#define ASN_CONTEXT (0x80)
+#endif
+#ifndef ASN_PRIVATE
+#define ASN_PRIVATE (0xC0)
+#endif
+#ifndef ASN_PRIMITIVE
+#define ASN_PRIMITIVE (0x00)
+#endif
+#ifndef ASN_CONSTRUCTOR
+#define ASN_CONSTRUCTOR (0x20)
+#endif
+#define ASN_LONG_LEN (0x80)
+#define ASN_EXTENSION_ID (0x1F)
+#define ASN_BIT8 (0x80)
+
+#define IS_CONSTRUCTOR(byte) ((byte) & ASN_CONSTRUCTOR)
+#define IS_EXTENSION_ID(byte) (((byte) & ASN_EXTENSION_ID) == ASN_EXTENSION_ID)
+
+#define ASN_UNI_PRIM (ASN_UNIVERSAL | ASN_PRIMITIVE)
+#define ASN_SEQ_CON (ASN_SEQUENCE | ASN_CONSTRUCTOR)
+
+#define ASN_MAX_NAME_LEN 128
+#define SNMP_VERSION_1 0
+#define SNMP_VERSION_2C 1
+#define SNMP_VERSION_2STERN 2
+#define SNMP_VERSION_3 3
+
+// defined types (from the SMI, RFC 1065)
+#define SMI_IPADDRESS (ASN_APPLICATION | 0)
+#define SMI_COUNTER (ASN_APPLICATION | 1)
+#define SMI_GAUGE (ASN_APPLICATION | 2)
+#define SMI_TIMETICKS (ASN_APPLICATION | 3)
+#define SMI_OPAQUE (ASN_APPLICATION | 4)
+#define SMI_NSAP (ASN_APPLICATION | 5)
+#define SMI_COUNTER64 (ASN_APPLICATION | 6)
+#define SMI_UINTEGER (ASN_APPLICATION | 7)
+
+#define GET_REQ_MSG (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x0)
+#define GETNEXT_REQ_MSG (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x1)
+#define GET_RSP_MSG (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x2)
+#define SET_REQ_MSG (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x3)
+#define TRP_REQ_MSG (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x4)
+
+#define GETBULK_REQ_MSG (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x5)
+#define INFORM_REQ_MSG (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x6)
+#define TRP2_REQ_MSG (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x7)
+#define REPORT_MSG (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x8)
+
+#define SNMP_NOSUCHOBJECT (ASN_CONTEXT | ASN_PRIMITIVE | 0x0)
+#define SNMP_NOSUCHINSTANCE (ASN_CONTEXT | ASN_PRIMITIVE | 0x1)
+#define SNMP_ENDOFMIBVIEW (ASN_CONTEXT | ASN_PRIMITIVE | 0x2)
+
+
+#ifdef _DEBUG
+#define ASNERROR(string) debugprintf(3, "ASN parse error (%s)\n", string )
+#else
+#define ASNERROR(string)
+#endif
+
+
+typedef struct sockaddr_in ipaddr;
+
+// pdu
+struct snmp_pdu {
+ int command; // pdu type
+ unsigned long reqid; // Request id
+#ifdef _SNMPv3
+ unsigned long msgid;
+ unsigned long maxsize_scopedpdu;
+#endif
+ unsigned long errstat; // Error status
+ unsigned long errindex; // Error index
+
+ // Trap information
+ oid *enterprise; // System OID
+ int enterprise_length;
+ ipaddr agent_addr; // address of object generating trap
+ int trap_type; // trap type
+ int specific_type; // specific type
+ unsigned long time; // Uptime
+
+ // vb list
+ struct variable_list *variables;
+};
+
+// vb list
+struct variable_list {
+ struct variable_list *next_variable; // NULL for last variable
+ oid *name; // Object identifier of variable
+ int name_length; // number of subid's in name
+ unsigned char type; // ASN type of variable
+ union { // value of variable
+ long *integer;
+ unsigned char *string;
+ oid *objid;
+ unsigned char *bitstring;
+ struct counter64 *counter64;
+ } val;
+ int val_len;
+};
+
+struct counter64 {
+ unsigned long high;
+ unsigned long low;
+};
+
+
+// prototypes for encoding routines
+DLLOPT unsigned char *asn_parse_int(unsigned char *data, int *datalength,
+ unsigned char *type,
+ long *intp);
+
+
+inline unsigned char *asn_parse_int(unsigned char *data, int *datalength,
+ unsigned char *type,
+ unsigned long *intp)
+{ return asn_parse_int(data, datalength, type, (long*)intp); }
+
+
+DLLOPT unsigned char *asn_parse_unsigned_int(unsigned char *data,
+ int *datalength,
+ unsigned char *type,
+ unsigned long *intp);
+inline unsigned char *asn_parse_unsigned_int(unsigned char *data,
+ int *datalength,
+ unsigned char *type,
+ long *intp)
+{ return asn_parse_unsigned_int(data, datalength, type, (unsigned long*)intp); }
+
+DLLOPT unsigned char *asn_build_int(unsigned char *data, int *datalength,
+ const unsigned char type,
+ const long *intp);
+
+inline unsigned char *asn_build_int(unsigned char *data, int *datalength,
+ const unsigned char type,
+ const unsigned long *intp)
+{ return asn_build_int(data, datalength, type, (const long*)intp); }
+
+DLLOPT unsigned char *asn_build_unsigned_int(unsigned char *data,
+ int *datalength,
+ unsigned char type,
+ unsigned long *intp);
+
+DLLOPT unsigned char *asn_parse_string(unsigned char *data, int *datalength,
+ unsigned char *type,
+ unsigned char *string,
+ int *strlength);
+
+DLLOPT unsigned char *asn_build_string(unsigned char *data, int *datalength,
+ const unsigned char type,
+ const unsigned char *string,
+ const int strlength);
+
+DLLOPT unsigned char *asn_parse_header(unsigned char *data, int *datalength,
+ unsigned char *type);
+
+DLLOPT unsigned char *asn_build_header(unsigned char *data, int *datalength,
+ unsigned char type, int length);
+
+DLLOPT unsigned char *asn_build_sequence(unsigned char *data,
+ int *datalength,
+ unsigned char type,
+ int length);
+
+DLLOPT unsigned char *asn_parse_length(unsigned char *data,
+ unsigned long *length);
+
+DLLOPT unsigned char *asn_build_length(unsigned char *data, int *datalength,
+ int length);
+
+DLLOPT unsigned char *asn_parse_objid(unsigned char *data, int *datalength,
+ unsigned char *type,
+ oid *objid, int *objidlength);
+
+DLLOPT unsigned char *asn_build_objid(unsigned char *data, int *datalength,
+ unsigned char type,
+ oid *objid, int objidlength);
+
+DLLOPT unsigned char *asn_parse_null(unsigned char *data, int *datalength,
+ unsigned char *type);
+
+DLLOPT unsigned char *asn_build_null(unsigned char *data,int *datalength,
+ unsigned char type);
+
+DLLOPT unsigned char *asn_parse_bitstring(unsigned char *data, int *datalength,
+ unsigned char *type,
+ unsigned char *string,
+ int *strlength);
+
+DLLOPT unsigned char *asn_build_bitstring(unsigned char *data, int *datalength,
+ unsigned char type,
+ unsigned char *string,
+ int strlength);
+
+DLLOPT unsigned char *asn_parse_unsigned_int64(unsigned char *data,
+ int *datalength,
+ unsigned char *type,
+ struct counter64 *cp);
+
+DLLOPT unsigned char *asn_build_unsigned_int64(unsigned char *data,
+ int *datalength,
+ unsigned char type,
+ struct counter64 *cp);
+
+DLLOPT struct snmp_pdu *snmp_pdu_create(int command);
+
+DLLOPT void snmp_free_pdu(struct snmp_pdu *pdu);
+
+DLLOPT int snmp_build(struct snmp_pdu *pdu,
+ unsigned char *packet,
+ int *out_length,
+ const long version,
+ const unsigned char* community, const int community_len);
+
+DLLOPT void snmp_add_var(struct snmp_pdu *pdu,
+ oid *name, int name_length,
+ SmiVALUE *smival);
+
+DLLOPT int snmp_parse(struct snmp_pdu *pdu,
+ unsigned char *data, int data_length,
+ unsigned char *community_name, int &community_len,
+ snmp_version &version);
+
+DLLOPT unsigned char *build_vb(struct snmp_pdu *pdu,
+ unsigned char *buf, int *buf_len);
+
+DLLOPT unsigned char *build_data_pdu(struct snmp_pdu *pdu,
+ unsigned char *buf, int *buf_len,
+ unsigned char *vb_buf, int vb_buf_len);
+
+DLLOPT unsigned char *snmp_build_var_op(unsigned char *data,
+ oid * var_name, int *var_name_len,
+ unsigned char var_val_type,
+ int var_val_len,
+ unsigned char *var_val,
+ int *listlength);
+
+DLLOPT unsigned char *snmp_parse_var_op(unsigned char *data,
+ oid *var_name, int *var_name_len,
+ unsigned char *var_val_type,
+ int *var_val_len,
+ unsigned char **var_val,
+ int *listlength);
+
+DLLOPT int snmp_parse_data_pdu(struct snmp_pdu *pdu,
+ unsigned char *&data, int &length);
+
+DLLOPT int snmp_parse_vb(struct snmp_pdu *pdu,
+ unsigned char *&data, int &data_len);
+
+DLLOPT void clear_pdu(struct snmp_pdu *pdu, bool clear_all = false);
+
+/**
+ * Encode the given values for the HeaderData into the buffer.
+ * <pre>
+ * HeaderData ::= SEQUENCE {
+ * msgID INTEGER (0..2147483647),
+ * msgMaxSize INTEGER (484..2147483647),
+ * msgFlags OCTET STRING (SIZE(1)),
+ * msgSecurityModel INTEGER (0..2147483647)
+ * }
+ * </pre>
+ * @param outBuf - The buffer
+ * @param maxLength - IN: length of the buffer
+ * OUT: free bytes left in the buffer
+ * @param msgID - The message ID
+ * @param maxMessageSize - The maximum size of a SNMPv3 message
+ * @param msgFlags - The message Flags
+ * @param securityModel - The security model
+ *
+ * @return - Pointer to the first free byte in the buffer or
+ * NULL if an error occured
+ */
+DLLOPT unsigned char *asn1_build_header_data(unsigned char *outBuf,
+ int *maxLength,
+ long msgID,
+ long maxMessageSize,
+ unsigned char msgFlags,
+ long securityModel);
+
+/**
+ * Parse the filled HeaderData of a SNMPv3 message and return
+ * the encoded values.
+ * <pre>
+ * HeaderData ::= SEQUENCE {
+ * msgID INTEGER (0..2147483647),
+ * msgMaxSize INTEGER (484..2147483647),
+ * msgFlags OCTET STRING (SIZE(1)),
+ * msgSecurityModel INTEGER (0..2147483647)
+ * }
+ * </pre>
+ *
+ * @param buf - The buffer to parse
+ * @param buf_len - IN: The length of the buffer
+ * OUT: The number of bytes after this object
+ * int the buffer
+ * @param msg_id - OUT: The message id
+ * @param msg_max_size - OUT: THe maximum message size of the sender
+ * @param msg_flags - OUT: The message flags
+ * @param msg_security_model - OUT: The security model used to build this
+ * message
+ *
+ * @return - Returns a pointer to the first byte past the end of
+ * the object HeaderData (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+DLLOPT unsigned char *asn1_parse_header_data(unsigned char *buf, int *buf_len,
+ long *msg_id, long *msg_max_size,
+ unsigned char *msg_flags,
+ long *msg_security_model);
+
+/**
+ * Parse the ScopedPDU and return the encoded values.
+ * <pre>
+ * ScopedPDU ::= SEQUENCE {
+ * contextEngineID OCTET STRING,
+ * contextName OCTET STRING,
+ * data ANY -- e.g., PDUs as defined in RFC 1905
+ * }
+ * </pre>
+ *
+ * @param scoped_pdu - The buffer to parse
+ * @param scoped_pdu_len - IN: The length of the buffer
+ * OUT: The number of bytes after this object
+ * int the buffer
+ * @param context_engine_id - OUT: The parsed contextEngineID
+ * @param context_engine_id_len - OUT: The length of the contextEngineID
+ * @param context_name - OUT: The parsed contextName
+ * @param context_name_len - OUT: The length of the contextName
+ *
+ * @return - Pointer to the data object of the scopedPDU or
+ * NULL on any error.
+ */
+DLLOPT unsigned char *asn1_parse_scoped_pdu(
+ unsigned char *scoped_pdu, int *scoped_pdu_len,
+ unsigned char *context_engine_id, int *context_engine_id_len,
+ unsigned char *context_name, int *context_name_len );
+
+/**
+ * Encode the given values for the scopedPDU into the buffer.
+ * <pre>
+ * ScopedPDU ::= SEQUENCE {
+ * contextEngineID OCTET STRING
+ * contextName OCTET STRING
+ * data ANY -- PDU
+ * }
+ * </pre>
+ * param outBuf - The buffer
+ * param max_len - IN: length of the buffer
+ * OUT: free bytes left in the buffer
+ * param contextEngineID - The contextEngineID
+ * param contextEngineIDLength - The length of the contextEngineID
+ * param contextName - The contextName
+ * param contextNameLength - The length of the contextName
+ * param data - The already encoded data
+ * param dataLength - The length of the data
+ *
+ * @return - Pointer to the first free byte in the buffer or
+ * NULL if an error occured
+ */
+DLLOPT unsigned char *asn1_build_scoped_pdu(
+ unsigned char *outBuf, int *max_len,
+ unsigned char *contextEngineID, long contextEngineIDLength,
+ unsigned char *contextName, long contextNameLength,
+ unsigned char *data, long dataLength);
+
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _ASN1
--- /dev/null
+/*_############################################################################
+ _##
+ _## auth_priv.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+// $Id: auth_priv.h 345 2008-10-29 20:14:40Z katz $
+
+#ifndef _AUTH_PRIV_
+#define _AUTH_PRIV_
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+
+#include "snmp_pp/usm_v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define SNMPv3_USM_MAX_KEY_LEN 32
+
+/* Accept Messages with auth/priv param fields up to this length */
+#define SNMPv3_AP_MAXLENGTH_AUTHPARAM 128
+#define SNMPv3_AP_MAXLENGTH_PRIVPARAM 128
+
+
+#define SNMPv3_AP_OUTPUT_LENGTH_MD5 16
+#define SNMPv3_AP_OUTPUT_LENGTH_SHA 20
+
+class OctetStr;
+
+/**
+ * Abstract class for auth modules.
+ *
+ * This class has to be subclassed to add new authentication
+ * protocols.
+ *
+ */
+class DLLOPT Auth
+{
+public:
+
+ virtual ~Auth() {};
+
+ /**
+ * Generate the localized key for the given password and engine id.
+ *
+ * @param password - the password
+ * @param password_len - the length of the password
+ * @param engine_id - pointer to snmpEngineID
+ * @param engine_id_len - length of snmpEngineID
+ * @param key - pointer to an empty buffer that will be filled
+ * with generated key
+ * @param key_len - IN: length of the buffer
+ * OUT: length of the key
+ *
+ * @return SNMPv3_USM_OK on success
+ */
+ virtual int password_to_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len) = 0;
+
+ /**
+ * Generate a hash value for the given data.
+ *
+ * @param data - the data
+ * @param data_len - the length of the data
+ * @param digest - pointer to the generated digest
+ *
+ * @return SNMPv3_USM_OK on success
+ */
+ virtual int hash(const unsigned char *data,
+ const unsigned int data_len,
+ unsigned char *digest) const = 0;
+
+ /**
+ * Authenticate an outgoing message.
+ *
+ * This method fills the authentication parameters field of the
+ * given message. The param auth_par_ptr is pointing inside the
+ * message buffer and must be zeroed before the authentication value
+ * is computed.
+ *
+ * @param key - pointer to the (fixed length) key
+ * @param msg - pointer to the whole message
+ * @param msg_len - the length of the message
+ * @param auth_par_ptr - pointer to the auth field inside the msg buffer
+ *
+ * @return SNMPv3_USM_OK on success and
+ * SNMPv3_USM_ERROR for unexpected errors.
+ */
+ virtual int auth_out_msg(const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr) = 0;
+
+
+ /**
+ * Authenticate an incoming message.
+ *
+ * This method checks if the value in the authentication parameters
+ * field of the message is valid.
+ *
+ * The following procedure is used to verify the authenitcation value
+ * - copy the authentication value to a temp buffer
+ * - zero the auth field
+ * - recalculate the authenthication value
+ * - compare the two authentcation values
+ * - write back the received authentication value if values differ
+ *
+ * @param key - pointer to the (fixed length) key
+ * @param msg - pointer to the whole message
+ * @param msg_len - the length of the message
+ * @param auth_par_ptr - pointer to the auth field inside the msg buffer
+ * @param auth_par_len - Length of the received auth field
+ *
+ * @return SNMPv3_USM_OK if the msg is valid,
+ * SNMPv3_USM_AUTHENTICATION_FAILURE if not and
+ * SNMPv3_USM_ERROR for unexpected errors.
+ */
+ virtual int auth_inc_msg(const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr,
+ const int auth_par_len) = 0;
+
+ /**
+ * Get the unique id of the authentication protocol.
+ */
+ virtual int get_id() const = 0;
+
+
+ /**
+ * Get the unique identifier string of the authentication protocol.
+ */
+ virtual const char *get_id_string() const = 0;
+
+ /**
+ * Set the pointer to the salt that should be used.
+ */
+ virtual void set_salt(pp_uint64 *new_salt) { salt = new_salt; };
+
+ /**
+ * Get the maximum length that is needed for the
+ * msgAuthenticationParameters field.
+ */
+ virtual int get_auth_params_len() const = 0;
+
+ /**
+ * Get length of a hash output.
+ */
+ virtual int get_hash_len() const = 0;
+
+ protected:
+ pp_uint64 *salt;
+};
+
+
+/**
+ * Abstract class for priv modules
+ *
+ * This class has to be subclassed to add new privacy
+ * protocols.
+ *
+ */
+class DLLOPT Priv
+{
+public:
+ virtual ~Priv() {};
+
+ /**
+ * Encrypt the buffer with the given key.
+ *
+ * This method fills the privacy parameters field of the given
+ * message.
+ *
+ * @param key - pointer to the encryption key
+ * @param key_len - length of encryption key
+ * @param buffer - pointer to the unencrypted buffer
+ * @param buffer_len - length of the buffer
+ * @param out_buffer - pointer to the buffer for the encryptet data
+ * @param out_buffer_len - Input: Length of the output buffer.
+ * Output: Bytes written
+ * @param privacy_params - Buffer, where the privacy parameters
+ * are written to.
+ * @param privacy_params_len - Length of the privacy parameters buffer
+ * @param engine_boots - The engine boots value for the message
+ * @param engine_time - The engine time value for the message
+ *
+ * @return SNMPv3_USM_OK on success
+ */
+ virtual int encrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ unsigned char *privacy_params,
+ unsigned int *privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time) = 0;
+
+
+ /**
+ * Decrypt the buffer with the given key.
+ *
+ * This method needs the privacy parameters field for the given
+ * message.
+ *
+ * @param key - pointer to the (fixed length) dencryption key
+ * @param key_len - length of encryption key
+ * @param buffer - pointer to the encrypted buffer
+ * @param buffer_len - length of the buffer
+ * @param out_buffer - pointer to the buffer for the decryptet data
+ * @param out_buffer_len - Input: Length of the output buffer.
+ * Output: Bytes written
+ * @param privacy_params - Buffer, where the privacy parameters
+ * are read from.
+ * @param privacy_params_len - Length of the privacy parameters buffer
+ * @param engine_boots - The engine boots value for the message
+ * @param engine_time - The engine time value for the message
+ *
+ * @return SNMPv3_USM_OK on success
+ */
+ virtual int decrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ const unsigned char *privacy_params,
+ const unsigned int privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time) = 0;
+
+ /**
+ * Extend a localized key that is too short.
+ *
+ * Some privacy protocols require a key that is longer than the key
+ * generated by the pasword to key algorithm of the authentication
+ * protocol. This function extends a short key to the required length.
+ *
+ * @param password - the password
+ * @param password_len - the length of the password
+ * @param engine_id - pointer to snmpEngineID
+ * @param engine_id_len - length of snmpEngineID
+ * @param key - pointer to the short key that was generated
+ * using Auth::password_to_key() function
+ * @param key_len - IN: length of the short key
+ * OUT: length of the extended key
+ * @param max_key_len - Length of the key buffer
+ * @param auth - Pointer of the authentication protocol that
+ * should be used
+ *
+ * @return SNMPv3_USM_OK on success
+ */
+
+ virtual int extend_short_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len,
+ const unsigned int max_key_len,
+ Auth *auth) = 0;
+
+ /**
+ * Get the uniqhe id of the privacy protocol.
+ */
+ virtual int get_id() const = 0;
+
+ /**
+ * Get the unique identifier string of the privacy protocol.
+ */
+ virtual const char *get_id_string() const = 0;
+
+ /**
+ * Set the pointer to the salt that should be used.
+ */
+ virtual void set_salt(pp_uint64 *new_salt) { salt = new_salt; };
+
+ /**
+ * Get the maximum length that is needed for the
+ * msgPrivacyParameters field.
+ */
+ virtual int get_priv_params_len() const = 0;
+
+ /**
+ * Get the minimum key length needed for encryption and decryption.
+ */
+ virtual int get_min_key_len() const = 0;
+
+ /**
+ * Decrease a too long length to the right value.
+ */
+ virtual void fix_key_len(unsigned int &key_len) const = 0;
+
+ protected:
+ pp_uint64 *salt;
+
+};
+
+typedef Auth* AuthPtr;
+typedef Priv* PrivPtr;
+
+
+/**
+ * Class that holds all authentication and privacy protocols
+ * for a snmp entity.
+ */
+class DLLOPT AuthPriv
+{
+public:
+
+ /**
+ * Default constructor, initializes random values
+ */
+ AuthPriv(int &construct_state);
+
+ /**
+ * Destructor, deletes all auth and priv protocol objets.
+ */
+ ~AuthPriv();
+
+ /**
+ * Add the default authentication protocols.
+ *
+ * The following authentication protocols are added:
+ * - MD5
+ * - SHA
+ *
+ * The following privacy protocols are added:
+ * - DES
+ * - AES128, AES192 and AES256 if libtomcrypt or OpenSSL is enabled
+ * - IDEA if enabled
+ *
+ * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_ERROR.
+ */
+ int add_default_modules();
+
+ /**
+ * Add a new authentication protocol.
+ *
+ * All added objects will be deleted in the destructor
+ *
+ * @param auth - Pointer to a new auth protocol object
+ *
+ * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_ERROR
+ */
+ int add_auth(Auth *auth);
+
+ /**
+ * Delete a authentication protocol.
+ *
+ * @param auth_id - The id of the authentication protocol to remove
+ *
+ * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_ERROR
+ */
+ int del_auth(const int auth_id);
+
+ /**
+ * Add a new privacy protocol.
+ *
+ * All added objects will be deleted in the destructor
+ *
+ * @param priv - Pointer to a new privacy protocol object
+ *
+ * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_ERROR
+ */
+ int add_priv(Priv *priv);
+
+ /**
+ * Delete a privacy protocol.
+ *
+ * @param priv_id - The id of the privacy protocol to remove
+ *
+ * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_ERROR
+ */
+ int del_priv(const int priv_id);
+
+ /**
+ * Call the password-to-key method of the specified authentication
+ * protocol.
+ */
+ int password_to_key_auth(const int auth_prot,
+ const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len);
+
+ /**
+ * Call the password-to-key method of the specified privacy
+ * protocol.
+ */
+ int password_to_key_priv(const int auth_prot,
+ const int priv_prot,
+ const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len);
+
+ /**
+ * Get the keyChange value for the specified keys using the given
+ * authentication protocol.
+ */
+ int get_keychange_value(const int auth_prot,
+ const OctetStr& old_key,
+ const OctetStr& new_key,
+ OctetStr& keychange_value);
+
+ /**
+ * Get a pointer to a privacy protocol object.
+ */
+ Priv *get_priv(const int priv_prot);
+
+ /**
+ * Get a pointer to a authentication protocol object.
+ */
+ Auth *get_auth(const int auth_prot);
+
+ /**
+ * Get the unique id for the given auth protocol.
+ *
+ * @param string_id - The string returned by Auth::get_id_string()
+ *
+ * @return The id or -1
+ */
+ int get_auth_id(const char *string_id) const;
+
+ /**
+ * Get the unique id for the given priv protocol.
+ *
+ * @param string_id - The string returned by Priv::get_id_string()
+ *
+ * @return The id or -1
+ */
+ int get_priv_id(const char *string_id) const;
+
+ /**
+ * Encrypt a message.
+ */
+ int encrypt_msg(const int priv_prot,
+ const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ unsigned char *privacy_params,
+ unsigned int *privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time);
+
+ /**
+ * Decrypt a message.
+ */
+ int decrypt_msg(const int priv_prot,
+ const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ const unsigned char *privacy_params,
+ const unsigned int privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time);
+
+ /**
+ * Get the length of the authentication parameters field of the given
+ * authentication protocol.
+ */
+ int get_auth_params_len(const int auth_prot);
+
+ /**
+ * Get the length of the privacy parameters field of the given
+ * privacy protocol.
+ */
+ int get_priv_params_len(const int priv_prot);
+
+ /**
+ * Fill in the authentication field of an outgoing message
+ */
+ int auth_out_msg(const int auth_prot,
+ const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr);
+
+ /**
+ * Check the authentication field of an incoming message
+ */
+ int auth_inc_msg(const int auth_prot,
+ const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr,
+ const int auth_par_len);
+
+private:
+
+ AuthPtr *auth; ///< Array of pointers to Auth-objects
+ PrivPtr *priv; ///< Array of pointers to Priv-objects
+ int auth_size; ///< current size of the auth array
+ int priv_size; ///< current size of the priv array
+ pp_uint64 salt; ///< current salt value (64 bits)
+};
+
+
+/**
+ * Authentication module using SHA.
+ *
+ * @see Auth
+ */
+class DLLOPT AuthSHA: public Auth
+{
+public:
+ int password_to_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len);
+
+ int hash(const unsigned char *data,
+ const unsigned int data_len,
+ unsigned char *digest) const;
+
+ int auth_out_msg(const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr);
+
+ int auth_inc_msg(const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr,
+ const int auth_par_len);
+
+ int get_id() const { return SNMP_AUTHPROTOCOL_HMACSHA; };
+
+ const char *get_id_string() const { return "HMAC-SHA"; };
+
+ int get_auth_params_len() const { return 12; };
+
+ int get_hash_len() const { return SNMPv3_AP_OUTPUT_LENGTH_SHA;};
+};
+
+/**
+ * Authentication module using MD5.
+ *
+ * @see Auth
+ */
+class DLLOPT AuthMD5: public Auth
+{
+public:
+ int password_to_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len);
+
+ int hash(const unsigned char *data,
+ const unsigned int data_len,
+ unsigned char *digest) const;
+
+ int auth_out_msg(const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr);
+
+
+ int auth_inc_msg(const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr,
+ const int auth_par_len);
+
+ int get_id() const { return SNMP_AUTHPROTOCOL_HMACMD5; };
+
+ const char *get_id_string() const { return "HMAC-MD5"; };
+
+ int get_auth_params_len() const { return 12; };
+
+ int get_hash_len() const { return SNMPv3_AP_OUTPUT_LENGTH_MD5;};
+};
+
+/**
+ * Encryption module using DES.
+ *
+ * @see Priv
+ */
+class DLLOPT PrivDES: public Priv
+{
+ public:
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+ PrivDES();
+ private:
+ int cipher;
+ public:
+#endif
+ int encrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ unsigned char *privacy_params,
+ unsigned int *privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time);
+
+ int decrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ const unsigned char *privacy_params,
+ const unsigned int privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time);
+
+ int extend_short_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len,
+ const unsigned int max_key_len,
+ Auth *auth)
+ { return SNMPv3_USM_ERROR; /* not needed for DES! */ };
+
+ int get_id() const { return SNMP_PRIVPROTOCOL_DES; };
+ const char *get_id_string() const { return "DES"; };
+ int get_priv_params_len() const { return 8; };
+ int get_min_key_len() const { return 16; };
+ void fix_key_len(unsigned int &key_len) const
+ { key_len = (key_len >= 16 ? 16 : 0); };
+};
+
+#ifdef _USE_IDEA
+/**
+ * Encryption module using IDEA.
+ *
+ * @see Priv
+ */
+class DLLOPT PrivIDEA: public Priv
+{
+public:
+
+ int encrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ unsigned char *privacy_params,
+ unsigned int *privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time);
+
+ int decrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ const unsigned char *privacy_params,
+ const unsigned int privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time);
+
+ int extend_short_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len,
+ const unsigned int max_key_len,
+ Auth *auth)
+ { return SNMPv3_USM_ERROR; /* not needed for IDEA! */ };
+
+ int get_id() const { return SNMP_PRIVPROTOCOL_IDEA; };
+ const char *get_id_string() const { return "IDEA"; };
+ int get_priv_params_len() const { return 8; };
+ int get_min_key_len() const { return 16; };
+ void fix_key_len(unsigned int &key_len) const
+ { key_len = (key_len >= 16 ? 16 : 0); };
+};
+
+#endif
+
+
+#if defined(_USE_LIBTOMCRYPT) || defined(_USE_OPENSSL)
+
+/**
+ * Encryption module using AES (only available with libtomcrypt).
+ *
+ * @see Priv
+ */
+class DLLOPT PrivAES: public Priv
+{
+public:
+
+ PrivAES(const int aes_type_);
+
+ int encrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ unsigned char *privacy_params,
+ unsigned int *privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time);
+
+ int decrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ const unsigned char *privacy_params,
+ const unsigned int privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time);
+
+ int extend_short_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len,
+ const unsigned int max_key_len,
+ Auth *auth);
+
+ int get_id() const { return aes_type; };
+ const char *get_id_string() const;
+ int get_priv_params_len() const { return 8; };
+ int get_min_key_len() const { return key_bytes; };
+ void fix_key_len(unsigned int &key_len) const
+ { key_len = (key_len >= (unsigned)key_bytes ? key_bytes : 0); };
+
+ private:
+ int aes_type;
+ int key_bytes;
+ int rounds;
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+ int cipher;
+#endif
+ int need_byteswap;
+};
+#endif // _USE_LIBTOMCRYPT or _USE_OPENSSL
+
+#ifdef _USE_3DES_EDE
+/**
+ * Encryption module using TripleDES-EDE KEY
+ *
+ *
+ * @see Priv
+ */
+#define TRIPLEDES_EDE_KEY_LEN 32
+
+
+class DLLOPT Priv3DES_EDE: public Priv
+{
+public:
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+ Priv3DES_EDE();
+ private:
+ int cipher;
+ public:
+#endif
+
+ int encrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ unsigned char *privacy_params,
+ unsigned int *privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time);
+
+ int decrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ const unsigned char *privacy_params,
+ const unsigned int privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time);
+
+ int extend_short_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len,
+ const unsigned int max_key_len,
+ Auth *auth);
+
+ int get_id() const { return SNMP_PRIVPROTOCOL_3DESEDE; };
+ const char *get_id_string() const { return "3DESEDE"; };
+ int get_priv_params_len() const { return 8; };
+ int get_min_key_len() const { return TRIPLEDES_EDE_KEY_LEN; };
+ void fix_key_len(unsigned int &key_len) const
+ { key_len = (key_len >= TRIPLEDES_EDE_KEY_LEN
+ ? TRIPLEDES_EDE_KEY_LEN : 0); };
+#ifdef _TEST
+ bool test();
+#endif
+};
+
+#endif // _USE_3DES_EDE
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _SNMPv3
+
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## collect.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ C O L L E C T . H
+
+ COLLECTION CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION: Simple Collection classes for SNMP++ classes.
+
+=====================================================================*/
+// $Id: collect.h 349 2008-11-17 23:23:35Z katz $
+
+#ifndef _COLLECTION_H_
+#define _COLLECTION_H_
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define MAXT 25 // elements per block
+
+template <class T> class SnmpCollection
+{
+ class cBlock
+ {
+ public:
+ cBlock(cBlock *p, cBlock *n) : prev(p), next(n) {};
+ T *item[MAXT];
+ cBlock *prev;
+ cBlock *next;
+ };
+
+ public:
+
+ /**
+ * Create an empty collection.
+ */
+ SnmpCollection()
+ : count(0), data(0,0) {};
+
+ /**
+ * Create a collection using a single template object.
+ */
+ SnmpCollection(const T &t)
+ : count(1), data(0, 0)
+ {
+ data.item[0] = (T*) (t.clone());
+ };
+
+ /**
+ * Create a collection with another collection (copy constructor).
+ */
+ SnmpCollection(const SnmpCollection<T> &c)
+ : count(0), data(0, 0)
+ {
+ if (c.count == 0) return;
+
+ // load up the new collection
+ cBlock *current = &data;
+ cBlock *nextBlock;
+ int cn = 0;
+
+ while (count < c.count)
+ {
+ if (cn >= MAXT)
+ {
+ nextBlock = new cBlock(current, 0);
+ current->next = nextBlock;
+ current = nextBlock;
+ cn=0;
+ }
+ T *tmp = 0;
+ c.get_element(tmp, count);
+ current->item[cn] = (T*) (tmp->clone());
+ count++;
+ cn++;
+ }
+ };
+
+ /**
+ * Destroy the collection.
+ */
+ ~SnmpCollection()
+ {
+ clear(); // just delete the data
+ };
+
+ /**
+ * Get the size of the collection.
+ */
+ int size() const
+ {
+ return count;
+ };
+
+ /**
+ * Append an item to the collection.
+ */
+ SnmpCollection& operator +=(const T &i)
+ {
+ cBlock *current = &data;
+ int cn = (int) count % MAXT;
+ while (current->next)
+ current = current->next;
+ if ((count > 0) && ((count % MAXT) == 0))
+ {
+ cBlock *add = new cBlock(current, 0);
+ if (!add) return *this;
+ current->next = add;
+ add->item[0] = (T*) (i.clone());
+ }
+ else
+ {
+ current->item[cn] = (T*) (i.clone());
+ }
+ count++;
+
+ return *this;
+ };
+
+ /**
+ * Assign one collection to another.
+ */
+ SnmpCollection &operator =(const SnmpCollection<T> &c)
+ {
+ if (this == &c) return *this; // check for self assignment
+
+ clear(); // delete the data
+
+ if (c.count == 0) return *this;
+
+ // load up the new collection
+ cBlock *current = &data;
+ cBlock *nextBlock;
+ int cn = 0;
+ count = 0;
+ while (count < c.count)
+ {
+ if (cn >= MAXT)
+ {
+ nextBlock = new cBlock(current, 0);
+ current->next = nextBlock;
+ current = nextBlock;
+ cn=0;
+ }
+ T *tmp = 0;
+ c.get_element(tmp, count);
+ current->item[cn] = (T*) (tmp->clone());
+ count++;
+ cn++;
+ }
+
+ return *this;
+ };
+
+ /**
+ * Access an element in the collection.
+ *
+ * @return The requestet element or an empty element if out of bounds.
+ */
+ T operator[](const int p) const
+ {
+ if ((p < count) && (p >= 0))
+ {
+ cBlock const *current = &data;
+ int bn = (int) (p / MAXT);
+ int cn = (int) p % MAXT;
+ for (int z=0; z<bn; z++)
+ current = current->next;
+ return *(current->item[cn]);
+ }
+ else
+ {
+ // return an instance of nothing!!
+ T t;
+ return t;
+ }
+ };
+
+ /**
+ * Set an element in the collection.
+ *
+ * @return 0 on success and -1 on failure.
+ */
+ int set_element( const T& i, const int p)
+ {
+ if ((p < 0) || (p > count)) return -1; // not found!
+
+ cBlock *current = &data;
+ int bn = (int) p / MAXT;
+ int cn = (int) p % MAXT;
+ for (int z=0; z<bn; z++)
+ current = current->next;
+ delete current->item[cn];
+ current->item[cn] = (T*) (i.clone());
+ return 0;
+ };
+
+ /**
+ * Get an element in the collection.
+ *
+ * @return 0 on success and -1 on failure.
+ */
+ int get_element(T &t, const int p) const
+ {
+ if ((p < 0) || (p > count)) return -1; // not found!
+
+ cBlock const *current = &data;
+ int bn = (int) p / MAXT;
+ int cn = (int) p % MAXT;
+ for (int z=0; z<bn; z++)
+ current = current->next;
+ t = *(current->item[cn]);
+ return 0;
+ };
+
+ /**
+ * Get a pointer to an element in the collection.
+ *
+ * @return 0 on success and -1 on failure.
+ */
+ int get_element(T *&t, const int p) const
+ {
+ if ((p < 0) || (p > count)) return -1; // not found!
+
+ cBlock const *current = &data;
+ int bn = (int) p / MAXT;
+ int cn = (int) p % MAXT;
+ for (int z=0; z<bn; z++)
+ current = current->next;
+ t = current->item[cn];
+ return 0;
+ };
+
+ /**
+ * Apply an function to the entire collection, iterator.
+ */
+ void apply(void f(T&))
+ {
+ T temp;
+ for ( int z=0; z<count; z++)
+ {
+ this->get_element(temp, z);
+ f(temp);
+ }
+ };
+
+ /**
+ * Looks for an element in the collection.
+ *
+ * @return TRUE if found.
+ */
+ int find(const T& i, int &pos) const
+ {
+ T temp;
+ for (int z=0; z<count; z++)
+ {
+ this->get_element(temp, z);
+ if ( temp == i) {
+ pos = z;
+ return TRUE;
+ }
+ }
+ return FALSE;
+ };
+
+ /**
+ * Delete an element in the collection.
+ */
+ int remove(const T& i)
+ {
+ // first see if we have it
+ int pos;
+ if (find(i, pos))
+ {
+ SnmpCollection<T> newCollection;
+
+ for (int z=0; z<count; z++)
+ {
+ if (z != pos)
+ {
+ T item;
+ get_element(item, z);
+ newCollection += item;
+ }
+ }
+
+ // assign new collection to 'this'
+ operator =(newCollection);
+
+ return TRUE;
+ }
+ return FALSE; // not found thus not removed
+ };
+
+ /**
+ * Delete all elements within the collection.
+ */
+ void clear()
+ {
+ if (count == 0) return;
+
+ cBlock *current = &data;
+ int z=0;
+ int cn=0;
+ while ( z< count)
+ {
+ if (cn >= MAXT)
+ {
+ cn =0;
+ current = current->next;
+ }
+ delete current->item[cn];
+ cn++;
+ z++;
+ }
+
+ // delete the blocks
+ while (current->next)
+ current = current->next;
+ while (current->prev)
+ {
+ current = current->prev;
+ delete current->next;
+ }
+
+ count = 0;
+ data.next=0;
+ data.prev=0;
+ };
+
+ private:
+ int count;
+ cBlock data;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _COLLECTION_H_
+
--- /dev/null
+/*_############################################################################
+ _##
+ _## config_snmp_pp.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+
+// $Id: config_snmp_pp.h 1823 2010-08-25 21:59:53Z fock $
+
+#ifndef _CONFIG_SNMP_PP_H_
+#define _CONFIG_SNMP_PP_H_
+
+#define SNMP_PP_VERSION_STRING "3.2.25"
+#define SNMP_PP_VERSION 3
+#define SNMP_PP_RELEASE 2
+#define SNMP_PP_PATCHLEVEL 25
+
+//! The maximum size of a message that can be sent or received.
+#define MAX_SNMP_PACKET 4096
+
+#ifndef DLLOPT
+#if defined (WIN32) && defined (SNMP_PP_DLL)
+#ifdef SNMP_PP_EXPORTS
+#define DLLOPT __declspec(dllexport)
+#define DLLOPT_TEMPL
+#else
+#define DLLOPT __declspec(dllimport)
+#define DLLOPT_TEMPL extern
+#endif
+#else
+#define DLLOPT
+#define DLLOPT_TEMPL
+#endif
+#endif
+
+// define SNMP_PP_IPv6 if you want to use IPv6
+// #define SNMP_PP_IPv6
+
+// define SNMP_PP_NAMESPACE to enclose all library names in Snmp_pp namespace
+// #define SNMP_PP_NAMESPACE
+
+// define _NO_SNMPv3 here or in the Makefile if you do not want to use SNMPv3
+// (default is to use SNMPv3)
+// #define _NO_SNMPv3
+
+// If you have not disabled SNMPv3, snmp++ will use libdes
+// (separate package) as default.
+// define _USE_LIBTOMCRYPT if you want to use libtomcrypt instead
+// Note that _USE_OPENSSL will override libtomcrypt for SHA1, MD5, DES and AES.
+// #define _USE_LIBTOMCRYPT
+
+// If you define _USE_OPENSSL, snmp++ will use OpenSSL for SHA1,
+// MD5, DES and AES. Please note that you will have to change the Makefiles
+// of the examples: Add -lssl to the link command
+// #define _USE_OPENSSL
+
+// If you do not use SNMP++ for commercial purposes or if you
+// have licensed IDEA (read README.v3) you may define the following
+// to enable IDEA support. (note this is not defined by a rfc)
+// #define _USE_IDEA
+
+// Enable 3DES Privacy (note this is not defined by a rfc)
+// #define _USE_3DES_EDE
+
+// define _NO_THREADS here or in the Makefile if you do not want thread support
+// (default is to include thread support)
+// #define _NO_THREADS
+
+// define _NO_LOGGING if you do not want any logging output
+// (increases performance drastically and minimizes memory consumption)
+//#define _NO_LOGGING
+
+// define _IPX_ADDRESS and/or _MAC_ADDRESS if you want to use the
+// classess IpxAddress/IpxSockAddress and/or MacAddress
+// #define _IPX_ADDRESS
+// #define _MAC_ADDRESS
+
+// define this if you want to send out broadcasts
+#define SNMP_BROADCAST
+
+
+// Not fully tested!
+//#define HAVE_POLL_SYSCALL
+
+// Some older(?) compilers need a special declaration of
+// template classes
+// #define _OLD_TEMPLATE_COLLECTION
+
+// We have inet_aton() function if not compiling with VC++ or Borland C++
+#ifndef _MSC_VER
+#ifndef __BCPLUSPLUS__
+#define HAVE_INET_ATON
+#endif
+#endif
+
+// If IPv6 is enabled assume that inet_pton() is available
+// If IPv6 and gcc then assume gethostbyname2() is available
+#ifdef SNMP_PP_IPv6
+#define HAVE_INET_PTON
+#ifdef __GNUC__
+#define HAVE_GETHOSTBYNAME2
+#endif
+#endif
+
+// can we use the reentrant version of these functions or
+// are the standard functions thread safe
+#ifdef __CYGWIN32__
+#define HAVE_LOCALTIME_R
+#define HAVE_REENTRANT_LOCALTIME
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#undef HAVE_GETHOSTBYNAME2
+#elif __MINGW32__
+//FIXME: snmp++/src/address.cpp:865: error: `inet_ntop' was not declared in this scope
+//FIXME: snmp++/src/address.cpp:988: error: `inet_pton' was not declared in this scope
+//FIXME: snmp++/src/notifyqueue.cpp:538: error: `inet_pton' was not declared in this scope
+#undef HAVE_INET_ATON
+#undef HAVE_GETHOSTBYNAME2
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#define HAVE_REENTRANT_LOCALTIME
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#elif __APPLE__
+#define HAVE_LOCALTIME_R
+#define HAVE_REENTRANT_LOCALTIME
+#elif __GNUC__
+#define HAVE_GETHOSTBYNAME_R
+#define HAVE_LOCALTIME_R
+#define HAVE_GETHOSTBYADDR_R
+#elif __DECCXX
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#define HAVE_LOCALTIME_R
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#elif __sun
+#define HAVE_GETHOSTBYNAME_R
+#define HAVE_LOCALTIME_R
+#define HAVE_GETHOSTBYADDR_R
+#elif __HP_aCC
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#define HAVE_LOCALTIME_R
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#elif _MSC_VER
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#define HAVE_REENTRANT_LOCALTIME
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#elif _AIX
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#define HAVE_LOCALTIME_R
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#endif
+
+// Define a unsigned 64 bit integer:
+#ifdef WIN32
+#ifdef SNMP_PP_IPv6
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <windows.h>
+#include <winsock.h>
+#endif
+#ifdef __BCPLUSPLUS__
+typedef unsigned __int64 pp_uint64;
+#else
+typedef ULONGLONG pp_uint64;
+#endif
+#else // not WIN32
+typedef unsigned long long pp_uint64;
+#endif
+
+// Define a type used for sockets
+#ifdef _MSC_VER
+ typedef SOCKET SnmpSocket;
+#else
+ typedef int SnmpSocket;
+#endif
+
+#ifdef HAVE_POLL_SYSCALL
+#include <poll.h>
+#endif
+
+///////////////////////////////////////////////////////////////////////
+// Changes below this line should not be necessary
+///////////////////////////////////////////////////////////////////////
+
+
+// Make use of mutable keyword
+//#define SNMP_PP_MUTABLE mutable
+#define SNMP_PP_MUTABLE
+
+#define SAFE_INT_CAST(expr) ((int)(expr))
+#define SAFE_UINT_CAST(expr) ((unsigned int)(expr))
+
+// Safe until 32 bit second counter wraps to zero (time functions)
+#define SAFE_LONG_CAST(expr) ((long)(expr))
+#define SAFE_ULONG_CAST(expr) ((unsigned long)(expr))
+
+#ifndef _NO_THREADS
+
+#ifndef HAVE_REENTRANT_LOCALTIME
+#ifndef HAVE_LOCALTIME_R
+// If you see this warning, and your system has a reentrant localtime
+// or localtime_r function report your compiler, OS,... to the authors
+// of this library, so that these settings can be changed
+#warning Threads_defined_but_no_reentrant_LOCALTIME_function
+#endif
+#endif
+
+#ifndef HAVE_GETHOSTBYADDR_R
+#ifndef HAVE_REENTRANT_GETHOSTBYADDR
+// If you see this warning, and your system has a reentrant localtime
+// or localtime_r function report your compiler, OS,... to the authors
+// of this library, so that these settings can be changed
+#warning Threads_defined_but_no_reentrant_GETHOSTBYADDR_function
+#endif
+#endif
+
+#ifndef HAVE_GETHOSTBYNAME_R
+#ifndef HAVE_REENTRANT_GETHOSTBYNAME
+// If you see this warning, and your system has a reentrant localtime
+// or localtime_r function report your compiler, OS,... to the authors
+// of this library, so that these settings can be changed
+#warning Threads_defined_but_no_reentrant_GETHOSTBYNAME_function
+#endif
+#endif
+
+#endif // _NO_THREADS
+
+
+#ifndef _NO_SNMPv3
+#ifndef _SNMPv3
+#define _SNMPv3
+#endif
+#endif
+
+#ifndef _NO_THREADS
+#ifdef WIN32
+
+#ifndef _THREADS
+#define _WIN32THREADS
+#define VC_EXTRALEAN
+#define _THREADS
+#endif
+
+#else // !WIN32
+
+#ifndef _THREADS
+#define _THREADS
+#endif
+
+#ifdef __APPLE__
+#define __unix
+#endif
+
+#ifndef POSIX_THREADS
+#ifdef __unix
+#define POSIX_THREADS
+#endif
+#endif
+
+#endif // WIN32
+#endif // !_NO_THREADS
+
+#endif // _CONFIG_SNMP_PP_H_
--- /dev/null
+/*_############################################################################
+ _##
+ _## counter.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ C O U N T E R. H
+
+ COUNTER32 CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ Class definition for SMI Counter32 class.
+
+=====================================================================*/
+// $Id: counter.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _COUNTER
+#define _COUNTER
+
+#include "snmp_pp/integer.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//------------[ Counter32 Class ]------------------------------------------
+/**
+ * The counter class allows all the functionality of unsigned
+ * integers but is recognized as a distinct SMI type. Counter32
+ * class objects may be set or get into Vb objects.
+ */
+class DLLOPT Counter32: public SnmpUInt32
+{
+ public:
+ /**
+ * Constructor to create a Counter object with value zero.
+ */
+ Counter32() : SnmpUInt32() { smival.syntax = sNMP_SYNTAX_CNTR32; };
+
+ /**
+ * Constructor with a value.
+ *
+ * @param i - unsigned 32 bit value
+ */
+ Counter32(const unsigned long i) : SnmpUInt32(i)
+ { smival.syntax = sNMP_SYNTAX_CNTR32; };
+
+ /**
+ * Copy constructor.
+ *
+ * @param c - Object to copy from
+ */
+ Counter32(const Counter32 &c);
+
+ /**
+ * Return the syntax.
+ *
+ * @return Returns always sNMP_SYNTAX_CNTR32
+ */
+ SmiUINT32 get_syntax() const { return sNMP_SYNTAX_CNTR32; };
+
+ /**
+ * Clone operator.
+ *
+ * @return Pointer to a newly created copy of the object.
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *)new Counter32(*this); };
+
+ /**
+ * Map other SnmpSyntax objects to Counter32.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ /**
+ * Overloaded assignment for Counter32.
+ *
+ * @param uli - new value
+ * @return self reference
+ */
+ Counter32& operator=(const Counter32 &uli)
+ { smival.value.uNumber = uli.smival.value.uNumber;
+ m_changed = true; return *this;};
+
+ /**
+ * Overloaded assignment for unsigned longs.
+ *
+ * @param i - new value
+ * @return self reference
+ */
+ Counter32& operator=(const unsigned long i)
+ { smival.value.uNumber = i; m_changed = true; return *this;};
+
+ /**
+ * Casting to unsigned long.
+ *
+ * @return Current value as an unsigned long
+ */
+ operator unsigned long() { return smival.value.uNumber; };
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _COUNTER
--- /dev/null
+/*_############################################################################
+ _##
+ _## ctr64.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ C O U N T E R 6 4 . H
+
+ COUNTER64 CLASSES DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION: SNMP Counter64 class definition.
+
+=====================================================================*/
+// $Id: ctr64.h 1558 2009-07-03 20:16:53Z katz $
+
+#ifndef _CTR64
+#define _CTR64
+
+#include "snmp_pp/smival.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define CTR64OUTBUF 30 //!< maximum ascii string for a 64-bit counter
+
+//---------[ 64 bit Counter Class ]--------------------------------
+/**
+ * Counter64 Class encapsulates two unsigned integers into a
+ * a single entity. This type has is available in SNMPv2 but
+ * may be used anywhere where needed.
+ */
+class DLLOPT Counter64: public SnmpSyntax
+{
+ public:
+
+ //-----------[ Constructors and Destrucotr ]----------------------
+
+ /**
+ * Constructs a valid Couter64 with value 0.
+ */
+ Counter64();
+
+ /**
+ * Constructs a valid Counter64 with the given value as the lower 32 bits.
+ *
+ * @param lo - value (0..MAX_UINT32)
+ */
+ Counter64(unsigned long lo);
+
+ /**
+ * Constructs a valid Counter64 with the given values.
+ *
+ * @param hi - value for the high 32 bits (0..MAX_UINT32)
+ * @param lo - value for the low 32 bits (0..MAX_UINT32)
+ */
+ Counter64(unsigned long hi, unsigned long lo);
+
+ /**
+ * Copy constructor.
+ *
+ * @param ctr64 - value
+ */
+ Counter64(const Counter64 &ctr64);
+
+ /**
+ * Destructor (ensure that SnmpSyntax::~SnmpSyntax() is overridden).
+ */
+ ~Counter64() {};
+
+ //-----------[ conversion from/to unsigned long long ]----------------
+
+ /**
+ * Get the value of the object as 64 bit integer.
+ *
+ * @param c64 - The Counter64 object whose value should be returned
+ * @return value as a unsigned 64 bit integer
+ */
+ static pp_uint64 c64_to_ll(const Counter64 &c64);
+
+ /**
+ * Get the value of this object as 64 bit integer.
+ *
+ * @return value as a unsigned 64 bit integer
+ */
+ pp_uint64 c64_to_ll() const;
+
+ /**
+ * Convert a 64 bit integer to a Counter64.
+ *
+ * @param ld - the value to convert
+ * @return A Counter64 object with the value of the param ld.
+ */
+ static Counter64 ll_to_c64(const pp_uint64 &ll);
+
+ //-----------[ get/set using 32 bit variables ]----------------------
+
+ /**
+ * Get the high 32 bit part.
+ *
+ * @return The high part of the Counter64
+ */
+ unsigned long high() const { return smival.value.hNumber.hipart; };
+
+ /**
+ * Get the low 32 bit part.
+ *
+ * @return The low part of the Counter64
+ */
+ unsigned long low() const { return smival.value.hNumber.lopart; };
+
+ /**
+ * Set the high 32 bit part. The low part will stay unchanged.
+ *
+ * @param h - The new high part of the Counter64
+ */
+ void set_high(const unsigned long h)
+ { smival.value.hNumber.hipart = h; m_changed = true; };
+
+ /**
+ * Set the low 32 bit part. The high part will stay unchanged.
+ *
+ * @param l - The new low part of the Counter64
+ */
+ void set_low(const unsigned long l)
+ { smival.value.hNumber.lopart = l; m_changed = true; };
+
+
+ //-----------[ SnmpSyntax methods ]----------------------
+
+ /**
+ * Get a printable ASCII string representing the current value.
+ *
+ * @note The returned string is valid as long as the object is not
+ * modified.
+ *
+ * @return Null terminated string.
+ */
+ const char *get_printable() const;
+
+ /**
+ * Get the Syntax of the object.
+ *
+ * @return This method always returns sNMP_SYNTAX_CNTR64.
+ */
+ SmiUINT32 get_syntax() const { return sNMP_SYNTAX_CNTR64; };
+
+ /**
+ * Clone the object.
+ *
+ * @return A cloned Counter64 object allocated through new.
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *) new Counter64(*this); };
+
+ /**
+ * Overloaded assignement operator.
+ *
+ * @param val - Try to map the given value to a Counter64 and assign it
+ * @return Always *this with the new value.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ /**
+ * Return validity of the object.
+ *
+ * @return Always true
+ */
+ bool valid() const { return true; };
+
+ /**
+ * Return the space needed for serialization.
+ *
+ * @return The needed space that depends on the current value.
+ */
+ int get_asn1_length() const;
+
+ /**
+ * Reset the object.
+ */
+ void clear()
+ { smival.value.hNumber.hipart = 0; smival.value.hNumber.lopart = 0;
+ m_changed = true; };
+
+ //-----------[ overloaded operators ]----------------------
+
+ /**
+ * Assign a Counter64 to a Counter64.
+ */
+ Counter64& operator=(const Counter64 &ctr64);
+
+ /**
+ * Assign a unsigned long to a Counter64.
+ *
+ * @param i - The new low part. The high part is cleared.
+ */
+ Counter64& operator=(const unsigned long i);
+
+ /**
+ * Add two Counter64.
+ */
+ Counter64 operator+(const Counter64 &c) const;
+
+ /**
+ * Add a unsigned long and a Counter64.
+ */
+ DLLOPT friend Counter64 operator+(unsigned long ul, const Counter64 &c64)
+ { return Counter64(ul) + c64; };
+
+ /**
+ * Subtract two Counter64.
+ */
+ Counter64 operator-(const Counter64 &c) const;
+
+ /**
+ * Subtract a unsigned long and a Counter64.
+ */
+ DLLOPT friend Counter64 operator-(unsigned long ul, const Counter64 &c64)
+ { return Counter64(ul) - c64; };
+
+ /**
+ * Multiply two Counter64.
+ */
+ Counter64 operator*(const Counter64 &c) const;
+
+ /**
+ * Multiply a unsigned long and a Counter64.
+ */
+ DLLOPT friend Counter64 operator*(unsigned long ul, const Counter64 &c64)
+ { return Counter64(ul) * c64; };
+
+ /**
+ * Divide two Counter64.
+ */
+ Counter64 operator/(const Counter64 &c) const;
+
+ /**
+ * Divide a unsigned long and a Counter64.
+ */
+ DLLOPT friend Counter64 operator/(unsigned long ul, const Counter64 &c64)
+ { return Counter64(ul) / c64; };
+
+ //-------[ overloaded comparison operators ]--------------
+
+ /**
+ * Equal operator for two Cunter64.
+ */
+ DLLOPT friend bool operator==(const Counter64 &lhs, const Counter64 &rhs);
+
+ /**
+ * Not equal operator for two Cunter64.
+ */
+ DLLOPT friend bool operator!=(const Counter64 &lhs, const Counter64 &rhs);
+
+ /**
+ * Less than operator for two Cunter64.
+ */
+ DLLOPT friend bool operator<(const Counter64 &lhs, const Counter64 &rhs);
+
+ /**
+ * Less than or equal operator for two Cunter64.
+ */
+ DLLOPT friend bool operator<=(const Counter64 &lhs, const Counter64 &rhs);
+
+ /**
+ * Greater than operator for two Cunter64.
+ */
+ DLLOPT friend bool operator>(const Counter64 &lhs, const Counter64 &rhs);
+
+ /**
+ * Greater than or equal operator for two Cunter64.
+ */
+ DLLOPT friend bool operator>=(const Counter64 &lhs, const Counter64 &rhs);
+
+ private:
+
+ SNMP_PP_MUTABLE char output_buffer[CTR64OUTBUF];
+ SNMP_PP_MUTABLE bool m_changed;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## eventlist.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ E V E N T L I S T . H
+
+ CEventList CLASS DEFINITION
+
+ COPYRIGHT HEWLETT PACKARD COMPANY 1999
+
+ INFORMATION NETWORKS DIVISION
+
+ NETWORK MANAGEMENT SECTION
+
+ DESIGN + AUTHOR: Tom Murray
+
+ DESCRIPTION:
+ Queue for holding all event sources (snmp messages, user
+ defined input sources, user defined timeouts, etc)
+=====================================================================*/
+// $Id: eventlist.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _EVENTLIST
+#define _EVENTLIST
+
+//----[ includes ]-----------------------------------------------------
+#include <limits.h>
+#include <sys/types.h> // NOTE: due to 10.10 bug, order is important
+ // in that all routines must include types.h
+ // and time.h in same order otherwise you
+ // will get conflicting definitions of
+ // "fd_set" resulting in link time errors.
+#ifdef WIN32
+#include <time.h>
+#else
+#if !(defined CPU && CPU == PPC603)
+#include <sys/time.h> // time stuff and fd_set
+#endif
+#include <float.h>
+#endif
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/reentrant.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define MAX_UINT32 MAXLONG
+
+class msec;
+class Pdu;
+
+//----[ CEvents class ]------------------------------------------------
+class DLLOPT CEvents: public SnmpSynchronized {
+ public:
+
+ // allow destruction of derived classes
+ virtual ~CEvents() {};
+
+ // find the next timeout
+ virtual int GetNextTimeout(msec &sendTime) = 0;
+
+ // set up parameters for select/poll
+#ifdef HAVE_POLL_SYSCALL
+ virtual int GetFdCount() = 0;
+ virtual bool GetFdArray(struct pollfd *readfds, int &remaining) = 0;
+ virtual int HandleEvents(const struct pollfd *readfds, const int fds) = 0;
+#else
+ virtual void GetFdSets(int &maxfds, fd_set &readfds, fd_set &writefds,
+ fd_set &exceptfds) = 0;
+ // process events pending on the active file descriptors
+ virtual int HandleEvents(const int maxfds,
+ const fd_set &readfds,
+ const fd_set &writefds,
+ const fd_set &exceptfds) = 0;
+#endif
+ // return number of outstanding messages
+ virtual int GetCount() = 0;
+
+ // process any timeout events
+ virtual int DoRetries(const msec &sendtime) = 0;
+
+ // check to see if there is a termination condition
+ virtual int Done() = 0;
+};
+
+
+class DLLOPT CEventList: public SnmpSynchronized {
+ public:
+ CEventList() : m_head(0, 0, 0), m_msgCount(0), m_done(0) {};
+ ~CEventList();
+
+ // add an event source to the list
+ CEvents *AddEntry(CEvents *events);
+
+ // tell main_loop to exit after one pass
+ void SetDone() REENTRANT({ m_done += 1; });
+
+ // see if main loop should terminate
+ int GetDone() { return m_done; };
+
+ // find the time of the next event that will timeout
+ int GetNextTimeout(msec &sendTime);
+
+#ifdef HAVE_POLL_SYSCALL
+ int GetFdCount();
+ bool GetFdArray(struct pollfd *readfds, int &remaining);
+ int HandleEvents(const struct pollfd *readfds, const int fds);
+#else
+ // set up paramters for select
+ void GetFdSets(int &maxfds, fd_set &readfds, fd_set &writefds,
+ fd_set &exceptfds);
+
+ // process events pending on the active file descriptors
+ int HandleEvents(const int maxfds,
+ const fd_set &readfds,
+ const fd_set &writefds,
+ const fd_set &exceptfds);
+#endif
+
+ // return number of outstanding messages
+ int GetCount() { return m_msgCount; };
+
+
+ // process any timeout events
+ int DoRetries(const msec &sendtime);
+
+ // check to see if there is a termination condition
+ int Done();
+
+ private:
+
+ class DLLOPT CEventListElt
+ {
+ public:
+ CEventListElt(CEvents *events,
+ CEventListElt *next,
+ CEventListElt *previous);
+
+ ~CEventListElt();
+ CEventListElt *GetNext() { return m_Next; }
+ CEvents *GetEvents() { return m_events; }
+
+ private:
+
+ CEvents *m_events;
+ class CEventListElt *m_Next;
+ class CEventListElt *m_previous;
+ };
+
+ CEventListElt m_head;
+ int m_msgCount;
+ int m_done;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## eventlistholder.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+
+#ifndef _EVENTLISTHOLDER_H_
+#define _EVENTLISTHOLDER_H_
+
+//----[ includes ]-----------------------------------------------------
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/snmperrs.h"
+#include "snmp_pp/eventlist.h"
+#include "snmp_pp/reentrant.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class CSNMPMessageQueue;
+class CNotifyEventQueue;
+class Pdu;
+class v3MP;
+class Snmp;
+
+typedef unsigned long Uint32;
+
+class DLLOPT EventListHolder
+{
+ public:
+ EventListHolder(Snmp *snmp_session);
+ ~EventListHolder() {};
+
+ CSNMPMessageQueue *&snmpEventList() { return m_snmpMessageQueue; };
+ CNotifyEventQueue *¬ifyEventList() { return m_notifyEventQueue; };
+
+ Uint32 SNMPGetNextTimeout();
+
+#ifdef HAVE_POLL_SYSCALL
+ int GetFdCount();
+ bool GetFdArray(struct pollfd *readfds, int &remaining);
+#endif
+ void SNMPGetFdSets(int & maxfds,
+ fd_set & readfds,
+ fd_set & writefds,
+ fd_set & exceptfds);
+
+ //---------[ Main Loop ]------------------------------------------
+ /**
+ * Infinite loop which blocks when there is nothing to do and handles
+ * any events.
+ *
+ * @note If no messages are outstanding, select() is called with the
+ * given timeout, so any async messages that are sent out later
+ * are not processed until this select call returns.
+ */
+ void SNMPMainLoop(const int max_block_milliseconds = 0 /* = infinite */);
+
+ //---------[ Exit Main Loop ]---------------------------------------
+ // Force the SNMP Main Loop to terminate immediately
+ void SNMPExitMainLoop();
+
+ /**
+ * Block until an event shows up - then handle the event(s).
+ *
+ * @note If no messages are outstanding, select() is called with the
+ * given timeout, so any async messages that are sent out later
+ * are not processed until this select call returns.
+ */
+ int SNMPProcessEvents(const int max_block_milliseconds = 0 /* = infinite */);
+
+ //---------[ Process Pending Events ]-------------------------------
+ // Pull all available events out of their sockets - do not block
+ int SNMPProcessPendingEvents();
+
+ //---------[ Block For Response ]-----------------------------------
+ // Wait for the completion of an outstanding SNMP event (msg).
+ // Handle any other events as they occur.
+ int SNMPBlockForResponse(const unsigned long req_id,
+ Pdu & pdu);
+
+ private:
+
+ CSNMPMessageQueue *m_snmpMessageQueue; // contains all outstanding messages
+ CNotifyEventQueue *m_notifyEventQueue; // contains all sessions waiting for notifications
+ CEventList m_eventList; // contains all expected events
+
+ SnmpSynchronized pevents_mutex;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _EVENTLISTHOLDER_H_
--- /dev/null
+/*_############################################################################
+ _##
+ _## gauge.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ G A U G E. H
+
+ GAUGE32 CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ Class definition for SMI Gauge32 class.
+=====================================================================*/
+// $Id: gauge.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _GAUGE_H_
+#define _GAUGE_H_
+
+#include "snmp_pp/integer.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//------------[ Gauge32 Class ]------------------------------------------
+/**
+ * The gauge class allows all the functionality of unsigned integers
+ * but is recognized as a distinct SMI type. Gauge32 objects may be
+ * set or get into Vb objects.
+ */
+class DLLOPT Gauge32: public SnmpUInt32
+{
+ public:
+
+ //-----------[ Constructors and Destrucotr ]----------------------
+
+ /**
+ * Constructs a valid Gauge32 with value 0.
+ */
+ Gauge32() : SnmpUInt32() { smival.syntax = sNMP_SYNTAX_GAUGE32; };
+
+ /**
+ * Constructs a valid Gauge32 with the given value.
+ *
+ * @param ul - value (0..MAX_UINT32)
+ */
+ Gauge32(const unsigned long ul) : SnmpUInt32(ul)
+ { smival.syntax = sNMP_SYNTAX_GAUGE32; };
+
+ /**
+ * Copy constructor.
+ *
+ * @param g32 - value
+ */
+ Gauge32(const Gauge32 &g32);
+
+ /**
+ * Destructor (ensure that SnmpUInt32::~SnmpUInt32() is overridden).
+ */
+ ~Gauge32() {};
+
+ //-----------[ SnmpSyntax methods ]----------------------
+
+ /**
+ * Get the Syntax of the object.
+ *
+ * @return This method always returns sNMP_SYNTAX_GAUGE32.
+ */
+ SmiUINT32 get_syntax() const { return sNMP_SYNTAX_GAUGE32; };
+
+ /**
+ * Clone the object.
+ *
+ * @return A cloned Gauge32 object allocated through new.
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *) new Gauge32(*this); };
+
+ //-----------[ Overload some operators ]----------------------
+
+ /**
+ * Assign a Gauge32 to a Gauge32.
+ */
+ Gauge32& operator=(const Gauge32 &uli)
+ { smival.value.uNumber = uli.smival.value.uNumber;
+ m_changed = true; return *this;};
+
+ /**
+ * Assign a unsigned long to a Gauge32.
+ *
+ * @param ul - New value
+ */
+ Gauge32& operator=(const unsigned long ul)
+ { smival.value.uNumber = ul; m_changed = true; return *this; };
+
+ // otherwise, behave like an unsigned int
+ /**
+ * Cast a Gauge32 to unsigned long.
+ *
+ * @return Current value as unsigned long.
+ */
+ operator unsigned long() { return smival.value.uNumber; };
+
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _GAUGE_H_
--- /dev/null
+/*_############################################################################
+ _##
+ _## idea.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+// $Id: idea.h 1791 2010-07-26 19:41:54Z katz $
+
+/*
+
+idea.h
+
+Author: Tatu Ylonen <ylo@cs.hut.fi>
+
+Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ All rights reserved
+
+Created: Sun Jun 25 04:44:30 1995 ylo
+
+The IDEA encryption algorithm.
+
+*/
+
+#ifndef IDEA_H
+#define IDEA_H
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifdef _USE_IDEA
+
+typedef unsigned short word16;
+typedef unsigned int word32;
+
+typedef struct
+{
+ word16 key_schedule[52];
+} IDEAContext;
+
+/* Sets idea key for encryption. */
+void idea_set_key(IDEAContext *c, const unsigned char key[16]);
+
+/* Destroys any sensitive data in the context. */
+void idea_destroy_context(IDEAContext *c);
+
+/* Performs the IDEA cipher transform on a block of data. */
+void idea_transform(IDEAContext *c, word32 l, word32 r, word32 *output);
+
+/* Encrypts len bytes from src to dest in CFB mode. Len need not be a multiple
+ of 8; if it is not, iv at return will contain garbage.
+ Otherwise, iv will be modified at end to a value suitable for continuing
+ encryption. */
+void idea_cfb_encrypt(IDEAContext *c, unsigned char *iv, unsigned char *dest,
+ const unsigned char *src, unsigned int len);
+
+
+/* Decrypts len bytes from src to dest in CFB mode. Len need not be a multiple
+ of 8; if it is not, iv at return will contain garbage.
+ Otherwise, iv will be modified at end to a value suitable for continuing
+ decryption. */
+void idea_cfb_decrypt(IDEAContext *c, unsigned char *iv, unsigned char *dest,
+ const unsigned char *src, unsigned int len);
+
+#endif /* IDEA_H */
+#endif /* _USE_IDEA */
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+/*
+
+getput.h
+
+Author: Tatu Ylonen <ylo@cs.hut.fi>
+
+Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ All rights reserved
+
+Created: Wed Jun 28 22:36:30 1995 ylo
+
+Macros for storing and retrieving data in msb first and lsb first order.
+
+*/
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifndef GETPUT_H
+#define GETPUT_H
+
+#ifdef _USE_IDEA
+
+/*------------ macros for storing/extracting msb first words -------------*/
+
+#define GET_32BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 24) | \
+ ((unsigned long)(unsigned char)(cp)[1] << 16) | \
+ ((unsigned long)(unsigned char)(cp)[2] << 8) | \
+ ((unsigned long)(unsigned char)(cp)[3]))
+
+#define GET_16BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 8) | \
+ ((unsigned long)(unsigned char)(cp)[1]))
+
+#define PUT_32BIT(cp, value) do { \
+ (cp)[0] = (value) >> 24; \
+ (cp)[1] = (value) >> 16; \
+ (cp)[2] = (value) >> 8; \
+ (cp)[3] = (value); } while (0)
+
+#define PUT_16BIT(cp, value) do { \
+ (cp)[0] = (value) >> 8; \
+ (cp)[1] = (value); } while (0)
+
+/*------------ macros for storing/extracting lsb first words -------------*/
+
+#define GET_32BIT_LSB_FIRST(cp) \
+ (((unsigned long)(unsigned char)(cp)[0]) | \
+ ((unsigned long)(unsigned char)(cp)[1] << 8) | \
+ ((unsigned long)(unsigned char)(cp)[2] << 16) | \
+ ((unsigned long)(unsigned char)(cp)[3] << 24))
+
+#define GET_16BIT_LSB_FIRST(cp) \
+ (((unsigned long)(unsigned char)(cp)[0]) | \
+ ((unsigned long)(unsigned char)(cp)[1] << 8))
+
+#define PUT_32BIT_LSB_FIRST(cp, value) do { \
+ (cp)[0] = (value); \
+ (cp)[1] = (value) >> 8; \
+ (cp)[2] = (value) >> 16; \
+ (cp)[3] = (value) >> 24; } while (0)
+
+#define PUT_16BIT_LSB_FIRST(cp, value) do { \
+ (cp)[0] = (value); \
+ (cp)[1] = (value) >> 8; } while (0)
+
+#endif // _USE_IDEA
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif /* GETPUT_H */
+
--- /dev/null
+/*_############################################################################
+ _##
+ _## integer.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ I N T E G E R. H
+
+ INTEGER CLASS DEFINITION
+
+ DESIGN + AUTHOR: Jeff Meyer
+
+ DESCRIPTION:
+ Class definition for Integer classes.
+
+=====================================================================*/
+// $Id: integer.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _SNMPINTEGER
+#define _SNMPINTEGER
+
+#include "snmp_pp/smival.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define INTOUTBUF 15 // largest ASCII formatted integer
+
+//------------[ Integer Classes ]------------------------------------------
+
+/**
+ * 32 bit unsigned integer class.
+ *
+ * The integer class allows all the functionality of the various
+ * integers but is contained in a Value object for consistency
+ * among the various types.
+ * class objects may be set or get into Vb objects.
+ */
+class DLLOPT SnmpUInt32 : public SnmpSyntax
+{
+ public:
+
+ /**
+ * Constructor, sets value to zero.
+ */
+ SnmpUInt32();
+
+ /**
+ * Constructor with value.
+ *
+ * @param i - initial value
+ */
+ SnmpUInt32(const unsigned long i);
+
+ /**
+ * Copy constructor.
+ *
+ * @param c - initial value
+ */
+ SnmpUInt32(const SnmpUInt32 &c);
+
+ /**
+ * Destructor (ensure that SnmpSyntax::~SnmpSyntax() is overridden).
+ */
+ virtual ~SnmpUInt32() {};
+
+ /**
+ * Return the syntax.
+ *
+ * @return This method always returns sNMP_SYNTAX_UINT32.
+ */
+ virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_UINT32; };
+
+ /**
+ * Overloaded assignment for unsigned longs.
+ *
+ * @param i - new value
+ * @return self reference
+ */
+ SnmpUInt32& operator=(const unsigned long i);
+
+ /**
+ * Overloaded assignment for SnmpUInt32.
+ *
+ * @param uli - new value
+ * @return self reference
+ */
+ SnmpUInt32& operator=(const SnmpUInt32 &uli);
+
+ /**
+ * Map other SnmpSyntax objects to SnmpUInt32.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ /**
+ * Behave like an unsigned long.
+ *
+ * @return value as unsigned long
+ */
+ operator unsigned long() const { return smival.value.uNumber; };
+
+ /**
+ * Get a printable ASCII value.
+ */
+ virtual const char *get_printable() const;
+
+ /**
+ * Clone operator.
+ *
+ * @return Pointer to a newly created copy of the object.
+ */
+ virtual SnmpSyntax *clone() const
+ { return (SnmpSyntax *)new SnmpUInt32(*this); };
+
+ /**
+ * Return validity of the object.
+ * An SnmpUInt32 will only be invalid after a failed asignment
+ * of another SnmpSyntax object.
+ */
+ bool valid() const { return valid_flag; };
+
+ /**
+ * Return the space needed for serialization.
+ */
+ int get_asn1_length() const;
+
+ /**
+ * Reset the object.
+ */
+ void clear()
+ { smival.value.uNumber = 0; valid_flag = true; m_changed = true; };
+
+ protected:
+ bool valid_flag;
+ SNMP_PP_MUTABLE char output_buffer[INTOUTBUF];
+ SNMP_PP_MUTABLE bool m_changed;
+};
+
+
+/**
+ * 32 bit signed integer class.
+ */
+class DLLOPT SnmpInt32 : public SnmpSyntax
+{
+ public:
+
+ /**
+ * Constructor, sets value to zero.
+ */
+ SnmpInt32();
+
+ /**
+ * Constructor with value.
+ *
+ * @param i - initial value
+ */
+ SnmpInt32 (const long i);
+
+ /**
+ * Copy constructor.
+ *
+ * @param c - initial value
+ */
+ SnmpInt32 (const SnmpInt32 &c);
+
+ /**
+ * Destructor (ensure that SnmpSyntax::~SnmpSyntax() is overridden).
+ */
+ virtual ~SnmpInt32() {};
+
+ /**
+ * Return the syntax.
+ *
+ * @return This method always returns sNMP_SYNTAX_INT32.
+ */
+ virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_INT32; };
+
+ /**
+ * Overloaded assignment for longs.
+ *
+ * @param i - new value
+ * @return self reference
+ */
+ SnmpInt32& operator=(const long i);
+
+ /**
+ * Overloaded assignment for SnmpInt32.
+ *
+ * @param li - new value
+ * @return self reference
+ */
+ SnmpInt32& operator=(const SnmpInt32 &li);
+
+ /**
+ * Map other SnmpSyntax objects to SnmpInt32.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ /**
+ * Behave like an long.
+ *
+ * @return value as long
+ */
+ operator long() const { return (long) smival.value.sNumber; };
+
+ /**
+ * Get a printable ASCII value.
+ */
+ const char *get_printable() const;
+
+ /**
+ * Clone operator.
+ *
+ * @return Pointer to a newly created copy of the object.
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *)new SnmpInt32(*this); };
+
+ /**
+ * Return validity of the object.
+ * An SnmpUInt32 will only be invalid after a failed asignment
+ * of another SnmpSyntax object.
+ */
+ bool valid() const { return valid_flag; };
+
+ /**
+ * Return the space needed for serialization.
+ */
+ int get_asn1_length() const;
+
+ /**
+ * Reset the object.
+ */
+ void clear()
+ { smival.value.sNumber = 0; valid_flag = true; m_changed = true; };
+
+ protected:
+ bool valid_flag;
+ SNMP_PP_MUTABLE char output_buffer[INTOUTBUF];
+ SNMP_PP_MUTABLE bool m_changed;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## log.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+
+
+
+#ifndef _log_h_
+#define _log_h_
+
+#include <snmp_pp/config_snmp_pp.h>
+#include <snmp_pp/reentrant.h>
+
+#ifndef WIN32
+#include <sys/types.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// Log entry class
+#define ERROR_LOG 0x10
+#define WARNING_LOG 0x20
+#define EVENT_LOG 0x30
+#define INFO_LOG 0x40
+#define DEBUG_LOG 0x50
+#define USER_LOG 0x60
+
+#define LOG_TYPES 6
+
+#ifdef _NO_LOGGING
+
+#define LOG_BEGIN(x)
+#define LOG(x)
+#define LOG_END
+
+#define LOG_UNUSED(x)
+
+#else
+
+#define LOG_BEGIN(x) \
+{ \
+ if (DefaultLog::log()->log_needed(x)) \
+ { \
+ DefaultLog::log()->lock(); \
+ DefaultLog::create_log_entry(x);
+
+#define LOG(x) *DefaultLog::log_entry() += x
+
+#define LOG_END \
+ *DefaultLog::log() += DefaultLog::log_entry(); \
+ DefaultLog::delete_log_entry(); \
+ DefaultLog::log()->unlock(); \
+ } \
+}
+
+#define LOG_UNUSED(x) x
+
+#endif
+
+
+/*--------------------------- class LogEntry --------------------------*/
+
+/**
+ * The LogEntry class represents log entries. An instance of LogEntry can be
+ * added to a Log. Each LogEntry can be classified into the log classes
+ * ERROR_LOG, WARNING_LOG, EVENT_LOG, INFO_LOG, DEBUG_LOG and USER_LOG with up
+ * to 16 severity levels. A log entry consists of a descriptor string and
+ * optional several string or numeric values.
+ *
+ * The log class USER_LOG can be used for applications, it is not used
+ * within snmp++ and agent++.
+ *
+ * @note A error log of level 0 will stop program execution!
+ *
+ * @see Log
+ *
+ * @author Frank Fock
+ * @author Marty Janzen
+ * @version 3.5f
+ */
+
+class DLLOPT LogEntry {
+public:
+ /**
+ * Constructor with log class and severity level
+ *
+ * @param t - The type of the log entry. The type is composed
+ * by a logical OR of the log entry class with a level
+ * of 0 up to 15.
+ * @note A error log of level 0 will stop program execution!
+ */
+ LogEntry(unsigned char t) : type(t), count(0) {}
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~LogEntry() {}
+
+ /**
+ * Initialize a new log entry, showing timestamp, class, and level.
+ */
+ virtual void init(void);
+
+ /**
+ * Add a numeric value to the log entry.
+ *
+ * @param l - A numeric value.
+ */
+ virtual LogEntry& operator+=(const long);
+
+ /**
+ * Add a string value to the log entry.
+ *
+ * @param l - A numeric value.
+ */
+ virtual LogEntry& operator+=(const char*);
+
+ /**
+ * Get the contents of this log entry.
+ *
+ * @return Current contents of this log entry.
+ */
+ virtual const char* get_value(void) const { return ""; }
+
+ /**
+ * Get the class of this log entry.
+ *
+ * @return Log entry class.
+ */
+ unsigned char get_class(void) const { return type & 0xF0; }
+
+ /**
+ * Get the level of this log entry.
+ *
+ * @return Log entry level.
+ */
+ unsigned char get_level(void) const { return type & 0x0F; }
+
+protected:
+ /**
+ * Add a string to the log.
+ *
+ * @param s - A string value.
+ * @return TRUE if the value has been added and FALSE if the log
+ * entry is full.
+ */
+ virtual bool add_string(const char*) = 0;
+
+ /**
+ * Add an integer to the log.
+ *
+ * @param s - An integer value.
+ * @return TRUE if the value has been added and FALSE if the log
+ * entry is full.
+ */
+ virtual bool add_integer(long);
+
+ /**
+ * Add the current time to the log.
+ */
+ virtual bool add_timestamp(void);
+
+protected:
+ unsigned char type;
+ int count;
+};
+
+
+/*------------------------- class LogEntryImpl ------------------------*/
+
+#define MAX_LOG_SIZE 2550 // increased until debugprintf is not used!
+
+/**
+ * The LogEntryImpl class implements a log entry using a dynamically
+ * allocated, but fixed-size buffer.
+ * @see Log
+ *
+ * @author Marty Janzen
+ * @version 3.5f
+ */
+
+class DLLOPT LogEntryImpl : public LogEntry {
+public:
+ /**
+ * Constructor with log class and severity level
+ *
+ * @param t - The type of the log entry. The type is composed
+ * by logical or the log entry class with a level
+ * of 0 up to 15.
+ * @note A error log of level 0 will stop program execution!
+ */
+ LogEntryImpl(unsigned char);
+
+ /**
+ * Destructor.
+ */
+ ~LogEntryImpl();
+
+ /**
+ * Get the contents of this log entry.
+ *
+ * @return Current contents of this log entry.
+ */
+ virtual const char* get_value(void) const { return value; }
+
+protected:
+ /**
+ * Count the bytes left for additional values.
+ *
+ * @return The number of bytes left in this log entry.
+ */
+ unsigned int bytes_left()
+ { return (unsigned int)(MAX_LOG_SIZE-(ptr-value)-1); }
+
+ /**
+ * Add a string to the log.
+ *
+ * @param s - A string value.
+ * @return TRUE if the value has been added and FALSE if the log
+ * entry is full.
+ */
+ bool add_string(const char*);
+
+private:
+ char* value;
+ char* ptr;
+ bool output_stopped;
+};
+
+
+/*--------------------------- class AgentLog --------------------------*/
+
+/**
+ * The AgentLog class is an abstract base class representing a log for
+ * information that is generated during the run time of an AGENT++
+ * SNMP agent. A derived class only needs to provide appropriate
+ * create_log_entry() and operator+= methods.
+ * @see LogEntry
+ *
+ * @author Frank Fock
+ * @version 3.5.14
+ */
+
+class DLLOPT AgentLog {
+public:
+ /**
+ * Default constructor.
+ */
+ AgentLog();
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~AgentLog() {}
+
+ /**
+ * Lock the receiver. Default action is to perform no locking.
+ */
+ virtual void lock() {}
+
+ /**
+ * Unlock the receiver. Default action is to perform no locking.
+ */
+ virtual void unlock() {}
+
+ /**
+ * Set a filter on a specified log class. Only log entries with
+ * a level less or equal than the specified level will be logged.
+ *
+ * @param logclass - A log entry class. @see LogEntry
+ * @param filter - A value between 0 and 15.
+ */
+ virtual void set_filter(int logclass, unsigned char filter);
+
+ /**
+ * Gets the log level for the given log class.
+ * @return
+ * a unsigned char value between 0 and 15
+ */
+ virtual unsigned char get_filter(int logclass) const;
+
+ /**
+ * Create a new LogEntry.
+ *
+ * @param t - The type of the log entry.
+ * @return A new instance of LogEntry (or of a derived class).
+ */
+ virtual LogEntry* create_log_entry(unsigned char) const = 0;
+
+ /**
+ * Add a LogEntry to the receiver Log.
+ *
+ * @param log - A log entry.
+ * @return The receiver log itself.
+ */
+ virtual AgentLog& operator+=(const LogEntry*) = 0;
+
+ /**
+ * Check whether a logging for the given type of LogEntry
+ * has to be done or not.
+ *
+ * @param type
+ * the type of the log entry. The type is composed
+ * by logical or the log entry class with a level
+ * of 0 up to 15.
+ * @return
+ * TRUE if logging is needed, FALSE otherwise.
+ */
+ virtual bool log_needed(unsigned char t)
+ { return ((t & 0x0F) <= logfilter[(t / 16) - 1]); }
+
+ /**
+ * Return the current time as a string.
+ *
+ * @param
+ * a buffer (of at least 18 characters, for the default method)
+ * into which to place a string containg the current time.
+ * If no buffer is supplied, a static area is used.
+ * @return
+ * a string containing the current time. Either the supplied
+ * buffer or the static area.
+ */
+ virtual const char* now(char* = 0);
+
+ /**
+ * Return the current time as a string, using the current
+ * default log object. (For backward compatibility.)
+ * @note that the user is responsible for deleting the returned
+ * string, using delete [].
+ *
+ * @return
+ * a string containg the current time.
+ */
+ static const char* get_current_time();
+
+protected:
+ unsigned char logfilter[LOG_TYPES];
+ char static_buf[18];
+};
+
+
+/*------------------------- class AgentLogImpl ------------------------*/
+
+/**
+ * The AgentLogImpl class is an implementation of AgentLog which writes
+ * log messages to a file, or to stdout or stderr.
+ * @see LogEntry
+ *
+ * @author Frank Fock
+ * @version 3.5f
+ */
+
+class DLLOPT AgentLogImpl : public AgentLog {
+public:
+ /**
+ * Default constructor, with optional pointer to an open log file.
+ * Log is directed to the file if given, otherwise to stdout
+ *
+ * @param fp - An open log file. 0 implies stdout.
+ */
+ AgentLogImpl(FILE* = stdout);
+
+ /**
+ * Constructor with file name of a log file. Log is directed
+ * to the given file.
+ *
+ * @param fname - The file name of a log file.
+ */
+ AgentLogImpl(const char*);
+
+ /**
+ * Destructor.
+ */
+ ~AgentLogImpl();
+
+ /**
+ * Set destination of logs to a given file.
+ *
+ * @param fname - A file name. "" directs logs to stdout.
+ */
+ void set_dest(const char*);
+
+ /**
+ * Set destination of logs to a given file.
+ *
+ * @param fp - A pointer to an open file. 0 directs logs to stdout.
+ */
+ void set_dest(FILE*);
+
+ /**
+ * Lock the receiver.
+ */
+ void lock()
+ {
+#ifdef _THREADS
+ logLock.lock();
+#endif
+ }
+
+ /**
+ * Unlock the receiver.
+ */
+ void unlock()
+ {
+#ifdef _THREADS
+ logLock.unlock();
+#endif
+ }
+
+ /**
+ * Create a new LogEntry.
+ *
+ * @param t - The type of the log entry.
+ * @return A new instance of LogEntry (or of a derived class).
+ */
+ virtual LogEntry* create_log_entry(unsigned char) const;
+
+ /**
+ * Add a LogEntry to the receiver Log.
+ *
+ * @param log - A log entry.
+ * @return The receiver log itself.
+ */
+ virtual AgentLog& operator+=(const LogEntry*);
+
+protected:
+ SnmpSynchronized logLock;
+ FILE* logfile;
+ bool close_needed;
+};
+
+
+/*--------------------------- class DefaultLog --------------------------*/
+
+/**
+ * The DefaultLog class has a static Log member, that is used by the
+ * AGENT++ API for logging.
+ *
+ * @version 3.5.24
+ * @author Frank Fock (singleton pattern -> Philippe Roger)
+ */
+
+class DLLOPT DefaultLog {
+public:
+ DefaultLog() { }
+ ~DefaultLog() { }
+
+ /**
+ * Initialize the default logger with the given logging implementation.
+ *
+ * @note Call cleanup function before the application exits
+ * @note The DefaultLog class takes ownership of the pointer. Do
+ * not delete it yourself.
+ * @note This method is NOT THREADSAFE. It must be called in main()
+ * before any logging takes place.
+ *
+ * @param logger
+ * an AgentLog instance to be used as default logger. A previously
+ * set logger will be deleted.
+ */
+ static void init(AgentLog* logger)
+ { if (instance) delete instance; instance = logger; }
+
+ /**
+ * Initialize the default logger with the given logging implementation
+ * if there is currently no logger instance set.
+ *
+ * @note Call cleanup function before the application exits
+ * @note The DefaultLog class takes ownership of the pointer. Do
+ * not delete it yourself.
+ * @note This method is THREADSAFE.
+ *
+ * @param logger
+ * an AgentLog instance to be used as default logger.
+ * @return
+ * the existing logger (if there was any) or the new logger pointer.
+ * @since 3.5.24
+ */
+ static AgentLog* init_ts(AgentLog* logger);
+
+ /**
+ * Free the logging implementation.
+ * @note This method is THREADSAFE.
+ */
+ static void cleanup();
+
+ /**
+ * Return the default logger.
+ *
+ * @return
+ * a pointer to an AgentLog instance.
+ */
+ static AgentLog* log();
+
+ /**
+ * Create a new log entry or reuse an existing one.
+ *
+ * @param type
+ * the type of the log entry as bitwise or of log class and level.
+ */
+ static void create_log_entry(unsigned char t)
+ { if (!entry) { entry = log()->create_log_entry(t); entry->init();} }
+
+ /**
+ * Return the current log entry. If there is none, an ERROR_LOG entry
+ * with level 1 will be created.
+ *
+ * @return
+ * a pointer to a LogEntry instance.
+ */
+ static LogEntry* log_entry()
+ { if (!entry) create_log_entry(ERROR_LOG | 1); return entry; }
+
+ /**
+ * Delete current log entry.
+ */
+ static void delete_log_entry()
+ { if (entry) delete entry; entry = 0; }
+
+protected:
+
+ static AgentLog* instance;
+ static LogEntry* entry;
+ static SnmpSynchronized mutex;
+};
+
+
+#ifdef SNMP_PP_NAMESPACE
+}
+#endif
+#endif // _log_h_
--- /dev/null
+/*_############################################################################
+ _##
+ _## md5.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#if !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
+/* MD5.H - header file for MD5C.C */
+
+/* Copyright (C) 1991, RSA Data Security, Inc. All rights reserved.
+
+ License to copy and use this software is granted provided that it
+ is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ License is also granted to make and use derivative works provided
+ that such works are identified as "derived from the RSA Data
+ Security, Inc. MD5 Message-Digest Algorithm" in all material
+ mentioning or referencing the derived work.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+// $Id: md5.h 288 2007-03-22 22:37:09Z katz $
+
+#ifndef _MD5_H_
+#define _MD5_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned int UINT4; /* for alpha */
+/*typedef unsigned long int UINT4; */
+
+/* BYTE defines a unsigned character */
+typedef unsigned char BYTE;
+
+/* internal signed value */
+typedef signed int signeddigit;
+
+#ifndef NULL_PTR
+#define NULL_PTR ((POINTER)0)
+#endif
+
+#ifndef UNUSED_ARG
+#define UNUSED_ARG(x) x = *(&x);
+#endif
+
+#ifndef PROTOTYPES
+#define PROTOTYPES
+#endif
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list. */
+
+#ifdef PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+DLLOPT void MD5Init PROTO_LIST ((MD5_CTX *));
+DLLOPT void MD5Update PROTO_LIST ((MD5_CTX *, const unsigned char *, const unsigned int));
+DLLOPT void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
--- /dev/null
+/*_############################################################################
+ _##
+ _## mp_v3.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+
+// $Id: mp_v3.h 320 2007-11-08 22:05:23Z katz $
+
+#ifndef _MP_V3
+#define _MP_V3
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+
+#include "snmp_pp/reentrant.h"
+#include "snmp_pp/target.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class Pdu;
+class OctetStr;
+
+#define MAX_HOST_NAME_LENGTH 128
+
+#define oidMPDGroup "1.3.6.1.6.3.11.2.1"
+#define oidSnmpUnknownSecurityModels "1.3.6.1.6.3.11.2.1.1.0"
+#define oidSnmpInvalidMsgs "1.3.6.1.6.3.11.2.1.2.0"
+#define oidSnmpUnknownPDUHandlers "1.3.6.1.6.3.11.2.1.3.0"
+
+/** @name Error codes of the v3MP */
+//@{
+#define SNMPv3_MP_ERROR -1400
+#define SNMPv3_MP_OK -1401
+#define SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL -1402
+#define SNMPv3_MP_NOT_IN_TIME_WINDOW -1403
+#define SNMPv3_MP_DOUBLED_MESSAGE -1404
+#define SNMPv3_MP_INVALID_MESSAGE -1405
+#define SNMPv3_MP_INVALID_ENGINEID -1406
+#define SNMPv3_MP_NOT_INITIALIZED -1407
+#define SNMPv3_MP_PARSE_ERROR -1408
+#define SNMPv3_MP_UNKNOWN_MSGID -1409
+#define SNMPv3_MP_MATCH_ERROR -1410
+#define SNMPv3_MP_COMMUNITY_ERROR -1411
+#define SNMPv3_MP_WRONG_USER_NAME -1412
+#define SNMPv3_MP_BUILD_ERROR -1413
+#define SNMPv3_MP_USM_ERROR -1414
+#define SNMPv3_MP_UNKNOWN_PDU_HANDLERS -1415
+#define SNMPv3_MP_UNAVAILABLE_CONTEXT -1416
+#define SNMPv3_MP_UNKNOWN_CONTEXT -1417
+#define SNMPv3_MP_REPORT_SENT -1418
+//@}
+
+/** @name Statistics on error codes. */
+//@{
+#define SNMPv3_MP_MAX_ERROR SNMPv3_MP_ERROR
+#define SNMPv3_MP_MIN_ERROR SNMPv3_MP_REPORT_SENT
+#define SNMPv3_MP_ERRORCOUNT SNMPv3_MP_MAX_ERROR - SNMPv3_MP_MIN_ERROR
+//@}
+
+class Snmp;
+class USM;
+
+/**
+ * The SNMPv3 Message Processing Model (v3MP).
+ *
+ * If SNMPv3 is used, the application needs to create _one_ object of
+ * this class. This object will automatically create an object of the
+ * USM class. A pointer to this object is returned from the get_usm()
+ * method. See the USM documentation for a description on how to create
+ * and delete users.
+ *
+ * The only thing that may be configured after creation of the v3MP is
+ * the engine id table of the v3MP. Entries for other SNMP entities
+ * can be added through add_to_engine_id_table(). It is only required
+ * to add entries to this table if you want to disable engine id
+ * discovery and/or you don't want the delay caused by the automatic
+ * engine id discovery of SNMPv3.
+ */
+class DLLOPT v3MP
+{
+ friend class SnmpMessage;
+ friend class CSNMPMessageQueue;
+ public:
+ /**
+ * Initialize the v3MP.
+ *
+ * Set the engineID of this SNMP entity and the Snmp object used to
+ * send reports. This function creates a new USM object that can
+ * be configured after getting a pointer to it through get_usm().
+ *
+ * The user is responsible to save and restore and increment the
+ * snmpEngineBoots counter (The functions getBootCounter() and
+ * saveBootCounter() can be used to do this.).
+ *
+ * @param engine_id - The locale engine id
+ * @param engine_boots - The new value for the snmpEngineBoots counter
+ * @param construct_status - OUT: SNMPv3_MP_OK or SNMPv3_MP_ERROR
+ *
+ */
+ v3MP(const OctetStr& engine_id,
+ unsigned int engine_boots, int &construct_status);
+
+ /**
+ * Get the engine id of this SNMP entity.
+ *
+ * @param id - OUT: The engineID of this SNMP entity
+ *
+ * @return - SNMPv3_MP_OK or SNMPv3_MP_ERROR
+ */
+ void get_local_engine_id(OctetStr &id) { id = own_engine_id_oct; };
+
+ /**
+ * Get the engine id of this SNMP entity as a OctetStr reference.
+ *
+ * @return Local engine id.
+ */
+ const OctetStr& get_local_engine_id() const
+ { return own_engine_id_oct; };
+
+ /**
+ * Get a pointer to the USM object that is used by the v3MP.
+ */
+ USM *get_usm() { return usm; };
+
+ /**
+ * Free all allocated ressources of the v3MP and leave it in an
+ * uninitialized state. After a call to this function, you can use
+ * mpInit() to reinitialize the v3MP.
+ *
+ */
+ ~v3MP();
+
+ /**
+ * Add an entry to the engine id table.
+ *
+ * In this table all known engine ids are stored. If the discovery
+ * mode of the USM is enabled, snmp++ will add entries to this table
+ * whenever a new engine id is dicovered.
+ *
+ * @param engine_id - The engine id
+ * @param host - The numerical IP address
+ * @param port - The port
+ *
+ * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+ */
+ int add_to_engine_id_table(const OctetStr &engine_id,
+ const OctetStr &host, int port)
+ { return engine_id_table.add_entry(engine_id, host, port); };
+
+ /**
+ * Remove an entry from the engine id table.
+ *
+ * @param host - The numerical IP address
+ * @param port - The port
+ *
+ * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+ */
+ int remove_from_engine_id_table(const OctetStr &host, int port)
+ { return engine_id_table.delete_entry(host, port); };
+
+ /**
+ * Remove an entry from the engine id table.
+ *
+ * @param engine_id - The engine id
+ *
+ * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+ */
+ int remove_from_engine_id_table(const OctetStr &engine_id)
+ { return engine_id_table.delete_entry(engine_id); };
+
+ /**
+ * Get the engine id of the SNMP entity at the given host/port.
+ *
+ * @param engine_id - OUT: The engine id
+ * @param hostport - The numerical IP address and port
+ * (syntax: a.b.c.d/port)
+ *
+ * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+ * SNMPv3_MP_OK
+ */
+ int get_from_engine_id_table(OctetStr &engine_id,
+ const OctetStr &hostport) const
+ { return engine_id_table.get_entry(engine_id, hostport); };
+
+ /**
+ * Get the engineID of the SNMP entity at the given host/port.
+ *
+ * @param engineID - OUT: The engineID
+ * @param host - The numerical IP address
+ * @param port - The port
+ *
+ * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+ * SNMPv3_MP_OK
+ */
+ int get_from_engine_id_table(OctetStr &engineID,
+ const OctetStr &host, int port) const
+ { return engine_id_table.get_entry(engineID, host, port); };
+
+ /**
+ * Remove all entries from the engine id table.
+ *
+ * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+ * SNMPv3_MP_OK
+ */
+ int reset_engine_id_table()
+ { return engine_id_table.reset(); };
+
+ /**
+ * Remove all occurences of this engine id from v3MP and USM.
+ *
+ * @param engine_id - The engine id to remove
+ *
+ * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+ * SNMPv3_MP_OK
+ */
+ int remove_engine_id(const OctetStr &engine_id);
+
+ // ----------[ Access to status counters for agent++ ]--------------
+
+ /**
+ * Get the value of the status counter snmpUnknownSecurityModels.
+ *
+ * @return - The status counter
+ */
+ unsigned long get_stats_unknown_security_models() const
+ { return snmpUnknownSecurityModels; };
+
+ /**
+ * Get the value of the status counter snmpInvalidMsgs.
+ *
+ * @return - The status counter
+ */
+ unsigned long get_stats_invalid_msgs() const
+ { return snmpInvalidMsgs; };
+
+ /**
+ * Get the value of the status counter snmpUnknownPDUHandlers.
+ *
+ * @return - The status counter
+ */
+ unsigned long get_stats_unknown_pdu_handlers() const
+ { return snmpUnknownPDUHandlers; };
+
+ /**
+ * Increment the value of the status counter snmpUnknownSecurityModels.
+ */
+ void inc_stats_unknown_security_models()
+ { snmpUnknownSecurityModels++; };
+
+ /**
+ * Increment the value of the status counter snmpInvalidMsgs.
+ */
+ void inc_stats_invalid_msgs() { snmpInvalidMsgs++; };
+
+ /**
+ * Increment the value of the status counter snmpUnknownPDUHandlers.
+ */
+ void inc_stats_unknown_pdu_handlers() { snmpUnknownPDUHandlers++; };
+
+ // temporary pointer will be removed...
+ static v3MP *I;
+
+ protected:
+
+ /**
+ * Parse the given buffer as a SNMPv3-Message.
+ *
+ * @param snmp_session - IN: The session used to receive the msg
+ * @param pdu - OUT: Parsed values are put into this struct
+ * @param inBuf - The buffer to parse
+ * @param inBufLength - The length of the buffer
+ * @param securityEngineID - OUT: The parsed securityEngineID
+ * @param securityName - OUT: The parsed securityName
+ * @param contextEngineID - OUT: The parsed contextEngineID
+ * @param contextName - OUT: The parsed contextName
+ * @param securityLevel - OUT: The parsed security level
+ * @param msgSecurityModel - OUT: The security model used
+ * @param spp_version - OUT: SNMP version (SNMPv3)
+ * @param from_address - Where the message came from (used to send
+ * a report if neccessary)
+ *
+ * @return - SNMPv3_MP_OK or any error listed in snmperr.h
+ */
+ int snmp_parse(Snmp *snmp_session,
+ struct snmp_pdu *pdu,
+ unsigned char *inBuf,
+ int inBufLength,
+ OctetStr &securityEngineID,
+ OctetStr &securityName,
+ OctetStr &contextEngineID,
+ OctetStr &contextName,
+ long &securityLevel,
+ long &msgSecurityModel,
+ snmp_version &spp_version,
+ UdpAddress from_address);
+
+ /**
+ * Tests if the given buffer contains a SNMPv3-Message. The buffer is
+ * only parsed to extract the version of the message, no other checks
+ * are made.
+ *
+ * @param buffer - The message
+ * @param length - The length of the message
+ *
+ * @return - TRUE if the version could be extracted and it
+ * is a SNMPv3 message. On any error: FALSE.
+ *
+ */
+ static bool is_v3_msg( unsigned char *buffer, int length);
+
+ /**
+ * Do the complete process of encoding the given values into the buffer
+ * ready to send to the target.
+ *
+ * @param pdu - The pdu structure
+ * @param packet - The buffer to store the serialized message
+ * @param out_length - IN: Length of the buffer,
+ * OUT: Length of the message
+ * @param securityEngineID - The securityEngineID
+ * @param securityNameIn - The securityName
+ * @param securityModel - Use this security model
+ * @param securityLevel - Use this security level
+ * @param contextEngineID - The contextEngineID
+ * @param contextName - The contextName
+ *
+ * @return - SNMPv3_MP_OK or any error listed in snmperr.h
+ */
+ int snmp_build(struct snmp_pdu *pdu,
+ unsigned char *packet,
+ int *out_length, // maximum Bytes in packet
+ const OctetStr &securityEngineID,
+ const OctetStr &securityNameIn,
+ int securityModel, int securityLevel,
+ const OctetStr &contextEngineID,
+ const OctetStr &contextName);
+
+ /**
+ * Delete the entry with the given request id from the cache.
+ * This function is used in eventlist.cpp when a request
+ * has timed out.
+ *
+ * @param requestID - The request id.
+ * @param local_request - Does the request id belong to a local or to
+ * a remote request?
+ */
+ void delete_from_cache(unsigned long requestID,
+ const bool local_request = true)
+ { cache.delete_entry(requestID, local_request); };
+
+ public:
+
+ /**
+ * Delete the entry with the given request id from the cache.
+ * This function is used in agent++ RequestList.
+ *
+ * @param requestID - The request id.
+ * @param messageID - The message id.
+ * @param local_request - Does the request id belong to a local or to
+ * a remote request?
+ */
+ void delete_from_cache(unsigned long requestID,
+ unsigned long messageID,
+ const bool local_request)
+ { cache.delete_entry(requestID, messageID, local_request); };
+
+ private:
+
+ /**
+ * Send a report message.
+ *
+ * @param scopedPDU - The scopedPDU as received. If the pdu is not
+ * encrypted, the request id is extracted
+ * @param scopedPDULength - The lkength of the scopedPDU
+ * @param pdu - The pdu structure.
+ * @param errorCode - The code of the error that occured.
+ * @param sLevel - Send the report with this security level.
+ * @param sModel - Use this security model.
+ * @param sName - Use this security name
+ * @param destination - Send the report to this address.
+ * @param snmp_session - Snmp session to use for sending a report
+ *
+ * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+ */
+ int send_report(unsigned char* scopedPDU, int scopedPDULength,
+ struct snmp_pdu *pdu, int errorCode, int sLevel,
+ int sModel, OctetStr &sName,
+ UdpAddress &destination, Snmp *snmp_session);
+
+
+
+ // =====================[ member classes ]==============================
+
+ /**
+ * The engine id table is used to store known engine ids with
+ * corresponding hostadress and port.
+ */
+ class DLLOPT EngineIdTable
+ {
+ public:
+
+ EngineIdTable(int initial_size = 10);
+ ~EngineIdTable();
+
+ /**
+ * Add an entry to the table.
+ *
+ * @param engine_id - The engineID
+ * @param host - The numerical IP address
+ * @param port - The port
+ *
+ * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+ */
+ int add_entry(const OctetStr &engine_id,
+ const OctetStr &host, int port);
+
+ /**
+ * Get the engine_id of the SNMP entity at the given host/port.
+ *
+ * @param engine_id - OUT: The engineID
+ * @param hostport - The numerical IP address and port
+ * (syntax: a.b.c.d/port)
+ *
+ * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+ * SNMPv3_MP_OK
+ */
+ int get_entry(OctetStr &engine_id, const OctetStr &hostport) const;
+
+ /**
+ * Get the engineID of the SNMP entity at the given host/port.
+ *
+ * @param engine_id - OUT: The engineID
+ * @param host - The numerical IP address
+ * @param port - The port
+ *
+ * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+ * SNMPv3_MP_OK
+ */
+ int get_entry(OctetStr &engine_id, const OctetStr &host, int port) const;
+
+ /**
+ * Remove all entries from the engine id table.
+ *
+ * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+ * SNMPv3_MP_OK
+ */
+ int reset();
+
+ /**
+ * Remove the given engine id from the table.
+ *
+ * @param engine_id - The engine id to remove
+ *
+ * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+ * SNMPv3_MP_OK
+ */
+ int delete_entry(const OctetStr &engine_id);
+
+ /**
+ * Remove the entry for the given address/port from the table.
+ *
+ * @param host - Numeric IP address
+ * @param port - listen port of the snmp entity
+ *
+ * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+ * SNMPv3_MP_OK
+ */
+ int delete_entry(const OctetStr &host, int port);
+
+ private:
+ int initialize_table(const int size);
+
+ struct Entry_T
+ {
+ OctetStr engine_id;
+ OctetStr host;
+ int port;
+ };
+
+ struct Entry_T *table;
+ int max_entries; ///< the maximum number of entries
+ int entries; ///< the current amount of entries
+ SNMP_PP_MUTABLE SnmpSynchronized lock;
+ };
+
+
+ /**
+ * Holds cache entries for currently processed requests.
+ */
+ class DLLOPT Cache
+ {
+ public:
+ Cache();
+ ~Cache();
+
+ struct Entry_T
+ {
+ int msg_id;
+ unsigned long req_id;
+ OctetStr sec_engine_id;
+ int sec_model;
+ OctetStr sec_name;
+ int sec_level;
+ OctetStr context_engine_id;
+ OctetStr context_name;
+ struct SecurityStateReference *sec_state_ref;
+ int error_code;
+ bool local_request;
+ };
+
+ /**
+ * Add an entry to the cache.
+ *
+ * @param msg_id - The message id of the message
+ * @param req_id - The request id of the message
+ * @param sec_engine_id - The authoritative engineID
+ * @param sec_model - The security model used for this message
+ * @param sec_name - The name of the user
+ * @param sec_level - The security level used for this message
+ * @param context_engine_id - The context_engine_id
+ * @param context_name - The context_name
+ * @param sec_state_ref - The reference of the USM
+ * @param error_code - The code of the error that occured while
+ * parsing the received message
+ *
+ * @return - SNMPv3_MP_OK, SNMPv3_MP_ERROR or SNMPv3_DOUBLED_MESSAGE
+ * (an entry with the given values is already in the cache)
+ */
+ int add_entry(int msg_id, unsigned long req_id,
+ const OctetStr &sec_engine_id,
+ int sec_model,
+ const OctetStr &sec_name,
+ int sec_level,
+ const OctetStr &context_engine_id,
+ const OctetStr &context_name,
+ struct SecurityStateReference *sec_state_ref,
+ int error_code, bool local_request);
+ /**
+ * Search the cache for a message id, return the error code and
+ * the sec_state_ref and delete the entry from the cache.
+ *
+ * @param msg_id - Search for this message id
+ * @param error_code - OUT: The error code of the received message
+ * @param sec_state_ref - IN: Pointer to a pointer of the structure
+ * OUT: The structure as received by the USM when
+ * the message was parsed.
+ *
+ * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+ */
+ int get_entry(int msg_id, bool local_request, int *error_code,
+ struct SecurityStateReference **sec_state_ref);
+
+ /**
+ * Delete the entry with the given request id from the cache.
+ * This function is used in eventlist.cpp when a request
+ * has timed out.
+ *
+ * @param req_id - The request id.
+ */
+ void delete_entry(unsigned long req_id, bool local_request);
+
+ /**
+ * Delete the entry with the given request and message id from the cache.
+ *
+ * @param req_id - The request id.
+ * @param msg_id - The message id.
+ */
+ void delete_entry(unsigned long req_id, int msg_id,
+ bool local_request);
+
+ /**
+ * Search the cache for a message id, return the whole entry and
+ * delete the entry from the cache.
+ *
+ * @param searchedID - Search for this message id
+ * @param res - IN: Pointer to an empy structure
+ * OUT: The filled structure
+ *
+ * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+ */
+ int get_entry(int searchedID, bool local_request,
+ struct Cache::Entry_T *res);
+
+ void delete_content(struct Cache::Entry_T &ce);
+
+ void set_usm(USM *usm_to_use) { usm = usm_to_use; };
+
+ private:
+#ifdef _THREADS
+ SNMP_PP_MUTABLE SnmpSynchronized lock;
+#endif
+ struct Entry_T *table; ///< whole table
+ int max_entries; ///< the maximum number of entries
+ int entries; ///< the current amount of entries
+ USM *usm;
+ };
+
+
+ // =====================[ member variables ]==============================
+ EngineIdTable engine_id_table;
+ Cache cache;
+
+ // the engineID of this SNMP entity
+ unsigned char *own_engine_id;
+ int own_engine_id_len;
+ OctetStr own_engine_id_oct;
+
+ unsigned int cur_msg_id; ///< msgID to use for next message
+ SNMP_PP_MUTABLE SnmpSynchronized cur_msg_id_lock;
+
+ USM *usm; ///< the USM object used
+
+ // MIB Counters
+ unsigned int snmpUnknownSecurityModels;
+ unsigned int snmpInvalidMsgs;
+ unsigned int snmpUnknownPDUHandlers;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _SNMPv3
+
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## msec.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+*/
+// $Id: msec.h 307 2007-09-14 20:01:45Z katz $
+
+#ifndef _MSEC_H_
+#define _MSEC_H_
+
+//----[ includes ]-----------------------------------------------------
+#include <sys/types.h> /* NOTE: due to 10.10 bug, order is important
+ * in that all routines must include types.h
+ * and time.h in same order otherwise you will
+ * get conflicting definitions of "fd_set"
+ * resulting in link time errors.
+ */
+#ifdef WIN32
+#elif defined (CPU) && CPU == PPC603
+#include <sys/times.h>
+#else
+#include <sys/time.h>
+#include <sys/param.h>
+#endif
+
+#include <time.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/smi.h"
+#include "snmp_pp/reentrant.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//----[ defines ]------------------------------------------------------
+#define MSECOUTBUF 20
+
+//----[ msec class ]---------------------------------------------------
+/**
+ * Time handling...
+ */
+class DLLOPT msec
+{
+ public:
+ /**
+ * Constructor, sets the time to the current system time.
+ */
+ msec() { refresh(); };
+
+ /**
+ * Constructor using another msec object
+ *
+ * @param in_msec - Time for this object
+ */
+ msec(const msec &in_msec) : m_time(in_msec.m_time), m_changed(true) {};
+
+ /**
+ * Constructor using seconds and milli sconds.
+ *
+ * @param sec - Seconds
+ * @param milsec - Milli seconds
+ */
+ msec(const int sec, const int milsec) : m_changed(true)
+ { m_time.tv_sec = sec; m_time.tv_usec = milsec; };
+
+ DLLOPT friend int operator==(const msec &t1, const msec &t2);
+ DLLOPT friend int operator!=(const msec &t1, const msec &t2);
+ DLLOPT friend int operator<(const msec &t1, const msec &t2);
+ DLLOPT friend int operator>(const msec &t1, const msec &t2);
+ DLLOPT friend int operator<=(const msec &t1, const msec &t2)
+ { return((t1 < t2) || (t1 == t2)); };
+ DLLOPT friend int operator>=(const msec &t1, const msec &t2)
+ { return((t1 > t2) || (t1 == t2)); };
+
+ msec &operator-=(const long millisec);
+ msec &operator-=(const timeval &t1);
+ msec &operator+=(const long millisec);
+ msec &operator+=(const timeval &t1);
+ msec &operator=(const msec &t)
+ { m_time = t.m_time; m_changed = true; return *this; };
+ msec &operator=(const timeval &t1);
+
+ /**
+ * Use as an unsigned long.
+ *
+ * @return Time in milli seconds
+ */
+ operator unsigned long() const
+ { return ((m_time.tv_sec * 1000) + m_time.tv_usec); };
+
+ /**
+ * Set the time to the current system time.
+ */
+ void refresh();
+
+ /**
+ * Set the object out into the future as far as possible.
+ */
+ void SetInfinite()
+ { m_time.tv_sec = (time_t) -1; m_time.tv_usec = 0; m_changed = true; };
+
+ /**
+ * Check if the time is infinite.
+ *
+ * @return True, if the time is infinite.
+ */
+ int IsInfinite() const
+ { return ((m_time.tv_sec == (time_t) -1) && (m_time.tv_usec == 0)); };
+
+ /**
+ * Get the difference between this and the given time.
+ * If future is before this objects time, "timeout" will be set to zero.
+ *
+ * @param future - Time to compare to
+ * @param timeout - Will be filled with the difference
+ */
+ void GetDelta(const msec &future, timeval &timeout) const;
+
+ /**
+ * Get the difference between this object and the current system time.
+ * If the system time is before this objects time,
+ * "timeout" will be set to zero.
+ *
+ * @param timeout - Will be filled with the difference
+ */
+ void GetDeltaFromNow(timeval &timeout) const
+ { msec now; now.GetDelta(*this, timeout); };
+
+ /**
+ * Return the time as printable string.
+ */
+ const char *get_printable() const;
+
+private:
+ timeval m_time;
+ SNMP_PP_MUTABLE char m_output_buffer[MSECOUTBUF];
+ SNMP_PP_MUTABLE bool m_changed;
+
+#if !defined HAVE_LOCALTIME_R && !defined HAVE_REENTRANT_LOCALTIME
+#ifdef _THREADS
+ static SnmpSynchronized m_localtime_mutex;
+#endif
+#endif
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _MSEC_H_
--- /dev/null
+/*_############################################################################
+ _##
+ _## msgqueue.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ M S G Q U E U E . H
+
+ CSNMPMessageQueue CLASS DEFINITION
+
+ COPYRIGHT HEWLETT PACKARD COMPANY 1999
+
+ INFORMATION NETWORKS DIVISION
+
+ NETWORK MANAGEMENT SECTION
+
+ DESIGN + AUTHOR: Tom Murray
+
+ DESCRIPTION:
+ Queue for holing SNMP event sources (outstanding snmp messages)
+
+=====================================================================*/
+// $Id: msgqueue.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _MSGQUEUE
+#define _MSGQUEUE
+
+//----[ includes ]-----------------------------------------------------
+#include <sys/types.h> // NOTE: due to 10.10 bug, order is important
+ // in that all routines must include types.h
+ // and time.h in same order otherwise you
+ // will get conflicting definitions of
+ // "fd_set" resulting in link time errors.
+#ifndef WIN32
+#if !(defined CPU && CPU == PPC603)
+#include <sys/time.h> // time stuff and fd_set
+#endif
+#endif
+
+//----[ snmp++ includes ]----------------------------------------------
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/address.h"
+#include "snmp_pp/target.h"
+#include "snmp_pp/pdu.h"
+#include "snmp_pp/msec.h"
+#include "snmp_pp/uxsnmp.h"
+#include "snmp_pp/eventlist.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//----[ defines ]------------------------------------------------------
+
+
+
+//----[ CSNMPMessage class ]-------------------------------------------
+
+
+ /*-----------------------------------------------------------*/
+ /* CSNMPMessage */
+ /* a description of a single MIB access operation. */
+ /*-----------------------------------------------------------*/
+class DLLOPT CSNMPMessage
+{
+ public:
+ CSNMPMessage(unsigned long id,
+ Snmp * snmp,
+ SnmpSocket socket,
+ const SnmpTarget &target,
+ Pdu &pdu,
+ unsigned char * rawPdu,
+ size_t rawPduLen,
+ const Address & address,
+ snmp_callback callBack,
+ void * callData);
+ virtual ~CSNMPMessage();
+ unsigned long GetId() const { return m_uniqueId; };
+ void ResetId(const unsigned long newId) { m_uniqueId = newId; };
+ void SetSendTime();
+ void GetSendTime(msec &sendTime) const { sendTime = m_sendTime; };
+ SnmpSocket GetSocket() const { return m_socket; };
+ int SetPdu(const int reason, const Pdu &pdu, const UdpAddress &fromaddress);
+ int GetPdu(int &reason, Pdu &pdu)
+ { pdu = m_pdu; reason = m_reason; return 0; };
+ int GetReceived() const { return m_received; };
+ int ResendMessage();
+ int Callback(const int reason);
+ SnmpTarget *GetTarget() { return m_target; };
+
+ protected:
+
+ unsigned long m_uniqueId;
+ msec m_sendTime;
+ Snmp * m_snmp;
+ SnmpSocket m_socket;
+ SnmpTarget * m_target;
+ Pdu m_pdu;
+ unsigned char * m_rawPdu;
+ size_t m_rawPduLen;
+ Address * m_address;
+ snmp_callback m_callBack;
+ void * m_callData;
+ int m_reason;
+ int m_received;
+};
+
+ /*-----------------------------------------------------------*/
+ /* CSNMPMessageQueue */
+ /* class describing a collection of outstanding SNMP msgs. */
+ /*-----------------------------------------------------------*/
+class DLLOPT CSNMPMessageQueue: public CEvents
+{
+ public:
+ CSNMPMessageQueue(EventListHolder *holder, Snmp *session);
+ virtual ~CSNMPMessageQueue();
+ CSNMPMessage *AddEntry(unsigned long id, Snmp *snmp, SnmpSocket socket,
+ const SnmpTarget &target, Pdu &pdu, unsigned char * rawPdu,
+ size_t rawPduLen, const Address & address,
+ snmp_callback callBack, void * callData);
+ CSNMPMessage *GetEntry(const unsigned long uniqueId);
+ int DeleteEntry(const unsigned long uniqueId);
+ void DeleteSocketEntry(const SnmpSocket socket);
+ // find the next msg that will timeout
+ CSNMPMessage *GetNextTimeoutEntry();
+ // find the next timeout
+ int GetNextTimeout(msec &sendTime);
+#ifdef HAVE_POLL_SYSCALL
+ int GetFdCount();
+ bool GetFdArray(struct pollfd *readfds, int &remaining);
+ int HandleEvents(const struct pollfd *readfds, const int fds);
+#else
+ // set up parameters for select
+ void GetFdSets(int &maxfds, fd_set &readfds, fd_set &writefds,
+ fd_set &exceptfds);
+ int HandleEvents(const int maxfds,
+ const fd_set &readfds,
+ const fd_set &writefds,
+ const fd_set &exceptfds);
+#endif
+
+ // return number of outstanding messages
+ int GetCount() { return m_msgCount; };
+
+ int DoRetries(const msec &sendtime);
+
+ int Done();
+ int Done(unsigned long);
+
+ protected:
+
+ /*---------------------------------------------------------*/
+ /* CSNMPMessageQueueElt */
+ /* a container for a single item on a linked lists of */
+ /* CSNMPMessages. */
+ /*---------------------------------------------------------*/
+ class DLLOPT CSNMPMessageQueueElt
+ {
+ public:
+ CSNMPMessageQueueElt(CSNMPMessage *message,
+ CSNMPMessageQueueElt *next,
+ CSNMPMessageQueueElt *previous);
+
+ ~CSNMPMessageQueueElt();
+ CSNMPMessageQueueElt *GetNext() { return m_Next; }
+ CSNMPMessage *GetMessage() { return m_message; }
+ CSNMPMessage *TestId(const unsigned long uniqueId);
+
+ private:
+
+ CSNMPMessage *m_message;
+ class CSNMPMessageQueueElt *m_Next;
+ class CSNMPMessageQueueElt *m_previous;
+ };
+
+ CSNMPMessageQueueElt m_head;
+ int m_msgCount;
+ EventListHolder *my_holder;
+ Snmp *m_snmpSession;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## notifyqueue.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ N O T I F Y Q U E U E. H
+
+ CNotifyEventQueue CLASS DEFINITION
+
+ COPYRIGHT HEWLETT PACKARD COMPANY 1999
+
+ INFORMATION NETWORKS DIVISION
+
+ NETWORK MANAGEMENT SECTION
+
+ DESIGN + AUTHOR: Tom Murray
+
+ DESCRIPTION:
+ Queue for holding sessions waiting for notifiactions
+
+=====================================================================*/
+// $Id: notifyqueue.h 1550 2009-06-26 19:59:30Z katz $
+
+#ifndef _NOTIFYQUEUE
+#define _NOTIFYQUEUE
+
+//----[ includes ]-----------------------------------------------------
+#include <sys/types.h> // NOTE: due to 10.10 bug, order is important
+ // in that all routines must include types.h
+ // and time.h in same order otherwise you
+ // will get conflicting definitions of
+ // "fd_set" resulting in link time errors.
+#ifndef WIN32
+#if !(defined CPU && CPU == PPC603)
+#include <sys/time.h> // time stuff and fd_set
+#endif
+#endif
+
+//----[ snmp++ includes ]----------------------------------------------
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/oid.h"
+#include "snmp_pp/target.h"
+#include "snmp_pp/eventlist.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class Snmp; // instead of snmp_pp.h
+class msec;
+class EventListHolder;
+
+//----[ defines ]------------------------------------------------------
+
+//----[ CNotifyEvent class ]-------------------------------------------
+
+/*----------------------------------------------------------------*/
+/* CNotifyEvent */
+/* a description of a sessions waiting for async notifiactions. */
+/*----------------------------------------------------------------*/
+class DLLOPT CNotifyEvent
+{
+ public:
+
+ CNotifyEvent(Snmp* snmp,
+ const OidCollection &trapids,
+ const TargetCollection &targets);
+ ~CNotifyEvent();
+ Snmp * GetId() { return m_snmp; };
+ int notify_filter(const Oid &trapid, SnmpTarget &target) const;
+ int Callback(SnmpTarget &target, Pdu &pdu, SnmpSocket fd, int status);
+ void get_filter(OidCollection &o, TargetCollection &t)
+ { o = *notify_ids; t = *notify_targets; };
+
+ protected:
+ Snmp *m_snmp;
+ TargetCollection *notify_targets;
+ OidCollection *notify_ids;
+};
+
+ /*-----------------------------------------------------------*/
+ /* CNotifyEventQueue */
+ /* class describing a collection of outstanding SNMP msgs. */
+ /*-----------------------------------------------------------*/
+class DLLOPT CNotifyEventQueue: public CEvents
+{
+ public:
+ CNotifyEventQueue(EventListHolder *holder, Snmp *session);
+ ~CNotifyEventQueue();
+ int AddEntry(Snmp * snmp,
+ const OidCollection &trapids,
+ const TargetCollection &targets);
+ CNotifyEvent * GetEntry(Snmp * snmp);
+ void DeleteEntry(Snmp * snmp);
+
+ // find the next timeout
+ int GetNextTimeout(msec &/*timeout*/) { return 1; }; // we have no timeouts
+ // set up parameters for select
+#ifdef HAVE_POLL_SYSCALL
+ int GetFdCount();
+ bool GetFdArray(struct pollfd *readfds, int &remaining);
+ int HandleEvents(const struct pollfd *readfds, const int fds);
+#else
+ void GetFdSets(int &maxfds, fd_set &readfds, fd_set &writefds,
+ fd_set &exceptfds);
+ int HandleEvents(const int maxfds,
+ const fd_set &readfds,
+ const fd_set &writefds,
+ const fd_set &exceptfds);
+#endif
+ // return number of outstanding messages
+ int GetCount() { return m_msgCount; };
+
+ int DoRetries(const msec &/*sendtime*/) { return 0; }; // nothing to retry
+
+ int Done() { return 0; }; // we are never done
+ void set_listen_port(int port) { m_listen_port = port; };
+ int get_listen_port() { return m_listen_port; };
+ SnmpSocket get_notify_fd() const;
+
+ protected:
+
+ /*-----------------------------------------------------------*/
+ /* CNotifyEventQueueElt */
+ /* a container for a single item on a linked lists of */
+ /* CNotifyEvents. */
+ /*-----------------------------------------------------------*/
+ class DLLOPT CNotifyEventQueueElt
+ {
+ public:
+ CNotifyEventQueueElt(CNotifyEvent *notifyevent,
+ CNotifyEventQueueElt *next,
+ CNotifyEventQueueElt *previous);
+
+ ~CNotifyEventQueueElt();
+ CNotifyEventQueueElt *GetNext() { return m_Next; };
+ CNotifyEvent *GetNotifyEvent() { return m_notifyevent; };
+ CNotifyEvent *TestId(Snmp *snmp);
+
+ private:
+
+ CNotifyEvent *m_notifyevent;
+ class CNotifyEventQueueElt *m_Next;
+ class CNotifyEventQueueElt *m_previous;
+ };
+
+ void cleanup();
+
+ CNotifyEventQueueElt m_head;
+ int m_msgCount;
+ SnmpSocket m_notify_fd;
+ int m_listen_port;
+ EventListHolder *my_holder;
+ Snmp *m_snmpSession;
+ UdpAddress m_notify_addr;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // NOTIFYQUEUE
--- /dev/null
+/*_############################################################################
+ _##
+ _## octet.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ O C T E T . H
+
+ OCTETSTR CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ This class is fully contained and does not rely on or any other
+ SNMP libraries. This class is portable across any platform
+ which supports C++.
+=====================================================================*/
+// $Id: octet.h 1824 2010-08-29 19:47:08Z katz $
+
+#ifndef _OCTET_CLS
+#define _OCTET_CLS
+
+#include "snmp_pp/smival.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//------------[ SNMP++ OCTETSTR CLASS DEF ]-----------------------------
+class DLLOPT OctetStr: public SnmpSyntax
+{
+ public:
+
+ /**
+ * Enum for setting the hex output format.
+ */
+ enum OutputType
+ {
+ OutputHexAndClear,
+ OutputHex,
+ OutputClear
+ };
+
+ //-----------[ Constructors and Destrucotr ]----------------------
+
+ /**
+ * Constructs a valid OctetStr with zero length.
+ */
+ OctetStr();
+
+ /**
+ * Constructs a OctetStr with the given value.
+ * The OctetStr will be valid unless a call to new fails.
+ *
+ * @param str - Null terminated string
+ */
+ OctetStr(const char *str);
+
+ /**
+ * Constructs a OctetStr with the given value.
+ * The OctetStr will be valid unless a call to new fails.
+ *
+ * @param str - string that may contain null bytes
+ * @param len - length of the string
+ */
+ OctetStr(const unsigned char *str, unsigned long len);
+
+ /**
+ * Construct a OctetStr from another OctetStr.
+ * The OctetStr will be valid unless a call to new fails.
+ *
+ * @param octet - Value for the new object
+ */
+ OctetStr(const OctetStr &octet);
+
+ /**
+ * Destructor, frees allocated space.
+ */
+ ~OctetStr();
+
+ //-----------[ Overloaded operators ]----------------------
+
+ /**
+ * Assign a char string to a OctetStr.
+ */
+ OctetStr& operator=(const char *str);
+
+ /**
+ * Assign a OctetStr to a OctetStr.
+ */
+ OctetStr& operator=(const OctetStr &octet);
+
+ /**
+ * Equal operator for two OctetStr.
+ */
+ DLLOPT friend int operator==(const OctetStr &lhs, const OctetStr &rhs);
+
+ /**
+ * Not equal operator for two OctetStr.
+ */
+ DLLOPT friend int operator!=(const OctetStr &lhs, const OctetStr &rhs);
+
+ /**
+ * Not equal operator for two OctetStr.
+ */
+ DLLOPT friend int operator<(const OctetStr &lhs, const OctetStr &rhs);
+
+ /**
+ * Less than operator for two OctetStr.
+ */
+ DLLOPT friend int operator<=(const OctetStr &lhs,const OctetStr &rhs);
+
+ /**
+ * Greater than operator for two OctetStr.
+ */
+ DLLOPT friend int operator>(const OctetStr &lhs, const OctetStr &rhs);
+
+ /**
+ * Greater than or equal operator for two OctetStr.
+ */
+ DLLOPT friend int operator>=(const OctetStr &lhs, const OctetStr &rhs);
+
+ /**
+ * Equal operator for OctetStr and char string.
+ */
+ DLLOPT friend int operator==(const OctetStr &lhs, const char *rhs);
+
+ /**
+ * Not equal operator for OctetStr and char string.
+ */
+ DLLOPT friend int operator!=(const OctetStr &lhs, const char *rhs);
+
+ /**
+ * Less than operator for OctetStr and char string.
+ */
+ DLLOPT friend int operator<(const OctetStr &lhs, const char *rhs);
+
+ /**
+ * Less than or equal operator for OctetStr and char string.
+ */
+ DLLOPT friend int operator<=(const OctetStr &lhs, const char *rhs);
+
+ /**
+ * Greater than operator for OctetStr and char string.
+ */
+ DLLOPT friend int operator>(const OctetStr &lhs, const char *rhs);
+
+ /**
+ * Greater than or equal operator for OctetStr and char string.
+ */
+ DLLOPT friend int operator>=(const OctetStr &lhs, const char *rhs);
+
+ /**
+ * Append a char string to this OctetStr.
+ */
+ OctetStr& operator+=(const char *a);
+
+ /**
+ * Append a single char to this OctetStr.
+ */
+ OctetStr& operator+=(const unsigned char c);
+
+ /**
+ * Append another OctetStr to this OctetStr.
+ */
+ OctetStr& operator+=(const OctetStr& octet);
+
+ /**
+ * Allow access as if it was an array.
+ *
+ * @note The given param is not checked for validity.
+ */
+ unsigned char &operator[](int i)
+ { m_changed = true; return smival.value.string.ptr[i]; };
+
+ /**
+ * Allow access as if it was an array for const OctetStr objects.
+ *
+ * @note The given param is not checked for validity.
+ */
+ unsigned char operator[](int i) const { return smival.value.string.ptr[i]; };
+
+ /**
+ * Return the syntax.
+ *
+ * @return This method always returns sNMP_SYNTAX_OCTETS.
+ */
+ SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OCTETS; };
+
+ /**
+ * Return the space needed for serialization.
+ */
+ int get_asn1_length() const;
+
+ /**
+ * Return validity of the object.
+ */
+ bool valid() const { return validity; };
+
+ /**
+ * Clone this object.
+ *
+ * @return Pointer to the newly created object (allocated through new).
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *) new OctetStr(*this); };
+
+ /**
+ * Map other SnmpSyntax objects to OctetStr.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ /**
+ * Get a printable ASCII value of the string.
+ *
+ * @note Depending on the selected output format, this method will
+ * return get_printable_hex() or get_printable_clear() if the
+ * string contains not printable characters.
+ *
+ * @return Printable, null terminated string
+ */
+ const char *get_printable() const;
+
+ /**
+ * Get an ASCII formatted hex dump of the contents.
+ * If the output format was set to OctetStr::OutputHexAndClear,
+ * the produced string of this method will look like this:
+ * <pre>
+ * 09 4F 63 74 65 74 53 74 72 3A 3A 67 65 74 5F 70 .OctetStr::get_p
+ * 72 69 6E 74 61 62 6C 65 5F 68 65 78 28 29 rintable_hex()
+ * </pre>
+ * If the output format was set to OctetStr::OutputHex the
+ * produced string will look like this:
+ * <pre>
+ * 09 4F 63 74 65 74 53 74 72 3A 3A 67 65 74 5F 70
+ * 72 69 6E 74 61 62 6C 65 5F 68 65 78 28 29
+ * </pre>
+ * @return Printable, null terminated string.
+ */
+ const char *get_printable_hex() const;
+
+ /**
+ * Get the contents with all non printable characters replaced.
+ *
+ * @return Printable, null terminated string.
+ */
+ const char *get_printable_clear() const;
+
+ /**
+ * Set the output format for get_pritable_hex().
+ */
+ static void set_hex_output_type(const enum OutputType ot)
+ { hex_output_type = ot; };
+
+ /**
+ * Set the char get_printable_hex() and get_printable_clear()
+ * will use for non printable characters.
+ */
+ static void set_np_char(const char np) { nonprintable_char = np; };
+
+ /**
+ * Set the data on an already constructed OctetStr.
+ * The given string is copied to an internal member var, so the
+ * params can be destroyed afterwards.
+ *
+ * @param str - The new string value
+ * @param len - Length of the given string
+ */
+ void set_data(const unsigned char *str, unsigned long len);
+
+ /**
+ * Get the length of the string.
+ */
+ unsigned long len() const { return smival.value.string.len; };
+
+ /**
+ * Get a pointer to internal data.
+ */
+ unsigned char *data() const { return smival.value.string.ptr; };
+
+ // compare n elements of an octet
+ int nCompare(const unsigned long n, const OctetStr &o) const;
+
+ /**
+ * Build an OctetStr from a hex string.
+ * Called with "5465 737469 6e672074686973206D657468 6f 64 21"
+ * the returned value will be "Testing this method!"
+ *
+ * @param hex_string - The hex string (may contain spaces)
+ * @return created string
+ */
+ static OctetStr from_hex_string(const OctetStr &hex_string);
+
+ /**
+ * Set the character for linefeeds in get_printable() functions.
+ *
+ * The default linefeeds are \n for Unix and \r\n on other systems.
+ *
+ * @param lf_chars - string less than 3 bytes
+ * @return true on success
+ */
+ static bool set_linefeed_chars(const char* lf_chars);
+
+ /**
+ * Null out the contents of the string. The string will be empty
+ * after calling this method
+ */
+ void clear();
+
+ /**
+ * Append or shorten the internal data buffer.
+ *
+ * The buffer will either be shortened or extended. In the second case
+ * zeroes are added to the end of the string.
+ *
+ * @param new_len - The new length for the string
+ * @return true on success
+ */
+ bool set_len(const unsigned long new_len);
+
+ protected:
+
+ enum OutputFunction
+ {
+ OutputFunctionDefault,
+ OutputFunctionHex,
+ OutputFunctionClear
+ };
+
+ SNMP_PP_MUTABLE char *output_buffer; // formatted Octet value
+ SNMP_PP_MUTABLE unsigned int output_buffer_len; // allocated space for string
+ SNMP_PP_MUTABLE bool m_changed;
+ SNMP_PP_MUTABLE enum OutputType output_last_type;
+ SNMP_PP_MUTABLE char output_last_np_char;
+ SNMP_PP_MUTABLE enum OutputFunction output_last_function;
+
+
+ bool validity; // validity boolean
+
+ static enum OutputType hex_output_type;
+ static char nonprintable_char;
+ static char linefeed_chars[3];
+};
+
+//-----------[ End OctetStr Class ]-------------------------------------
+
+/**
+ * The OpaqueStr class represents the Opaque SNMP type. It is derived from
+ * the SNMP++ class OctetStr and has the same interfaces and behavior,
+ * except that its syntax is sNMP_SYNTAX_OPAQUE.
+ */
+class OpaqueStr: public OctetStr
+{
+ public:
+ /**
+ * Constructor creating a valid zero length OpaqueStr.
+ */
+ OpaqueStr(): OctetStr()
+ { smival.syntax = sNMP_SYNTAX_OPAQUE; };
+
+ /**
+ * Constructs a OpaqueStr with the given value.
+ * The OpaqueStr will be valid unless a call to new fails.
+ *
+ * @param str - Null terminated string
+ */
+ OpaqueStr(const char *str) : OctetStr(str)
+ { smival.syntax = sNMP_SYNTAX_OPAQUE; };
+
+ /**
+ * Constructs a OpaqueStr with the given value.
+ * The OpaqueStr will be valid unless a call to new fails.
+ *
+ * @param str - string that may contain null bytes
+ * @param len - length of the string
+ */
+ OpaqueStr(const unsigned char *str, unsigned long length)
+ : OctetStr(str, length) { smival.syntax = sNMP_SYNTAX_OPAQUE; };
+
+ /**
+ * Construct a OpaqueStr from an OctetStr.
+ * The OpaqueStr will be valid unless a call to new fails.
+ *
+ * @param octet - Value for the new object
+ */
+ OpaqueStr(const OctetStr &octet) : OctetStr(octet)
+ { smival.syntax = sNMP_SYNTAX_OPAQUE; };
+
+ /**
+ * Construct a OpaqueStr from another OpaqueStr.
+ * The OpaqueStr will be valid unless a call to new fails.
+ *
+ * @param opaque - Value for the new object
+ */
+ OpaqueStr(const OpaqueStr& opaque) : OctetStr(opaque)
+ { smival.syntax = sNMP_SYNTAX_OPAQUE; };
+
+ /**
+ * Clone this object.
+ *
+ * @return Pointer to the newly created object (allocated through new).
+ */
+ virtual SnmpSyntax *clone() const { return new OpaqueStr(*this); }
+
+ /**
+ * Return the syntax.
+ *
+ * @return This method always returns sNMP_SYNTAX_OPAQUE.
+ */
+ virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OPAQUE; };
+
+ /**
+ * Map other SnmpSyntax objects to OpaqueStr.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val)
+ { return OctetStr::operator=(val); }
+
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _OCTET_CLS
--- /dev/null
+/*_############################################################################
+ _##
+ _## oid.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ O I D. H
+
+ OID CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ This class is fully contained and does not rely on or any other
+ SNMP libraries. This class is portable across any platform
+ which supports C++.
+
+=====================================================================*/
+// $Id: oid.h 1775 2010-07-11 09:59:28Z katz $
+
+#ifndef _OID_H_
+#define _OID_H_
+
+//------------------------------------------------------------------------
+
+#include "snmp_pp/smival.h" // derived class for all values
+#include "snmp_pp/collect.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+/**
+ * The Object Identifier Class.
+ *
+ * The Object Identification (Oid) class is the encapsulation of an
+ * SMI object identifier. The SMI object is a data identifier for a
+ * data element found in a Management Information Base (MIB), as
+ * defined by a MIB definition. The SMI Oid, its related structures
+ * and functions, are a natural fit for object orientation. In fact,
+ * the Oid class shares many common features to the C++ String
+ * class. For those of you familiar with the C++ String class or
+ * Microsoft's Foundation Classes (MFC) CString class, the Oid class
+ * will be familiar and easy to use. The Oid class is designed to be
+ * efficient and fast. The Oid class allows definition and
+ * manipulation of object identifiers.
+ *
+ * @note Oid holds two internal buffers for get_printable() functions.
+ * The buffer returned by get_printable() is valid until the
+ * Oid object is modified. The functions get_printable(len) and
+ * get_printable(start, len) share the same buffer which is
+ * freed and newly allocated for each call.
+ */
+class DLLOPT Oid : public SnmpSyntax
+{
+ public:
+
+ /**
+ * Construct an invalid Oid.
+ */
+ Oid();
+
+ /**
+ * Construct an Oid from a string.
+ *
+ * Depending on the second param, the oid_string can either be
+ * - a dotted oid string (like "1.3.6.1.6"). An arbitrary part
+ * of the oid can be given as a string value enclosed in
+ * '$' characters. For example the oid string
+ * "1.3.6.1.6.1.12.1.3.$public0$" will result to the oid
+ * 1.3.6.1.6.1.12.1.3.112.117.98.108.105.99.95.48
+ * - a normal string (like "public"). The Oid will have the
+ * ASCII values of the string characters. So "public" will
+ * result to the oid 112.117.98.108.105.99
+ *
+ * @param oid_string - for example "1.3.1.6.1.10"
+ * @param is_dotted_oid_string - Select format within oid_string
+ */
+ Oid(const char *oid_string, const bool is_dotted_oid_string = true);
+
+ /**
+ * Constructor using another oid object (copy constructor).
+ *
+ * @param oid - Source Oid
+ */
+ Oid(const Oid &oid);
+
+ /**
+ * Constructor from array.
+ *
+ * @param raw_oid - array of oid values
+ * @param oid_len - length of array
+ */
+ Oid(const unsigned long *raw_oid, int oid_len);
+
+ /**
+ * Destructor.
+ */
+ virtual ~Oid();
+
+ /**
+ * Return the current syntax.
+ *
+ * @return always sNMP_SYNTAX_OID
+ */
+ SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OID; };
+
+ /**
+ * Assignment from a string.
+ *
+ * @param dotted_oid_string - New value (for example "1.3.6.1.6.0");
+ */
+ virtual Oid& operator=(const char *dotted_oid_string);
+
+ /**
+ * Assign one Oid to another.
+ */
+ virtual Oid& operator=(const Oid &oid);
+
+ /**
+ * Return the space needed for serialization.
+ */
+ int get_asn1_length() const;
+
+ /**
+ * Overloaded equal operator.
+ */
+ DLLOPT friend int operator==(const Oid &lhs, const Oid &rhs);
+
+ /**
+ * Overloaded not equal operator.
+ */
+ DLLOPT friend int operator!=(const Oid &lhs, const Oid &rhs)
+ { return (!(lhs == rhs)); }; // just invert ==
+
+ /**
+ * Overloaded less than < operator.
+ */
+ DLLOPT friend int operator<(const Oid &lhs, const Oid &rhs);
+
+ /**
+ * Overloaded less than <= operator.
+ */
+ DLLOPT friend int operator<=(const Oid &lhs, const Oid &rhs)
+ { return ((lhs < rhs) || (lhs == rhs)); };
+
+ /**
+ * Overloaded greater than > operator.
+ */
+ DLLOPT friend int operator>(const Oid &lhs, const Oid &rhs)
+ { return (!(lhs <= rhs)); }; // just invert existing <=
+
+ /**
+ * Overloaded greater than >= operator.
+ */
+ DLLOPT friend int operator>=(const Oid &lhs, const Oid &rhs)
+ { return (!(lhs < rhs)); }; // just invert existing <
+
+ /**
+ * Overloaded equal operator operator.
+ */
+ DLLOPT friend int operator==(const Oid &lhs, const char *rhs);
+
+ /**
+ * Overloaded not equal operator.
+ */
+ DLLOPT friend int operator!=(const Oid &lhs, const char *rhs);
+
+ /**
+ * Overloaded less than < operator.
+ */
+ DLLOPT friend int operator<(const Oid &lhs, const char *rhs);
+
+ /**
+ * Overloaded less than <= operator.
+ */
+ DLLOPT friend int operator<=(const Oid &lhs, char *rhs);
+
+ /**
+ * Overloaded greater than > operator.
+ */
+ DLLOPT friend int operator>(const Oid &lhs, const char *rhs);
+
+ /**
+ * Overloaded greater than >= operator.
+ */
+ DLLOPT friend int operator>=(const Oid &lhs, const char *rhs);
+
+ /**
+ * Overloaded operator +, Concatenate two Oids.
+ */
+ DLLOPT friend Oid operator +(const Oid &lhs, const Oid &rhs)
+ { Oid tmp(lhs); tmp += rhs; return tmp;};
+
+ /**
+ * Append operator, appends the dotted oid string.
+ *
+ * @param a - dotted oid string, for example "5.192.14.6"
+ */
+ Oid& operator+=(const char *a);
+
+ /**
+ * Appends an int.
+ *
+ * @param i - Value to add at the end of the Oid
+ */
+ Oid& operator+=(const unsigned long i);
+
+ /**
+ * Appends an Oid.
+ *
+ * @param o - Oid to add at the end
+ */
+ Oid& operator+=(const Oid &o);
+
+ /**
+ * Allows element access as an array.
+ * This method behaves like real array: if your index
+ * is out of bounds, you're lost!
+ *
+ * @param index - valid index -- 0 to (len() - 1)
+ *
+ * @return Value on the given index
+ */
+ unsigned long &operator[](const unsigned int index)
+ { m_changed = true; return smival.value.oid.ptr[index]; };
+
+ /**
+ * Allows element access as an array for const objects.
+ * This method behaves like real array: if your index
+ * is out of bounds, you're lost!
+ *
+ * @param index - valid index -- 0 to (len() - 1)
+ *
+ * @return Value on the given position
+ */
+ unsigned long operator[](const unsigned int index) const
+ { return (index >= len()) ? 0 : smival.value.oid.ptr[index]; };
+
+ /**
+ * Get the WinSnmp oid part.
+ * @note This method returns a pointer to internal data.
+ * If it is modified, the Oid changes too.
+ *
+ * @return pointer to the internal oid structure.
+ */
+ SmiLPOID oidval() { return (SmiLPOID) &smival.value.oid; };
+
+ /**
+ * Set the data from raw form.
+ *
+ * @param raw_oid - Array of new values
+ * @param oid_len - Length of the array raw_oid
+ */
+ void set_data(const unsigned long *raw_oid, const unsigned int oid_len);
+
+ /**
+ * Set the data from raw form.
+ *
+ * @param str - Array of new values (a string)
+ * @param str_len - Length of the array raw_oid
+ */
+ void set_data(const char *str, const unsigned int str_len);
+
+ /**
+ * Get the length of the oid.
+ */
+ unsigned long len() const { return smival.value.oid.len; };
+
+ /**
+ * Trim off the rightmost values of an oid.
+ *
+ * @param n - Trim off n values from the right (default is one)
+ */
+ void trim(const unsigned long n = 1);
+
+ /**
+ * Compare two Oids from the left in direction left-to-right.
+ *
+ * @param n - Subvalues to compare
+ * @param o - The Oid to compare with
+ *
+ * @return 0 if equal / -1 if less / 1 if greater
+ */
+ int nCompare(const unsigned long n, const Oid &o) const;
+
+ /**
+ * Return validity of the object.
+ */
+ bool valid() const { return (smival.value.oid.ptr ? true : false); };
+
+ /**
+ * Get a printable ASCII string of the whole value.
+ *
+ * @return Dotted oid string (for example "1.3.6.1.6.0")
+ */
+ const char *get_printable() const
+ { return get_printable(1, smival.value.oid.len, (char*&)iv_str); };
+
+ /**
+ * Get a printable ASCII string of the right part of the value.
+ *
+ * @param n - positions to print, counted from right.
+ *
+ * @return Dotted oid string (for example "6.0")
+ */
+ const char *get_printable(const unsigned long n) const
+ { return get_printable(smival.value.oid.len - n + 1, n, (char*&)iv_part_str); };
+
+ /**
+ * Get a printable ASCII string of a part of the value.
+ *
+ * @param start - First position to print, starting with 1 (not zero!)
+ * @param n - positions to print.
+ * @param buffer - pointer to the returned buffer
+ *
+ * @note If buffer is not NULL, this function calls "delete [] buffer",
+ * a new buffer is allocated using "new" and the caller has
+ * to delete it.
+ *
+ * @return Dotted oid string (for example "3.6.1.6")
+ */
+ const char *get_printable(const unsigned long start,
+ const unsigned long n,
+ char *&buffer) const;
+
+ /**
+ * Get a printable ASCII string of a part of the value.
+ *
+ * @param start - First position to print, starting with 1 (not zero!)
+ * @param n - positions to print.
+ *
+ * @return Dotted oid string (for example "3.6.1.6")
+ */
+ const char *get_printable(const unsigned long start,
+ const unsigned long n) const
+ { return get_printable(start, n, (char*&)iv_part_str); };
+
+ /**
+ * Clone this object.
+ *
+ * @return Pointer to the newly created object (allocated through new).
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *) new Oid(*this); };
+
+ /**
+ * Map other SnmpSyntax objects to Oid.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ /**
+ * Clear the Oid.
+ */
+ void clear() { delete_oid_ptr(); };
+
+ protected:
+ /**
+ * Convert a string to an smi oid.
+ *
+ * @param string - input string
+ * @param dstOid - destination oid
+ */
+ virtual int StrToOid(const char *string, SmiLPOID dstOid) const;
+
+ /**
+ * Clone an smi oid.
+ *
+ * @param srcOid - source oid
+ * @param dstOid - destination oid
+ */
+ virtual int OidCopy(SmiLPOID srcOid, SmiLPOID dstOid) const;
+
+ /**
+ * Convert an smi oid to its string representation.
+ *
+ * @param srcOid - source oid
+ * @param size - size of string
+ * @param string - pointer to string
+ */
+ virtual int OidToStr(const SmiOID *srcOid,
+ SmiUINT32 size,
+ char *string) const;
+
+ /**
+ * Free the internal oid pointer and set the pointer and the length to zero.
+ */
+ inline void delete_oid_ptr();
+
+ //----[ instance variables ]
+
+ SNMP_PP_MUTABLE char *iv_str; // used for returning complete oid string
+ SNMP_PP_MUTABLE char *iv_part_str; // used for returning part oid string
+ SNMP_PP_MUTABLE bool m_changed;
+};
+
+//-----------[ End Oid Class ]-------------------------------------
+
+// create OidCollection type
+typedef SnmpCollection <Oid> OidCollection;
+
+inline void Oid::delete_oid_ptr()
+{
+ // delete the old value
+ if (smival.value.oid.ptr)
+ {
+ delete [] smival.value.oid.ptr;
+ smival.value.oid.ptr = 0;
+ }
+ smival.value.oid.len = 0;
+ m_changed = true;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif //_OID_H_
--- /dev/null
+/*_############################################################################
+ _##
+ _## oid_def.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ SNMP++ O I D _ D E F . H
+
+ OID_DEF DEFINITIONS
+
+ DESCRIPTION:
+ Some common Oid definitions.
+
+ DESIGN + AUTHOR: Peter E Mellquist
+=====================================================================*/
+// $Id: oid_def.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _OID_DEF
+#define _OID_DEF
+
+#include "snmp_pp/oid.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+/** SMI trap oid def */
+class snmpTrapsOid: public Oid {
+ public:
+ DLLOPT snmpTrapsOid() : Oid("1.3.6.1.6.3.1.1.5") {};
+};
+
+/** SMI Enterprose Oid */
+class snmpTrapEnterpriseOid: public Oid {
+ public:
+ DLLOPT snmpTrapEnterpriseOid() : Oid("1.3.6.1.6.3.1.1.4.3.0") {};
+};
+
+/** SMI Cold Start Oid */
+class coldStartOid: public snmpTrapsOid {
+ public:
+ DLLOPT coldStartOid() { *this+=".1"; };
+};
+
+/** SMI WarmStart Oid */
+class warmStartOid: public snmpTrapsOid {
+ public:
+ DLLOPT warmStartOid() { *this+=".2"; };
+};
+
+/** SMI LinkDown Oid */
+class linkDownOid: public snmpTrapsOid {
+ public:
+ DLLOPT linkDownOid() { *this+=".3"; };
+};
+
+/** SMI LinkUp Oid */
+class linkUpOid: public snmpTrapsOid {
+ public:
+ DLLOPT linkUpOid() { *this+=".4"; };
+};
+
+/** SMI Authentication Failure Oid */
+class authenticationFailureOid: public snmpTrapsOid {
+ public:
+ DLLOPT authenticationFailureOid() { *this+=".5"; };
+};
+
+/** SMI egpneighborloss Oid */
+class egpNeighborLossOid: public snmpTrapsOid {
+ public:
+ DLLOPT egpNeighborLossOid() { *this+=".6"; };
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _OID_DEF
--- /dev/null
+/*_############################################################################
+ _##
+ _## pdu.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ P D U . H
+
+ PDU CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ Pdu class definition. Encapsulation of an SMI Protocol
+ Data Unit (PDU) in C++.
+
+=====================================================================*/
+// $Id: pdu.h 288 2007-03-22 22:37:09Z katz $
+
+#ifndef _PDU_CLS
+#define _PDU_CLS
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/address.h"
+#include "snmp_pp/timetick.h"
+#include "snmp_pp/octet.h"
+#include "snmp_pp/oid.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class Vb;
+
+#define PDU_MAX_RID 32767 ///< max request id to use
+#define PDU_MIN_RID 1000 ///< min request id to use
+
+//=======================================================================
+// Pdu Class
+//=======================================================================
+/**
+ * Pdu class...
+ */
+class DLLOPT Pdu
+{
+ public:
+
+ /**
+ * Constructor no args.
+ *
+ * This constructor creates a valid empty Pdu object.
+ */
+ Pdu();
+
+ /**
+ * Constructor with vbs.
+ *
+ * The Pdu class does not take ownership of the array and the Vb
+ * objects, so if these were allocated with new, they must be freed
+ * by te user with delete.
+ *
+ * @param pvbs - Array of pointers to Vb objects
+ * @param pvb_count - Length of the array
+ */
+ Pdu(Vb* pvbs, const int pvb_count);
+
+ /**
+ * Constructor with another Pdu instance.
+ *
+ * @param pdu - source pdu object
+ */
+ Pdu(const Pdu &pdu) : vbs(0), vbs_size(0), vb_count(0) { *this = pdu; };
+
+ /**
+ * Destructor
+ */
+ virtual ~Pdu();
+
+ /**
+ * Overloaded assignment operator.
+ *
+ * @param pdu - Pdu that should be assigned to this object
+ */
+ Pdu& operator=(const Pdu &pdu);
+
+ /**
+ * Append a vb to the pdu.
+ *
+ * @param vb - The Vb that should be added (as last vb) to the pdu
+ */
+ Pdu& operator+=(const Vb &vb);
+
+ /**
+ * Clone a Pdu object.
+ *
+ * @return Pointer to a newly created Pdu object, that is identical to this
+ */
+ Pdu *clone() const { return new Pdu(*this); };
+
+ /**
+ * Get Pointers to all Vbs from Pdu.
+ *
+ * The caller has to allocate the array. The returned pointers point
+ * to the Vb objects that are internally used by the pdu. So any
+ * changes to the returned Vb objects will change the pdu. If the
+ * pdu is modified (e.g. through Pdu::trim()) afterwards, the
+ * returned array will contain invalid pointers.
+ *
+ * @param pvbs - Array of empty pointers of size pvb_count
+ * @param pvb_count - Amount of Vb pointers to get
+ *
+ * @return TRUE on success
+ */
+ int get_vblist(Vb* pvbs, const int pvb_count) const;
+
+ /**
+ * Deposit all Vbs to Pdu.
+ *
+ * The vb objects of the pdu will be freed and the objects from the
+ * array will be cloned and added to the pdu. If this method returns
+ * FALSE, the pdu will not conatin any Vb objects.
+ *
+ * @param pvbs - Array of valid pointers of size pvb_count
+ * @param pvb_count - Amount of Vb pointers i the array
+ *
+ * @return TRUE on success
+ */
+ int set_vblist(Vb* pvbs, const int pvb_count);
+
+ /**
+ * Get a particular Vb.
+ *
+ * @param vb - Object to store the vb
+ * @param index - The vb to get (zero is the first vb)
+ *
+ * @return TRUE on success
+ */
+ int get_vb(Vb &vb, const int index) const;
+
+ /**
+ * Return a reference to a particular Vb.
+ *
+ * @note Before calling this method, make sure that there
+ * is a Vb using get_vb_count().
+ *
+ * @param index - The Vb to return starting with 0.
+ * @return A const reference to the Vb
+ */
+ const Vb &get_vb(const int index) const { return *vbs[index]; };
+
+ /**
+ * Set a particular vb.
+ *
+ * If this method returns FALSE, the pdu has not been modified.
+ *
+ * @param vb - Source vb
+ * @param index - The vb to set (zero is the first vb)
+ *
+ * @return TRUE on success
+ */
+ int set_vb(Vb &vb, const int index);
+
+ /**
+ * Get the number of vbs.
+ *
+ * @return The number of Vb objects within the pdu.
+ */
+ int get_vb_count() const { return vb_count; };
+
+ /**
+ * Get a Vb.
+ *
+ * @note The index has to be checked by the caller.
+ *
+ * @param i zero based index
+ */
+ Vb& operator[](const int i) { return *vbs[i]; };
+
+ /**
+ * Get the error status.
+ *
+ * @return The SNMP error status
+ */
+ int get_error_status() const { return error_status; };
+
+ /**
+ * Set the error status.
+ *
+ * @param err - The new SNMP error status.
+ */
+ void set_error_status(const int err) { error_status = err; };
+
+ /**
+ * Clear the error status.
+ */
+ void clear_error_status() { error_status = 0; };
+
+ /**
+ * Get the error index.
+ *
+ * @return The SNMP error index
+ */
+ int get_error_index() const { return error_index; };
+
+ /**
+ * Set the error index.
+ *
+ * @param err - The new SNMP error index.
+ */
+ void set_error_index(const int index) { error_index = index; };
+
+ /**
+ * Clear the error index.
+ */
+ void clear_error_index() { error_index = 0; };
+
+ /**
+ * Clear error status and error index.
+ */
+ void clear_error() { set_error_status(0); set_error_index(0); }
+
+ /**
+ * Get the request id.
+ *
+ * @return The SNMP request id
+ */
+ unsigned long get_request_id() const { return request_id; };
+
+ /**
+ * Set the request id.
+ *
+ * @param rid - The new SNMP request id
+ */
+ void set_request_id(const unsigned long rid) { request_id = rid; };
+
+ /**
+ * Get the pdu type.
+ */
+ unsigned short get_type() const { return pdu_type; };
+
+ /**
+ * Set the pdu type.
+ */
+ void set_type(unsigned short type) { pdu_type = type; };
+
+ /**
+ * Returns validity of Pdu instance.
+ */
+ bool valid() const { return validity; };
+
+ /**
+ * Trim off vbs.
+ *
+ * @param count - number of vbs to trim of, starting with the last
+ * @return TRUE on success, FALSE if nothing was done
+ */
+ int trim(const int count=1);
+
+ /**
+ * Delete a Vb anywhere within the Pdu.
+ *
+ * @param position - Delete the Vb at this position (starting with 0)
+ * @return TRUE on success
+ */
+ int delete_vb(const int position);
+
+ /**
+ * Set notify timestamp.
+ */
+ void set_notify_timestamp(const TimeTicks &ts) { notify_timestamp = ts; };
+
+ /**
+ * Get notify timestamp.
+ */
+ void get_notify_timestamp(TimeTicks &ts) const { ts = notify_timestamp; };
+
+ /**
+ * Set the notify id.
+ *
+ * @return true if the set succeeded.
+ */
+ bool set_notify_id(const Oid &id)
+ { notify_id = id; return (notify_id.len() == id.len()); };
+
+ /**
+ * Get the notify id.
+ *
+ * @return true if the get succeeded.
+ */
+ bool get_notify_id(Oid &id) const
+ { id = notify_id; return (notify_id.len() == id.len()); };
+
+ /**
+ * Set the notify enterprise.
+ *
+ * @return true if the set succeeded.
+ */
+ bool set_notify_enterprise(const Oid &e)
+ { notify_enterprise = e; return (notify_enterprise.len() == e.len()); };
+
+ /**
+ * Get the notify enterprise.
+ *
+ * @return true if the get succeeded.
+ */
+ bool get_notify_enterprise(Oid & e) const
+ { e = notify_enterprise; return (notify_enterprise.len() == e.len()); };
+
+#ifdef _SNMPv3
+ /**
+ * Set the security level that should be used when this Pdu is sent.
+ * The default security level of a Pdu is SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV.
+ *
+ * @param level - One of SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV,
+ * SNMP_SECURITY_LEVEL_AUTH_NOPRIV,
+ * SNMP_SECURITY_LEVEL_AUTH_PRIV
+ */
+ void set_security_level(const int level) { security_level = level; };
+
+ /**
+ * Return the security level of the Pdu.
+ *
+ * @return - the security level
+ */
+ int get_security_level() const { return security_level; };
+
+ /**
+ * Set the context name of the Pdu.
+ *
+ * @param name - The context name
+ */
+ bool set_context_name(const OctetStr &name)
+ { context_name = name; return (context_name.valid() && name.valid()); };
+
+ /**
+ * Set the context name of the Pdu.
+ *
+ * @param name - The context name
+ */
+ bool set_context_name(const char *name)
+ { context_name = name; return context_name.valid(); };
+
+ /**
+ * Get the context name of the Pdu.
+ *
+ * @param name - Object fot the context name
+ */
+ bool get_context_name(OctetStr &name) const
+ { name = context_name; return (context_name.valid() && name.valid()); };
+
+ /**
+ * Get the context name of the Pdu.
+ *
+ * @return - Return the context name as an OctetStr
+ */
+ const OctetStr& get_context_name() const { return context_name; };
+
+ /**
+ * Set the context engine id of the Pdu.
+ *
+ * @param id - The new context engine id
+ */
+ bool set_context_engine_id(const OctetStr &id) { context_engine_id = id;
+ return (context_engine_id.valid() && id.valid()); };
+
+ /**
+ * Set the context engine id of the Pdu.
+ *
+ * @param id - The new context engine id
+ */
+ bool set_context_engine_id(const char *id)
+ { context_engine_id = id; return context_engine_id.valid(); };
+
+ /**
+ * Get the context engine id of the Pdu.
+ *
+ * @param id - Object for the context engine
+ */
+ bool get_context_engine_id(OctetStr &id) const { id = context_engine_id;
+ return (context_engine_id.valid() && id.valid()); };
+
+ /**
+ * Get the context engine id of the Pdu.
+ *
+ * @return - Return the context engine id as an OctetStr
+ */
+ const OctetStr& get_context_engine_id() const { return context_engine_id; };
+
+ /**
+ * Set the SNMPv3 message id (msgID)
+ *
+ * @param msg_id - the message id of the received message
+ */
+ void set_message_id(const unsigned long msg_id) { message_id = msg_id; }
+
+ /**
+ * Get the SNMPv3 message id (msgID)
+ *
+ * @return - the message id of the received message
+ */
+ unsigned long get_message_id() const { return message_id; }
+
+ /**
+ * Set the maximum size of the scoped pdu to be included in a
+ * possible response message.
+ *
+ * @param l - the maximum size
+ */
+ void set_maxsize_scopedpdu(unsigned long l) { maxsize_scopedpdu = l; };
+
+ /**
+ * Get the maximum size of the scoped pdu to be included in a
+ * possible response message.
+ *
+ * @return - the maximum size
+ */
+ unsigned long get_maxsize_scopedpdu() const { return maxsize_scopedpdu; };
+
+#endif // _SNMPv3
+
+ /**
+ * Get the SNMPv1 trap address
+ */
+ int get_v1_trap_address(GenAddress &address) const;
+
+ /**
+ * Set the SNMPv1 trap address
+ */
+ int set_v1_trap_address(const Address &address);
+
+ /**
+ * Return the length of the encoded vbs with pdu header.
+ *
+ * @note this method wll not work for v1 traps.
+ */
+ int get_asn1_length() const;
+
+ /**
+ * Clear the Pdu contents (destruct and construct in one go)
+ */
+ void clear();
+
+ /**
+ * Does the type of response match the type of request.
+ */
+ static bool match_type(const int request, const int response);
+
+ //-------------[ protected members ]--------------------------
+ protected:
+
+ /**
+ * Extend the vbs array.
+ *
+ * @return true on success
+ */
+ bool extend_vbs();
+
+ Vb **vbs; // pointer to array of Vbs
+ int vbs_size; // Size of array
+ int vb_count; // count of Vbs
+ int error_status; // SMI error status
+ int error_index; // SMI error index
+ bool validity; // valid boolean
+ unsigned long request_id; // SMI request id
+ unsigned short pdu_type; // derived at run time based on request type
+ // for notify Pdu objects only
+ // traps & notifies
+ TimeTicks notify_timestamp; // a timestamp associated with an infor
+ Oid notify_id; // an id
+ Oid notify_enterprise;
+ GenAddress v1_trap_address; // address object
+ int v1_trap_address_set;
+#ifdef _SNMPv3
+ // specific Objects for SNMPv3
+ int security_level; // the securityLevel with which this Pdu
+ // should be sent or was received
+ unsigned long message_id;
+ unsigned long maxsize_scopedpdu;
+ OctetStr context_name;
+ OctetStr context_engine_id;
+#endif // _SNMPv3
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif //_PDU_CLS
--- /dev/null
+/*_############################################################################
+ _##
+ _## reentrant.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+// $Id: reentrant.h 307 2007-09-14 20:01:45Z katz $
+
+#ifndef _reentrant_h_
+#define _reentrant_h_
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/smi.h"
+
+#ifdef _THREADS
+#ifdef WIN32
+#include <process.h>
+#elif defined (CPU) && CPU == PPC603
+#include <semLib.h>
+#else
+#include <pthread.h>
+#endif
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class DLLOPT SnmpSynchronized {
+
+ public:
+ SnmpSynchronized();
+ virtual ~SnmpSynchronized();
+#ifdef _THREADS
+#ifdef WIN32
+ CRITICAL_SECTION _mutex;
+#elif defined (CPU) && CPU == PPC603
+ SEM_ID _mutex;
+#else
+ pthread_mutex_t _mutex;
+#endif
+#endif
+ void lock();
+ void unlock();
+};
+
+class DLLOPT SnmpSynchronize {
+
+ public:
+ SnmpSynchronize(SnmpSynchronized& sync) : s(sync) { s.lock(); };
+ ~SnmpSynchronize() { s.unlock(); }
+
+ protected:
+ SnmpSynchronized& s;
+
+};
+
+#define REENTRANT(x) { SnmpSynchronize _synchronize(*this); x }
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif
+
--- /dev/null
+/*_############################################################################
+ _##
+ _## sha.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#if !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
+// $Id: sha.h 288 2007-03-22 22:37:09Z katz $
+/****************************************************************
+ * SHS.h - Secure Hash Standard (draft) FIPS 180-1 *
+ * *
+ * Copyright (C) 1994 Uri Blumenthal, uri@watson.ibm.com *
+ * Copyright (C) 1994 IBM T. J. Watson esearch Center *
+ * *
+ * Feel free to use this code, as long as you acknowledge the *
+ * ownership by U. Blumenthal and IBM Corp. and agree to hold *
+ * both harmless in case of ANY problem you may have with this *
+ * code. *
+ ****************************************************************/
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+typedef struct {
+ /* Message Digest words */
+ unsigned long int h[5];
+ /* Message length in bits */
+ unsigned long int count[2];
+ /* Current byte position in not-full-yet buf */
+ int index;
+ /* Buffer for the remainder of bytes mod 64 */
+ unsigned char X[64];
+} SHA_CTX;
+
+DLLOPT void SHAInit(SHA_CTX *ctx);
+DLLOPT void SHAUpdate(SHA_CTX *ctx, const unsigned char *buf, unsigned int lenBuf);
+DLLOPT void SHAFinal(unsigned char *digest, SHA_CTX *ctx);
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
--- /dev/null
+/*_############################################################################
+ _##
+ _## smi.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ S M I . H
+
+ SMI DEFINITIONS
+
+ AUTHOR: Peter E Mellquist
+=====================================================================*/
+// $Id: smi.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _SMIDEF
+#define _SMIDEF
+
+// make sure configuration is included first
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define WINFAR
+#define STRCAT strcat
+#define STRLEN strlen
+#define MEMCPY memcpy
+#define STRCPY strcpy
+#define MEMCMP memcmp
+#define XPORT
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+//----------[ ASN/BER Base Types ]-----------------------------------------
+/** @name ASN/BER Base Types
+ *
+ * Basic Encoding Rules (BER) (used in forming SYNTAXes and certain
+ * SNMP types/values).
+ */
+//@{
+#define aSN_UNIVERSAL (0x00)
+#define aSN_APPLICATION (0x40)
+#define aSN_CONTEXT (0x80)
+#define aSN_PRIVATE (0xC0)
+#define aSN_PRIMITIVE (0x00)
+#define aSN_CONSTRUCTOR (0x20)
+//@}
+
+//------[ SNMP ObjectSyntax Values ]---------------------------------------
+#define sNMP_SYNTAX_SEQUENCE (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x10)
+
+/** @name Syntax Types
+ *
+ * These values are used in the "syntax" member of the smiVALUE
+ * structure which follows.
+ *
+ * The get_syntax() method of any class derived from SnmpSyntax returns
+ * one of these values.
+ *
+ * @note UInt32 is indistinguishable from Gauge32 per SNMPv2 Draft Standard
+ * @note NsapAddr is obsoleted as unique SMI type per SNMPv2 Draft Standard
+ */
+//@{
+#define sNMP_SYNTAX_INT (aSN_UNIVERSAL | aSN_PRIMITIVE | 0x02)
+#define sNMP_SYNTAX_BITS (aSN_UNIVERSAL | aSN_PRIMITIVE | 0x03)
+#define sNMP_SYNTAX_OCTETS (aSN_UNIVERSAL | aSN_PRIMITIVE | 0x04)
+#define sNMP_SYNTAX_NULL (aSN_UNIVERSAL | aSN_PRIMITIVE | 0x05)
+#define sNMP_SYNTAX_OID (aSN_UNIVERSAL | aSN_PRIMITIVE | 0x06)
+#define sNMP_SYNTAX_INT32 sNMP_SYNTAX_INT
+#define sNMP_SYNTAX_IPADDR (aSN_APPLICATION | aSN_PRIMITIVE | 0x00)
+#define sNMP_SYNTAX_CNTR32 (aSN_APPLICATION | aSN_PRIMITIVE | 0x01)
+#define sNMP_SYNTAX_GAUGE32 (aSN_APPLICATION | aSN_PRIMITIVE | 0x02)
+#define sNMP_SYNTAX_TIMETICKS (aSN_APPLICATION | aSN_PRIMITIVE | 0x03)
+#define sNMP_SYNTAX_OPAQUE (aSN_APPLICATION | aSN_PRIMITIVE | 0x04)
+#define sNMP_SYNTAX_CNTR64 (aSN_APPLICATION | aSN_PRIMITIVE | 0x06)
+#define sNMP_SYNTAX_UINT32 sNMP_SYNTAX_GAUGE32
+//@}
+
+//-------------------------------------------------------------------------
+
+//---------------[ Exception conditions for SNMPv2 ]-----------------------
+/** @name Exception conditions for SNMPv2 */
+//@{
+#define sNMP_SYNTAX_NOSUCHOBJECT (aSN_CONTEXT | aSN_PRIMITIVE | 0x00)
+#define sNMP_SYNTAX_NOSUCHINSTANCE (aSN_CONTEXT | aSN_PRIMITIVE | 0x01)
+#define sNMP_SYNTAX_ENDOFMIBVIEW (aSN_CONTEXT | aSN_PRIMITIVE | 0x02)
+//@}
+
+//--------------[ different types of PDU's ]-------------------------------
+/** @name Pdu types */
+//@{
+#define sNMP_PDU_GET (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x0)
+#define sNMP_PDU_GETNEXT (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x1)
+#define sNMP_PDU_RESPONSE (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x2)
+#define sNMP_PDU_SET (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x3)
+#define sNMP_PDU_V1TRAP (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x4)
+#define sNMP_PDU_GETBULK (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x5)
+#define sNMP_PDU_INFORM (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x6)
+#define sNMP_PDU_TRAP (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x7)
+#define sNMP_PDU_REPORT (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x8)
+//@}
+
+
+//------[ smi typedefs ]---------------------------------------------------
+/** @name SMI typedefs
+ *
+ * SNMP-related types from RFC1442 (SMI).
+ */
+//@{
+
+// byte
+typedef unsigned char SmiBYTE, WINFAR *SmiLPBYTE;
+
+// int
+typedef long SmiINT, WINFAR *SmiLPINT;
+
+// int 32
+typedef SmiINT SmiINT32, WINFAR *SmiLPINT32;
+
+// unit32
+typedef unsigned long SmiUINT32, WINFAR *SmiLPUINT32;
+
+// octet struct
+typedef struct {
+ SmiUINT32 len;
+ SmiLPBYTE ptr;} SmiOCTETS, WINFAR *SmiLPOCTETS;
+
+// bits
+typedef SmiOCTETS SmiBITS, WINFAR *SmiLPBITS;
+
+// SMI oid struct
+typedef struct {
+ SmiUINT32 len;
+ SmiLPUINT32 ptr;} SmiOID, WINFAR *SmiLPOID;
+
+// ipaddr
+typedef SmiOCTETS SmiIPADDR, WINFAR *SmiLPIPADDR;
+
+// 32bit counter
+typedef SmiUINT32 SmiCNTR32, WINFAR *SmiLPCNTR32;
+
+// gauge
+typedef SmiUINT32 SmiGAUGE32, WINFAR *SmiLPGAUGE32;
+
+// timeticks
+typedef SmiUINT32 SmiTIMETICKS, WINFAR *SmiLPTIMETICKS;
+
+// opaque
+typedef SmiOCTETS SmiOPAQUE, WINFAR *SmiLPOPAQUE;
+
+// nsapaddr
+typedef SmiOCTETS SmiNSAPADDR, WINFAR *SmiLPNSAPADDR;
+
+// 64 bit counter
+typedef struct {
+ SmiUINT32 hipart;
+ SmiUINT32 lopart;} SmiCNTR64, WINFAR *SmiLPCNTR64;
+//@}
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif
+
+
--- /dev/null
+/*_############################################################################
+ _##
+ _## smival.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ S M I V A L . H
+
+ SMIVALUE CLASS DEFINITION
+
+ DESIGN + AUTHOR: Jeff Meyer
+
+ DESCRIPTION:
+ SMIValue class definition. Superclass for the various types
+ of SNMP values (Address, Oid, Octet, etc.). Provides
+ only a few functions, most info is in subclass.
+
+=====================================================================*/
+// $Id: smival.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _SMIVALUE
+#define _SMIVALUE
+
+//----[ includes ]-----------------------------------------------------
+#include "snmp_pp/smi.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+//----[ macros ]-------------------------------------------------------
+#if defined(USE_CPP_CASTS)
+#define PP_CONST_CAST(___type, ___ptr) const_cast< ___type >(___ptr)
+#else
+#define PP_CONST_CAST(___type, ___ptr) ((___type)(___ptr))
+#endif
+
+//======================================================================
+// SMI value structure conforming with SMI RFC
+//
+typedef struct { /* smiVALUE portion of VarBind */
+ SmiUINT32 syntax; /* Insert SNMP_SYNTAX_<type> */
+ union {
+ SmiINT sNumber; /* SNMP_SYNTAX_INT
+ SNMP_SYNTAX_INT32 */
+ SmiUINT32 uNumber; /* SNMP_SYNTAX_UINT32
+ SNMP_SYNTAX_CNTR32
+ SNMP_SYNTAX_GAUGE32
+ SNMP_SYNTAX_TIMETICKS */
+ SmiCNTR64 hNumber; /* SNMP_SYNTAX_CNTR64 */
+ SmiOCTETS string; /* SNMP_SYNTAX_OCTETS
+ SNMP_SYNTAX_BITS
+ SNMP_SYNTAX_OPAQUE
+ SNMP_SYNTAX_IPADDR
+ SNMP_SYNTAX_NSAPADDR */
+ SmiOID oid; /* SNMP_SYNTAX_OID */
+ SmiBYTE empty; /* SNMP_SYNTAX_NULL
+ SNMP_SYNTAX_NOSUCHOBJECT
+ SNMP_SYNTAX_NOSUCHINSTANCE
+ SNMP_SYNTAX_ENDOFMIBVIEW */
+ } value;
+ } SmiVALUE, *SmiLPVALUE;
+//=================================================================
+
+//--------------------------------------------------------------------
+//----[ SnmpSyntax class ]--------------------------------------------
+//--------------------------------------------------------------------
+
+/**
+ * An "abstract" (pure virtual) class that serves as the base class
+ * for all specific SNMP syntax types.
+ */
+class DLLOPT SnmpSyntax {
+
+public:
+
+ /**
+ * Virtual function for getting a printable ASCII value for any SNMP
+ * value.
+ *
+ * @note The returned string is valid as long as the object is not
+ * modified.
+ * @note This function is NOT thread safe.
+ */
+ virtual const char *get_printable() const = 0;
+
+ /**
+ * Return the current syntax.
+ */
+ virtual SmiUINT32 get_syntax() const = 0;
+
+ /**
+ * Virtual clone operation for creating a new Value from an existing
+ * value.
+ *
+ * @note The caller MUST use the delete operation on the return
+ * value when done.
+ */
+ virtual SnmpSyntax * clone() const = 0;
+
+ /**
+ * Virtual destructor to ensure deletion of derived classes...
+ */
+ virtual ~SnmpSyntax() {};
+
+ /**
+ * Overloaded assignment operator.
+ *
+ * @note This should be pure virtual, but buggy VC++ compiler
+ * complains about unresolved reference at link time.
+ */
+ virtual SnmpSyntax& operator=(const SnmpSyntax &/*val*/) { return *this; };
+
+ /**
+ * Return validity of the object.
+ */
+ virtual bool valid() const = 0;
+
+ /**
+ * Return the space needed for serialization.
+ */
+ virtual int get_asn1_length() const = 0;
+
+ /**
+ * Reset the object.
+ */
+ virtual void clear() = 0;
+
+protected:
+
+ SmiVALUE smival;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _SMIVALUE
--- /dev/null
+/*_############################################################################
+ _##
+ _## snmp_pp.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ SNMP++ S N M P_PP . H
+
+ SNMP CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+=====================================================================*/
+// $Id: snmp_pp.h 1685 2009-11-24 13:45:38Z katz $
+
+#ifndef _SNMP_PP_H_
+#define _SNMP_PP_H_
+
+// this is snmp++v3
+#define SNMP_PP_V3
+
+//-----[ snmp++ classes ]------------------------------------------------
+#include "snmp_pp/config_snmp_pp.h" // config file (SNMPv3)
+#include "snmp_pp/oid.h" // snmp++ oid class
+#include "snmp_pp/vb.h" // snbmp++ vb class
+#include "snmp_pp/target.h" // snmp++ target class
+#include "snmp_pp/pdu.h" // snmp++ pdu class
+#include "snmp_pp/snmperrs.h" // error macros and strings
+#include "snmp_pp/address.h" // snmp++ address class defs
+#include "snmp_pp/v3.h" // SNMPv3
+#include "snmp_pp/mp_v3.h" // SNMPv3
+#include "snmp_pp/usm_v3.h" // SNMPv3
+#include "snmp_pp/reentrant.h"
+#include "snmp_pp/uxsnmp.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/msec.h"
+#include "snmp_pp/eventlist.h"
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/log.h"
+
+#endif //_SNMP_PP_H_
--- /dev/null
+/*_############################################################################
+ _##
+ _## snmperrs.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ S N M P E R R S. H
+
+ SNMP++ ERROR CODE AND STRING DEFINITIONS
+
+ DESCRIPTION:
+ Definition of error macros and error strings
+
+ DESIGN + AUTHOR: Jeff Meyer
+============================================================================*/
+// $Id: snmperrs.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _SNMPERRS_H
+#define _SNMPERRS_H
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//-------[ Positive SNMP ++ Error Return Codes ]------------------------------
+/** @name Pdu error codes
+ * These values are error status values from RFC 1905
+ *
+ * The values can be returned via Pdu::get_error_status()
+ */
+//@{
+#define SNMP_ERROR_SUCCESS 0 //!< Success Status
+#define SNMP_ERROR_TOO_BIG 1 //!< Pdu encoding too big
+#define SNMP_ERROR_NO_SUCH_NAME 2 //!< No such VB name, see error index
+#define SNMP_ERROR_BAD_VALUE 3 //!< Bad Vb
+#define SNMP_ERROR_READ_ONLY 4 //!< VB is read only, see error index
+#define SNMP_ERROR_GENERAL_VB_ERR 5 //!< General VB error, see error index
+#define SNMP_ERROR_NO_ACCESS 6 //!< No access to MIBs data
+#define SNMP_ERROR_WRONG_TYPE 7 //!< Requested type was incorrect
+#define SNMP_ERROR_WRONG_LENGTH 8 //!< Request Pdu has inccorect length
+#define SNMP_ERROR_WRONG_ENCODING 9 //!< Request Pdu has wrong encoding
+#define SNMP_ERROR_WRONG_VALUE 10 //!< Request Pdu has wrong value
+#define SNMP_ERROR_NO_CREATION 11 //!< Unable to create object specified
+#define SNMP_ERROR_INCONSIST_VAL 12 //!< Inconsistent value in request
+#define SNMP_ERROR_RESOURCE_UNAVAIL 13 //!< Resources unavailable
+#define SNMP_ERROR_COMITFAIL 14 //!< Unable to comit
+#define SNMP_ERROR_UNDO_FAIL 15 //!< Unable to undo
+#define SNMP_ERROR_AUTH_ERR 16 //!< Authorization error
+#define SNMP_ERROR_NOT_WRITEABLE 17 //!< Mib Object not writeable
+#define SNMP_ERROR_INCONSIS_NAME 18 //!< Inconsistent naming used
+//@}
+
+//-------[ Negative SNMP ++ Result/Error Return Codes ]-------------------
+
+/** @name Snmp class return codes
+ */
+//@{
+
+// General
+#define SNMP_CLASS_SUCCESS 0 //!< success
+#define SNMP_CLASS_ERROR -1 //!< general error
+#define SNMP_CLASS_RESOURCE_UNAVAIL -2 //!< e.g., malloc failed
+#define SNMP_CLASS_INTERNAL_ERROR -3 //!< unexpected / internal error
+#define SNMP_CLASS_UNSUPPORTED -4 //!< unsupported function
+
+// Callback reasons:
+#define SNMP_CLASS_TIMEOUT -5 //!< outstanding request timed out
+#define SNMP_CLASS_ASYNC_RESPONSE -6 //!< received response for outstd request
+#define SNMP_CLASS_NOTIFICATION -7 //!< received notification (trap/inform)
+#define SNMP_CLASS_SESSION_DESTROYED -8 //!< snmp::destroyed with oustanding reqs pending
+
+// Snmp Class:
+#define SNMP_CLASS_INVALID -10 //!< snmp::mf called on invalid instance
+#define SNMP_CLASS_INVALID_PDU -11 //!< invalid pdu passed to mf
+#define SNMP_CLASS_INVALID_TARGET -12 //!< invalid target passed to mf
+#define SNMP_CLASS_INVALID_CALLBACK -13 //!< invalid callback to mf
+#define SNMP_CLASS_INVALID_REQID -14 //!< invalid request id to cancel
+#define SNMP_CLASS_INVALID_NOTIFYID -15 //!< missing trap/inform oid
+#define SNMP_CLASS_INVALID_OPERATION -16 //!< snmp operation not allowed for specified target
+#define SNMP_CLASS_INVALID_OID -17 //!< invalid oid passed to mf
+#define SNMP_CLASS_INVALID_ADDRESS -18 //!< invalid address passed to mf
+#define SNMP_CLASS_ERR_STATUS_SET -19 //!< agent returned response pdu with error_status set
+
+// Transport Errors:
+#define SNMP_CLASS_TL_UNSUPPORTED -20 //!< transport unsupported
+#define SNMP_CLASS_TL_IN_USE -21 //!< transport in use
+#define SNMP_CLASS_TL_FAILED -22 //!< transport operation failed
+#define SNMP_CLASS_TL_ACCESS_DENIED -23 //!< transport missing rights
+
+// extras
+#define SNMP_CLASS_SHUTDOWN -24 //!< used for back door shutdown
+
+// ASN.1 parse errors
+#define SNMP_CLASS_BADVERSION -50 //!< unsupported version
+#define SNMP_CLASS_ASN1ERROR -51 //!< used for ASN.1 parse errors
+//@}
+
+#define MAX_POS_ERROR SNMP_ERROR_INCONSIS_NAME
+#define MAX_NEG_ERROR SNMP_CLASS_SHUTDOWN
+
+
+#ifdef _INCLUDE_SNMP_ERR_STRINGS
+
+/**
+ * ASCII strings returned through Snmp::error() function.
+ *
+ * @note altering the strings in this header file will not affect the
+ * return values of Snmp::error(), unless you rebuild the SNMP++
+ * library from source.
+ */
+//@{
+static const char * pErrs[] = {
+ "Success", // 0
+ "SNMP: Response PDU Too Big", // 1
+ "SNMP: Variable does not exist", // 2
+ "SNMP: Cannot modify variable: Bad Value", // 3
+ "SNMP: Cannot modify object, Read Only", // 4
+ "SNMP: Cannot perform operation, General Error", // 5
+ "SNMP: Cannot access variable, No Access", // 6
+ "SNMP: Cannot create/modify variable, Wrong Type", // 7
+ "SNMP: Cannot create/set variable, Wrong Length", // 8
+ "SNMP: Cannot create/set variable, Wrong Encoding", // 9
+ "SNMP: Cannot create/set variable, Wrong Value", // 10
+ "SNMP: Cannot create variable, Creation Not Allowed", // 11
+ "SNMP: Cannot create/set variable, Inconsistent Value", // 12
+ "SNMP: Cannot create/set variable, Resource Unavailable", // 13
+ "SNMP: Cannot create/set variable, Commit Failed", // 14
+ "SNMP: Cannot create/set variable, Undo Failed", // 15
+ "SNMP: Cannot perform operation, Authorization Error", // 16
+ "SNMP: Cannot create/set variable, Not Writable", // 17
+ "SNMP: Cannot create variable, Inconsistent Name", // 18
+ "SNMP: Unknown Error Status" // 19
+};
+
+#ifdef _SNMPv3
+static const char * nv3Errs[] = {
+ "SNMPv3: v3MP error", // -1400
+ "SNMPv3: v3MP ok", // -1401
+ "SNMPv3: Unsupported Security Model", // -1402
+ "SNMPv3: Message not in Time Window", // -1403
+ "SNMPv3: received same Message twice",// -1404
+ "SNMPv3: Invalid Message", // -1405
+ "SNMPv3: Invalid EngineID", // -1406
+ "SNMPv3: v3MP not initialized", // -1407
+ "SNMPv3: Parse Error", // -1408
+ "SNMPv3: Received Message with unknown MsgID", // -1409
+ "SNMPv3: Message does not match known message", // -1410
+ "SNMPv3: Community format error", // -1411
+ "SNMPv3: Unknown UserName", //-1412
+ "SNMPv3: Build error", //-1413
+ "SNMPv3: USM: error", //-1414
+ "SNMPv3: Unknown pdu handlers", //-1415
+ "SNMPv3: Unavailable Context", //-1416
+ "SNMPv3: Unknown Context", //-1417
+ "SNMPv3: Report sent", //-1418
+ "SNMPv3: Unknown errorcode"
+};
+
+static const char * pv3Errs[] = {
+ "SNMPv3: USM: ok", // 1400
+ "SNMPv3: USM: error", // 1401
+ "SNMPv3: USM: Configfile write error", // 1402
+ "SNMPv3: USM: Unsupported SecurityLevel", // 1403
+ "SNMPv3: USM: Unknown SecurityName", // 1404
+ "SNMPv3: USM: Encryption error", // 1405
+ "SNMPv3: USM: Decryption error", // 1406
+ "SNMPv3: USM: Authentication error", // 1407
+ "SNMPv3: USM: Authentication failure", // 1408
+ "SNMPv3: USM: Parse error", // 1409
+ "SNMPv3: USM: Unknown EngineID", // 1410
+ "SNMPv3: USM: Message not in TimeWindow", // 1411
+ "SNMPv3: USM: Unsupported AuthProtocol", // 1412
+ "SNMPv3: USM: Unsupported PrivProtocol", // 1413
+ "SNMPv3: USM: Address error", // 1414
+ "SNMPv3: USM: Could not create file", // 1415
+ "SNMPv3: USM: Could not open file", // 1416
+ "SNMPv3: USM: Could not rename file", // 1417
+ "SNMPv3: USM: Could not delete file", // 1418
+ "SNMPv3: USM: Could not write into file", // 1419
+ "SNMPv3: USM: Could not read from file", // 1420
+ "SNMPv3: USM: unknown errorcode"
+};
+#endif
+
+static const char * nErrs[] =
+{
+ // General:
+ "SNMP++: Success", // 0 SNMP_CLASS_SUCCESS
+ "SNMP++: Operation failed", // 1 SNMP_CLASS_ERROR
+ "SNMP++: Resource unavailable", // 2 SNMP_CLASS_RESOURCE_UNAVAIL
+ "SNMP++: Internal error", // 3 SNMP_CLASS_INTERNAL_ERROR
+ "SNMP++: Unsupported function", // 4 SNMP_CLASS_UNSUPPORTED
+
+ // Callback reasons:
+ "SNMP++: SNMP request timed out", // 5 SNMP_CLASS_TIMEOUT
+ "SNMP++: Received SNMP Response", // 6 SNMP_CLASS_ASYNC_RESPONSE
+ // 7 SNMP_CLASS_NOTIFICATION
+ "SNMP++: Received SNMP Notification (trap or inform)",
+ // 8 SNMP_CLASS_SESSION_DESTROYED
+ "SNMP++: Closing session with outstanding requests",
+ "Unknown error code", // 9 reserved for future
+
+ // Snmp Class errors:
+ "SNMP++: Class not valid", // 10 SNMP_CLASS_INVALID
+ "SNMP++: Invalid Pdu", // 11 SNMP_CLASS_INVALID_PDU
+ "SNMP++: Invalid Target", // 12 SNMP_CLASS_INVALID_TARGET
+ "SNMP++: Invalid (null) Callback Function", // 13 SNMP_CLASS_INVALID_CALLBACK
+ "SNMP++: Invalid Request Id", // 14 SNMP_CLASS_INVALID_REQID
+ "SNMP++: Invalid Notification Id", // 15 SNMP_CLASS_INVALID_NOTIFYID
+ // 16 SNMP_CLASS_INVALID_OPERATION
+ "SNMP++: SNMP Operation not supported on specified Target",
+ "SNMP++: Invalid Object Identifier", // 17 SNMP_CLASS_INVALID_OID
+ "SNMP++: Invalid Address", // 18 SNMP_CLASS_INVALID_ADDRESS
+ // 19 SNMP_CLASS_ERR_STATUS_SET
+ "SNMP++: Agent indicates error in SNMP request",
+
+ // Transport Errors:
+ "SNMP++: Transport is not supported", // 20 SNMP_CLASS_TL_UNSUPPORTED
+ "SNMP++: Transport is in use", // 21 SNMP_CLASS_TL_IN_USE
+ "SNMP++: Transport operation failed", // 22 SNMP_CLASS_TL_FAILED
+ "SNMP++: Transport access denied", // 23 SNMP_CLASS_TL_ACCESS_DENIED
+ "SNMP++: Blocked Mode Shutdown", // 24 SNMP_CLASS_SHUTDOWN
+
+ "Unknown error code", // unknown error code
+};
+//@}
+#endif //_INCLUDE_SNMP_ERR_STRINGS
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif //_SNMPERRS_H
--- /dev/null
+/*_############################################################################
+ _##
+ _## snmpmsg.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ S N M P M E S S A G E . H
+
+ SNMPMESSAGE CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ ASN.1 encoding / decoding class
+
+=====================================================================*/
+// $Id: snmpmsg.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _SNMPMSG
+#define _SNMPMSG
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#include "snmp_pp/smival.h"
+#include "snmp_pp/pdu.h"
+#include "snmp_pp/target.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/mp_v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+DLLOPT void freeSmivalDescriptor( SmiVALUE* );
+DLLOPT int convertVbToSmival( const Vb&, SmiVALUE* );
+
+#define SNMP_MSG_OID_SYSUPTIME "1.3.6.1.2.1.1.3.0"
+#define SNMP_MSG_OID_TRAPID "1.3.6.1.6.3.1.1.4.1.0"
+
+class Snmp;
+
+// SnmpMessage Class
+class DLLOPT SnmpMessage
+{
+ public:
+
+ // construct a SnmpMessage object
+ SnmpMessage() : bufflen(MAX_SNMP_PACKET), valid_flag(false) {};
+ // load up using a Pdu, community and SNMP version
+ // performs ASN.1 serialization
+ // result status returned
+ private:
+ int load( const Pdu &pdu, // Pdu to serialize
+ const OctetStr &community, // community name to use
+ const snmp_version version, // SNMP version, v1 or v2
+ const OctetStr *engine_id, // optional v3
+ const OctetStr *security_name, // optional v3
+ const int security_model); // optional v3
+ public:
+ int load( const Pdu &pdu, // Pdu to serialize
+ const OctetStr &community, // community name to use
+ const snmp_version version) // SNMP version, v1 or v2
+ { return load(pdu, community, version, 0, 0, 0); };
+
+ // load up message using ASN.1 data stream
+ // status is returned
+ int load( unsigned char *data, // data to be loaded
+ unsigned long len); // len of data to be loaded
+
+ // unload ( unserialize ) into SNMP++ Pdu, community and version
+ // status is returned
+ private:
+ int unload( Pdu &pdu, // Pdu returned
+ OctetStr &community, // community name
+ snmp_version &version, // version
+ OctetStr *engine_id, // optional v3
+ OctetStr *security_name, // optional v3
+ long int *security_model,
+ UdpAddress *from_addr,
+ Snmp *snmp_session);
+ public:
+ int unload( Pdu &pdu, // Pdu returned
+ OctetStr &community, // community name
+ snmp_version &version) // version
+ { return unload(pdu, community, version, 0, 0, 0, 0, 0); };
+
+
+#ifdef _SNMPv3
+ int loadv3( const Pdu &pdu, // Pdu to serialize
+ const OctetStr &engine_id, // engine_id to use
+ const OctetStr &sec_name, // securit_name to use
+ const int sec_model, // security_model to use
+ const snmp_version version) // SNMP version, v3
+ { return load(pdu, "", version, &engine_id, &sec_name, sec_model); }
+
+ int unloadv3( Pdu &pdu, // Pdu returned
+ snmp_version &version, // version
+ OctetStr &engine_id, // optional v3
+ OctetStr &security_name, // optional v3
+ long int &security_model,
+ UdpAddress &from_addr,
+ Snmp &snmp_session);
+
+ // returns TRUE if the message in the buffer is a v3 message
+ bool is_v3_message() {return v3MP::is_v3_msg(databuff, (int)bufflen);};
+
+#endif
+
+ // return the validity of the message
+ bool valid() const { return valid_flag;};
+
+ // return raw data
+ // check validity
+ unsigned char *data() { return databuff; };
+
+ // returns len
+ // check validity
+ unsigned long len() const { return bufflen; };
+
+protected:
+
+ unsigned char databuff[MAX_SNMP_PACKET];
+ unsigned int bufflen;
+ bool valid_flag;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _SNMPMSG
--- /dev/null
+/*_############################################################################
+ _##
+ _## target.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ T A R G E T . H
+
+ TARGET CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ Target class defines target SNMP agents.
+
+=====================================================================*/
+// $Id: target.h 1539 2009-05-27 22:12:53Z katz $
+
+#ifndef _TARGET
+#define _TARGET
+
+//----[ includes ]-----------------------------------------------------
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/address.h"
+#include "snmp_pp/octet.h"
+#include "snmp_pp/collect.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+//----[ enumerated types for SNMP versions ]---------------------------
+/**
+ * The SNMP version to use is passed with this enum.
+ */
+enum snmp_version
+{
+ version1, ///< (0) SNMPv1
+ version2c ///< (1) SNMPv2c
+#ifdef _SNMPv3
+ ,version2stern, ///< (2) Dont use this!
+ version3 ///< (3) SNMPv3
+#endif
+};
+
+//----[ Target class ]-------------------------------------------------
+/**
+ * Abstract class used to provide a virtual interface into Targets.
+ *
+ * @note Although it is possible to create an object of this class,
+ * you won't be happy with that...
+ */
+class DLLOPT SnmpTarget
+{
+ public:
+
+ /**
+ * Enum to identify a target object through SnmpTarget::get_type() method.
+ */
+ enum target_type
+ {
+ type_base, ///< It is a SnmpTarget object
+ type_ctarget, ///< It is a CTarget object
+ type_utarget ///< It is a Utarget object
+ };
+
+ /**
+ * Create a SnmpTarget object with default values.
+ * The validity of the target will be false.
+ */
+ SnmpTarget()
+ : validity(false), timeout(default_timeout), retries(default_retries),
+ version(version1), ttype(type_base) {};
+
+ /**
+ * Create a SnmpTarget object with the given Address.
+ */
+ SnmpTarget(const Address &address)
+ : validity(false), timeout(default_timeout), retries(default_retries),
+ version(version1), ttype(type_base), my_address(address)
+ { if (my_address.valid()) validity = true; };
+
+ /**
+ * Destructor that has nothing to do.
+ */
+ virtual ~SnmpTarget() {};
+
+ /**
+ * Return the type of the target object.
+ *
+ * If a SNMP message is received through a callback (that only
+ * passes a SnmpTarget pointer to the callback function), this
+ * method can be used to check the type of the object before doing a
+ * cast to CTarget or UTarget.
+ */
+ target_type get_type() const { return ttype; };
+
+ /**
+ * Returns the validity of the target object.
+ *
+ * @return true, if the target is valid.
+ */
+ bool valid() const { return validity;};
+
+ /**
+ * Set the retry value.
+ *
+ * @param r - The number of retries if no response is received.
+ */
+ void set_retry(const int r) { retries = r; };
+
+ /**
+ * Get the retry value.
+ *
+ * @return The number of retries on timeout.
+ */
+ int get_retry() const { return retries; };
+
+
+ /**
+ * Set the timeout for requests.
+ *
+ * The default timeout for requests is 1 second (100).
+ *
+ * @param t - Timeout in 10ms, so 100 will set the timeout to 1 second.
+ */
+ void set_timeout(const unsigned long t) { timeout = t; };
+
+ /**
+ * Get the timeout.
+ *
+ * @return The timeout for requests sent using this target object.
+ */
+ unsigned long get_timeout() const { return timeout; };
+
+ /**
+ * Change the default timeout.
+ *
+ * Changing the default timeout value will only have an effect for
+ * target objects that are created after setting this value.
+ *
+ * @param t - The new default timeout value
+ */
+ static void set_default_timeout(const unsigned long t)
+ { default_timeout = t; };
+
+ /**
+ * Change the default retries vlaue.
+ *
+ * Changing the default retries value will only have an effect for
+ * target objects that are created after setting this value.
+ *
+ * @param r - The new retries value
+ */
+ static void set_default_retries(const int r) { default_retries = r; };
+
+ /**
+ * Clone operator.
+ *
+ * Virtual clone operation for creating a new SnmpTarget from an existing
+ * SnmpTarget.
+ *
+ * @note The caller MUST use the delete operation on the return
+ * value when done.
+ *
+ * @return A pointer to the new object on success, 0 on failure.
+ */
+ virtual SnmpTarget *clone() const;
+
+ /**
+ * Get the address object.
+ *
+ * @param address - GenAddress object to store the target address.
+ * @return TRUE on success.
+ */
+ int get_address(GenAddress &address) const;
+
+ /**
+ * Get the address object.
+ *
+ * @return The target address.
+ */
+ const GenAddress &get_address() const { return my_address; };
+
+ /**
+ * Set the address object.
+ *
+ * @param address - The address that this target should use.
+ * @return TRUE on success.
+ */
+ virtual int set_address(const Address &address);
+
+ /**
+ * Get the SNMP version for this target.
+ *
+ * @return The SNMP version of this target object.
+ * @see enum snmp_version
+ */
+ snmp_version get_version() const { return version;};
+
+ /**
+ * Set the SNMP version of this target.
+ *
+ * @param v - The SNMP version that should be used for sending messages.
+ */
+ void set_version(const snmp_version v) { version = v; };
+
+ /**
+ * Overloeaded compare operator.
+ *
+ * Two SnmpTarget objects are considered equal, if all member
+ * variables are equal.
+ *
+ * @return 1 if targets are equal, 0 if not.
+ */
+ int operator==(const SnmpTarget &rhs) const;
+
+ /**
+ * Reset the object.
+ */
+ virtual void clear();
+
+ protected:
+ bool validity; ///< Validity of the object
+ unsigned long timeout; ///< xmit timeout in 10 milli secs
+ int retries; ///< number of retries
+ snmp_version version; ///< SNMP version to use
+ target_type ttype; ///< Type of the target
+ GenAddress my_address; ///< Address object
+
+ static unsigned long default_timeout; ///< default timeout for new objects
+ static int default_retries; ///< default retries for new objects
+};
+
+//----[ CTarget class ]----------------------------------------------
+/**
+ * Community based target object.
+ * This target can be used for SNMPv1 and SNMPv2c messages.
+ */
+class DLLOPT CTarget: public SnmpTarget
+{
+ public:
+ /**
+ * Constructor with no args.
+ * The validity of the target will be false.
+ */
+ CTarget();
+
+ /**
+ * Constructor with all args.
+ *
+ * @param address - Address of the target host (cann be any address object)
+ * @param read_community_name - Community for get requests
+ * @param write_community_name - Community for set requests
+ */
+ CTarget(const Address &address,
+ const char *read_community_name,
+ const char *write_community_name);
+
+ /**
+ * Constructor with all args.
+ *
+ * @param address - Address of the target host (cann be any address object)
+ * @param read_community_name - Community for get requests
+ * @param write_community_name - Community for set requests
+ */
+ CTarget(const Address &address,
+ const OctetStr &read_community_name,
+ const OctetStr &write_community_name);
+
+ /**
+ * Constructor with only address.
+ *
+ * The read and write community names will be set to "public".
+ *
+ * @param address - Address of the target host (cann be any address object)
+ */
+ CTarget(const Address &address);
+
+ /**
+ * Constructor from existing CTarget.
+ */
+ CTarget(const CTarget &target);
+
+ /**
+ * Destructor, that has nothing to do.
+ */
+ ~CTarget() {};
+
+ /**
+ * Clone operator.
+ *
+ * Clone operation for creating a new CTarget from an existing
+ * CTarget.
+ *
+ * @note The caller MUST use the delete operation on the return
+ * value when done.
+ *
+ * @return A pointer to the new object on success, 0 on failure.
+ */
+ SnmpTarget *clone() const { return (SnmpTarget *) new CTarget(*this); };
+
+ /**
+ * Get the read community name.
+ *
+ * @return C string of the read community.
+ */
+ const char * get_readcommunity() const
+ { return (const char *) read_community.get_printable(); };
+
+ /**
+ * Get the read community name.
+ *
+ * @param oct - OctetStr that will be filled with the read community name.
+ */
+ void get_readcommunity(OctetStr& oct) const { oct = read_community; };
+
+ /**
+ * Set the read community name.
+ *
+ * @param str - The new read community name
+ */
+ void set_readcommunity(const char * str) { read_community = str; };
+
+ /**
+ * Set the read community name.
+ *
+ * @param oct - The new read community name
+ */
+ void set_readcommunity(const OctetStr& oct) { read_community = oct; };
+
+ /**
+ * Get the write community name.
+ *
+ * @return C string of the write community.
+ */
+ const char * get_writecommunity() const
+ { return (const char *) write_community.get_printable(); };
+
+ /**
+ * Get the write community name.
+ *
+ * @param oct - OctetStr that will be filled with the write community name.
+ */
+ void get_writecommunity(OctetStr &oct) const { oct = write_community; };
+
+ /**
+ * Set the write community name.
+ *
+ * @param str - The new write community name
+ */
+ void set_writecommunity(const char *str) { write_community = str; };
+
+ /**
+ * Set the write community name.
+ *
+ * @param oct - The new write community name
+ */
+ void set_writecommunity(const OctetStr &oct) { write_community = oct; };
+
+ /**
+ * Overloaded assignment operator.
+ */
+ CTarget& operator=(const CTarget& target);
+
+ /**
+ * Overloeaded compare operator.
+ *
+ * Two CTarget objects are considered equal, if all member variables
+ * and the base classes are equal.
+ *
+ * @return 1 if targets are equal, 0 if not.
+ */
+ int operator==(const CTarget &rhs) const;
+
+ /**
+ * Get all values of a CTarget object.
+ *
+ * @param read_comm - Read community name
+ * @param write_comm - Write community name
+ * @param address - Address of the target
+ * @param t - Timeout value
+ * @param r - Retries value
+ * @param v - The SNMP version of this target
+ *
+ * @return TRUE on success and FALSE on failure.
+ */
+ int resolve_to_C(OctetStr& read_comm,
+ OctetStr& write_comm,
+ GenAddress &address,
+ unsigned long &t,
+ int &r,
+ unsigned char &v) const;
+
+ /**
+ * Reset the object.
+ */
+ void clear();
+
+ protected:
+ OctetStr read_community; // get community
+ OctetStr write_community; // set community
+};
+
+// create OidCollection type
+typedef SnmpCollection<SnmpTarget> TargetCollection;
+
+#ifdef _SNMPv3
+#define INITIAL_USER "initial"
+#else
+#define INITIAL_USER "public"
+#endif
+
+//----[ UTarget class ]----------------------------------------------
+/**
+ * User based Target.
+ *
+ * This class is used for SNMPv3 targets.
+ */
+class DLLOPT UTarget: public SnmpTarget
+{
+ public:
+ /**
+ * Constructor with no args.
+ * The validity of the target will be false.
+ */
+ UTarget();
+
+ /**
+ * Constructor with all args.
+ *
+ * @param address - Address of the target host (cann be any address object)
+ * @param sec_name - The security name
+ * @param sec_model - The security model to use
+ */
+ UTarget(const Address &address,
+ const char *sec_name,
+ const int sec_model);
+
+ /**
+ * Constructor with all args.
+ *
+ * @param address - Address of the target host (cann be any address object)
+ * @param sec_name - The security name
+ * @param sec_model - The security model to use
+ */
+ UTarget(const Address &address,
+ const OctetStr &sec_name,
+ const int sec_model);
+
+ /**
+ * Constructor with only address.
+ *
+ * Assumes the following defaults: security_name: initial, version: SNMPv3,
+ * security_model: v3MP.
+ *
+ * @param address - Address of the target host (cann be any address object)
+ */
+ UTarget(const Address &address);
+
+ /**
+ * Constructor from existing UTarget.
+ */
+ UTarget(const UTarget &target);
+
+ /**
+ * Destructor, that has nothing to do.
+ */
+ ~UTarget() {};
+
+ /**
+ * Clone operator.
+ *
+ * Clone operation for creating a new UTarget from an existing
+ * UTarget.
+ *
+ * @note The caller MUST use the delete operation on the return
+ * value when done.
+ *
+ * @return A pointer to the new object on success, 0 on failure.
+ */
+ SnmpTarget *clone() const { return (SnmpTarget *) new UTarget(*this); };
+
+ /**
+ * Set the address object.
+ *
+ * This method is the same as in SnmpTarget, but it deletes engine_id.
+ *
+ * @param address - The address that this target should use.
+ * @return TRUE on success.
+ */
+ int set_address(const Address &address);
+
+ /**
+ * Get the security name.
+ *
+ * @return A const reference to the security name.
+ */
+ const OctetStr& get_security_name() const { return security_name;} ;
+
+ /**
+ * Get the security name.
+ *
+ * @param oct - OctetStr that will be filled with the security name.
+ */
+ void get_security_name(OctetStr& oct) const { oct = security_name; };
+
+ /**
+ * Set the security name.
+ *
+ * @param str - The new security name
+ */
+ void set_security_name(const char * str) { security_name = str; };
+
+ /**
+ * Set the security name.
+ *
+ * @param oct - The new security name
+ */
+ void set_security_name(const OctetStr& oct) { security_name = oct; };
+
+#ifdef _SNMPv3
+ /**
+ * Set the engine id.
+ *
+ * In most cases it is not necessary for the user to set the engine
+ * id as snmp++ performs engine id discovery. If the engine id is
+ * set by the user, no engine_id discovery is made, even if the
+ * engine id set by the user is wrong.
+ *
+ * @param str - The engine id to use
+ */
+ void set_engine_id(const char * str) { engine_id = str; };
+
+ /**
+ * Set the engine id.
+ *
+ * In most cases it is not necessary for the user to set the engine
+ * id as snmp++ performs engine id discovery. If the engine id is
+ * set by the user, no engine_id discovery is made, even if the
+ * engine id set by the user is wrong.
+ *
+ * @param oct - The engine id to use
+ */
+ void set_engine_id(const OctetStr &oct) { engine_id = oct; };
+
+ /**
+ * Get the engine id.
+ *
+ * @return A const reference to the enigne id of this target.
+ */
+ const OctetStr& get_engine_id() const { return engine_id; };
+
+ /**
+ * Get the engine id.
+ *
+ * @param oct - OctetStr that will be filled with the engine id
+ */
+ void get_engine_id(OctetStr& oct) const { oct = engine_id; };
+#endif
+
+ /**
+ * Get the security_model.
+ *
+ * @return An integer representing the security_model of this target.
+ */
+ int get_security_model() const { return security_model; };
+
+ /**
+ * Set the security_model.
+ *
+ * @param sec_model - The security model to use.
+ */
+ void set_security_model(int sec_model) { security_model = sec_model; };
+
+ /**
+ * Overloaded assignment operator.
+ */
+ UTarget& operator=(const UTarget& target);
+
+ /**
+ * Overloeaded compare operator.
+ *
+ * Two UTarget objects are considered equal, if all member variables
+ * (beside the engine id) and the base classes are equal.
+ *
+ * @return 1 if targets are equal, 0 if not.
+ */
+ virtual int operator==(const UTarget &rhs) const;
+
+ /**
+ * Get all values of a UTarget object.
+ *
+ * @param sec_name - security name
+ * @param sec_model - security model
+ * @param address - Address of the target
+ * @param t - Timeout value
+ * @param r - Retries value
+ * @param v - The SNMP version of this target
+ *
+ * @return TRUE on success and FALSE on failure.
+ */
+ int resolve_to_U(OctetStr& sec_name,
+ int &sec_model,
+ GenAddress &address,
+ unsigned long &t,
+ int &r,
+ unsigned char &v) const;
+
+ /**
+ * Reset the object.
+ */
+ void clear();
+
+ protected:
+ OctetStr security_name;
+ int security_model;
+#ifdef _SNMPv3
+ OctetStr engine_id;
+#endif
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif //_TARGET
--- /dev/null
+/*_############################################################################
+ _##
+ _## timetick.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ T I M E T I C K. H
+
+ TIMETICK CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ Class definition for SMI Timeticks class.
+
+=====================================================================*/
+// $Id: timetick.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _TIMETICKS
+#define _TIMETICKS
+
+#include "snmp_pp/integer.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define TICKOUTBUF 30 // max formatted time string
+
+//------------[ TimeTicks Class ]-----------------------------------
+/**
+ * The timeticks class allows all the functionality of unsigned
+ * integers but is recognized as a distinct SMI type. TimeTicks
+ * objects may be get or set into Vb objects.
+ */
+class DLLOPT TimeTicks : public SnmpUInt32
+{
+ public:
+ /**
+ * Constructs a zero TimeTicks object.
+ */
+ TimeTicks() : SnmpUInt32()
+ { smival.syntax = sNMP_SYNTAX_TIMETICKS; };
+
+ /**
+ * Constructs a TimeTicks object with the given value.
+ *
+ * @param val - time in hundredths of seconds.
+ */
+ TimeTicks(const unsigned long val) : SnmpUInt32(val)
+ { smival.syntax = sNMP_SYNTAX_TIMETICKS; };
+
+ /**
+ * Copy constructor.
+ *
+ * @param t - Time for the new object.
+ */
+ TimeTicks(const TimeTicks &t);
+
+ /**
+ * Destructor.
+ */
+ ~TimeTicks() {};
+
+ /**
+ * Return the syntax.
+ *
+ * @return Always returns sNMP_SYNTAX_TIMETICKS.
+ */
+ SmiUINT32 get_syntax() const { return sNMP_SYNTAX_TIMETICKS; };
+
+ /**
+ * Get a printable ASCII value.
+ */
+ const char *get_printable() const;
+
+ /**
+ * Clone operator.
+ *
+ * @return Pointer to a newly created copy of the object.
+ */
+ SnmpSyntax *clone() const { return (SnmpSyntax *) new TimeTicks(*this); };
+
+ /**
+ * Map other SnmpSyntax objects to TimeTicks.
+ */
+ SnmpSyntax& operator=(const SnmpSyntax &val);
+
+ /**
+ * Overloaded assignment for TimeTicks.
+ *
+ * @param uli - new value
+ * @return self reference
+ */
+ TimeTicks& operator=(const TimeTicks &uli)
+ { smival.value.uNumber = uli.smival.value.uNumber;
+ m_changed = true; return *this; };
+
+ /**
+ * Overloaded assignment for unsigned longs.
+ *
+ * @param i - new value in hundrets of seconds
+ * @return self reference
+ */
+ TimeTicks& operator=(const unsigned long i)
+ { smival.value.uNumber = i; m_changed = true; return *this; };
+
+ /**
+ * Casting to unsigned long.
+ *
+ * @return Current value as hundrets of seconds
+ */
+ operator unsigned long() { return smival.value.uNumber; };
+
+ /**
+ * Reset the object.
+ */
+ void clear()
+ { smival.value.uNumber = 0; m_changed = true; };
+
+ protected:
+ SNMP_PP_MUTABLE char output_buffer[TICKOUTBUF]; // for storing printed form
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## usm_v3.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+// $Id: usm_v3.h 1825 2010-08-29 20:10:54Z katz $
+
+#ifndef _USM_V3
+#define _USM_V3
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+
+#include "snmp_pp/smi.h"
+#include "snmp_pp/octet.h"
+#include "snmp_pp/address.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifndef MAXUINT32
+#define MAXUINT32 4294967295u
+#endif
+
+// the maximum allowed length of the username
+#define MAXLEN_USMUSERNAME 32
+#define MAXLEN_USMSECURITYNAME MAXLEN_USMUSERNAME
+
+#define SNMPv3_AUTHFLAG 0x01
+#define SNMPv3_PRIVFLAG 0x02
+#define SNMPv3_REPORTABLEFLAG 0x04
+
+#define NOKEY 0
+#define AUTHKEY 1
+#define PRIVKEY 2
+#define OWNAUTHKEY 3
+#define OWNPRIVKEY 4
+
+/** @name SecurityLevels
+ *
+ * When sending a SNMPv3 message, one of these security levels can be
+ * set on the Pdu object.
+ */
+//@{
+#define SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV 1 ///< noAuthNoPriv
+#define SNMP_SECURITY_LEVEL_AUTH_NOPRIV 2 ///< authNoPriv
+#define SNMP_SECURITY_LEVEL_AUTH_PRIV 3 ///< authPriv
+//@}
+
+/** @name AuthProtocols
+ *
+ * Each user of the USM must use one authentication protocol (which
+ * may be none.
+ */
+//@{
+#define SNMP_AUTHPROTOCOL_NONE 1 ///< None
+#define SNMP_AUTHPROTOCOL_HMACMD5 2 ///< HMAC-MD5
+#define SNMP_AUTHPROTOCOL_HMACSHA 3 ///< HMAC-SHA
+//@}
+
+/** @name PrivProtocols
+ *
+ * Each user of the USM must use one privacy protocol (which may be
+ * none.
+ */
+//@{
+#define SNMP_PRIVPROTOCOL_NONE 1 ///< None
+#define SNMP_PRIVPROTOCOL_DES 2 ///< DES
+#define SNMP_PRIVPROTOCOL_AES128 4 ///< AES128 (RFC 3826)
+
+#define SNMP_PRIVPROTOCOL_IDEA 9 ///< IDEA (non standard)
+#define SNMP_PRIVPROTOCOL_AES192 20 ///< AES192 (non standard)
+#define SNMP_PRIVPROTOCOL_AES256 21 ///< AES256 (non standard)
+#define SNMP_PRIVPROTOCOL_3DESEDE 3 ///< 3DES (expired draft standard)
+//@}
+
+/** @name USM-ErrorCodes
+ *
+ * Each method of the class USM may return one of the following
+ * error codes.
+ */
+//@{
+#define SNMPv3_USM_OK 1400
+#define SNMPv3_USM_ERROR 1401
+#define SNMPv3_USM_ERROR_CONFIGFILE 1402
+#define SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL 1403
+#define SNMPv3_USM_UNKNOWN_SECURITY_NAME 1404
+#define SNMPv3_USM_ENCRYPTION_ERROR 1405
+#define SNMPv3_USM_DECRYPTION_ERROR 1406
+#define SNMPv3_USM_AUTHENTICATION_ERROR 1407
+#define SNMPv3_USM_AUTHENTICATION_FAILURE 1408
+#define SNMPv3_USM_PARSE_ERROR 1409
+#define SNMPv3_USM_UNKNOWN_ENGINEID 1410
+#define SNMPv3_USM_NOT_IN_TIME_WINDOW 1411
+#define SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL 1412
+#define SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL 1413
+#define SNMPv3_USM_ADDRESS_ERROR 1414
+#define SNMPv3_USM_FILECREATE_ERROR 1415
+#define SNMPv3_USM_FILEOPEN_ERROR 1416
+#define SNMPv3_USM_FILERENAME_ERROR 1417
+#define SNMPv3_USM_FILEDELETE_ERROR 1418
+#define SNMPv3_USM_FILEWRITE_ERROR 1419
+#define SNMPv3_USM_FILEREAD_ERROR 1420
+//@}
+
+/** @name Statistics on error codes. */
+//@{
+#define SNMPv3_USM_MAX_ERROR SNMPv3_USM_FILEREAD_ERROR
+#define SNMPv3_USM_MIN_ERROR SNMPv3_USM_OK
+#define SNMPv3_USM_ERRORCOUNT SNMPv3_USM_MAX_ERROR - SNMPv3_USM_MIN_ERROR
+//@}
+
+#define oidUsmStats "1.3.6.1.6.3.15.1.1"
+#define oidUsmStatsUnsupportedSecLevels "1.3.6.1.6.3.15.1.1.1.0"
+#define oidUsmStatsNotInTimeWindows "1.3.6.1.6.3.15.1.1.2.0"
+#define oidUsmStatsUnknownUserNames "1.3.6.1.6.3.15.1.1.3.0"
+#define oidUsmStatsUnknownEngineIDs "1.3.6.1.6.3.15.1.1.4.0"
+#define oidUsmStatsWrongDigests "1.3.6.1.6.3.15.1.1.5.0"
+#define oidUsmStatsDecryptionErrors "1.3.6.1.6.3.15.1.1.6.0"
+
+#define oidUsmUserTable "1.3.6.1.6.3.15.1.2.2"
+#define oidUsmUserEntry "1.3.6.1.6.3.15.1.2.2.1"
+
+#define oidUsmAuthProtocolBase "1.3.6.1.6.3.10.1.1"
+#define oidUsmNoAuthProtocol "1.3.6.1.6.3.10.1.1.1"
+#define oidUsmHMACMD5AuthProtocol "1.3.6.1.6.3.10.1.1.2"
+#define oidUsmHMACSHAAuthProtocol "1.3.6.1.6.3.10.1.1.3"
+
+#define oidUsmPrivProtocolBase "1.3.6.1.6.3.10.1.2"
+#define oidUsmNoPrivProtocol "1.3.6.1.6.3.10.1.2.1"
+#define oidUsmDESPrivProtocol "1.3.6.1.6.3.10.1.2.2"
+#define oidUsmIDEAPrivProtocol "1.3.6.1.6.3.10.1.2.9"
+#define oidUsmAES128PrivProtocol "1.3.6.1.6.3.10.1.2.4"
+#define oidUsmAES192PrivProtocol "1.3.6.1.6.3.10.1.2.20"
+#define oidUsmAES256PrivProtocol "1.3.6.1.6.3.10.1.2.21"
+#define oidUsm3DESEDEPrivProtocol "1.3.6.1.6.3.10.1.2.3"
+
+
+#define USM_KeyUpdate 1
+#define USM_PasswordUpdate 2
+#define USM_PasswordKeyUpdate 3
+#define USM_PasswordAllKeyUpdate 4
+
+class SnmpTarget;
+class Pdu;
+
+struct UsmKeyUpdate;
+
+struct UsmUserTableEntry {
+ unsigned char *usmUserEngineID; long int usmUserEngineIDLength;
+ unsigned char *usmUserName; long int usmUserNameLength;
+ unsigned char *usmUserSecurityName; long int usmUserSecurityNameLength;
+ long int usmUserAuthProtocol;
+ unsigned char *usmUserAuthKey; long int usmUserAuthKeyLength;
+ long int usmUserPrivProtocol;
+ unsigned char *usmUserPrivKey; long int usmUserPrivKeyLength;
+};
+
+struct UsmUser {
+ unsigned char *engineID; long int engineIDLength;
+ unsigned char *usmUserName; long int usmUserNameLength;
+ unsigned char *securityName; long int securityNameLength;
+ long int authProtocol;
+ unsigned char *authKey; long int authKeyLength;
+ long int privProtocol;
+ unsigned char *privKey; long int privKeyLength;
+};
+
+struct UsmUserNameTableEntry {
+ OctetStr usmUserName;
+ OctetStr usmUserSecurityName;
+ long int usmUserAuthProtocol;
+ long int usmUserPrivProtocol;
+ unsigned char *authPassword; long int authPasswordLength;
+ unsigned char *privPassword; long int privPasswordLength;
+};
+
+//-----------[ async methods callback ]-----------------------------------
+typedef void (*usm_add_user_callback)(const OctetStr &engine_id,
+ const OctetStr &usm_user_name,
+ const OctetStr &usm_user_security_name,
+ const int auth_protocol,
+ const OctetStr &auth_key,
+ const int priv_protocol,
+ const OctetStr &priv_key);
+
+struct SecurityStateReference;
+
+class AuthPriv;
+class USMTimeTable;
+class USMUserNameTable;
+class USMUserTable;
+class v3MP;
+
+/**
+ * This is the class for the User Based Security Model.
+ *
+ * To add or delete users, the methods add_usm_user() and delete_usm_user()
+ * should be used.
+ *
+ * USM distinguishes between userName and securityName. The following is
+ * from section 2.1 of RFC3414:
+ *
+ * "userName: A string representing the name of the user.
+ *
+ * securityName: A human-readable string representing the user in a format
+ * that is Security Model independent. There is a one-to-one relationship *
+ * between userName and securityName."
+ */
+class DLLOPT USM
+{
+ friend class v3MP;
+
+public:
+
+ /**
+ * Create an instance of the USM.
+ *
+ * @param engine_boots - The new value for the snmpEngineBoots counter
+ * @param engine_id - The local snmp engine id
+ * @param v3_mp - Pointer to the parent v3MP object.
+ * @param msg_id - OUT: The initial value for the msgID
+ * @param result - OUT: construct status, should be SNMPv3_USM_OK
+ */
+ USM(unsigned int engine_boots, const OctetStr &engine_id, const v3MP *v3_mp,
+ unsigned int *msg_id, int &result);
+
+ /**
+ * Destructor.
+ */
+ ~USM();
+
+ /**
+ * Enables the discovery mode of the USM, i.e. the USM accepts all messages
+ * with unknown engine ids and adds these engine ids to its tables.
+ */
+ void set_discovery_mode() { discovery_mode = true; };
+
+ /**
+ * Disables the discovery mode of the USM, i.e. the USM will not accept any
+ * message with an unknown engine id.
+ */
+ void unset_discovery_mode() { discovery_mode = false; };
+
+ /**
+ * Return TRUE if the USM discovery mode is enabled, FALSE else.
+ */
+ bool is_discovery_enabled() const { return discovery_mode; };
+
+ /**
+ * Add a new user to the usmUserNameTable. If the User is already known
+ * to the USM, the old entry is replaced.
+ * The USM will compute a userName for the given securityName, which
+ * will be the same as securityName (recommended).
+ *
+ * If discovery mode is enabled, localized user entries are
+ * automatically created for new engine ids.
+ *
+ * @param security_name - Unique securityName
+ * @param auth_protocol - Possible values are:
+ * SNMP_AUTHPROTOCOL_NONE,
+ * SNMP_AUTHPROTOCOL_HMACMD5,
+ * SNMP_AUTHPROTOCOL_HMACSHA
+ * @param priv_protocol - Possible values are:
+ * SNMP_PRIVPROTOCOL_NONE,
+ * SNMP_PRIVPROTOCOL_DES,
+ * SNMP_PRIVPROTOCOL_IDEA
+ * @param auth_password - Secret password for authentication
+ * @param priv_password - Secret password for privacy
+ *
+ * @return - SNMPv3_USM_OK or
+ * SNMP_v3_USM_ERROR (memory error, not initialized)
+ */
+ int add_usm_user(const OctetStr& security_name,
+ const long int auth_protocol,
+ const long int priv_protocol,
+ const OctetStr& auth_password,
+ const OctetStr& priv_password);
+
+ /**
+ * Add a new user to the usmUserNameTable. If the userName is already known
+ * to the USM, the old entry is replaced.
+ *
+ * It is not recommended to add users with userName != securityName.
+ *
+ * @param user_name - Unique userName
+ * @param security_name - Unique securityName
+ * @param auth_protocol - Possible values are:
+ * SNMP_AUTHPROTOCOL_NONE,
+ * SNMP_AUTHPROTOCOL_HMACMD5,
+ * SNMP_AUTHPROTOCOL_HMACSHA
+ * @param priv_protocol - Possible values are:
+ * SNMP_PRIVPROTOCOL_NONE,
+ * SNMP_PRIVPROTOCOL_DES,
+ * SNMP_PRIVPROTOCOL_IDEA
+ * @param auth_password - Secret password for authentication
+ * @param priv_password - Secret password for privacy
+ *
+ * @return - SNMPv3_USM_OK or
+ * SNMP_v3_USM_ERROR (memory error, not initialized)
+ */
+ int add_usm_user(const OctetStr& user_name,
+ const OctetStr& security_name,
+ const long int auth_protocol,
+ const long int priv_protocol,
+ const OctetStr& auth_password,
+ const OctetStr& priv_password);
+
+
+ /**
+ * Add or replace a localized user in the USM table.
+ *
+ * This function uses build_localized_keys() to generate localized
+ * keys for the given passwords. Then it calls add_localized_user()
+ * to add/replace the localized entry for the user.
+ *
+ * The passwords are not stored, so no additonal engine id discovery
+ * is possible.
+ *
+ * @param user_name - The name of the user (in the USM)
+ * @param security_name - The securityName of the user, this name
+ * is the same for all securityModels
+ * @param auth_protocol - Possible values are:
+ * SNMP_AUTHPROTOCOL_NONE,
+ * SNMP_AUTHPROTOCOL_HMACMD5,
+ * SNMP_AUTHPROTOCOL_HMACSHA,...
+ * @param priv_protocol - Possible values are:
+ * SNMP_PRIVPROTOCOL_NONE,
+ * SNMP_PRIVPROTOCOL_DES,
+ * SNMP_PRIVPROTOCOL_IDEA,...
+ * @param auth_password - Secret password for authentication
+ * @param priv_password - Secret password for privacy
+ * @param engine_id - The engineID, the key was localized with
+ *
+ * @return - SNMPv3_USM_OK
+ * SNMP_v3_USM_ERROR (not initialized, no memory)
+ */
+ int add_usm_user(const OctetStr& user_name,
+ const OctetStr& security_name,
+ const long int auth_protocol,
+ const long int priv_protocol,
+ const OctetStr& auth_password,
+ const OctetStr& priv_password,
+ const OctetStr& engine_id);
+
+ int add_usm_user(const OctetStr& security_name,
+ const long int auth_protocol,
+ const long int priv_protocol,
+ const OctetStr& auth_password,
+ const OctetStr& priv_password,
+ const OctetStr& engine_id)
+ { return add_usm_user(security_name, security_name, auth_protocol,
+ priv_protocol, auth_password, priv_password,
+ engine_id); };
+
+
+ /**
+ * Delete all occurences of the user with the given security name
+ * from the USM.
+ *
+ * @param security_name - the securityName of the user
+ */
+ void delete_usm_user(const OctetStr& security_name);
+
+
+ /**
+ * Save all localized users into a file.
+ *
+ * @param file - filename including path
+ *
+ * @return SNMPv3_USM_ERROR, SNMPv3_USM_FILECREATE_ERROR,
+ * SNMPv3_USM_FILERENAME_ERROR or SNMPv3_USM_OK
+ */
+ int save_localized_users(const char *file);
+
+ /**
+ * Load localized users from a file.
+ *
+ * @param file - filename including path
+ *
+ * @return SNMPv3_USM_ERROR, SNMPv3_USM_FILEOPEN_ERROR,
+ * SNMPv3_USM_FILEREAD_ERROR or SNMPv3_USM_OK
+ */
+ int load_localized_users(const char *file);
+
+ /**
+ * Save all users with their passwords into a file.
+ *
+ * @param file - filename including path
+ *
+ * @return SNMPv3_USM_ERROR, SNMPv3_USM_FILECREATE_ERROR,
+ * SNMPv3_USM_FILERENAME_ERROR or SNMPv3_USM_OK
+ */
+ int save_users(const char *file);
+
+ /**
+ * Load users with their passwords from a file.
+ *
+ * @param file - filename including path
+ *
+ * @return SNMPv3_USM_ERROR, SNMPv3_USM_FILEOPEN_ERROR,
+ * SNMPv3_USM_FILEREAD_ERROR or SNMPv3_USM_OK
+ */
+ int load_users(const char *file);
+
+ /**
+ * Add or replace a localized user in the USM table. Use this method
+ * only, if you know what you are doing.
+ *
+ * @param engine_id - The engineID, the key was localized with
+ * @param user_name - The name of the user (in the USM)
+ * @param security_name - The securityName of the user, this name
+ * is the same for all securityModels
+ * @param auth_protocol - Possible values are:
+ * SNMP_AUTHPROTOCOL_NONE,
+ * SNMP_AUTHPROTOCOL_HMACMD5,
+ * SNMP_AUTHPROTOCOL_HMACSHA,...
+ * @param auth_key - The key used for authentications
+ * @param priv_protocol - Possible values are:
+ * SNMP_PRIVPROTOCOL_NONE,
+ * SNMP_PRIVPROTOCOL_DES,
+ * SNMP_PRIVPROTOCOL_IDEA,...
+ * @param priv_key - The key used for privacy
+ *
+ * @return - SNMPv3_USM_OK
+ * SNMP_v3_USM_ERROR (not initialized, no memory)
+ */
+ int add_localized_user(const OctetStr &engine_id,
+ const OctetStr &user_name,
+ const OctetStr &security_name,
+ const long auth_protocol,
+ const OctetStr &auth_key,
+ const long priv_protocol,
+ const OctetStr &priv_key);
+
+ /**
+ * Generate localized keys for the given params.
+ *
+ * The buffers for the keys should be of size SNMPv3_USM_MAX_KEY_LEN.
+ *
+ * @param engine_id -
+ * @param auth_prot -
+ * @param priv_prot -
+ * @param auth_password -
+ * @param auth_password_len -
+ * @param priv_password -
+ * @param priv_password_len -
+ * @param auth_key - allocated space for the authentication key
+ * @param auth_key_len - IN: length of the buffer, OUT: key length
+ * @param priv_key - allocated space for the privacy key
+ * @param priv_key_len - IN: length of the buffer, OUT: key length
+ * @return SNMPv3_USM_OK, or USM error codes
+ */
+ int build_localized_keys(const OctetStr &engine_id,
+ const int auth_prot,
+ const int priv_prot,
+ const unsigned char *auth_password,
+ const unsigned int auth_password_len,
+ const unsigned char *priv_password,
+ const unsigned int priv_password_len,
+ unsigned char *auth_key,
+ unsigned int *auth_key_len,
+ unsigned char *priv_key,
+ unsigned int *priv_key_len);
+
+ /**
+ * Delete all localized entries of this user from the usmUserTable.
+ *
+ * @param user_name - The userName that should be deleted
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_OK (user deleted or not in table)
+ */
+ int delete_localized_user(const OctetStr& user_name);
+
+
+ /**
+ * Delete the entry with the given userName and engineID
+ * from the usmUserTable
+ *
+ * @param engine_id - The engineID
+ * @param user_name - The userName that should be deleted
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_OK (user deleted or not in table)
+ */
+ int delete_localized_user(const OctetStr& engine_id,
+ const OctetStr& user_name);
+
+
+ /**
+ * Delete this engine id form all USM tables (users and engine time).
+ *
+ * @param engine_id - the engine id
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_OK (entries deleted or not in table)
+ */
+ int remove_engine_id(const OctetStr &engine_id);
+
+ /**
+ * Delete the time information for the given engine id.
+ *
+ * @param engine_id - the engine id
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_OK (entry deleted or not in table)
+ */
+ int remove_time_information(const OctetStr &engine_id);
+
+ /**
+ * Replace a localized key of the user and engineID in the
+ * usmUserTable.
+ *
+ * @param user_name - The name of the user in the USM
+ * @param user_name_len - The length of the user name
+ * @param engine_id - Change the localized key for the SNMP
+ * entity with this engine id
+ * @param engine_id_len - The length of the engine id
+ * @param new_key - The new key
+ * @param new_key_len - The length of the new key
+ * @param type_of_key - AUTHKEY, OWNAUTHKEY, PRIVKEY or OWNPRIVKEY
+ *
+ * @return - SNMPv3_USM_ERROR (no such entry or not initialized),
+ * SNMPv3_USM_OK
+ */
+ int update_key(const unsigned char* user_name, const long user_name_len,
+ const unsigned char* engine_id, const long engine_id_len,
+ const unsigned char* new_key, const long new_key_len,
+ const int type_of_key);
+
+ /**
+ * Search for a user with the given securityName and engineID
+ * in the usmUserTable and return the entry. If no entry
+ * could be found, the usmUserNameTable is searched for the given
+ * securityName. If this table has an entry of this user, a
+ * localized entry is generated, added to the usmUserTable and
+ * returned to the caller.
+ *
+ * The caller has to call free_user() with the returned struct.
+ *
+ * @param engine_id -
+ * @param security_name -
+ *
+ * @return - a pointer to the structure if an entry could be found
+ * or was generated, NULL for all errors
+ */
+ struct UsmUser *get_user(const OctetStr &engine_id,
+ const OctetStr &security_name);
+
+ /**
+ * Free the structure returned from get_user(OctetStr,OctetStr).
+ */
+ void free_user(struct UsmUser *&user);
+
+ /**
+ * Get the security name from a user name.
+ *
+ * @param user_name -
+ * @param user_name_len -
+ * @param security_name - Buffer for the securityName
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+ * SNMPv3_USM_OK
+ */
+ int get_security_name(const unsigned char *user_name,
+ const long int user_name_len,
+ OctetStr &security_name);
+
+ /**
+ * Get the user name from a security name.
+ *
+ * @param user_name - Buffer for the userName
+ * @param user_name_len - Has to be set to the max length of the
+ * buffer. Is set to the length of the found
+ * securityName or to 0 if not found.
+ * @param security_name -
+ * @param security_name_len -
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+ * SNMPv3_USM_OK
+ */
+ int get_user_name(unsigned char *user_name,
+ long int *user_name_len,
+ const unsigned char *security_name,
+ const long int security_name_len);
+
+
+ /**
+ * Prepare a key update in the USM. The following procedure is used: To
+ * prepare the key update, this function adds the neccessary variable
+ * bindings to the Pdu to do the key update on the target SNMP entity.
+ * The Pdu has to be sent to the target. If the key update on the target
+ * is successful, usmCommitKeyUpdate() has to be called to do the local key
+ * update. On failure usmAbortKeyUpdate() has to be called to free
+ * temporary ressources.
+ *
+ * @param securityName - The name of the user
+ * @param target - A target to identify the SNMP entity on which the
+ * key will be updated
+ * @param newPassword - The new password for the user
+ * @param pdu - A PDU into which this funktion adds the VBs needed
+ * to change the keys on the target
+ * @param type - Indicates how and which key should be chaned:
+ * possilbe values are: AUTHKEY, PRIVKEY and
+ * OWNAUTHKEY, OWNPRIVKEY.
+ * @param status - The return status: SNMPv3_USM_OK or one of the
+ * error codes
+ *
+ * @return - A structure, that is needed to commit/abort the key update.
+ * If an error occurs, the return value is NULL
+ */
+ struct UsmKeyUpdate* key_update_prepare(const OctetStr& securityName,
+ SnmpTarget& target,
+ const OctetStr& newPassword,
+ Pdu& pdu, int type,
+ int &status,
+ const OctetStr& oldpass = "",
+ const OctetStr& oldengid= "",
+ const OctetStr& newengid= "");
+
+ /**
+ * Abort the local key update.
+ *
+ * @param uku - The pointer returned by usmPrepareKeyUpdate()
+ */
+ void key_update_abort(struct UsmKeyUpdate *uku);
+
+
+ /**
+ * Commit the local key update.
+ *
+ * @param uku - The pointer returned by usmPrepareKeyUpdate()
+ * @param update_type - One of USM_KeyUpdate, USM_PasswordKeyUpdate,
+ * USM_PasswordAllKeyUpdate
+ *
+ * @return - SNMPv3_USM_ERROR, SNMPv3_USM_OK
+ */
+ int key_update_commit(struct UsmKeyUpdate *uku, int update_type);
+
+
+ /**
+ * Get a pointer to the AuthPriv object used by the USM.
+ *
+ */
+ AuthPriv *get_auth_priv();
+
+
+ /**
+ * Return engineBoots and engineTime for a given engineID
+ *
+ * @param engine_id - The engineID of the SNMP entity
+ * @param engine_boots - OUT: boot counter (0 if not found)
+ * @param engine_time - OUT: engine time (0 if not found)
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_OK (entry found, values are filled)
+ * SNMPv3_USM_UNKNOWN_ENGINEID ( not found)
+ */
+ int get_time(const OctetStr &engine_id,
+ long int *engine_boots, long int *engine_time);
+
+
+
+ /**
+ * Return engineBoots and engineTime of the local snmp entity
+ *
+ * @param engine_boots - OUT: boot counter (0 if not found)
+ * @param engine_time - OUT: engine time (0 if not found)
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_OK (entry found, values are filled)
+ */
+ int get_local_time(long int *engine_boots, long int *engine_time) const;
+
+
+ /**
+ * Return the local snmp engine id.
+ */
+ const OctetStr& get_local_engine_id() const { return local_snmp_engine_id; };
+
+ /**
+ * Get the number of received messages with an unsupported securityLevel
+ *
+ * @return - usmStatsUnsupportedSecLevels
+ */
+ unsigned long get_stats_unsupported_sec_levels() const
+ { return usmStatsUnsupportedSecLevels; };
+
+ /**
+ * Get the number of received messages outside time window
+ *
+ * @return - usmStatsNotInTimeWindows
+ */
+ unsigned long get_stats_not_in_time_windows() const
+ { return usmStatsNotInTimeWindows; };
+
+ /**
+ * Get the number of received messages with a unknown userName
+ *
+ * @return - usmStatsUnknownUserNames
+ */
+ unsigned long get_stats_unknown_user_names() const
+ { return usmStatsUnknownUserNames; };
+
+ /**
+ * Get the number of received messages with a unknown engineID
+ *
+ * @return - usmStatsUnknownEngineIDs
+ */
+ unsigned long get_stats_unknown_engine_ids() const
+ { return usmStatsUnknownEngineIDs; };
+
+ /**
+ * Get the number of received messages with a wrong digest
+ *
+ * @return - usmStatsWrongDigests
+ */
+ unsigned long get_stats_wrong_digests() const
+ { return usmStatsWrongDigests; };
+
+ /**
+ * Get the number of received messages with decryption errors
+ *
+ * @return - usmStatsDecryptionErrors
+ */
+ unsigned long get_stats_decryption_errors() const
+ { return usmStatsDecryptionErrors; };
+
+ //@{
+ /**
+ * Increase the stats counter. Should only be used by agent++.
+ */
+ void inc_stats_unsupported_sec_levels();
+ void inc_stats_not_in_time_windows();
+ void inc_stats_unknown_user_names();
+ void inc_stats_unknown_engine_ids();
+ void inc_stats_wrong_digests();
+ void inc_stats_decryption_errors();
+ //@}
+
+ /**
+ * Lock the UsmUserNameTable for access through peek_first_user()
+ * and peek_next_user().
+ */
+ void lock_user_name_table();
+
+ /**
+ * Get a const pointer to the first entry of the UsmUserNameTable.
+ *
+ * @note Use lock_user_name_table() and unlock_user_name_table()
+ * for thread safety.
+ */
+ const UsmUserNameTableEntry *peek_first_user();
+
+ /**
+ * Get a const pointer to the next entry of the UsmUserNameTable.
+ *
+ * @note Use lock_user_name_table() and unlock_user_name_table()
+ * for thread safety.
+ */
+ const UsmUserNameTableEntry *peek_next_user(const UsmUserNameTableEntry *e);
+
+ /**
+ * Unlock the UsmUserNameTable after access through peek_first_user()
+ * and peek_next_user().
+ */
+ void unlock_user_name_table();
+
+ /**
+ * Lock the UsmUserTable for access through peek_first_luser()
+ * and peek_next_luser().
+ */
+ void lock_user_table();
+
+ /**
+ * Get a const pointer to the first entry of the UsmUserTable.
+ *
+ * @note Use lock_user_table() and unlock_user_table()
+ * for thread safety.
+ */
+ const UsmUserTableEntry *peek_first_luser();
+
+ /**
+ * Get a const pointer to the next entry of the UsmUserTable.
+ *
+ * @note Use lock_user_table() and unlock_user_table()
+ * for thread safety.
+ */
+ const UsmUserTableEntry *peek_next_luser(const UsmUserTableEntry *e);
+
+ /**
+ * Unlock the UsmUserTable after access through peek_first_luser()
+ * and peek_next_luser().
+ */
+ void unlock_user_table();
+
+ /**
+ * for v3MP:
+ *
+ * Delete the pointers within the structure and the structure
+ * itself.
+ *
+ * @param ssr - The structure that should be deleted.
+ */
+ void delete_sec_state_reference(struct SecurityStateReference *ssr);
+
+ /**
+ * Protected (for agent++):
+ *
+ * Get the user at the specified position of the usmUserTable.
+ *
+ * The returned pointer must NOT be deleted!
+ *
+ * @note lock_user_table() and unlock_user_table() must be used
+ * for thread synchronization.
+ *
+ * @param number - get the entry at position number (1...)
+ *
+ * @return - a pointer to the structure or NULL if number is out
+ * of range
+ */
+ const struct UsmUserTableEntry *get_user(int number);
+
+ /**
+ * Get the properties of the specified user.
+ *
+ * The returned pointer must NOT be deleted!
+ *
+ * @note lock_user_table() and unlock_user_table() must be used
+ * for thread synchronization.
+ *
+ * @param security_name - The security name of the user
+ *
+ * @return - a pointer to the structure or NULL if number is out
+ * of range
+ */
+ const struct UsmUserNameTableEntry *get_user(const OctetStr &security_name);
+
+ /**
+ * Protected (for agent++):
+ *
+ * Get the number of elements in the usmUserTable
+ *
+ * @note lock_user_table() and unlock_user_table() must be used
+ * for thread synchronization.
+ *
+ * @return - number of elements
+ */
+ int get_user_count() const;
+
+
+ /**
+ * Protected (for agent++)
+ *
+ * Register a callback function that is called if a new localized user
+ * has been added to the usm user table
+ */
+ void add_user_added_callback(const usm_add_user_callback cb);
+
+
+ protected:
+
+ /**
+ * Get a new security state reference (for v3MP).
+ *
+ * @return - A newly created security state reference.
+ */
+ struct SecurityStateReference *get_new_sec_state_reference();
+
+ /**
+ * Generate a complete message that is ready to send to the target.
+ *
+ * @param globalData - Buffer containing the serialized globalData,
+ * ready to be copied into the wholeMsg
+ * @param globalDataLength - The length of this buffer
+ * @param maxMessageSize - The maximum message size
+ * @param securityEngineID - The engineID of the authoritative SNMP entity
+ * @param securityName - The name of the user
+ * @param securityLevel - The security Level for this Message
+ * @param scopedPDU - Buffer containing the serialized scopedPDU,
+ * ready to be copied into the wholeMsg
+ * @param scopedPDULength - The length of this Buffer
+ * @param securityStateReference - The reference that was generated when
+ * the request was parsed. For request, this
+ * param has to be NULL. The reference
+ * is deleted by this function.
+ * @param wholeMsg - OUT: the buffer for the whole message
+ * @param wholeMsgLength - IN: lenght of the buffer.
+ * OUT: length of the generated message
+ *
+ * @return - SNMPv3_USM_OK on success. See snmperrs.h for the error codes
+ * of the USM.
+ */
+ int generate_msg(
+ unsigned char *globalData, // message header, admin data
+ int globalDataLength,
+ int maxMessageSize, // of the sending SNMP entity
+ const OctetStr &securityEngineID,// authoritative SNMP entity
+ const OctetStr &securityName, // on behalf of this principal
+ int securityLevel, // Level of Security requested
+ unsigned char *scopedPDU, // message (plaintext) payload
+ int scopedPDULength,
+ struct SecurityStateReference *securityStateReference,
+ unsigned char *wholeMsg, // OUT complete generated message
+ int *wholeMsgLength); // OUT length of generated message
+
+
+
+ /**
+ * Parse a received message.
+ *
+ * @param maxMessageSize - The maximum message size of the snding
+ * SNMP entity.
+ * @param securityParameters - The security parameters as received
+ * @param securityParametersLength - The length of the security parameters
+ * @param securityParametersPosition - The position of the security
+ * parameters in the message
+ * @param securityLevel - The securityLevel of the message
+ * @param wholeMsg - The buffer with the whole message
+ * @param wholeMsgLength - The length of the whole message
+ * @param msgData - The buffer with the messageData
+ * @param msgDataLength - The length of the messageData buffer
+ * @param security_engine_id - OUT: the authoritative engineID
+ * @param security_name - OUT: the name of the user
+ * @param scopedPDU - OUT: buffer containing the scopedPDU
+ * @param scopedPDULength - IN: length of the buffer
+ * OUT: length of the scopedPDU
+ * @param maxSizeResponseScopedPDU - OUT: maximum size for a scopedPDU in a
+ * response message
+ * @param securityStateReference - OUT: the securityStateReference
+ * @param fromAddress - IN: Address of the sender
+ *
+ * @return - SNMPv3_USM_OK on success. See snmperrs.h for the error codes
+ * of the USM.
+ */
+ int process_msg(
+ int maxMessageSize, // of the sending SNMP entity
+ unsigned char *securityParameters, // for the received message
+ int securityParametersLength,
+ int securityParametersPosition,
+ long int securityLevel, // Level of Security
+ unsigned char *wholeMsg, // as received on the wire
+ int wholeMsgLength, // length as received on the wire
+ unsigned char *msgData,
+ int msgDataLength,
+ OctetStr &security_engine_id, // authoritative SNMP entity
+ OctetStr &security_name, //identification of the principal
+ unsigned char *scopedPDU, // message (plaintext) payload
+ int *scopedPDULength,
+ long *maxSizeResponseScopedPDU,// maximum size of the Response PDU
+ struct SecurityStateReference *securityStateReference,
+ // reference to security state
+ // information, needed for response
+ const UdpAddress &fromAddress); // Address of the sender
+
+private:
+
+ /**
+ * Delete the pointers in the structure and set all values to 0/NULL.
+ *
+ * @param usp - The structure that should be deleted
+ */
+ void delete_sec_parameters( struct UsmSecurityParameters *usp);
+
+
+ /**
+ * Serialize the given values into the buffer according to the BER.
+ *
+ * UsmSecurityParameters ::=
+ * SEQUENCE {
+ * -- global User-based security parameters
+ * msgAuthoritativeEngineID OCTET STRING (5..32)
+ * msgAuthoritativeEngineBoots INTEGER (0..2147483647),
+ * msgAuthoritativeEngineTime INTEGER (0..2147483647),
+ * msgUserName OCTET STRING (SIZE(0..32)),
+ * -- authentication protocol specific parameters
+ * msgAuthenticationParameters OCTET STRING,
+ * -- privacy protocol specific parameters
+ * msgPrivacyParameters OCTET STRING
+ * }
+ *
+ * @param outBuf - buffer for the serialized values
+ * @param maxLength - before call: length of the buffer
+ * after call: bytes left in the buffer
+ * @param sp - the values to serialize
+ * @param position - after call: points to the first byte of the
+ * field for the authentication parameter
+ *
+ * @return - a pointer to the first free byte in the buffer,
+ * NULL on error
+ */
+ unsigned char *build_sec_params(unsigned char *outBuf, int *maxLength,
+ struct UsmSecurityParameters sp,
+ int *position);
+
+ /**
+ * Serialize the given values acording to the BER into the
+ * buffer. On success, the buffer contains a valid SNMPv3 message.
+ *
+ * @param outBuf - buffer for the serialized values
+ * @param maxLength - before call: length of the buffer
+ * after call: bytes left in the buffer
+ * @param globalData - Buffer that contains the serialized globalData
+ * @param globalDataLength - The length of this buffer
+ * @param positionAuthPar - after call: points to the first byte of the
+ * field for the authentication parameter
+ * @param securityParameters - The security parameters
+ * @param msgData - Buffer that contains the serialized msgData
+ * @param msgDataLength - The length of this buffer
+ *
+ * @return - a pointer to the first free byte in the buffer,
+ * NULL on error
+ */
+ unsigned char *build_whole_msg(
+ unsigned char *outBuf, int *maxLength,
+ unsigned char *globalData, long int globalDataLength,
+ int *positionAuthPar,
+ struct UsmSecurityParameters securityParameters,
+ unsigned char *msgData, long int msgDataLength);
+
+
+ /**
+ * Delete the pointers in the structure
+ *
+ * @param user - The structure that should be deleted
+ */
+ inline void delete_user_ptr(struct UsmUser *user);
+
+
+ private:
+
+ OctetStr local_snmp_engine_id; ///< local snmp engine id
+ const v3MP *v3mp; ///< Pointer to the v3MP that created this object
+
+ // 0: don't accept messages from hosts with a unknown engine id
+ bool discovery_mode;
+
+ // MIB Counters
+ unsigned int usmStatsUnsupportedSecLevels;
+ unsigned int usmStatsNotInTimeWindows;
+ unsigned int usmStatsUnknownUserNames;
+ unsigned int usmStatsUnknownEngineIDs;
+ unsigned int usmStatsWrongDigests;
+ unsigned int usmStatsDecryptionErrors;
+
+ // the instance of AuthPriv
+ AuthPriv *auth_priv;
+
+ // this table contains time values of contacted snmp entities
+ USMTimeTable *usm_time_table;
+
+ // Users that are known but not localized to a engine ID
+ USMUserNameTable *usm_user_name_table;
+
+ // Table containing localized Users ready to use
+ USMUserTable *usm_user_table;
+
+ // Callback for agent++ to indicate new users in usm tables
+ usm_add_user_callback usm_add_user_cb;
+
+};
+
+
+// only for compatibility do not use these values and functions:
+// =============================================================
+
+#define SecurityLevel_noAuthNoPriv SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV
+#define SecurityLevel_authNoPriv SNMP_SECURITY_LEVEL_AUTH_NOPRIV
+#define SecurityLevel_authPriv SNMP_SECURITY_LEVEL_AUTH_PRIV
+
+#define SNMPv3_usmNoAuthProtocol SNMP_AUTHPROTOCOL_NONE
+#define SNMPv3_usmHMACMD5AuthProtocol SNMP_AUTHPROTOCOL_HMACMD5
+#define SNMPv3_usmHMACSHAAuthProtocol SNMP_AUTHPROTOCOL_HMACSHA
+
+#define SNMPv3_usmNoPrivProtocol SNMP_PRIVPROTOCOL_NONE
+#define SNMPv3_usmDESPrivProtocol SNMP_PRIVPROTOCOL_DES
+#define SNMPv3_usmIDEAPrivProtocol SNMP_PRIVPROTOCOL_IDEA
+#define SNMPv3_usmAES128PrivProtocol SNMP_PRIVPROTOCOL_AES128
+#define SNMPv3_usmAES192PrivProtocol SNMP_PRIVPROTOCOL_AES192
+#define SNMPv3_usmAES256PrivProtocol SNMP_PRIVPROTOCOL_AES256
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _SNMPv3
+
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## uxsnmp.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+
+#ifndef _UXSNMP_H_
+#define _UXSNMP_H_
+
+#include "snmp_pp/reentrant.h"
+#include "snmp_pp/target.h"
+#include "snmp_pp/oid.h"
+#include "snmp_pp/address.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define SNMP_PP_WITH_UDPADDR // Snmp class has constructor with UdpAddress
+
+//-----[ internally used defines ]----------------------------------------
+#define MAXNAME 80 // maximum name length
+#define MAX_ADDR_LEN 10 // maximum address len, ipx is 4+6
+#define SNMP_SHUTDOWN_MSG 0x0400+177 // shut down msg for stoping a blocked message
+#ifndef INVALID_SOCKET
+#define INVALID_SOCKET ((SnmpSocket)(~0)) // value for invalid socket
+#endif
+
+//-----[ async defines for engine ]---------------------------------------
+#define sNMP_PDU_GET_ASYNC 21
+#define sNMP_PDU_GETNEXT_ASYNC 22
+#define sNMP_PDU_SET_ASYNC 23
+#define sNMP_PDU_GETBULK_ASYNC 24
+#define sNMP_PDU_INFORM_ASYNC 25
+
+//-----[ trap / notify macros ]-------------------------------------------
+#define IP_NOTIFY 162 // IP notification
+#define IPX_NOTIFY 0x2121 // IPX notification
+
+//------[ forward declaration of Snmp class ]-----------------------------
+class Snmp;
+class EventListHolder;
+class Pdu;
+class v3MP;
+
+//-----------[ async methods callback ]-----------------------------------
+/**
+ * Async methods of the class Snmp require the caller to provide a
+ * callback address of a function with this typedef.
+ *
+ * @note It is not allowed to call any synchronous Snmp methods within the
+ * callback. Async methods are allowed.
+ *
+ * @param reason - Reason for callback (see snmperrs.h)
+ * @param session - Pointer to Snmp object that was used to send the request
+ * @param pdu - The received Pdu if reason indicates a received message
+ * @param target - source target
+ * @param data - Pointer passed to the async method
+ */
+typedef void (*snmp_callback)(int reason, Snmp *session,
+ Pdu &pdu, SnmpTarget &target, void *data);
+
+
+//------------[ SNMP Class Def ]---------------------------------------------
+//
+/**
+ * SNMP class defintion. The Snmp class provides an object oriented
+ * approach to SNMP. The SNMP class is an encapsulation of SNMP
+ * sessions, gets, sets and get nexts. The class manages all SNMP
+ * resources and provides complete retry and timeout capability.
+ *
+ * This class is thread save.
+ *
+ * @note If you use the async methods to send requests you MUST call
+ * Snmp::eventListHolder->SNMPProcessPendingEvents() while waiting
+ * for the responses. This function triggers the resend of
+ * packets and calls your callback function if the response is
+ * received.
+ *
+ * @note Call srand() before creating the first Snmp object.
+ */
+class DLLOPT Snmp: public SnmpSynchronized
+{
+ public:
+ //------------------[ constructors ]----------------------------------
+
+ /** @name Constructors and Destructor */
+ //@{
+
+ /**
+ * Construct a new SNMP session using the given UDP port.
+ *
+ * @param status
+ * after creation of the session this parameter will
+ * hold the creation status.
+ * @param port
+ * an UDP port to be used for the session
+ * @param bind_ipv6
+ * Set this to true if IPv6 should be used. The default is
+ * IPv4.
+ */
+ Snmp(int &status, const unsigned short port = 0,
+ const bool bind_ipv6 = false);
+
+ /**
+ * Construct a new SNMP session using the given UDP address.
+ * Thus, binds the session on a specific IPv4 or IPv6 address.
+ *
+ * @param status
+ * after creation of the session this parameter will
+ * hold the creation status.
+ * @param addr
+ * an UDP address to be used for the session
+ */
+ Snmp(int &status, const UdpAddress &addr);
+
+ /**
+ * Construct a new SNMP session using the given UDP addresses.
+ * Using this constructor will bind to both IPv4 and IPv6 ports.
+ *
+ * @param status
+ * after creation of the session this parameter will
+ * hold the creation status.
+ * @param addr_v4
+ * an IPv4 UDP address to be used for the session
+ * @param addr_v6
+ * an IPv6 UDP address to be used for the session
+ */
+ Snmp(int &status, const UdpAddress& addr_v4, const UdpAddress& addr_v6);
+
+ //-------------------[ destructor ]------------------------------------
+ /**
+ * Destructor.
+ */
+ virtual ~Snmp();
+
+ //@}
+
+ //--------[ Get the version of the snmp++ library ]--------------------
+ /**
+ * Get the version of the snmp++ library.
+ *
+ * @return The version of the snmp++ lib at runtime.
+ */
+ static const char *get_version();
+
+
+ //-------------------[ returns error string ]--------------------------
+ /**
+ * Returns a human readable error string.
+ *
+ * @param c - Error code returned by any method of this class
+ * @return Null terminated error string.
+ */
+ static const char *error_msg(const int c);
+#ifdef _SNMPv3
+ /**
+ * Returns a human readable error string.
+ * If a report message is returned, then the contained Oid can be
+ * used to get a error string.
+ *
+ * @param v3Oid - Oid of a SNMPv3 report Pdu
+ * @return Null terminated error string.
+ */
+ static const char* error_msg(const Oid& v3Oid);
+#endif
+
+ //------------------------[ Windows Sockets ]----------------------------
+
+ /**
+ * Initialize the Winsock library (WSAStartup).
+ *
+ * @note on Win32 this method *must* be called before creating Snmp or
+ * Address objects.
+ */
+ static void socket_startup();
+
+
+ /**
+ * Shut down the Winsock library (WSACleanup).
+ */
+ static void socket_cleanup();
+
+ //------------------------[ send requests ]------------------------------
+
+ /** @name Sending SNMP Pdus
+ */
+ //@{
+
+ /**
+ * Send a blocking SNMP-GET request.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the get
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int get(Pdu &pdu, const SnmpTarget &target);
+
+ /**
+ * Send a async SNMP-GET request.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the get
+ * @param callback - User callback function to use
+ * @param callback_data - User definable data pointer
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int get(Pdu &pdu, const SnmpTarget &target,
+ const snmp_callback callback,
+ const void *callback_data = 0);
+
+ /**
+ * Send a blocking SNMP-GETNEXT request.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the getnext
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int get_next(Pdu &pdu, const SnmpTarget &target);
+
+ /**
+ * Send a async SNMP-GETNEXT request.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the getnext
+ * @param callback - User callback function to use
+ * @param callback_data - User definable data pointer
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int get_next(Pdu &pdu, const SnmpTarget &target,
+ const snmp_callback callback,
+ const void *callback_data = 0);
+
+ /**
+ * Send a blocking SNMP-SET request.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the set
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int set(Pdu &pdu, const SnmpTarget &target);
+
+ /**
+ * Send a async SNMP-SET request.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the set
+ * @param callback - User callback function to use
+ * @param callback_data - User definable data pointer
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int set(Pdu &pdu, const SnmpTarget &target,
+ const snmp_callback callback,
+ const void * callback_data = 0);
+
+ /**
+ * Send a blocking SNMP-GETBULK request.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the getbulk
+ * @param non_repeaters - number of non repeaters
+ * @param max_reps - maximum number of repetitions
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int get_bulk(Pdu &pdu, const SnmpTarget &target,
+ const int non_repeaters, const int max_reps);
+
+ /**
+ * Send a async SNMP-GETBULK request.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the getbulk
+ * @param non_repeaters - number of non repeaters
+ * @param max_reps - maximum number of repetitions
+ * @param callback - User callback function to use
+ * @param callback_data - User definable data pointer
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int get_bulk(Pdu &pdu, const SnmpTarget &target,
+ const int non_repeaters, const int max_reps,
+ const snmp_callback callback,
+ const void *callback_data = 0);
+
+ /**
+ * Send a SNMP-TRAP.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the trap
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int trap(Pdu &pdu, const SnmpTarget &target);
+
+
+ /**
+ * Send a SNMPv3-REPORT.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the report (must be a UTarget)
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int report(Pdu &pdu, const SnmpTarget &target);
+
+ /**
+ * Send a blocking INFORM-REQ.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the inform
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int inform(Pdu &pdu, const SnmpTarget &target);
+
+ /**
+ * Send a async INFORM-REQ.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the inform
+ * @param callback - User callback function to use
+ * @param callback_data - User definable data pointer
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int inform(Pdu &pdu, const SnmpTarget &target,
+ const snmp_callback callback,
+ const void * callback_data = 0);
+
+ /**
+ * Send a RESPONSE.
+ *
+ * @param pdu - Pdu to send
+ * @param target - Target for the response
+ * @param fd - file descriptor to use, should be the one
+ * that was passed to the callback function
+ *
+ * @return SNMP_CLASS_SUCCES or a negative error code
+ */
+ virtual int response(Pdu &pdu, const SnmpTarget &target,
+ const SnmpSocket fd = INVALID_SOCKET);
+
+
+ /**
+ * Send a SNMP Broadcast message.
+ *
+ * This member function sends out a valid SNMP message to a
+ * broadcast address and waits for responses. The source addresses
+ * of the response messages are added to the collection.
+ *
+ * The message is sent only once.
+ *
+ * @note SNMP_BROADCAST has to be defined in config_snmp_pp.h.
+ *
+ * @note There is no SNMP standard that defines "SNMP Broadcast
+ * discovery". SNMP agents are not forced to answer requests
+ * that are sent to a broadcast address.
+ *
+ * @note Do not use this method while waiting for other responses,
+ * as these responses will be added to the collection and dropped
+ * by this method. Solution for this problem: Use a special
+ * Snmp object only for broadcasts.
+ *
+ * @param addresses - The addresses of the agents, that answered.
+ * @param timeout_sec - Timeout in seconds
+ * @param addr - Broadcast address
+ * @param version - SNMP version to use
+ * @param community - Only needed for SNMPv1/v2c, defaults to "public"
+ *
+ */
+ virtual int broadcast_discovery(UdpAddressCollection &addresses,
+ const int timeout_sec,
+ const UdpAddress &addr,
+ const snmp_version version,
+ const OctetStr *community = 0);
+
+#ifdef _SNMPv3
+ virtual int engine_id_discovery(OctetStr &engine_id,
+ const int timeout_sec,
+ const UdpAddress &addr);
+#endif
+ //@}
+
+ /**
+ * Cancel a pending request.
+ *
+ * @param rid - The request id to cancel
+ *
+ * @return SNMP_CLASS_SUCCES or SNMP_CLASS_INVALID_REQID on failure
+ */
+ virtual int cancel(const unsigned long rid);
+
+
+ /** @name Trap and Inform handling
+ */
+ //@{
+
+ /**
+ * Set the port for listening to traps and informs.
+ *
+ * @note This function must be called before notify_register(),
+ * otherwise the default port is used.
+ */
+ virtual void notify_set_listen_port(const int port);
+
+ /**
+ * Get the port that is used for listening to traps and informs.
+ */
+ virtual int notify_get_listen_port();
+
+ /**
+ * Register to get traps and informs.
+ *
+ * @note Every call to one of the notify_register() methods overwrites
+ * the previous given values.
+ *
+ * @param trapids - ids to listen for
+ * @param targets - targets to listen for
+ * @param callback - User callback function to use
+ * @param callback_data - User definable data pointer
+ *
+ * @return SNMP_CLASS_SUCCESS, SNMP_CLASS_TL_FAILED or SNMP_CLASS_TL_IN_USE
+ */
+ virtual int notify_register(const OidCollection &trapids,
+ const TargetCollection &targets,
+ const snmp_callback callback,
+ const void *callback_data=0);
+
+ /**
+ * Unregister to get traps and informs.
+ * Undo the call to notify_register().
+ *
+ * @return Always SNMP_CLASS_SUCCESS
+ */
+ virtual int notify_unregister();
+
+ /**
+ * Get notify register info.
+ *
+ * @param trapids - ids listened for
+ * @param targets - targets listened for
+ *
+ * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_INVALID if not registered
+ */
+ virtual int get_notify_filter(OidCollection &trapids,
+ TargetCollection &targets);
+
+ //-----------------------[ access the trap reception info ]---------------
+ /**
+ * Get a pointer to the callback function used for trap reception.
+ *
+ * @return Pointer to the function set through notify_register()
+ */
+ snmp_callback get_notify_callback() { return notifycallback; };
+
+ /**
+ * Get a pointer to the data that is passed to the callback function.
+ *
+ * @return Pointer to the data set through notify_register()
+ */
+ void *get_notify_callback_data() { return notifycallback_data; };
+
+ //@}
+
+ /**
+ * Send raw UDP data.
+ * This method may be used to send any data to the recepient.
+ *
+ * @param send_buf - Data buffer
+ * @param send_len - Length of the data
+ * @param address - Recepient
+ * @param fd - socket to use, if not specified, the socket of the
+ * object is used
+ *
+ * @return 0 on success, -1 on failure
+ */
+ virtual int send_raw_data(unsigned char *send_buf,
+ size_t send_len, UdpAddress &address,
+ SnmpSocket fd = INVALID_SOCKET);
+
+ const IpAddress &get_listen_address() const {return listen_address; };
+
+ /**
+ * Start one thread listening for responses and notifications.
+ * This method is used to start response and notification processing in a
+ * multi threadded setup.
+ *
+ * @note start_poll_thread() itself is not thread safe. The caller must make
+ * sure that only one thread is calling start_poll_thread() or
+ * stop_poll_thread() at any point in time.
+ *
+ * @param timeout - Timeout for each call of the select() or poll()
+ * system call.
+ *
+ * @return true if the thread is now running and false if it failed to start.
+ */
+ bool start_poll_thread(const int timeout);
+
+ /**
+ * Stop the thread listening for responses and notifications.
+ * This method is used to stop the thread started with start_poll_thread().
+ *
+ * @note stop_poll_thread() itself is not thread safe. The caller must make
+ * sure that only one thread is calling start_poll_thread() or
+ * stop_poll_thread() at any point in time.
+ */
+ void stop_poll_thread();
+
+ EventListHolder *get_eventListHolder() { return eventListHolder; };
+
+protected:
+
+ /**
+ * Check for the status of the worker thread.
+ * @return BOOL - TRUE - if running, FALSE - otherwise
+ */
+ bool is_running(void) const
+ { return m_bThreadRunning; };
+
+ /**
+ * This is a working thread for the recovery of the pending events.
+ *
+ * @param pSnmp [in] pointer to the whole object
+ *
+ * @return int
+ * 0 - if succesful,
+ * 1 - in the case of error
+ */
+#ifdef WIN32
+ static int process_thread(Snmp *pSnmp);
+#else
+ static void* process_thread(void *arg);
+#endif
+
+ protected:
+
+ /**
+ * Generate a unique (for this Snmp obect) request id.
+ *
+ * @return Unique id between PDU_MIN_RID and PDU_MAX_RID
+ */
+ long MyMakeReqId();
+
+ /**
+ * Common init function used by constructors.
+ */
+ void init(int& status, IpAddress*[2],
+ const unsigned short port_v4, const unsigned short port_v6);
+
+ /**
+ * Set the notify timestamp of a trap pdu if the user did not set it.
+ */
+ void check_notify_timestamp(Pdu &pdu);
+
+ //-----------[ Snmp Engine ]----------------------------------------
+ /**
+ * gets, sets and get nexts go through here....
+ * This mf does all snmp sending and reception
+ * except for traps which are sent using trap().
+ *
+ * @note that for a UTarget with an empty engine id the
+ * Utarget::set_engine_id() may be called.
+ */
+ int snmp_engine( Pdu &pdu, // pdu to use
+ long int non_reps, // get bulk only
+ long int max_reps, // get bulk only
+ const SnmpTarget &target, // destination target
+ const snmp_callback cb, // async callback function
+ const void *cbd, // callback data
+ SnmpSocket fd = INVALID_SOCKET,
+ int reports_received = 0);
+
+ //--------[ map action ]------------------------------------------------
+ // map the snmp++ action to a SMI pdu type
+ void map_action(unsigned short action, unsigned short &pdu_action);
+
+#ifdef _SNMPv3
+ /**
+ * Internal used callback data structure for async v3 requests.
+ */
+ struct V3CallBackData
+ {
+ Pdu *pdu; ///< The Pdu that was sent
+ long int non_reps; ///< For GET-BULK requests
+ long int max_reps; ///< For GET-BULK requests
+ SnmpTarget *target; ///< Pointer to the Target object to use
+ snmp_callback oldCallback; ///< User callback function
+ const void *cbd; ///< User callback data
+ int reports_received; ///< How many reports are already received
+ };
+
+ friend void v3CallBack(int reason, Snmp *snmp, Pdu &pdu,
+ SnmpTarget &target, void *v3cd);
+ friend void deleteV3Callback(struct Snmp::V3CallBackData *&cbData);
+#endif
+
+ //---[ instance variables ]
+ SnmpSocket iv_snmp_session;
+#ifdef SNMP_PP_IPv6
+ SnmpSocket iv_snmp_session_ipv6;
+#endif
+
+ IpAddress listen_address;
+ long current_rid; // current rid to use
+
+ // inform receive member variables
+ snmp_callback notifycallback;
+ void * notifycallback_data;
+
+ // this member var will simulate a global var
+ EventListHolder *eventListHolder;
+
+private:
+
+ bool m_bThreadRunning;
+ int m_iPollTimeOut;
+
+ // Keep track of the thread.
+#ifdef _THREADS
+#ifdef WIN32
+ HANDLE m_hThread;
+ HANDLE m_hThreadEndEvent;
+#elif defined (CPU) && CPU == PPC603
+ int m_hThread;
+#else
+ pthread_t m_hThread;
+#endif
+#endif
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## v3.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+// $Id: v3.h 288 2007-03-22 22:37:09Z katz $
+
+#ifndef _V3_H
+#define _V3_H
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class OctetStr;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/** @name SNMPv3 Security Model values
+ */
+//@{
+#define SNMP_SECURITY_MODEL_ANY 0 //!< Not used in SNMP++.
+#define SNMP_SECURITY_MODEL_V1 1 //!< Can be used for SNMPv1 only.
+#define SNMP_SECURITY_MODEL_V2 2 //!< Can be used for SNMPv2 only.
+#define SNMP_SECURITY_MODEL_USM 3 //!< Can be used for SNMPv3 only.
+//@}
+
+/**
+ * Set the amount of log messages you want to get. To disable all
+ * messages, set the level to -1
+ *
+ * @param db_level - New level
+ */
+DLLOPT void debug_set_level(const int db_level);
+
+#ifdef _DEBUG
+
+/**
+ * SNMP++ logging function.
+ *
+ * The default is to log all messages with a level < 19. To change
+ * that either edit v3.cpp or use a "extern unsigned int debug_level"
+ * to change the level.
+ *
+ * @param db_level - Priority of the message (0 = high)
+ * @param format - Just like printf
+ */
+DLLOPT void debugprintf(int db_level, const char *format, ...);
+
+/**
+ * SNMP++ logging function for hex strings.
+ *
+ * @param db_level - Priority of the message (0 = high)
+ * @param comment - Comment printed before the hex dump (may be 0)
+ * @param data - pointer to the hex data
+ * @param len - length of the hex data
+ */
+DLLOPT void debughexcprintf(int db_level, const char* comment,
+ const unsigned char *data, const unsigned int len);
+
+//! Wrapper for debughexcprintf() without comment.
+#define debughexprintf(db_level, data, len) \
+ debughexcprintf(db_level, NULL, data, len);
+
+#else
+
+#ifndef _MSC_VER
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#define debugprintf(db_level,format...)
+#else
+void debugprintf(int db_level, const char *format, ...);
+#endif
+#else
+// disable any warning for wrong number of arguments in macro
+#pragma warning(disable:4002)
+#define debugprintf(db_level,format)
+#endif //_MSC_VER
+
+#define debughexprintf( db_level, data, len)
+#define debughexcprintf(db_level, comment, data, len)
+
+#endif
+
+#ifdef _SNMPv3
+
+#define MAXLENGTH_ENGINEID 32
+#define MAXLENGTH_CONTEXT_NAME 32
+#define MAXLENGTH_FILENAME 255
+#define MAXLENGTH_GLOBALDATA 42 // (2 + 1) + 7 + 7 + 3 + 7 + security
+
+#define oidV3SnmpEngine "1.3.6.1.6.3.10.2.1"
+#define oidV3SnmpEngineID "1.3.6.1.6.3.10.2.1.1.0"
+#define oidV3SnmpEngineBoots "1.3.6.1.6.3.10.2.1.2.0"
+#define oidV3SnmpEngineTime "1.3.6.1.6.3.10.2.1.3.0"
+#define oidV3SnmpEngineMaxMessageSize "1.3.6.1.6.3.10.2.1.4.0"
+
+// also defined in agent++/include/vacm.h
+#ifndef oidSnmpUnavailableContexts
+#define oidSnmpUnavailableContexts "1.3.6.1.6.3.12.1.4.0"
+#define oidSnmpUnknownContexts "1.3.6.1.6.3.12.1.5.0"
+#endif
+
+/** @name Error codes (storing engineBoots)
+ *
+ * These values are returned by getBootCounter() and saveBootCounter().
+ */
+//@{
+#define SNMPv3_OK 0 //!< No error
+#define SNMPv3_NO_ENTRY_ERROR -1 //!< No line for the engine id found
+#define SNMPv3_FILEOPEN_ERROR -2 //!< Unable to open file
+#define SNMPv3_TOO_LONG_ERROR -3 //!< The given engineID is too long
+#define SNMPv3_FILE_ERROR -4 //!< The given file contains a wrong line
+#define SNMPv3_FILECREATE_ERROR -5 //!< The File could not be created
+#define SNMPv3_FILERENAME_ERROR -6 //!< Error renaming the temporary file
+//@}
+
+/**
+ * Compare two strings.
+ *
+ * @param str1 - The first byte array
+ * @param ptr1len - Length of first array
+ * @param str2 - The second byte array
+ * @param ptr2len - Length of second array
+ *
+ * @return 1 if the strings are identical, 0 if not.
+ */
+DLLOPT int unsignedCharCompare(const unsigned char *str1,
+ const long int ptr1len,
+ const unsigned char *str2,
+ const long int ptr2len);
+
+/**
+ * String copy function.
+ *
+ * @note The returned string has to be deleted with "delete []".
+ *
+ * @param src - Source string
+ * @param srclen - Length of source string
+ *
+ * @return Pointer to a null terminated copy of src (or 0 on error).
+ */
+DLLOPT unsigned char *v3strcpy(const unsigned char *src, const int srclen);
+
+/**
+ * Encode the given string into the output buffer. For each byte
+ * of the string two bytes in the output buffer are used. The
+ * output buffer will contain chars from 0x64 to 0x79.
+ *
+ * @param in - The string (for example engine id) to encode
+ * @param in_length - The length of the engineID
+ * @param out - The output buffer for the encoded string, must have
+ * lenth 2 * in_length
+ */
+DLLOPT void encodeString(const unsigned char* in, const int in_length,
+ char* out);
+
+/**
+ * Decode the given encoded string into the output buffer.
+ *
+ * @param in - The encoded string
+ * @param in_length - The length of the encoded string
+ * @param out - Buffer for the decoded string (half size of input
+ * string). The String will be null terminated.
+ */
+DLLOPT void decodeString(const unsigned char* in, const int in_length,
+ char* out);
+
+/**
+ * Read the bootCounter of the given engineID stored in the given file.
+ *
+ * @param fileName - The name of the file
+ * @param engineId - Read the bootCounter for this enigneID
+ * @param boot - OUT: the bootCounter that was read
+ *
+ * @return One of SNMPv3_OK, SNMPv3_TOO_LONG_ERROR, SNMPv3_FILE_ERROR,
+ * SNMPv3_NO_ENTRY_ERROR, SNMPv3_FILEOPEN_ERROR
+ *
+ */
+DLLOPT int getBootCounter(const char *fileName,
+ const OctetStr &engineId, unsigned int &boot);
+
+/**
+ * Store the bootCounter of the given engineID in the given file.
+ *
+ * @param fileName - The name of the file
+ * @param engineId - Store the bootCounter for this enigneID
+ * @param boot - The bootCounter
+ *
+ * @return One of SNMPv3_OK, SNMPv3_FILEOPEN_ERROR, SNMPv3_FILECREATE_ERROR,
+ * SNMPv3_FILERENAME_ERROR.
+ *
+ */
+DLLOPT int saveBootCounter(const char *fileName,
+ const OctetStr &engineId, const unsigned int boot);
+
+
+#endif // _SNMPv3
+
+/**
+ * Tool class for easy allocation of buffer space.
+ */
+template <class T> class Buffer
+{
+ public:
+ /// Constructor: Allocate a buffer for size objects.
+ Buffer(const unsigned int size)
+ {
+ ptr = new T[size];
+ if (ptr)
+ len = size;
+ else
+ len = 0;
+ }
+
+ /// Destructor: Free allocated buffer
+ ~Buffer()
+ {
+ if (ptr) delete [] ptr;
+ }
+
+ /// Get the buffer pointer
+ T *get_ptr()
+ {
+ return ptr;
+ }
+
+ /// Overwrite the buffer space with zero.
+ void clear()
+ {
+ if (ptr)
+ memset(ptr, 0, len * sizeof(T));
+ }
+
+ private:
+ T *ptr;
+ unsigned int len;
+};
+
+// only for compatibility do not use these values:
+#define SecurityModel_any SNMP_SECURITY_MODEL_ANY
+#define SecurityModel_v1 SNMP_SECURITY_MODEL_V1
+#define SecurityModel_v2 SNMP_SECURITY_MODEL_V2
+#define SecurityModel_USM SNMP_SECURITY_MODEL_USM
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif // _V3_H
--- /dev/null
+/*_############################################################################
+ _##
+ _## vb.h
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ SNMP++ V B . H
+
+ VARIABLE BINDING CLASS DEFINITION
+
+ DESCRIPTION:
+ This module contains the class definition for the variable binding
+ class. The VB class is an encapsulation of a SNMP VB. A VB object is
+ composed of an SNMP++ Oid and an SMI value. The Vb class utilizes Oid
+ objects and thus requires the Oid class. The Vb class may be used
+ stand alone and does not require use of any other snmp library.
+
+ DESIGN + AUTHOR: Peter E. Mellquist
+
+=====================================================================*/
+// $Id: vb.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _VB_CLS
+#define _VB_CLS
+
+#include "snmp_pp/oid.h" // oid class def
+#include "snmp_pp/timetick.h" // time ticks
+#include "snmp_pp/counter.h" // counter
+#include "snmp_pp/gauge.h" // gauge class
+#include "snmp_pp/ctr64.h" // 64 bit counters
+#include "snmp_pp/octet.h" // octet class
+#include "snmp_pp/address.h" // address class def
+#include "snmp_pp/integer.h" // integer class
+#include "snmp_pp/snmperrs.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+//------------[ VB Class Def ]-------------------------------------
+/**
+ * The Vb class is the encapsulation of the SNMP variable binding.
+ *
+ * Variable binding lists in SNMP++ are represented as arrays of Vb
+ * objects. Vb objects are passed to and from SNMP objects to provide
+ * getting or setting MIB values. The vb class keeps its own memory
+ * for objects and does not utilize pointers to external data
+ * structures.
+ */
+class DLLOPT Vb
+{
+ //-----[ public members ]
+ public:
+
+ //-----[ constructors / destructors ]-------------------------------
+
+ /**
+ * Constructor with no arguments.
+ *
+ * This constructor creates an unitialized vb.
+ */
+ Vb() : iv_vb_value(0), exception_status(SNMP_CLASS_SUCCESS) {};
+
+ /**
+ * Constructor to initialize the oid.
+ *
+ * This constructor creates a vb with oid portion initialized.
+ */
+ Vb(const Oid &oid)
+ : iv_vb_oid(oid), iv_vb_value(0), exception_status(SNMP_CLASS_SUCCESS) {};
+
+ /**
+ * Copy constructor.
+ */
+ Vb(const Vb &vb) : iv_vb_value(0) { *this = vb; };
+
+ /**
+ * Destructor that frees all allocated memory.
+ */
+ ~Vb() { free_vb(); };
+
+ /**
+ * Overloaded assignment operator.
+ */
+ Vb& operator=(const Vb &vb);
+
+ /**
+ * Clone operator.
+ */
+ Vb *clone( ) const { return new Vb(*this); };
+
+ //-----[ set oid / get oid ]------------------------------------------
+
+ /**
+ * Set the oid from another oid.
+ */
+ void set_oid(const Oid &oid) { iv_vb_oid = oid; };
+
+ /**
+ * Get the oid portion.
+ *
+ * @note Check the validity of the object through Vb::valid() before
+ * calling this method.
+ */
+ void get_oid(Oid &oid) const { oid = iv_vb_oid; };
+
+ /**
+ * Get the oid portion as a const.
+ *
+ * @note Check the validity of the object through Vb::valid() before
+ * calling this method.
+ */
+ const Oid &get_oid() const { return iv_vb_oid; };
+
+ //-----[ set value ]--------------------------------------------------
+
+ /**
+ * Set the value using any SnmpSyntax object.
+ */
+ void set_value(const SnmpSyntax &val)
+ { free_vb(); iv_vb_value = val.clone(); };
+
+ /**
+ * Set the value with an int.
+ *
+ * The syntax of the Vb will be set to SMI INT32.
+ */
+ void set_value(const int i) { free_vb(); iv_vb_value = new SnmpInt32(i); };
+
+ /**
+ * Set the value with an unsigned int.
+ *
+ * The syntax of the Vb will be set to SMI UINT32.
+ */
+ void set_value(const unsigned int i)
+ { free_vb(); iv_vb_value = new SnmpUInt32(i); };
+
+ /**
+ * Set the value with a long int.
+ *
+ * @note Even on 64 bit platforms, only 32 bits are used
+ *
+ * The syntax of the Vb will be set to SMI INT32.
+ */
+ void set_value(const long i)
+ { free_vb(); iv_vb_value = new SnmpInt32(i); };
+
+ /**
+ * Set the value with an unsigned long int.
+ *
+ * @note Even on 64 bit platforms, only 32 bits are used
+ *
+ * The syntax of the Vb will be set to SMI UINT32.
+ */
+ void set_value(const unsigned long i)
+ { free_vb(); iv_vb_value = new SnmpUInt32(i); };
+
+ /**
+ * Set value using a null terminated string.
+ *
+ * The syntax of the Vb will be set to SMI octet.
+ */
+ void set_value(const char *ptr)
+ { free_vb(); iv_vb_value = new OctetStr(ptr); };
+
+ /**
+ * Set value using a string and length.
+ *
+ * The syntax of the Vb will be set to SMI octet.
+ */
+ void set_value(const unsigned char *ptr, const unsigned int len)
+ { free_vb(); iv_vb_value = new OctetStr(ptr, len); };
+
+ /**
+ * Set the value portion of the vb to null, if its not already.
+ */
+ void set_null() { free_vb(); };
+
+ //----[ get value ]------------------------------------------------
+
+ /**
+ * Get the value using a SnmpSyntax object.
+ *
+ * @param val - An object of a subclass of SnmpSyntax that will be
+ * assigned the value of the vb.
+ *
+ * @return SNMP_CLASS_SUCCESS if the vb value could be assigned to
+ * the passed SnmpSyntax object, else SNMP_CLASS_INVALID.
+ */
+ int get_value(SnmpSyntax &val) const;
+
+ /**
+ * Get the value.
+ *
+ * This method will only return success if the value of the vb is SMI INT32.
+ *
+ * @param i - returned value
+ *
+ * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+ */
+ int get_value(int &i) const;
+
+ /**
+ * Get the value.
+ *
+ * This method will only return success if the value of the vb can
+ * be mapped to an unsigned long (SMI types uint32, counter32, gauge
+ * and timeticks).
+ *
+ * @param i - returned value
+ *
+ * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+ */
+ int get_value(unsigned int &i) const;
+
+ /**
+ * Get the value.
+ *
+ * This method will only return success if the value of the vb is SMI INT32.
+ *
+ * @param i - returned value
+ *
+ * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+ */
+ int get_value(long &i) const;
+
+ /**
+ * Get the value.
+ *
+ * This method will only return success if the value of the vb can
+ * be mapped to an unsigned long (SMI types uint32, counter32, gauge
+ * and timeticks).
+ *
+ * @param i - returned value
+ *
+ * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+ */
+ int get_value(unsigned long &i) const;
+
+ /**
+ * Get the value.
+ *
+ * This method will only return success if the value of the vb is SMI OCTET.
+ *
+ * @note The caller must provide a target string big enough to
+ * handle the vb string. No length checks are done within
+ * this method. The returned string will be null terminated.
+ *
+ * @param ptr - Pointer to already allocated space to hold the vb
+ * value. The first char will be set to zero on failure.
+ * @param len - Returned length of the string. Will be set to 0 on failure.
+ *
+ * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+ */
+ int get_value(unsigned char *ptr, unsigned long &len) const;
+
+ /**
+ * Get the value.
+ *
+ * This method will only return success if the value of the vb is SMI OCTET.
+ *
+ * @note If the target space is not big enough to hold the complete
+ * string only part of the string is copied.
+ *
+ * @param ptr - Pointer to already allocated space to hold the vb
+ * value. The first char will be set to zero on failure.
+ * @param len - Returned length of the string. Will be set to 0
+ * on failure.
+ * @param maxlen - Maximum length of the space that ptr points to.
+ * @param add_null_byte - Add a null byte at end of output string.
+ *
+ *
+ * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+ */
+ int get_value(unsigned char *ptr,
+ unsigned long &len,
+ const unsigned long maxlen,
+ const bool add_null_byte = false) const;
+
+ /**
+ * Get the value.
+ *
+ * This method will only return success if the value of the vb is SMI OCTET.
+ *
+ * @note The caller must provide a target string big enough to
+ * handle the vb string. No length checks are done within
+ * this method. The returned string will be null terminated.
+ *
+ * @param ptr - Pointer to already allocated space to hold the vb
+ * value. The first char will be set to zero on failure.
+ *
+ * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+ */
+ int get_value(char *ptr) const;
+
+ /**
+ * Clone the value portion of the variable binding.
+ *
+ * The returned pointer must be deleted by the caller.
+ *
+ * @return
+ * a pointer to a clone of the value of the receiver.
+ */
+ SnmpSyntax* clone_value() const
+ { return ((iv_vb_value) ? iv_vb_value->clone() : 0); };
+
+
+ //-----[ misc]--------------------------------------------------------
+
+ /**
+ * Return the syntax or the exception status.
+ *
+ * @return If the SNMPv2 exception status is set, it is returned.
+ * otherwise the syntax of the value object is returned.
+ */
+ SmiUINT32 get_syntax() const;
+
+ /**
+ * Set the syntax.
+ *
+ * The Value portion of the Vb will be deleted and a new value portion
+ * is allocated with it's default value (zero).
+ *
+ * @param syntax - The new syntax.
+ */
+ void set_syntax(const SmiUINT32 syntax);
+
+ /**
+ * Set the exception status.
+ *
+ * @param status - the new SNMPv2 exception status.
+ */
+ void set_exception_status(const SmiUINT32 status)
+ { exception_status = status; };
+
+ /**
+ * Get the exception status.
+ */
+ SmiUINT32 get_exception_status() const { return exception_status; };
+
+ /**
+ * Return a formatted version of the value.
+ *
+ * @return A null terminated string (empty if no value).
+ */
+ const char *get_printable_value() const;
+
+ /**
+ * Return a formatted version of the Oid.
+ *
+ * @return A null terminated string (may be empty if no Oid has been set).
+ */
+ const char *get_printable_oid() const
+ { return iv_vb_oid.get_printable(); };
+
+ /**
+ * Return the validity of a Vb object.
+ *
+ * @return TRUE if oid and value have been set.
+ */
+ bool valid() const;
+
+ /**
+ * Return the space needed for serialization.
+ *
+ * @return the length of the BER encoding of this Vb.
+ */
+ int get_asn1_length() const;
+
+ /**
+ * Reset the object.
+ */
+ void clear() { free_vb(); iv_vb_oid.clear(); };
+
+ //-----[ protected members ]
+ protected:
+ Oid iv_vb_oid; // a vb is made up of a oid
+ SnmpSyntax *iv_vb_value; // and a value...
+ SmiUINT32 exception_status; // are there any vb exceptions??
+
+ /**
+ * Free the value portion.
+ */
+ void free_vb();
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif
+
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## IPv6Utility.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*===================================================================
+
+ SNMP++ IPv6Utility.h
+
+ DESCRIPTION:
+ This module contains the Utility functions for IPV6 support functions
+ required for WIN32 environment
+
+ Adapted and integrated into snmp++ by Ragavan Tetchinamourty
+
+=====================================================================*/
+//XXX char ipv6utility_cpp_version[] = "@(#) SNMP++ $Id: $";
+
+#include <stdio.h> //use vsnprintf
+#include "snmp_pp/IPv6Utility.h"
+
+//FIXME #if defined(_MSC_VER) && defined(SNMP_PP_IPv6)
+#if defined(WIN32) && defined(SNMP_PP_IPv6)
+
+#define NS_INT16SZ 2
+#define NS_INADDRSZ 4
+#define NS_IN6ADDRSZ 16
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define ENOSPC 28
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+
+static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size);
+
+#ifdef AF_INET6
+static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size);
+#endif
+
+static int inet_pton4(const char *src, unsigned char *dst);
+#ifdef AF_INET6
+static int inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+
+
+/* char *
+ * isc_net_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *
+inet_ntop(int af, const void *src, char *dst, size_t size)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4((const unsigned char*)src, dst, size));
+#ifdef AF_INET6
+ case AF_INET6:
+ return (inet_ntop6((const unsigned char*)src, dst, size));
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+#if defined(_MSC_VER)
+static int
+snprintf (char *str, int n, char *fmt, ...)
+{
+va_list a;
+va_start (a, fmt);
+int ret = vsnprintf (str, n, fmt, a);
+va_end (a);
+return ret;
+}
+#endif
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address
+ * return:
+ * `dst' (as a const)
+ * notes:
+ * (1) uses no statics
+ * (2) takes a unsigned char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, size_t size)
+{
+ /*static const */char *fmt = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+ size_t len;
+
+ len = snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3]);
+
+ if (len >= size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ memcpy(dst, tmp, len + 1);
+
+ return (dst);
+}
+
+/* const char *
+ * isc_inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static const char *
+inet_ntop6(const unsigned char *src, char *dst, size_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ struct { int base, len; } best, cur;
+ unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i, inc;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ cur.base = -1;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+ return (NULL);
+ tp += strlen(tp);
+ break;
+ }
+ inc = snprintf(tp, 5, "%x", words[i]);
+ // Ragavan Commented
+ //assert(inc < 5);
+ tp += inc;
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (NS_IN6ADDRSZ / NS_INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ memcpy(dst, tmp, tp - tmp);
+ return (dst);
+}
+#endif /* AF_INET6 */
+
+
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+inet_pton(int af,
+ const char *src,
+ void *dst)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, (unsigned char *)dst));
+#ifdef AF_INET6
+ case AF_INET6:
+ return (inet_pton6(src, (unsigned char *)dst));
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[NS_INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ unsigned int newstr = *tp * 10 + (pch - digits);
+
+ if (newstr > 255)
+ return (0);
+ *tp = newstr;
+ if (! saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ memcpy(dst, tmp, NS_INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+ return (1);
+}
+#endif // AF_INET6
+
+#endif // defined(_MSC_VER) && defined(SNMP_PP_IPv6)
--- /dev/null
+/*_############################################################################
+ _##
+ _## address.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ A D D R E S S. C P P
+
+ ADDRESS CLASS IMPLEMENTATION
+
+ DESIGN + AUTHOR: Peter E. Mellquist
+
+ DESCRIPTION: Implementation file for Address classes.
+=====================================================================*/
+char address_cpp_version[]="@(#) SNMP++ $Id: address.cpp 1711 2010-02-10 21:25:47Z katz $";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#if defined(__APPLE__)
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+#include "snmp_pp/address.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/IPv6Utility.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+/* Borlands isdigit has a bug */
+#ifdef __BCPLUSPLUS__
+#define my_isdigit(c) ((c) >= '0' && (c) <= '9')
+#else
+#define my_isdigit isdigit
+#endif
+
+#ifdef ADDRESS_DEBUG
+#define ADDRESS_TRACE debugprintf(0, "ADDRESS %p Enter %s", this, __PRETTY_FUNCTION__)
+#define ADDRESS_TRACE2 debugprintf(0, "ADDRESS op Enter %s", __PRETTY_FUNCTION__)
+#else
+#define ADDRESS_TRACE
+#define ADDRESS_TRACE2
+#endif
+
+#if !defined HAVE_GETHOSTBYNAME_R || !defined HAVE_GETHOSTBYADDR_R || !defined HAVE_REENTRANT_GETHOSTBYNAME || !defined HAVE_REENTRANT_GETHOSTBYADDR
+#ifdef _THREADS
+SnmpSynchronized Address::syscall_mutex;
+#endif
+#endif
+
+//=================================================================
+//======== Abstract Address Class Implementation ==================
+//=================================================================
+
+Address::Address()
+ : addr_changed(true), valid_flag(false)
+{
+ ADDRESS_TRACE;
+
+ memset(address_buffer, 0, sizeof(unsigned char)*ADDRBUF);
+}
+
+//------------[ Address::trim_white_space( char * ptr) ]------------
+// destructive trim white space
+void Address::trim_white_space(char *ptr)
+{
+ ADDRESS_TRACE;
+
+ char *tmp = ptr; // init
+ while (*tmp==' ') tmp++; // skip leading white space
+ while (*tmp && (*tmp != ' ')) *ptr++ = *tmp++; // move string to beginning
+ *ptr = 0; // set end of string
+}
+
+// Reset the object
+void Address::clear()
+{
+ addr_changed = true;
+ valid_flag = false;
+ memset(address_buffer, 0, sizeof(unsigned char)*ADDRBUF);
+}
+
+//-----------------------------------------------------------------------
+// overloaded equivlence operator, are two addresses equal?
+int operator==(const Address &lhs, const Address &rhs)
+{
+ ADDRESS_TRACE2;
+
+ return (strcmp((const char*)lhs, (const char*)rhs) == 0);
+}
+
+//------------------------------------------------------------------
+// overloaded > operator, is a1 > a2
+int operator>(const Address &lhs, const Address &rhs)
+{
+ ADDRESS_TRACE2;
+
+ return (strcmp((const char*)lhs, (const char*)rhs) > 0);
+}
+
+//-----------------------------------------------------------------
+// overloaded < operator, is a1 < a2
+int operator<(const Address &lhs, const Address &rhs)
+{
+ ADDRESS_TRACE2;
+
+ return (strcmp((const char*)lhs, (const char*)rhs) < 0);
+}
+
+//------------------------------------------------------------------
+// equivlence operator overloaded, are an address and a string equal?
+int operator==(const Address &lhs, const char *rhs)
+{
+ ADDRESS_TRACE2;
+
+ if (!rhs && !lhs.valid())
+ return TRUE;
+ if (strcmp((const char *)lhs, rhs) == 0)
+ return TRUE;
+ return FALSE;
+}
+
+//------------------------------------------------------------------
+// overloaded > , is a > inaddr
+int operator>(const Address &lhs, const char *rhs)
+{
+ ADDRESS_TRACE2;
+
+ if (!rhs)
+ return lhs.valid(); // if lhs valid then > NULL, else invalid !> NULL
+ if (strcmp((const char *)lhs, rhs) > 0)
+ return TRUE;
+ return FALSE;
+}
+
+//------------------------------------------------------------------
+// overloaded >= , is a >= inaddr
+int operator>=(const Address &lhs, const char *rhs)
+{
+ ADDRESS_TRACE2;
+
+ if (!rhs)
+ return TRUE; // always >= NULL
+ if (strcmp((const char *)lhs, rhs) >= 0)
+ return TRUE;
+ return FALSE;
+}
+
+//-----------------------------------------------------------------
+// overloaded < , are an address and a string equal?
+int operator<(const Address &lhs, const char *rhs)
+{
+ ADDRESS_TRACE2;
+
+ if (!rhs)
+ return FALSE; // always >= NULL
+ if (strcmp((const char *)lhs, rhs) < 0)
+ return TRUE;
+ return FALSE;
+}
+
+//-----------------------------------------------------------------
+// overloaded <= , is a <= inaddr
+int operator<=(const Address &lhs, const char *rhs)
+{
+ ADDRESS_TRACE2;
+
+ if (!rhs)
+ return !lhs.valid(); // invalid == NULL, else valid > NULL
+ if (strcmp((const char *)lhs, rhs) <= 0)
+ return TRUE;
+ return FALSE;
+}
+
+//=====================================================================
+//============ IPAddress Implementation ===============================
+//=====================================================================
+
+//-------[ construct an IP address with no agrs ]----------------------
+IpAddress::IpAddress()
+ : Address(), iv_friendly_name_status(0), ip_version(version_ipv4)
+{
+ ADDRESS_TRACE;
+
+ // always initialize what type this object is
+ smival.syntax = sNMP_SYNTAX_IPADDR;
+ smival.value.string.len = IPLEN;
+ smival.value.string.ptr = address_buffer;
+
+ memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+}
+
+//-------[ construct an IP address with a string ]---------------------
+IpAddress::IpAddress(const char *inaddr)
+ : Address()
+{
+ ADDRESS_TRACE;
+
+ // always initialize what type this object is
+ smival.syntax = sNMP_SYNTAX_IPADDR;
+ smival.value.string.len = IPLEN;
+ smival.value.string.ptr = address_buffer;
+
+ // parse_address initializes valid, address_buffer & iv_friendly_name
+ valid_flag = parse_address(inaddr);
+}
+
+//-----[ IP Address copy constructor ]---------------------------------
+IpAddress::IpAddress(const IpAddress &ipaddr)
+ : iv_friendly_name_status(0), ip_version(ipaddr.ip_version),
+ have_ipv6_scope(ipaddr.have_ipv6_scope)
+{
+ ADDRESS_TRACE;
+
+ // always initialize what type this object is
+ smival.syntax = sNMP_SYNTAX_IPADDR;
+ smival.value.string.len = ipaddr.smival.value.string.len;
+ smival.value.string.ptr = address_buffer;
+
+ memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+ valid_flag = ipaddr.valid_flag;
+ if (valid_flag)
+ {
+ // copy the address data
+ MEMCPY(address_buffer, ipaddr.address_buffer, smival.value.string.len);
+ // and the friendly name
+ strcpy(iv_friendly_name, ipaddr.iv_friendly_name);
+
+ if (!ipaddr.addr_changed)
+ {
+ memcpy(output_buffer, ipaddr.output_buffer,
+ sizeof(unsigned char) * OUTBUFF);
+ addr_changed = false;
+ }
+ }
+}
+
+//-----[ construct an IP address with a GenAddress ]---------------------
+IpAddress::IpAddress(const GenAddress &genaddr)
+ : iv_friendly_name_status(0)
+{
+ ADDRESS_TRACE;
+
+ // always initialize what type this object is
+ smival.syntax = sNMP_SYNTAX_IPADDR;
+ smival.value.string.len = IPLEN;
+ smival.value.string.ptr = address_buffer;
+
+ memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+ output_buffer[0]=0;
+
+ // allow use of an ip or udp genaddress
+ valid_flag = genaddr.valid();
+ if (valid_flag)
+ {
+ if (genaddr.get_type() == type_ip)
+ {
+ // copy in the IP address data
+ *this = genaddr.cast_ipaddress();
+ return;
+ }
+ else if (genaddr.get_type() == type_udp)
+ {
+ // copy in the IP address data
+ *this = genaddr.cast_udpaddress();
+ return;
+ }
+ }
+ valid_flag = false;
+ addr_changed = true;
+}
+
+//-----[ IP Address general = operator ]-------------------------------
+SnmpSyntax& IpAddress::operator=(const SnmpSyntax &val)
+{
+ ADDRESS_TRACE;
+
+ if (this == &val) return *this; // protect against assignment from itself
+
+ addr_changed = true;
+ valid_flag = false; // will get set TRUE if really valid
+ memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+
+ if (val.valid())
+ {
+ switch (val.get_syntax())
+ {
+ case sNMP_SYNTAX_IPADDR:
+ case sNMP_SYNTAX_OCTETS:
+ if ((((IpAddress &)val).smival.value.string.len == IPLEN) ||
+ (((IpAddress &)val).smival.value.string.len == UDPIPLEN))
+ {
+ MEMCPY(address_buffer,
+ ((IpAddress &)val).smival.value.string.ptr, IPLEN);
+ valid_flag = true;
+ ip_version = version_ipv4;
+ smival.value.string.len = IPLEN;
+ }
+ else if ((((IpAddress &)val).smival.value.string.len == IP6LEN_NO_SCOPE) ||
+ (((IpAddress &)val).smival.value.string.len == UDPIP6LEN_NO_SCOPE))
+ {
+ MEMCPY(address_buffer,
+ ((IpAddress &)val).smival.value.string.ptr, IP6LEN_NO_SCOPE);
+ valid_flag = true;
+ ip_version = version_ipv6;
+ smival.value.string.len = IP6LEN_NO_SCOPE;
+ have_ipv6_scope = false;
+ }
+ else if ((((IpAddress &)val).smival.value.string.len == IP6LEN_WITH_SCOPE) ||
+ (((IpAddress &)val).smival.value.string.len == UDPIP6LEN_WITH_SCOPE))
+ {
+ MEMCPY(address_buffer,
+ ((IpAddress &)val).smival.value.string.ptr, IP6LEN_WITH_SCOPE);
+ valid_flag = true;
+ ip_version = version_ipv6;
+ smival.value.string.len = IP6LEN_WITH_SCOPE;
+ have_ipv6_scope = true;
+ }
+ break;
+
+ // NOTE: as a value add, other types could have "logical"
+ // mappings, i.e. integer32 and unsigned32
+ }
+ }
+ return *this;
+}
+
+//------[ assignment to another ipaddress object overloaded ]-----------------
+IpAddress& IpAddress::operator=(const IpAddress &ipaddr)
+{
+ ADDRESS_TRACE;
+
+ if (this == &ipaddr) return *this; // protect against assignment from itself
+
+ valid_flag = ipaddr.valid_flag;
+ memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+
+ if (valid_flag)
+ {
+ if (ipaddr.ip_version == version_ipv4)
+ {
+ MEMCPY(address_buffer, ipaddr.address_buffer, IPLEN);
+ ip_version = version_ipv4;
+ smival.value.string.len = IPLEN;
+ }
+ else
+ {
+ if (ipaddr.have_ipv6_scope)
+ {
+ MEMCPY(address_buffer, ipaddr.address_buffer, IP6LEN_WITH_SCOPE);
+ ip_version = version_ipv6;
+ smival.value.string.len = IP6LEN_WITH_SCOPE;
+ have_ipv6_scope = true;
+ }
+ else
+ {
+ MEMCPY(address_buffer, ipaddr.address_buffer, IP6LEN_NO_SCOPE);
+ ip_version = version_ipv6;
+ smival.value.string.len = IP6LEN_NO_SCOPE;
+ have_ipv6_scope = false;
+ }
+ }
+ strcpy(iv_friendly_name, ipaddr.iv_friendly_name);
+
+ if (ipaddr.addr_changed)
+ addr_changed = true;
+ else
+ {
+ memcpy(output_buffer, ipaddr.output_buffer,
+ sizeof(unsigned char) * OUTBUFF);
+ addr_changed = false;
+ }
+ }
+ else
+ addr_changed = true;
+ return *this;
+}
+
+IpAddress& IpAddress::operator=(const char *inaddr)
+{
+ ADDRESS_TRACE;
+
+ valid_flag = parse_address(inaddr);
+ addr_changed = true;
+ return *this;
+}
+
+//-------[ return the friendly name ]----------------------------------
+char *IpAddress::friendly_name(int &status)
+{
+ ADDRESS_TRACE;
+
+ if ((iv_friendly_name[0]==0) && (valid_flag))
+ this->addr_to_friendly();
+ status = iv_friendly_name_status;
+ return iv_friendly_name;
+}
+
+// parse a dotted string
+int IpAddress::parse_dotted_ipstring(const char *inaddr)
+{
+ ADDRESS_TRACE;
+
+ int token_count=0;
+ char temp[30]; // temp buffer for destruction
+
+ // check len, an ip can never be bigger than 15
+ // 123456789012345
+ // XXX.XXX.XXX.XXX
+ if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
+
+ strcpy(temp, inaddr);
+ trim_white_space(temp);
+ if (strlen(temp) > 15) return FALSE;
+
+ /* Check for the following:
+ * - exactly three dots
+ * - no dot at begin or end
+ * - at least a digit between two dots
+ * - only dots and digits allowed
+ */
+ char *ptr = temp;
+ int dot_count = 0;
+ bool last_char_was_dot = true;
+
+ while (*ptr)
+ {
+ if (*ptr == '.')
+ {
+ if (last_char_was_dot) return FALSE;
+ ++dot_count;
+ last_char_was_dot = true;
+ }
+ else if (my_isdigit(*ptr))
+ {
+ last_char_was_dot = false;
+ }
+ else
+ return FALSE;
+ ++ptr;
+ }
+ if ((dot_count != 3) || (last_char_was_dot))
+ return FALSE;
+
+ ptr = temp;
+ while (*ptr)
+ {
+ unsigned long number = 0;
+
+ if (*ptr == '.') ++ptr; // skip over the dot
+
+ // grab a digit token and convert it to a long int
+ int digits = 0;
+ while ((*ptr) && (*ptr != '.'))
+ {
+ number = (number * 10) + *(ptr++) - '0';
+ ++digits;
+ }
+ if (digits > 3) return FALSE;
+ if (number > 255) return FALSE;
+
+ // stuff the value into the array and bump the counter
+ address_buffer[token_count++]= (unsigned char) number;
+ }
+
+ ip_version = version_ipv4;
+ smival.value.string.len = IPLEN;
+ return TRUE;
+}
+
+#define ATOI(x) if ((x >= 48) && (x <= 57)) x = x-48; /* 0-9 */ \
+ else if ((x >= 97) && (x <=102)) x = x-87; /* a-f */ \
+ else if ((x >= 65) && (x <= 70)) x = x-55; /* A-F */ \
+ else x=0
+
+// parse a coloned string
+int IpAddress::parse_coloned_ipstring(const char *inaddr)
+{
+ ADDRESS_TRACE;
+
+ unsigned char tmp_address_buffer[ADDRBUF];
+ char temp[60]; // temp buffer for destruction
+
+ // check len, an ipv6 can never be bigger than 39 + 11
+ // 123456789012345678901234567890123456789
+ // 1BCD:2BCD:3BCD:4BCD:5BCD:6BCD:7BCD:8BCD%4123456789
+ if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
+ strcpy(temp, inaddr);
+ trim_white_space(temp);
+
+ // first check for ipv6 scope
+ unsigned int scope = 0;
+ bool have_scope = false;
+
+ {
+ int scope_pos;
+ for (int i=strlen(temp)-1; i >=0 ; i--)
+ {
+ if (temp[i] == '%')
+ {
+ scope_pos = i;
+ have_scope = true;
+ break;
+ }
+ if (!isdigit(temp[i]))
+ break;
+ }
+ if (have_scope)
+ {
+ temp[scope_pos] = 0;
+ scope = atol(temp + scope_pos + 1);
+ }
+ }
+
+ if (strlen(temp) > 39) return FALSE;
+
+ char *in_ptr = temp;
+ char *out_ptr = (char*)tmp_address_buffer;
+ char *end_first_part = NULL;
+ char second[39];
+ int second_used = FALSE;
+ int colon_count = 0;
+ int had_double_colon = FALSE;
+ int last_was_colon = FALSE;
+ int had_dot = FALSE;
+ int dot_count = 0;
+ int digit_count = 0;
+ char digits[4];
+ char last_deliminiter = 0;
+
+ while (*in_ptr != 0)
+ {
+ if (*in_ptr == '.')
+ {
+ last_deliminiter = *in_ptr;
+ had_dot = TRUE;
+ dot_count++;
+ if (dot_count > 3)
+ return FALSE;
+ if ((digit_count > 3) || (digit_count < 1))
+ return FALSE;
+ for (int i=0; i<digit_count; i++)
+ if (!my_isdigit(digits[i]))
+ return FALSE;
+ digits[digit_count] = 0;
+ int value = atoi(digits);
+ if ((value > 0) && (value <= 255))
+ *out_ptr++ = (unsigned char) value;
+ else
+ {
+ if (strcmp(digits, "0") == 0)
+ *out_ptr++ = (unsigned char) 0;
+ else
+ return FALSE;
+ }
+ digit_count = 0;
+ }
+ else if (*in_ptr == ':')
+ {
+ last_deliminiter = *in_ptr;
+
+ if (had_dot)
+ return FALSE; // don't allow : after a dot
+
+ if (digit_count)
+ {
+ // move digits to right
+ {
+ for (int i=0; i<digit_count; i++)
+ {
+ ATOI(digits[digit_count - 1 - i]);
+ digits[3-i] = digits[digit_count - 1 - i];
+ }
+ }
+ {
+ for (int i=0; i<4-digit_count; i++)
+ digits[i] = 0;
+ }
+ {
+ // pack two digits into one byte
+ for (int i=0; i < 4; i += 2)
+ {
+ unsigned char c = digits[i];
+ unsigned char d = digits[i+1];
+ *out_ptr++ = (c*16 + d);
+ }
+ }
+ digit_count = 0;
+ }
+ colon_count++;
+ if (last_was_colon)
+ {
+ if (had_double_colon)
+ return FALSE;
+ end_first_part = out_ptr;
+ out_ptr = second;
+ second_used = TRUE;
+ had_double_colon = TRUE;
+ }
+ else
+ {
+ last_was_colon = TRUE;
+ }
+ }
+ else
+ {
+ if (digit_count >= 4)
+ return FALSE;
+ if (!isxdigit(*in_ptr))
+ return FALSE;
+ digits[digit_count] = tolower(*in_ptr);
+
+ digit_count++;
+ if (digit_count > 4)
+ return FALSE;
+ last_was_colon = 0;
+ }
+ in_ptr++;
+ }
+
+ // put last bytes from digits into buffer
+ if (digit_count)
+ {
+ if (last_deliminiter == ':')
+ {
+ {
+ // move digits to right
+ for (int i=0; i<digit_count; i++)
+ {
+ ATOI(digits[digit_count - 1 - i]);
+ digits[3-i] = digits[digit_count - 1 - i];
+ }
+ }
+ {
+ for (int i=0; i<4-digit_count; i++)
+ digits[i] = 0;
+ }
+ {
+ // pack two digits into one byte
+ for (int i=0; i < 4; i += 2)
+ {
+ unsigned char c = digits[i];
+ unsigned char d = digits[i+1];
+ *out_ptr++ = (c*16 + d);
+ }
+ }
+ digit_count = 0;
+ }
+ else if (last_deliminiter == '.')
+ {
+ if ((digit_count > 3) || (digit_count < 1))
+ return FALSE;
+ for (int i=0; i<digit_count; i++)
+ if (!my_isdigit(digits[i]))
+ return FALSE;
+ digits[digit_count] = 0;
+ int value = atoi(digits);
+ if ((value > 0) && (value <= 255))
+ *out_ptr++ = (unsigned char) value;
+ else
+ {
+ if (strcmp(digits, "0") == 0)
+ *out_ptr++ = (unsigned char) 0;
+ else
+ return FALSE;
+ }
+ //digit_count = 0;
+ }
+ else
+ return FALSE;
+ }
+
+ // must have between two and seven colons
+ if ((colon_count > 7) || (colon_count < 2))
+ return FALSE;
+
+ // if there was a dot there must be three of them
+ if ((dot_count > 0) && (dot_count != 3))
+ return FALSE;
+
+ if (second_used)
+ {
+ int len_first = SAFE_INT_CAST(end_first_part - (char*)tmp_address_buffer);
+ int len_second = SAFE_INT_CAST(out_ptr - second);
+
+ int i;
+ for (i=0; i<IP6LEN_NO_SCOPE-(len_first + len_second); i++)
+ *end_first_part++ = 0;
+ for (i=0; i<len_second; i++)
+ *end_first_part++ = second[i];
+ }
+
+ if (!end_first_part)
+ end_first_part = out_ptr;
+
+ // check for short address
+ if (end_first_part - (char*)tmp_address_buffer != IP6LEN_NO_SCOPE)
+ return FALSE;
+
+ ip_version = version_ipv6;
+ if (have_scope)
+ smival.value.string.len = IP6LEN_WITH_SCOPE;
+ else
+ smival.value.string.len = IP6LEN_NO_SCOPE;
+
+ memcpy(address_buffer, tmp_address_buffer, ADDRBUF);
+
+ if (have_scope)
+ {
+ unsigned int *scope_p = (unsigned int*)(address_buffer + IP6LEN_NO_SCOPE);
+ *scope_p = htonl(scope);
+ have_ipv6_scope = true;
+ }
+ else
+ have_ipv6_scope = false;
+
+ return TRUE;
+}
+
+#undef ATOI
+
+//-----[ IP Address parse Address ]---------------------------------
+bool IpAddress::parse_address(const char *inaddr)
+{
+ ADDRESS_TRACE;
+
+#if !defined HAVE_GETHOSTBYNAME_R && !defined HAVE_REENTRANT_GETHOSTBYNAME
+#ifdef _THREADS
+ SnmpSynchronize s(syscall_mutex);
+#endif
+#endif
+
+ addr_changed = true;
+
+ // parse the input char array fill up internal buffer with four ip
+ // bytes set and return validity flag
+
+ char ds[61];
+
+ // intialize the friendly_name member variable
+ memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+ iv_friendly_name_status = 0;
+
+ // is this a dotted IP notation string or a friendly name
+ if (parse_dotted_ipstring(inaddr))
+ {
+ // since this is a valid dotted string don't do any DNS
+ return TRUE;
+ }
+ else if (parse_coloned_ipstring(inaddr))
+ {
+ // since this is a valid ipv6 string don't do any DNS
+ return TRUE;
+ }
+ else // not a dotted string, try to resolve it via DNS
+ {
+#if defined (CPU) && CPU == PPC603
+ int lookupResult = hostGetByName(inaddr);
+
+ if (lookupResult == ERROR)
+ {
+ iv_friendly_name_status = lookupResult;
+ return FALSE;
+ }
+ // now lets check out the dotted string
+ strcpy(ds,inet_ntoa(lookupResult));
+
+ if (!parse_dotted_ipstring(ds))
+ return FALSE;
+
+ // save the friendly name
+ strcpy(iv_friendly_name, inaddr);
+
+ return TRUE;
+
+#else
+ hostent *lookupResult = 0;
+
+#ifdef HAVE_GETHOSTBYNAME_R
+ char buf[2048]; // TODO: Too big buffer?
+ int herrno = 0;
+ hostent lookup_buf;
+#if defined(__sun) || defined (__QNX_NEUTRINO)
+ lookupResult = gethostbyname_r(inaddr, &lookup_buf, buf, 2048, &herrno);
+#else
+ gethostbyname_r(inaddr, &lookup_buf, buf, 2048, &lookupResult, &herrno);
+#endif
+#ifdef SNMP_PP_IPv6
+ if (!lookupResult)
+ {
+#ifdef __sun
+ lookupResult = gethostbyname_r(inaddr, AF_INET6, &lookup_buf, buf, 2048,
+ &lookupResult, &herrno);
+#else
+ gethostbyname2_r(inaddr, AF_INET6, &lookup_buf, buf, 2048,
+ &lookupResult, &herrno);
+#endif
+ }
+#endif // SNMP_PP_IPv6
+#else // not HAVE_GETHOSTBYNAME_R
+ lookupResult = gethostbyname(inaddr);
+#ifdef SNMP_PP_IPv6
+ if (!lookupResult)
+ {
+#ifdef HAVE_GETHOSTBYNAME2
+ lookupResult = gethostbyname2(inaddr, AF_INET6);
+#else
+ lookupResult = gethostbyname(inaddr);
+#endif // HAVE_GETHOSTBYNAME2
+ }
+#endif // SNMP_PP_IPv6
+#endif // HAVE_GETHOSTBYNAME_R
+ if (lookupResult)
+ {
+#ifdef SNMP_PP_IPv6
+ if (lookupResult->h_length == sizeof(in6_addr))
+ {
+ in6_addr ipAddr;
+ memcpy((void *) &ipAddr, (void *) lookupResult->h_addr,
+ sizeof(in6_addr));
+
+ // now lets check out the coloned string
+ if (!inet_ntop(AF_INET6, &ipAddr, ds, 60))
+ return FALSE;
+ debugprintf(4, "from inet_ntop: %s", ds);
+ if (!parse_coloned_ipstring(ds))
+ return FALSE;
+
+ // save the friendly name
+ strcpy(iv_friendly_name, inaddr);
+
+ return TRUE;
+ }
+#endif // SNMP_PP_IPv6
+ if (lookupResult->h_length == sizeof(in_addr))
+ {
+ in_addr ipAddr;
+
+ memcpy((void *) &ipAddr, (void *) lookupResult->h_addr,
+ sizeof(in_addr));
+
+ // now lets check out the dotted string
+ strcpy(ds,inet_ntoa(ipAddr));
+
+ if (!parse_dotted_ipstring(ds))
+ return FALSE;
+
+ // save the friendly name
+ strcpy(iv_friendly_name, inaddr);
+
+ return TRUE;
+ }
+ } // end if lookup result
+ else
+ {
+#ifdef HAVE_GETHOSTBYNAME_R
+ iv_friendly_name_status = herrno;
+#else
+ iv_friendly_name_status = h_errno;
+#endif
+ return FALSE;
+ }
+#endif //PPC603
+ } // end else not a dotted string
+ return TRUE;
+}
+
+// using the currently defined address, do a DNS
+// and try to fill up the name
+int IpAddress::addr_to_friendly()
+{
+ ADDRESS_TRACE;
+
+#if !defined HAVE_GETHOSTBYADDR_R && !defined HAVE_REENTRANT_GETHOSTBYADDR
+#ifdef _THREADS
+ SnmpSynchronize s(syscall_mutex);
+#endif
+#endif
+
+#if defined (CPU) && CPU == PPC603
+ int lookupResult;
+ char hName[MAXHOSTNAMELEN+1];
+#else
+ hostent *lookupResult;
+#endif
+ char ds[61];
+
+ // can't look up an invalid address
+ if (!valid_flag) return -1;
+
+ // lets try and get the friendly name from the DNS
+ strcpy(ds, this->IpAddress::get_printable());
+
+#if !(defined (CPU) && CPU == PPC603) && defined HAVE_GETHOSTBYADDR_R
+ int herrno = 0;
+ hostent lookup;
+ char buf[2048]; // TODO: Buf size too big?
+#endif
+ if (ip_version == version_ipv4)
+ {
+ in_addr ipAddr;
+
+#if defined HAVE_INET_ATON
+ if (inet_aton((char*)ds, &ipAddr) == 0)
+ return -1; // bad address
+#elif defined HAVE_INET_PTON
+ if (inet_pton(AF_INET, (char*)ds, &ipAddr) <= 0)
+ return -1; // bad address
+#else
+ ipAddr.s_addr = inet_addr((char*)ds);
+ if (ipAddr.s_addr == INADDR_NONE)
+ return -1; // bad address
+#endif
+
+#if defined (CPU) && CPU == PPC603
+ lookupResult = hostGetByAddr(ipAddr.s_addr, hName);
+#elif defined HAVE_GETHOSTBYADDR_R
+#if defined(__sun) || defined(__QNX_NEUTRINO)
+ lookupResult = gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
+ AF_INET, &lookup, buf, 2048, &herrno);
+#else
+ gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
+ AF_INET, &lookup, buf, 2048, &lookupResult, &herrno);
+#endif
+#else
+ lookupResult = gethostbyaddr((char *) &ipAddr, sizeof(in_addr),
+ AF_INET);
+#endif
+ }
+ else
+ {
+#ifdef SNMP_PP_IPv6
+ if (have_ipv6_scope)
+ {
+ // remove scope from ds
+ for (int i=strlen(ds); i >=0; i--)
+ if (ds[i] == '%')
+ {
+ ds[i] = 0;
+ break;
+ }
+ }
+
+ in6_addr ipAddr;
+
+ if (inet_pton(AF_INET6, (char*)ds, &ipAddr) <= 0)
+ return -1; // bad address
+
+#if defined (CPU) && CPU == PPC603
+ lookupResult = hostGetByAddr(ipAddr.s_addr, hName);
+#elif defined HAVE_GETHOSTBYADDR_R
+#if defined(__sun) || defined(__QNX_NEUTRINO)
+ lookupResult = gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
+ AF_INET6, &lookup, buf, 2048, &herrno);
+#else
+ gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
+ AF_INET6, &lookup, buf, 2048, &lookupResult, &herrno);
+#endif
+#else
+ lookupResult = gethostbyaddr((char *) &ipAddr, sizeof(in6_addr),
+ AF_INET6);
+#endif // HAVE_GETHOSTBYADDR_R
+#else
+ return -1;
+#endif // SNMP_PP_IPv6
+ }
+ // if we found the name, then update the iv friendly name
+#if defined (CPU) && CPU == PPC603
+ if (lookupResult != ERROR)
+ {
+ strncpy(iv_friendly_name, hName, MAX_FRIENDLY_NAME);
+ return 0;
+ }
+ else
+ {
+ iv_friendly_name_status = lookupResult;
+ return lookupResult;
+ }
+
+ return -1; //should not get here
+
+#else
+ if (lookupResult)
+ {
+ strcpy(iv_friendly_name, lookupResult->h_name);
+ return 0;
+ }
+ else
+ {
+#ifdef HAVE_GETHOSTBYADDR_R
+ iv_friendly_name_status = herrno;
+#else
+ iv_friendly_name_status = h_errno;
+#endif
+ return iv_friendly_name_status;
+ }
+#endif //PPC603
+}
+
+unsigned int IpAddress::get_scope() const
+{
+ ADDRESS_TRACE;
+
+ if (valid_flag)
+ {
+ const unsigned int *scope;
+ if ((ip_version == version_ipv6) && (have_ipv6_scope))
+ scope = (const unsigned int*)(address_buffer + IP6LEN_NO_SCOPE);
+ else
+ return (unsigned int)-1;
+
+ return ntohl(*scope);
+ }
+ return (unsigned int)-1; // don't use uninitialized memory
+}
+
+bool IpAddress::set_scope(const unsigned int scope)
+{
+ ADDRESS_TRACE;
+
+ if (!valid_flag || (ip_version != version_ipv6))
+ return false;
+
+ unsigned int *scope_ptr = (unsigned int*)(address_buffer + IP6LEN_NO_SCOPE);
+
+ *scope_ptr = htonl(scope);
+ addr_changed = true;
+ smival.value.string.len = IP6LEN_WITH_SCOPE;
+ have_ipv6_scope = true;
+ return true;
+}
+
+//----[ IP address format output ]------------------------------------
+void IpAddress::format_output() const
+{
+ ADDRESS_TRACE;
+
+ // if valid format else null it
+ if (valid_flag)
+ {
+ if (ip_version == version_ipv4)
+ sprintf((char *) output_buffer,"%d.%d.%d.%d",address_buffer[0],
+ address_buffer[1], address_buffer[2], address_buffer[3]);
+ else
+ if (have_ipv6_scope)
+ sprintf((char *) output_buffer,
+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x%%%d",
+ address_buffer[ 0], address_buffer[ 1], address_buffer[ 2],
+ address_buffer[ 3], address_buffer[ 4], address_buffer[ 5],
+ address_buffer[ 6], address_buffer[ 7], address_buffer[ 8],
+ address_buffer[ 9], address_buffer[10], address_buffer[11],
+ address_buffer[12], address_buffer[13], address_buffer[14],
+ address_buffer[15], get_scope());
+ else
+ sprintf((char *) output_buffer,
+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+ address_buffer[ 0], address_buffer[ 1], address_buffer[ 2],
+ address_buffer[ 3], address_buffer[ 4], address_buffer[ 5],
+ address_buffer[ 6], address_buffer[ 7], address_buffer[ 8],
+ address_buffer[ 9], address_buffer[10], address_buffer[11],
+ address_buffer[12], address_buffer[13], address_buffer[14],
+ address_buffer[15]);
+ }
+ else
+ *(char *)output_buffer = 0;
+ IpAddress *nc_this = PP_CONST_CAST(IpAddress*, this);
+ nc_this->addr_changed = false;
+}
+
+//-----------------------------------------------------------------
+// logically and two IPaddresses and
+// return the new one
+void IpAddress::mask(const IpAddress& ipaddr)
+{
+ ADDRESS_TRACE;
+
+ if (valid() && ipaddr.valid())
+ {
+ int count = (ip_version == version_ipv4) ? IPLEN : IP6LEN_NO_SCOPE;
+
+ for (int i = 0; i < count; i++)
+ address_buffer[i] = address_buffer[i] & ipaddr.address_buffer[i];
+ addr_changed = true;
+ }
+}
+
+
+// Get the count of matching bits from the left.
+int IpAddress::get_match_bits(const IpAddress match_ip) const
+{
+ ADDRESS_TRACE;
+
+ int bits = 0;
+
+ if (valid() && match_ip.valid() &&
+ (ip_version == match_ip.ip_version))
+ {
+ int count = (ip_version == version_ipv4) ? IPLEN : IP6LEN_NO_SCOPE;
+
+ for (int i = 0; i < count; i++)
+ {
+ if (address_buffer[i] == match_ip.address_buffer[i])
+ bits += 8;
+ else
+ {
+ bits += 7;
+ unsigned char c1 = address_buffer[i] >> 1;
+ unsigned char c2 = match_ip.address_buffer[i] >> 1;
+ while (c1 != c2)
+ {
+ c1 = c1 >> 1;
+ c2 = c2 >> 1;
+ bits--;
+ }
+ break;
+ }
+ }
+ }
+
+ return bits;
+}
+
+// Map a IPv4 Address to a IPv6 address.
+int IpAddress::map_to_ipv6()
+{
+ ADDRESS_TRACE;
+
+ if (!valid())
+ return FALSE;
+
+ if (ip_version != version_ipv4)
+ return FALSE;
+
+ /* just copy IPv4 address to the end of the buffer
+ zero the first 10 bytes and fill 2 Bytes with 0xff */
+ memcpy(&address_buffer[12], address_buffer, 4);
+ memset(address_buffer, 0, 10);
+ address_buffer[10] = 0xff;
+ address_buffer[11] = 0xff;
+
+ smival.value.string.len = IP6LEN_NO_SCOPE;
+ ip_version = version_ipv6;
+ have_ipv6_scope = false;
+
+ addr_changed = true;
+ return TRUE;
+}
+
+// Reset the object
+void IpAddress::clear()
+{
+ Address::clear();
+ memset(output_buffer, 0, sizeof(output_buffer));
+ iv_friendly_name_status = 0;
+ ip_version = version_ipv4;
+ have_ipv6_scope = false;
+ memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+ smival.value.string.len = IPLEN;
+}
+
+//=======================================================================
+//========== Udp Address Implementation =================================
+//=======================================================================
+
+//-------[ construct an IP address with no agrs ]----------------------
+UdpAddress::UdpAddress()
+ : IpAddress()
+{
+ ADDRESS_TRACE;
+
+ // Inherits IP Address attributes
+ // Always initialize (override) what type this object is
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = UDPIPLEN;
+ smival.value.string.ptr = address_buffer;
+
+ sep = ':';
+ set_port(0);
+}
+
+//-----------------[ construct an Udp address with another Udp address ]---
+UdpAddress::UdpAddress(const UdpAddress &udpaddr)
+ : IpAddress(udpaddr)
+{
+ ADDRESS_TRACE;
+
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = udpaddr.smival.value.string.len;
+ smival.value.string.ptr = address_buffer;
+
+ // Copy the port value
+ sep = ':';
+ set_port(udpaddr.get_port());
+
+ if (!udpaddr.addr_changed)
+ {
+ memcpy(output_buffer, udpaddr.output_buffer,
+ sizeof(unsigned char) * OUTBUFF);
+ addr_changed = false;
+ }
+}
+
+// constructor with a dotted string
+UdpAddress::UdpAddress(const char *inaddr) : IpAddress()
+{
+ ADDRESS_TRACE;
+
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = UDPIPLEN;
+ smival.value.string.ptr = address_buffer;
+
+ valid_flag = parse_address(inaddr);
+ addr_changed = true;
+}
+
+//-----------------[ construct a UdpAddress from a GenAddress ]--------------
+UdpAddress::UdpAddress(const GenAddress &genaddr) : IpAddress()
+{
+ ADDRESS_TRACE;
+
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = UDPIPLEN;
+ smival.value.string.ptr = address_buffer;
+
+ valid_flag = genaddr.valid();
+
+ // allow use of an ip or udp genaddress
+ if (valid_flag)
+ {
+ if (genaddr.get_type() == type_udp)
+ {
+ *this = genaddr.cast_udpaddress(); // copy in the IP address data
+ }
+ else if (genaddr.get_type() == type_ip)
+ {
+ *this = genaddr.cast_ipaddress(); // copy in the IP address data
+ }
+ else
+ {
+ valid_flag = false;
+ }
+ }
+ sep = ':';
+}
+
+//--------[ construct a udp from an IpAddress ]--------------------------
+UdpAddress::UdpAddress(const IpAddress &ipaddr)
+ : IpAddress(ipaddr)
+{
+ ADDRESS_TRACE;
+
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ if (ip_version == version_ipv4)
+ smival.value.string.len = UDPIPLEN;
+ else
+ if (have_ipv6_scope)
+ smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+ else
+ smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+ smival.value.string.ptr = address_buffer;
+
+ sep = ':';
+ addr_changed = true;
+ set_port(0);
+}
+
+// copy an instance of this Value
+SnmpSyntax& UdpAddress::operator=(const SnmpSyntax &val)
+{
+ ADDRESS_TRACE;
+
+ if (this == &val) return *this; // protect against assignment from itself
+
+ valid_flag = false; // will get set TRUE if really valid
+ addr_changed = true;
+ if (val.valid())
+ {
+ switch (val.get_syntax())
+ {
+ case sNMP_SYNTAX_IPADDR:
+ {
+ UdpAddress temp_udp(val.get_printable());
+ *this = temp_udp; // valid_flag is set by the udp assignment
+ break;
+ }
+ case sNMP_SYNTAX_OCTETS:
+ if (((UdpAddress &)val).smival.value.string.len == UDPIPLEN)
+ {
+ MEMCPY(address_buffer,((UdpAddress &)val).smival.value.string.ptr,
+ UDPIPLEN);
+ memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+ valid_flag = true;
+ ip_version = version_ipv4;
+ smival.value.string.len = UDPIPLEN;
+ }
+ else if (((UdpAddress &)val).smival.value.string.len == UDPIP6LEN_NO_SCOPE)
+ {
+ MEMCPY(address_buffer,((UdpAddress &)val).smival.value.string.ptr,
+ UDPIP6LEN_NO_SCOPE);
+ memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+ valid_flag = true;
+ ip_version = version_ipv6;
+ smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+ have_ipv6_scope = false;
+ }
+ else if (((UdpAddress &)val).smival.value.string.len == UDPIP6LEN_WITH_SCOPE)
+ {
+ MEMCPY(address_buffer,((UdpAddress &)val).smival.value.string.ptr,
+ UDPIP6LEN_WITH_SCOPE);
+ memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+ valid_flag = true;
+ ip_version = version_ipv6;
+ smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+ have_ipv6_scope = true;
+ }
+ break;
+ // NOTE: as a value add, other types could have "logical"
+ // mappings, i.e. integer32 and unsigned32
+ }
+ }
+ return *this;
+}
+
+// assignment to another UdpAddress object overloaded
+UdpAddress& UdpAddress::operator=(const UdpAddress &udpaddr)
+{
+ ADDRESS_TRACE;
+
+ if (this == &udpaddr) return *this; // protect against assignment from itself
+
+ (IpAddress &)*this = udpaddr; // use ancestor assignment for ipaddr value
+ if (ip_version == version_ipv4)
+ smival.value.string.len = UDPIPLEN;
+ else
+ if (have_ipv6_scope)
+ smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+ else
+ smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+
+ set_port(udpaddr.get_port()); // copy to port value
+ if (udpaddr.addr_changed)
+ {
+ addr_changed = true;
+ }
+ else
+ {
+ memcpy(output_buffer, udpaddr.output_buffer,
+ sizeof(unsigned char) * OUTBUFF);
+ addr_changed = false;
+ }
+
+ return *this;
+}
+
+// assignment to another UdpAddress object overloaded
+UdpAddress& UdpAddress::operator=(const IpAddress &ipaddr)
+{
+ ADDRESS_TRACE;
+
+ if (this == &ipaddr) return *this; // protect against assignment from itself
+
+ (IpAddress &)*this = ipaddr; // use ancestor assignment for ipaddr value
+
+ if (ip_version == version_ipv4)
+ smival.value.string.len = UDPIPLEN;
+ else
+ if (have_ipv6_scope)
+ smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+ else
+ smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+
+ set_port(0); // copy to port value
+ addr_changed = true;
+ return *this;
+}
+
+UdpAddress& UdpAddress::operator=(const char *inaddr)
+{
+ ADDRESS_TRACE;
+
+ valid_flag = parse_address(inaddr);
+ addr_changed = true;
+ return *this;
+}
+
+//-----[ IP Address parse Address ]---------------------------------
+bool UdpAddress::parse_address(const char *inaddr)
+{
+ ADDRESS_TRACE;
+
+ addr_changed = true;
+
+ char buffer[MAX_FRIENDLY_NAME];
+
+ if (inaddr && (strlen(inaddr)< MAX_FRIENDLY_NAME))
+ {
+ strcpy(buffer, inaddr);
+ trim_white_space(buffer);
+ }
+ else
+ {
+ valid_flag = false;
+ return FALSE;
+ }
+ // look for port info @ the end of the string
+ // port can be delineated by a ':' or a '/'
+ // if neither are present then just treat it
+ // like a normal IpAddress
+
+ int remove_brackets = FALSE;
+ int found = FALSE;
+ int pos = (int)strlen(buffer) - 1; // safe to cast as max is MAX_FRIENDLY_NAME
+ int do_loop = TRUE;
+ int another_colon_found = FALSE;
+ bool scope_found = false;
+
+ if (pos < 0)
+ {
+ valid_flag = false;
+ return FALSE;
+ }
+
+ // search from the end, to find the start of the port
+ // [ipv4]:port [ipv4]/port ipv4/port ipv4:port [ipv4] ipv4
+ // [ipv6]:port [ipv6]/port ipv6/port [ipv6] ipv6
+ while (do_loop)
+ {
+ if (buffer[pos] == '/')
+ {
+ found = TRUE;
+ sep='/';
+ if (buffer[pos -1] == ']')
+ remove_brackets = TRUE;
+ break;
+ }
+ if (buffer[pos] == ':')
+ {
+ if ((pos > 1) && (buffer[pos -1] == ']'))
+ {
+ found = TRUE;
+ remove_brackets = TRUE;
+ sep=':';
+ break;
+ }
+
+ for (int i=pos - 1; i >= 0 ; i--)
+ {
+ if (buffer[i] == ':')
+ another_colon_found = TRUE;
+ if (buffer[i] == '%')
+ scope_found = true;
+ }
+ if (scope_found) // must be ipv6, so reset colon_found
+ another_colon_found = false;
+
+ if (!another_colon_found)
+ {
+ sep=':';
+ found = TRUE;
+ break;
+ }
+ }
+ if (buffer[pos] == ']')
+ {
+ // we found a ] without following a port, so increase pos
+ ++pos;
+ remove_brackets = TRUE;
+ break;
+ }
+ pos--;
+ do_loop = ((found == FALSE) && (pos >= 0) &&
+ (another_colon_found == FALSE));
+ }
+
+ if (remove_brackets)
+ {
+ buffer[pos-1] = 0;
+ buffer[0] = ' ';
+ }
+
+ bool result;
+ unsigned short port;
+
+ if (found)
+ {
+ buffer[pos] = 0;
+ port = atoi(&buffer[pos+1]);
+ result = IpAddress::parse_address(buffer);
+ }
+ else
+ {
+ port = 0;
+ result = IpAddress::parse_address(buffer);
+ }
+
+ if (ip_version == version_ipv4)
+ smival.value.string.len = UDPIPLEN;
+ else
+ if (have_ipv6_scope)
+ smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+ else
+ smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+
+ set_port(port);
+ return result;
+}
+
+
+//--------[ set the port number ]---------------------------------------
+void UdpAddress::set_port(const unsigned short p)
+{
+ ADDRESS_TRACE;
+
+ unsigned short *port_nbo;
+ if (ip_version == version_ipv4)
+ port_nbo = (unsigned short*)(address_buffer + IPLEN);
+ else
+ if (have_ipv6_scope)
+ port_nbo = (unsigned short*)(address_buffer + IP6LEN_WITH_SCOPE);
+ else
+ port_nbo = (unsigned short*)(address_buffer + IP6LEN_NO_SCOPE);
+ *port_nbo = htons(p);
+ addr_changed = true;
+}
+
+//---------[ get the port number ]--------------------------------------
+unsigned short UdpAddress::get_port() const
+{
+ ADDRESS_TRACE;
+
+ if (valid_flag)
+ {
+ const unsigned short *port_nbo;
+ if (ip_version == version_ipv4)
+ port_nbo = (const unsigned short*)(address_buffer + IPLEN);
+ else
+ if (have_ipv6_scope)
+ port_nbo = (const unsigned short*)(address_buffer + IP6LEN_WITH_SCOPE);
+ else
+ port_nbo = (const unsigned short*)(address_buffer + IP6LEN_NO_SCOPE);
+
+ return ntohs(*port_nbo);
+ }
+ return 0;// don't use uninitialized memory
+}
+
+//----[ UDP address format output ]------------------------------------
+void UdpAddress::format_output() const
+{
+ ADDRESS_TRACE;
+
+ IpAddress::format_output(); // allow ancestors to format their buffers
+
+ // if valid format else null it
+ if (valid_flag)
+ {
+ if (ip_version == version_ipv4)
+ sprintf((char *) output_buffer,"%s%c%d",
+ IpAddress::get_printable(),
+ '/',//TODO:look for problems in old code and change to "sep"
+ get_port() );
+ else
+ sprintf((char *) output_buffer,"[%s]%c%d",
+ IpAddress::get_printable(),
+ '/',//TODO:look for problems in old code and change to "sep"
+ get_port() );
+ }
+ else
+ *(char*)output_buffer = 0;
+ UdpAddress *nc_this = PP_CONST_CAST(UdpAddress*, this);
+ nc_this->addr_changed = false;
+}
+
+bool UdpAddress::set_scope(const unsigned int scope)
+{
+ ADDRESS_TRACE;
+
+ /* Save the port, as IpAddress::set_scope destroys it */
+ unsigned short old_port = get_port();
+
+ if (!IpAddress::set_scope(scope))
+ return false;
+
+ smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+
+ set_port(old_port);
+
+ return true;
+}
+
+/**
+ * Map a IPv4 UDP address to a IPv6 UDP address.
+ *
+ * @return - TRUE if no error occured.
+ */
+int UdpAddress::map_to_ipv6()
+{
+ ADDRESS_TRACE;
+
+ /* Save the port, as IpAddress::map_to_ipv6 destroys it */
+ unsigned short old_port = get_port();
+
+ /* Map IpAddress */
+ if (!IpAddress::map_to_ipv6())
+ return FALSE;
+
+ set_port(old_port);
+ smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+ ip_version = version_ipv6;
+
+ addr_changed = true;
+ return TRUE;
+}
+
+
+#ifdef _IPX_ADDRESS
+//=======================================================================
+//=========== IPX Address Implementation ================================
+//=======================================================================
+
+//----------[ constructor no args ]--------------------------------------
+IpxAddress::IpxAddress() : Address()
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = IPXLEN;
+ smival.value.string.ptr = address_buffer;
+
+ separator = 0;
+ valid_flag = false;
+ addr_changed = true;
+}
+
+
+//----------[ constructor with a string arg ]---------------------------
+IpxAddress::IpxAddress(const char *inaddr):Address()
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = IPXLEN;
+ smival.value.string.ptr = address_buffer;
+
+ separator = 0;
+ valid_flag = parse_address(inaddr);
+ addr_changed = true;
+}
+
+
+//-----[ IPX Address copy constructor ]----------------------------------
+IpxAddress::IpxAddress(const IpxAddress &ipxaddr)
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = IPXLEN;
+ smival.value.string.ptr = address_buffer;
+
+ separator = 0;
+ valid_flag = ipxaddr.valid_flag;
+ if (valid_flag)
+ MEMCPY(address_buffer, ipxaddr.address_buffer, IPXLEN);
+ addr_changed = true;
+}
+
+
+//----[ construct an IpxAddress from a GenAddress ]---------------------------
+IpxAddress::IpxAddress(const GenAddress &genaddr)
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = IPXLEN;
+ smival.value.string.ptr = address_buffer;
+
+ valid_flag = genaddr.valid();
+ // allow use of an ipx or ipxsock address
+ if (valid_flag)
+ {
+ if ((genaddr.get_type() == type_ipx) )
+ {
+ *this = genaddr.cast_ipxaddress(); // copy in the Ipx address data
+ }
+ else if ((genaddr.get_type() == type_ipxsock) )
+ {
+ *this = genaddr.cast_ipxsockaddress(); // copy in the Ipx address data
+ }
+ else
+ valid_flag = false;
+ }
+}
+
+//-----[ IPX Address general = operator ]-------------------------------
+SnmpSyntax& IpxAddress::operator=(const SnmpSyntax &val)
+{
+ // protect against assignment from itself
+ if (this == &val) return *this;
+
+ valid_flag = false; // will set to TRUE if really valid
+ if (val.valid()){
+ switch (val.get_syntax()){
+ case sNMP_SYNTAX_OCTETS:
+ if (((IpxAddress &)val).smival.value.string.len == IPXLEN){
+ MEMCPY(address_buffer, ((IpxAddress &)val).smival.value.string.ptr, IPXLEN);
+ valid_flag = true;
+ }
+ break;
+ }
+ }
+ addr_changed = true;
+ return *this;
+}
+
+//--------[ assignment to another IpAddress object overloaded ]----------
+IpxAddress& IpxAddress::operator=(const IpxAddress &ipxaddress)
+{
+ if (this == &ipxaddress) return *this;// protect against assignment from self
+
+ valid_flag = ipxaddress.valid_flag;
+ if (valid_flag)
+ MEMCPY(address_buffer, ipxaddress.address_buffer, IPXLEN);
+ addr_changed = true;
+ return *this;
+}
+
+
+//-----[ IPX Address parse Address ]-----------------------------------
+// Convert a string to a ten byte ipx address
+// On success sets validity TRUE or FALSE
+//
+// IPX address format
+//
+// NETWORK ID| MAC ADDRESS
+// 01 02 03 04|05 06 07 08 09 10
+// XX XX XX XX|XX XX XX XX XX XX
+//
+// Valid input format
+//
+// XXXXXXXX.XXXXXXXXXXXX
+// Total length must be 21
+// Must have a separator in it
+// First string length must be 8
+// Second string length must be 12
+// Each char must take on value 0-F
+//
+//
+// Input formats recognized
+//
+// XXXXXXXX.XXXXXXXXXXXX
+// XXXXXXXX:XXXXXXXXXXXX
+// XXXXXXXX-XXXXXXXXXXXX
+// XXXXXXXX.XXXXXX-XXXXXX
+// XXXXXXXX:XXXXXX-XXXXXX
+// XXXXXXXX-XXXXXX-XXXXXX
+bool IpxAddress::parse_address(const char *inaddr)
+{
+ char unsigned *str1,*str2;
+ char temp[30]; // don't destroy original
+ char unsigned *tmp;
+ size_t z, tmplen;
+
+ // save the orginal source
+ if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
+ strcpy(temp, inaddr);
+ trim_white_space(temp);
+ tmplen = strlen(temp);
+
+ // bad total length check
+ // 123456789012345678901
+ // XXXXXXXX-XXXXXXXXXXXX 21 len
+ //
+ // XXXXXXXX-XXXXXX-XXXXXX 22 len
+ // need at least 21 chars and no more than 22
+ if ((tmplen <21) || (tmplen >22))
+ return FALSE;
+
+ // convert the string to all lower case
+ // this allows hex values to be in upper or lower
+ for (z=0;z< tmplen;z++)
+ temp[z] = tolower(temp[z]);
+
+ // check for separated nodeid
+ // if found remove it
+ if (temp[15] == '-')
+ {
+ for(z=16;z<tmplen;z++)
+ temp[z-1] = temp[z];
+ temp[tmplen-1] = 0;
+ }
+
+ // no dot or colon separator check
+ separator = temp[8];
+ if ((separator != ':') &&
+ (separator != '.') &&
+ (separator != '-') &&
+ (separator != ' '))
+ return FALSE;
+
+ // separate the strings
+ str1 = (unsigned char *) temp;
+ while(*str1 != separator) str1++;
+ str2 = str1 + 1;
+ *str1 = 0;
+ str1= (unsigned char *) temp;
+
+ // check len of the network portion
+ if (strlen((char *) str1) != 8) return FALSE;
+
+ // check len of mac portion
+ if (strlen((char *) str2) != 12) return FALSE;
+
+ // ok we like then lens, make sure that all chars are 0-f
+ // check out the net id
+ tmp = str1;
+ while(*tmp != 0)
+ if (((*tmp >= '0') && (*tmp <= '9'))|| // good 0-9
+ ((*tmp >= 'a') && (*tmp <= 'f'))) // or a-f
+ tmp++;
+ else
+ return FALSE;
+
+ // check out the MAC address
+ tmp = str2;
+ while(*tmp != 0)
+ if (((*tmp >= '0') && (*tmp <= '9'))|| // good 0-9
+ ((*tmp >= 'a') && (*tmp <= 'f'))) // or a-f
+ tmp++;
+ else
+ return FALSE;
+
+ // convert to target string
+ tmp = str1;
+ while (*tmp != 0)
+ {
+ if ((*tmp >= '0') && (*tmp <= '9'))
+ *tmp = *tmp - (char unsigned )'0';
+ else
+ *tmp = *tmp - (char unsigned) 'a' + (char unsigned) 10;
+ tmp++;
+ }
+
+ // network id portion
+ address_buffer[0] = (str1[0]*16) + str1[1];
+ address_buffer[1] = (str1[2]*16) + str1[3];
+ address_buffer[2] = (str1[4]*16) + str1[5];
+ address_buffer[3] = (str1[6]*16) + str1[7];
+
+ tmp = str2;
+ while (*tmp != 0)
+ {
+ if ((*tmp >= '0') && (*tmp <= '9'))
+ *tmp = *tmp - (char unsigned) '0';
+ else
+ *tmp = *tmp - (char unsigned) 'a'+ (char unsigned) 10;
+ tmp++;
+ }
+
+ address_buffer[4] = (str2[0]*16) + str2[1];
+ address_buffer[5] = (str2[2]*16) + str2[3];
+ address_buffer[6] = (str2[4]*16) + str2[5];
+ address_buffer[7] = (str2[6]*16) + str2[7];
+ address_buffer[8] = (str2[8]*16) + str2[9];
+ address_buffer[9] = (str2[10]*16) + str2[11];
+
+ return TRUE;
+}
+
+//----[ IPX address format output ]-------------------------------------
+void IpxAddress::format_output() const
+{
+ if (valid_flag)
+ sprintf((char *) output_buffer,
+ "%02x%02x%02x%02x%c%02x%02x%02x%02x%02x%02x",
+ address_buffer[0],address_buffer[1],
+ address_buffer[2],address_buffer[3],'-',
+ address_buffer[4],address_buffer[5],
+ address_buffer[6],address_buffer[7],
+ address_buffer[8],address_buffer[9]);
+ else
+ *(char*)output_buffer = 0;
+ IpxAddress *nc_this = PP_CONST_CAST(IpxAddress*, this);
+ nc_this->addr_changed = false;
+}
+
+
+#ifdef _MAC_ADDRESS
+// get the host id portion of an ipx address
+int IpxAddress::get_hostid(MacAddress& mac) const
+{
+ if (valid_flag)
+ {
+ char buffer[18];
+ sprintf(buffer,"%02x:%02x:%02x:%02x:%02x:%02x", address_buffer[4],
+ address_buffer[5], address_buffer[6], address_buffer[7],
+ address_buffer[8], address_buffer[9]);
+ MacAddress temp(buffer);
+ mac = temp;
+ if (mac.valid())
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif // function that needs _MAC_ADDRESS
+
+//========================================================================
+//======== IpxSockAddress Implementation =================================
+//========================================================================
+
+//----------[ constructor no args ]--------------------------------------
+IpxSockAddress::IpxSockAddress() : IpxAddress()
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = IPXSOCKLEN;
+ smival.value.string.ptr = address_buffer;
+
+ set_socket(0);
+ addr_changed = true;
+}
+
+//-----------[ construct an IpxSockAddress with another IpxSockAddress]----
+IpxSockAddress::IpxSockAddress(const IpxSockAddress &ipxaddr)
+ : IpxAddress(ipxaddr)
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = IPXSOCKLEN;
+ smival.value.string.ptr = address_buffer;
+
+ // copy the socket value
+ set_socket(ipxaddr.get_socket());
+ addr_changed = true;
+}
+
+
+//---------------[ construct a IpxSockAddress from a string ]--------------
+IpxSockAddress::IpxSockAddress(const char *inaddr):IpxAddress()
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = IPXSOCKLEN;
+ smival.value.string.ptr = address_buffer;
+
+ valid_flag = parse_address(inaddr);
+ addr_changed = true;
+}
+
+
+//---------------[ construct a IpxSockAddress from a GenAddress ]----------
+IpxSockAddress::IpxSockAddress(const GenAddress &genaddr):IpxAddress()
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = IPXSOCKLEN;
+ smival.value.string.ptr = address_buffer;
+
+ valid_flag = false;
+ unsigned short socketid = 0;
+ // allow use of an ipx or ipxsock address
+ if ((genaddr.get_type() == type_ipx) )
+ {
+ valid_flag = genaddr.valid();
+ if (valid_flag)
+ {
+ // copy in the Ipx address data
+ IpxAddress temp_ipx((const char *) genaddr);
+ *this = temp_ipx;
+ }
+ }
+ else if ((genaddr.get_type() == type_ipxsock) )
+ {
+ valid_flag = genaddr.valid();
+ if (valid_flag)
+ {
+ // copy in the Ipx address data
+ IpxSockAddress temp_ipxsock((const char *) genaddr);
+ *this = temp_ipxsock;
+ // socketid info since are making an IpxSockAddress
+ socketid = temp_ipxsock.get_socket();
+ }
+ }
+ set_socket(socketid);
+ addr_changed = true;
+}
+
+//------------[ construct an IpxSockAddress from a IpxAddress ]--------------
+IpxSockAddress::IpxSockAddress(const IpxAddress &ipxaddr):IpxAddress(ipxaddr)
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = IPXSOCKLEN;
+ smival.value.string.ptr = address_buffer;
+
+ set_socket(0);
+ addr_changed = true;
+}
+
+// copy an instance of this Value
+SnmpSyntax& IpxSockAddress::operator=(const SnmpSyntax &val)
+{
+ if (this == &val) return *this; // protect against assignment from itself
+
+ valid_flag = false; // will set to TRUE if really valid
+ if (val.valid()){
+ switch (val.get_syntax()){
+ case sNMP_SYNTAX_OCTETS:
+ {
+ // See if it is of the Ipx address family
+ // This handles IpxSockAddress == IpxAddress
+ IpxSockAddress temp_ipx(val.get_printable());
+ if (temp_ipx.valid()){
+ *this = temp_ipx; // ipxsock = ipxsock
+ }
+ // See if it is an OctetStr of appropriate length
+ else if (((IpxSockAddress &)val).smival.value.string.len == IPXSOCKLEN){
+ MEMCPY(address_buffer,
+ ((IpxSockAddress &)val).smival.value.string.ptr,
+ IPXSOCKLEN);
+ valid_flag = true;
+ }
+ }
+ break;
+ }
+ }
+ addr_changed = true;
+ return *this;
+}
+
+// assignment to another IpAddress object overloaded
+IpxSockAddress& IpxSockAddress::operator=(const IpxSockAddress &ipxaddr)
+{
+ if (this == &ipxaddr) return *this; // protect against assignment from itself
+
+ (IpxAddress&)*this = ipxaddr; // use ancestor assignment for ipx addr
+ set_socket(ipxaddr.get_socket()); // copy socket value
+ addr_changed = true;
+ return *this;
+}
+
+//----[ IPX address format output ]-------------------------------------
+void IpxSockAddress::format_output() const
+{
+ IpxAddress::format_output(); // allow ancestors to format their buffers
+
+ if (valid_flag)
+ sprintf((char *) output_buffer,"%s/%d",
+ IpxAddress::get_printable(), get_socket());
+ else
+ *(char*)output_buffer = 0;
+ IpxSockAddress *nc_this = PP_CONST_CAST(IpxSockAddress*, this);
+ nc_this->addr_changed = false;
+}
+
+//-----[ IP Address parse Address ]---------------------------------
+bool IpxSockAddress::parse_address(const char *inaddr)
+{
+ char buffer[MAX_FRIENDLY_NAME];
+ unsigned short socketid=0;
+
+ if (inaddr && (strlen(inaddr)< MAX_FRIENDLY_NAME))
+ strcpy(buffer, inaddr);
+ else
+ {
+ valid_flag = false;
+ return FALSE;
+ }
+ // look for port info @ the end of the string
+ // port can be delineated by a ':' or a '/'
+ // if neither are present then just treat it
+ // like a normal IpAddress
+ char *tmp;
+ tmp = strstr(buffer,"/");
+
+ if (tmp != NULL)
+ {
+ *tmp=0; // new null terminator
+ tmp++;
+ socketid = atoi(tmp);
+ }
+ set_socket(socketid);
+ return IpxAddress::parse_address(buffer);
+}
+
+
+
+//-------------[ set the socket number ]----------------------------------
+void IpxSockAddress::set_socket(const unsigned short s)
+{
+ unsigned short sock_nbo = htons(s);
+ MEMCPY(&address_buffer[IPXLEN], &sock_nbo, 2);
+ addr_changed = true;
+}
+
+//--------------[ get the socket number ]---------------------------------
+unsigned short IpxSockAddress::get_socket() const
+{
+ if (valid_flag)
+ {
+ unsigned short sock_nbo;
+ MEMCPY(&sock_nbo, &address_buffer[IPXLEN], 2);
+ return ntohs(sock_nbo);
+ }
+ return 0; // don't use uninitialized memory
+}
+#endif // _IPX_ADDRESS
+
+#ifdef _MAC_ADDRESS
+//========================================================================
+//======== MACAddress Implementation =====================================
+//========================================================================
+
+//--------[ constructor, no arguments ]-----------------------------------
+MacAddress::MacAddress() : Address()
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = MACLEN;
+ smival.value.string.ptr = address_buffer;
+
+ valid_flag = false;
+ addr_changed = true;
+}
+
+//-----[ MAC Address copy constructor ]---------------------------------
+MacAddress::MacAddress(const MacAddress &macaddr)
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = MACLEN;
+ smival.value.string.ptr = address_buffer;
+
+ valid_flag = macaddr.valid_flag;
+ if (valid_flag)
+ MEMCPY(address_buffer, macaddr.address_buffer, MACLEN);
+ addr_changed = true;
+}
+
+//---------[ constructor with a string argument ]-------------------------
+MacAddress::MacAddress(const char *inaddr):Address()
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = MACLEN;
+ smival.value.string.ptr = address_buffer;
+
+ valid_flag = parse_address(inaddr);
+ addr_changed = true;
+}
+
+//-----[ construct a MacAddress from a GenAddress ]------------------------
+MacAddress::MacAddress(const GenAddress &genaddr)
+{
+ // always initialize SMI info
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = MACLEN;
+ smival.value.string.ptr = address_buffer;
+
+ valid_flag = false;
+ // allow use of mac address
+ if (genaddr.get_type() == type_mac)
+ {
+ valid_flag = genaddr.valid();
+ if (valid_flag)
+ {
+ // copy in the Mac address data
+ *this = genaddr.cast_macaddress();
+ }
+ }
+ addr_changed = true;
+}
+
+//------[ assignment to another ipaddress object overloaded ]--------------
+MacAddress& MacAddress::operator=(const MacAddress &macaddress)
+{
+ if (this == &macaddress) return *this;// protect against assignment from self
+
+ valid_flag = macaddress.valid_flag;
+ if (valid_flag)
+ MEMCPY(address_buffer, macaddress.address_buffer, MACLEN);
+ addr_changed = true;
+ return *this;
+}
+
+
+
+//-----[ MAC Address general = operator ]---------------------------------
+SnmpSyntax& MacAddress::operator=(const SnmpSyntax &val)
+{
+ if (this == &val) return *this; // protect against assignment from itself
+
+ valid_flag = false; // will set to TRUE if really valid
+ if (val.valid())
+ {
+ switch (val.get_syntax())
+ {
+ case sNMP_SYNTAX_OCTETS:
+ if (((MacAddress &)val).smival.value.string.len == MACLEN)
+ {
+ MEMCPY(address_buffer, ((MacAddress &)val).smival.value.string.ptr,
+ MACLEN);
+ valid_flag = true;
+ }
+ break;
+ }
+ }
+ addr_changed = true;
+ return *this;
+}
+
+//-----[ MAC Address parse Address ]--------------------------------------
+// Convert a string to a six byte MAC address
+// On success sets validity TRUE or FALSE
+//
+// MAC address format
+//
+// MAC ADDRESS
+// 01 02 03 04 05 06
+// XX:XX:XX:XX:XX:XX
+// Valid input format
+//
+// XXXXXXXXXXXX
+// Total length must be 17
+// Each char must take on value 0-F
+//
+//
+bool MacAddress::parse_address(const char *inaddr)
+{
+ char temp[30]; // don't destroy original
+ char unsigned *tmp;
+ size_t z;
+
+ // save the orginal source
+ if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
+ strcpy(temp, inaddr);
+ trim_white_space(temp);
+
+ // bad total length check
+ if (strlen(temp) != 17)
+ return FALSE;
+
+ // check for colons
+ if ((temp[2] != ':')||(temp[5] != ':')||(temp[8]!=':')||(temp[11]!=':')||(temp[14] !=':'))
+ return FALSE;
+
+ // strip off the colons
+ tmp = (unsigned char *) temp;
+ int i = 0;
+ while (*tmp != 0)
+ {
+ if (*tmp != ':')
+ {
+ temp[i] = *tmp;
+ i++;
+ }
+ tmp++;
+ }
+ temp[i] = 0;
+
+ // convert to lower
+ for(z=0;z<strlen(temp);z++)
+ temp[z] = tolower(temp[z]);
+
+
+ // check out the MAC address
+ tmp = (unsigned char *) temp;
+ while(*tmp != 0)
+ if (((*tmp >= '0') && (*tmp <= '9'))|| // good 0-9
+ ((*tmp >= 'a') && (*tmp <= 'f'))) // or a-f
+ tmp++;
+ else
+ return FALSE;
+
+ // convert to target string
+ tmp = (unsigned char *) temp;
+ while (*tmp != 0)
+ {
+ if ((*tmp >= '0') && (*tmp <= '9'))
+ *tmp = *tmp - (char unsigned )'0';
+ else
+ *tmp = *tmp - (char unsigned) 'a' + (char unsigned) 10;
+ tmp++;
+ }
+
+ address_buffer[0] = (temp[0]*16) + temp[1];
+ address_buffer[1] = (temp[2]*16) + temp[3];
+ address_buffer[2] = (temp[4]*16) + temp[5];
+ address_buffer[3] = (temp[6]*16) + temp[7];
+ address_buffer[4] = (temp[8]*16) + temp[9];
+ address_buffer[5] = (temp[10]*16) + temp[11];
+
+ return TRUE;
+}
+
+//----[ MAC address format output ]---------------------------------
+void MacAddress::format_output() const
+{
+ if (valid_flag)
+ sprintf((char*)output_buffer,"%02x:%02x:%02x:%02x:%02x:%02x",
+ address_buffer[0], address_buffer[1], address_buffer[2],
+ address_buffer[3], address_buffer[4], address_buffer[5]);
+ else
+ *(char*)output_buffer = 0;
+ MacAddress *nc_this = PP_CONST_CAST(MacAddress*, this);
+ nc_this->addr_changed = false;
+}
+
+unsigned int MacAddress::hashFunction() const
+{
+ return ((((address_buffer[0] << 8) + address_buffer[1]) * HASH0)
+ + (((address_buffer[2] << 8) + address_buffer[3]) * HASH1)
+ + (((address_buffer[4] << 8) + address_buffer[5]) * HASH2));
+}
+#endif // _MAC_ADDRESS
+
+//========================================================================
+//========== Generic Address Implementation ==============================
+//========================================================================
+
+//-----------[ constructor, no arguments ]--------------------------------
+GenAddress::GenAddress() : Address()
+{
+ ADDRESS_TRACE;
+
+ // initialize SMI info
+ // BOK: this is generally not used for GenAddress,
+ // but we need this to be a replica of the real address'
+ // smival info so that operator=SnmpSyntax will work.
+ smival.syntax = sNMP_SYNTAX_NULL; // to be overridden
+ smival.value.string.len = 0; // to be overridden
+ smival.value.string.ptr = address_buffer; // constant
+
+ valid_flag = false;
+ address = 0;
+ output_buffer[0] = 0;
+}
+
+//-----------[ constructor with a string argument ]----------------------
+GenAddress::GenAddress(const char *addr,
+ const Address::addr_type use_type)
+{
+ ADDRESS_TRACE;
+
+ // initialize SMI info
+ // BOK: smival is generally not used for GenAddress, but
+ // we need this to be a replica of the real address'
+ // smival info so that <class>::operator=SnmpSyntax
+ // will work.
+ smival.syntax = sNMP_SYNTAX_NULL; // to be overridden
+ smival.value.string.len = 0; // to be overridden
+ smival.value.string.ptr = address_buffer; // constant
+
+ address = 0;
+ parse_address(addr, use_type);
+
+ // Copy real address smival info into GenAddr smival
+ // BOK: smival is generally not used for GenAddress, but
+ // we need this to be a replica of the real address'
+ // smival info so that <class>::operator=SnmpSyntax
+ // will work.
+ if (valid_flag ) {
+ smival.syntax = ((GenAddress *)address)->smival.syntax;
+ smival.value.string.len =
+ ((GenAddress *)address)->smival.value.string.len;
+ memcpy(smival.value.string.ptr,
+ ((GenAddress *)address)->smival.value.string.ptr,
+ (size_t)smival.value.string.len);
+ }
+ output_buffer[0] = 0;
+}
+
+//-----------[ constructor with an Address argument ]--------------------
+GenAddress::GenAddress(const Address &addr)
+{
+ ADDRESS_TRACE;
+
+ output_buffer[0] = 0;
+ // initialize SMI info
+ // BOK: this is generally not used for GenAddress,
+ // but we need this to be a replica of the real address'
+ // smival info so that operator=SnmpSyntax will work.
+ smival.syntax = sNMP_SYNTAX_NULL; // to be overridden
+ smival.value.string.len = 0; // to be overridden
+ smival.value.string.ptr = address_buffer; // constant
+
+ valid_flag = false;
+ // make sure that the object is valid
+ if (!addr.valid()) {
+ address = 0;
+ return;
+ }
+
+ // addr can be a GenAddress object and calling clone() on that is bad...
+ if (addr.is_gen_address())
+ address = (Address *)(((const GenAddress&)addr).address->clone());
+ else
+ address = (Address*)addr.clone();
+
+ if (address)
+ valid_flag = address->valid();
+
+ // Copy real address smival info into GenAddr smival
+ // BOK: smival is generally not used for GenAddress, but
+ // we need this to be a replica of the real address'
+ // smival info so that <class>::operator=SnmpSyntax
+ // will work.
+ if (valid_flag )
+ {
+ smival.syntax = address->get_syntax();
+ smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
+ memcpy(smival.value.string.ptr,
+ ((GenAddress *)address)->smival.value.string.ptr,
+ (size_t)smival.value.string.len);
+ }
+}
+
+//-----------------[ constructor with another GenAddress object ]-------------
+GenAddress::GenAddress(const GenAddress &addr)
+{
+ ADDRESS_TRACE;
+
+ output_buffer[0] = 0;
+ // initialize SMI info
+ // BOK: this is generally not used for GenAddress,
+ // but we need this to be a replica of the real address'
+ // smival info so that operator=SnmpSyntax will work.
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.len = 0;
+ smival.value.string.ptr = address_buffer;
+
+ valid_flag = false;
+ // make sure that the object is valid
+ if (!addr.valid_flag)
+ {
+ address = 0;
+ return;
+ }
+
+ address = (Address *)addr.address->clone();
+ if (address)
+ valid_flag = address->valid();
+
+ // Copy real address smival info into GenAddr smival
+ // BOK: smival is generally not used for GenAddress, but
+ // we need this to be a replica of the real address'
+ // smival info so that <class>::operator=SnmpSyntax
+ // will work.
+ if (valid_flag )
+ {
+ smival.syntax = ((GenAddress *)address)->smival.syntax;
+ smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
+ memcpy(smival.value.string.ptr,
+ ((GenAddress *)address)->smival.value.string.ptr,
+ (size_t)smival.value.string.len);
+ }
+}
+
+//------[ assignment GenAddress = GenAddress ]-----------------------------
+GenAddress& GenAddress::operator=(const GenAddress &addr)
+{
+ ADDRESS_TRACE;
+
+ if (this == &addr) return *this; // protect against assignment from itself
+
+ valid_flag = false;
+ if (address)
+ {
+ delete address;
+ address = 0;
+ }
+ if (addr.address)
+ address = (Address *)(addr.address->clone());
+ if (address)
+ valid_flag = address->valid();
+
+ // Copy real address smival info into GenAddr smival
+ // BOK: smival is generally not used for GenAddress, but
+ // we need this to be a replica of the real address'
+ // smival info so that <class>::operator=SnmpSyntax
+ // will work.
+ if (valid_flag )
+ {
+ smival.syntax = ((GenAddress *)address)->smival.syntax;
+ smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
+ memcpy(smival.value.string.ptr,
+ ((GenAddress *)address)->smival.value.string.ptr,
+ (size_t)smival.value.string.len);
+ }
+
+ return *this;
+}
+
+//------[ assignment GenAddress = Address ]--------------------------------
+GenAddress& GenAddress::operator=(const Address &addr)
+{
+ ADDRESS_TRACE;
+
+ if (this == &addr) return *this; // protect against assignment from itself
+
+ valid_flag = false;
+ if (address)
+ {
+ delete address;
+ address = 0;
+ }
+
+ // addr can be a GenAddress object and calling clone() on that is bad...
+ if (addr.is_gen_address())
+ address = (Address *)(((const GenAddress&)addr).address->clone());
+ else
+ address = (Address*)addr.clone();
+
+ if (address)
+ valid_flag = address->valid();
+
+ // Copy real address smival info into GenAddr smival
+ // BOK: smival is generally not used for GenAddress, but
+ // we need this to be a replica of the real address'
+ // smival info so that <class>::operator=SnmpSyntax
+ // will work.
+ if (valid_flag )
+ {
+ smival.syntax = ((GenAddress *)address)->smival.syntax;
+ smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
+ memcpy(smival.value.string.ptr,
+ ((GenAddress *)address)->smival.value.string.ptr,
+ (size_t)smival.value.string.len);
+ }
+
+ return *this;
+}
+
+
+//------[ assignment GenAddress = any SnmpSyntax ]-----------------------
+SnmpSyntax& GenAddress::operator=(const SnmpSyntax &val)
+{
+ ADDRESS_TRACE;
+
+ if (this == &val) return *this; // protect against assignment from itself
+
+ valid_flag = false; // will get set to TRUE if really valid
+ if (address)
+ {
+ delete address;
+ address = 0;
+ }
+
+ if (val.valid())
+ {
+ switch (val.get_syntax() )
+ {
+ //-----[ ip address case ]-------------
+ // BOK: this case shouldn't be needed since there is an explicit
+ // GenAddr=Address assignment that will override this assignment.
+ // Left here for posterity.
+ case sNMP_SYNTAX_IPADDR:
+ {
+ address = new IpAddress(val.get_printable());
+ if (address)
+ valid_flag = address->valid();
+ }
+ break;
+
+ //-----[ udp address case ]------------
+ //-----[ ipx address case ]------------
+ //-----[ mac address case ]------------
+ // BOK: This is here only to support GenAddr = primitive OctetStr.
+ // The explicit GenAddr=Address assignment will handle the cases
+ // GenAddr = [UdpAdd|IpxAddr|IpxSock|MacAddr].
+ // Note, using the heuristic of octet str len to determine type of
+ // address to create is not accurate when address lengths are equal
+ // (e.g., UDPIPLEN == MACLEN). It gets worse if we add AppleTalk or
+ // OSI which use variable length addresses!
+ case sNMP_SYNTAX_OCTETS:
+ {
+ unsigned long val_len;
+ val_len = ((GenAddress &)val).smival.value.string.len;
+
+ if ((val_len == UDPIPLEN) || IS_UDPIP6LEN(val_len))
+ address = new UdpAddress;
+ else if ((val_len == IPLEN) || IS_IP6LEN(val_len))
+ address = new IpAddress;
+#ifdef _IPX_ADDRESS
+ else if (val_len == IPXLEN)
+ address = new IpxAddress;
+ else if (val_len == IPXSOCKLEN)
+ address = new IpxSockAddress;
+#endif
+#ifdef _MAC_ADDRESS
+ else if (val_len == MACLEN)
+ address = new MacAddress;
+#endif
+
+ if (address)
+ {
+ *address = val;
+ valid_flag = address->valid();
+ }
+ }
+ break;
+ } // end switch
+ }
+
+ // Copy real address smival info into GenAddr smival
+ // BOK: smival is generally not used for GenAddress, but
+ // we need this to be a replica of the real address'
+ // smival info so that <class>::operator=SnmpSyntax
+ // will work.
+ if (valid_flag )
+ {
+ smival.syntax = ((GenAddress *)address)->smival.syntax;
+ smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
+ memcpy(smival.value.string.ptr,
+ ((GenAddress *)address)->smival.value.string.ptr,
+ (size_t)smival.value.string.len);
+ }
+
+ return *this;
+}
+
+
+// redefined parse address for macs
+bool GenAddress::parse_address(const char *addr,
+ const Address::addr_type use_type)
+{
+ ADDRESS_TRACE;
+
+ if (address) delete address;
+
+ // try to create each of the addresses until the correct one
+ // is found
+
+ //BOK: Need to try IPX Sock and IPX before UDP since on Win32,
+ // gethostbyname() seems to think the ipx network number
+ // portion is a valid ipaddress string... stupid WinSOCK!
+
+#ifdef _IPX_ADDRESS
+ if ((use_type == Address::type_invalid) ||
+ (use_type == Address::type_ipxsock))
+ {
+ // ipxsock address
+ address = new IpxSockAddress(addr);
+ valid_flag = address->valid();
+ if (valid_flag && ((IpxSockAddress*)address)->get_socket())
+ return TRUE; // ok its an ipxsock address
+
+ delete address; // otherwise delete it and try another
+ }
+
+ if ((use_type == Address::type_invalid) ||
+ (use_type == Address::type_ipx))
+ {
+ // ipx address
+ address = new IpxAddress(addr);
+ valid_flag = address->valid();
+ if (valid_flag)
+ return TRUE; // ok its an ipx address
+
+ delete address; // otherwise delete it and try another
+ }
+#endif // _IPX_ADDRESS
+
+ //TM: Must try the derived classes first...one pitfall of the
+ //following solution is if someone creates with a port/socket of 0 the
+ //class will get demoted to ip/ipx. The only proper way to do this is
+ //to parse the strings ourselves.
+
+ if ((use_type == Address::type_invalid) ||
+ (use_type == Address::type_udp))
+ {
+ // udp address
+ address = new UdpAddress(addr);
+ valid_flag = address->valid();
+ if (valid_flag && ((UdpAddress*)address)->get_port())
+ return TRUE; // ok its a udp address
+
+ delete address; // otherwise delete it and try another
+ }
+
+ if ((use_type == Address::type_invalid) ||
+ (use_type == Address::type_ip))
+ {
+ // ip address
+ address = new IpAddress(addr);
+ valid_flag = address->valid();
+ if (valid_flag)
+ return TRUE; // ok its an ip address
+
+ delete address; // otherwise delete it and try another
+ }
+
+#ifdef _MAC_ADDRESS
+ if ((use_type == Address::type_invalid) ||
+ (use_type == Address::type_mac))
+ {
+ // mac address
+ address = new MacAddress(addr);
+ valid_flag = address->valid();
+ if (valid_flag)
+ return TRUE; // ok, its a mac
+
+ delete address; // otherwise its invalid
+ }
+#endif // _MAC_ADDRESS
+
+ address = 0;
+ return FALSE;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## asn1.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+
+/*===================================================================
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ A S N 1. C P P
+
+ ASN encoder / decoder implementation
+
+ DESIGN + AUTHOR: Peter E. Mellquist
+=====================================================================*/
+char asn1_cpp_version[]="#(@) SNMP++ $Id: asn1.cpp 1557 2009-07-03 20:16:09Z katz $";
+
+#ifdef __unix
+#include /**/ <sys/types.h>
+#include /**/ <netinet/in.h>
+#endif
+
+#include /**/ <stdlib.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/snmperrs.h"
+#include "snmp_pp/log.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*
+ * asn_parse_int - pulls a long out of an ASN int type.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the end of this object.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_parse_int(unsigned char *data,
+ int *datalength,
+ unsigned char *type,
+ long *intp)
+{
+ /*
+ * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+ * timestamp 0x43 asnlength byte {byte}*
+ */
+ unsigned char *bufp = data;
+ unsigned long asn_length;
+ long value = 0;
+
+ *type = *bufp++;
+ if ((*type != 0x02) && (*type != 0x43) &&
+ (*type != 0x41)) {
+ ASNERROR("Wrong Type. Not an integer");
+ return NULL;
+ }
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL) {
+ ASNERROR("bad length");
+ return NULL;
+ }
+ if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+ ASNERROR("overflow of message (int)");
+ return NULL;
+ }
+ if (asn_length > sizeof(*intp)) {
+ ASNERROR("I don't support such large integers");
+ return NULL;
+ }
+ *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+ if (*bufp & 0x80)
+ value = -1; /* integer is negative */
+ while(asn_length--)
+ value = (value << 8) | *bufp++;
+ *intp = value;
+ return bufp;
+}
+
+
+/*
+ * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the end of this object.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_parse_unsigned_int(unsigned char *data,
+ int *datalength,
+ unsigned char *type,
+ unsigned long *intp)
+{
+ /*
+ * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+ * 0x43 asnlength byte {byte}*
+ */
+ unsigned char *bufp = data;
+ unsigned long asn_length;
+ unsigned long value = 0;
+
+ // get the type
+ *type = *bufp++;
+ if ((*type != 0x02) && (*type != 0x43) &&
+ (*type != 0x41) && (*type != 0x42) &&
+ (*type != 0x47)) {
+ ASNERROR("Wrong Type. Not an unsigned integer");
+ return NULL;
+ }
+
+ // pick up the len
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL) {
+ ASNERROR("bad length");
+ return NULL;
+ }
+
+ // check the len for message overflow
+ if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+ ASNERROR("overflow of message (uint)");
+ return NULL;
+ }
+
+ // check for legal uint size
+ if ((asn_length > 5) || ((asn_length > 4) && (*bufp != 0x00))) {
+ ASNERROR("I don't support such large integers");
+ return NULL;
+ }
+
+ // check for leading 0 octet
+ if (*bufp == 0x00) {
+ bufp++;
+ asn_length--;
+ }
+
+ // fix the returned data length value
+ *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+
+ // calculate the value
+ for (long i=0;i<(long)asn_length;i++)
+ value = (value << 8) + (unsigned long) *bufp++;
+
+ *intp = value; // assign return value
+
+ return bufp; // return the bumped pointer
+}
+
+
+/*
+ * asn_build_int - builds an ASN object containing an integer.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the end of this object.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_build_int(unsigned char *data, int *datalength,
+ const unsigned char type,
+ const long *intp)
+{
+ /*
+ * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+ */
+ long integer = *intp;
+ unsigned long mask;
+ int intsize = sizeof(long);
+
+ /* Truncate "unnecessary" bytes off of the most significant end of this
+ * 2's complement integer. There should be no sequence of 9
+ * consecutive 1's or 0's at the most significant end of the
+ * integer.
+ */
+ mask = 0x1FFul << ((8 * (sizeof(long) - 1)) - 1);
+ /* mask is 0xFF800000 on a big-endian machine */
+ while((((integer & mask) == 0) || ((integer & mask) == mask))
+ && intsize > 1) {
+ intsize--;
+ integer <<= 8;
+ }
+ data = asn_build_header(data, datalength, type, intsize);
+ if (data == NULL) return NULL;
+ if (*datalength < intsize) return NULL;
+ *datalength -= intsize;
+ mask = 0xFFul << (8 * (sizeof(long) - 1));
+ /* mask is 0xFF000000 on a big-endian machine */
+ while(intsize--) {
+ *data++ = (unsigned char)((integer & mask) >> (8 * (sizeof(long) - 1)));
+ integer <<= 8;
+ }
+ return data;
+}
+
+
+/*
+ * asn_build_unsigned_int - builds an ASN object containing an integer.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the end of this object.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_build_unsigned_int(unsigned char *data, // modified data
+ int *datalength, // returned buffer length
+ unsigned char type, // SMI type
+ unsigned long *intp) // Uint to encode
+{
+ /*
+ * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+ */
+ unsigned long u_integer = *intp;
+ long u_integer_len;
+ long x;
+
+ // figure out the len
+ if (((u_integer >> 24) & 0xFF) != 0)
+ u_integer_len = 4;
+ else if (((u_integer >> 16) & 0xFF) !=0)
+ u_integer_len = 3;
+ else if (((u_integer >> 8) & 0xFF) !=0)
+ u_integer_len = 2;
+ else
+ u_integer_len = 1;
+
+ // check for 5 byte len where first byte will be a null
+ if (((u_integer >> (8 * (u_integer_len -1))) & 0x080) !=0) {
+ u_integer_len++;
+ }
+
+ // build up the header
+ data = asn_build_header(data, datalength, type, u_integer_len);
+ if (data == NULL) return NULL;
+ if (*datalength < u_integer_len) return NULL;
+
+ // special case, add a null byte for len of 5
+ if (u_integer_len == 5) {
+ *data++ = 0;
+ for (x=1;x<u_integer_len;x++)
+ *data++= (unsigned char) (u_integer >> (8 * ((u_integer_len-1)-x)& 0xFF));
+ }
+ else
+ {
+ for (x=0;x<u_integer_len;x++)
+ *data++= (unsigned char) (u_integer >> (8 * ((u_integer_len-1)-x)& 0xFF));
+ }
+ *datalength -= u_integer_len;
+ return data;
+}
+
+
+/*
+ * asn_parse_string - pulls an octet string out of an ASN octet string type.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the beginning of the next object.
+ *
+ * "string" is filled with the octet string.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_parse_string(unsigned char *data,
+ int *datalength,
+ unsigned char *type,
+ unsigned char *str,
+ int *strlength)
+{
+ /*
+ * ASN.1 octet string ::= primstring | cmpdstring
+ * primstring ::= 0x04 asnlength byte {byte}*
+ * cmpdstring ::= 0x24 asnlength string {string}*
+ * ipaddress ::= 0x40 4 byte byte byte byte
+ */
+ unsigned char *bufp = data;
+ unsigned long asn_length;
+
+ *type = *bufp++;
+ if ((*type != 0x04) && (*type != 0x24) &&
+ (*type != 0x40) && (*type != 0x44) &&
+ (*type != 0x45)) {
+ ASNERROR("asn parse string: Wrong Type. Not a string");
+ return NULL;
+ }
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL)
+ return NULL;
+ if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+ ASNERROR("asn parse string: overflow of message");
+ return NULL;
+ }
+ if ((int)asn_length > *strlength) {
+ ASNERROR("asn parse string: String to parse is longer than buffer, aborting parsing.");
+ return NULL;
+ }
+
+ memcpy(str, bufp, asn_length);
+ *strlength = (int)asn_length;
+ *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+ return bufp + asn_length;
+}
+
+
+/*
+ * asn_build_string - Builds an ASN octet string object containing the input string.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the beginning of the next object.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_build_string(unsigned char *data,
+ int *datalength,
+ const unsigned char type,
+ const unsigned char *string,
+ const int strlength)
+{
+ /*
+ * ASN.1 octet string ::= primstring | cmpdstring
+ * primstring ::= 0x04 asnlength byte {byte}*
+ * cmpdstring ::= 0x24 asnlength string {string}*
+ * This code will never send a compound string.
+ */
+ data = asn_build_header(data, datalength, type, strlength);
+ if (data == NULL) return NULL;
+ if (*datalength < strlength) return NULL;
+
+ memcpy(data, string, strlength);
+ *datalength -= strlength;
+ return data + strlength;
+}
+
+
+/*
+ * asn_parse_header - interprets the ID and length of the current object.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * in this object following the id and length.
+ *
+ * Returns a pointer to the first byte of the contents of this object.
+ * Returns NULL on any error.
+ */
+unsigned char *asn_parse_header(unsigned char *data,
+ int *datalength,
+ unsigned char *type)
+{
+ unsigned char *bufp = data;
+ register int header_len;
+ unsigned long asn_length;
+
+ /* this only works on data types < 30, i.e. no extension octets */
+ if (IS_EXTENSION_ID(*bufp)) {
+ ASNERROR("can't process ID >= 30");
+ return NULL;
+ }
+ *type = *bufp;
+ bufp = asn_parse_length(bufp + 1, &asn_length);
+ if (bufp == NULL)
+ return NULL;
+ header_len = SAFE_INT_CAST(bufp - data);
+ if ((unsigned long)(header_len + asn_length) > (unsigned long)*datalength) {
+ ASNERROR("asn length too long");
+ return NULL;
+ }
+ *datalength = (int)asn_length;
+ return bufp;
+}
+
+/*
+ * asn_build_header - builds an ASN header for an object with the ID and
+ * length specified.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * in this object following the id and length.
+ *
+ * This only works on data types < 30, i.e. no extension octets.
+ * The maximum length is 0xFFFF;
+ *
+ * Returns a pointer to the first byte of the contents of this object.
+ * Returns NULL on any error.
+ */
+unsigned char *asn_build_header(unsigned char *data,
+ int *datalength,
+ unsigned char type,
+ int length)
+{
+ if (*datalength < 1)
+ return NULL;
+ *data++ = type;
+ (*datalength)--;
+ return asn_build_length(data, datalength, length);
+}
+
+/*
+ * asn_build_sequence - builds an ASN header for a sequence with the ID and
+ * length specified.
+ *
+ * This only works on data types < 30, i.e. no extension octets.
+ *
+ * Returns a pointer to the first byte of the contents of this object.
+ * Returns NULL on any error.
+ */
+unsigned char *asn_build_sequence(unsigned char *data,
+ int *datalength,
+ unsigned char type,
+ int length)
+{
+ if (*datalength < 2) /* need at least two octets for a sequence */
+ {
+ ASNERROR("build_sequence");
+ return NULL;
+ }
+ *data++ = type;
+ (*datalength)--;
+
+ unsigned char *data_with_length = asn_build_length(data, datalength, length);
+ if (data_with_length == NULL)
+ {
+ (*datalength)++; /* correct datalength to emulate old behavior of build_sequence */
+ return NULL;
+ }
+
+ return data_with_length;
+}
+
+/*
+ * asn_parse_length - interprets the length of the current object.
+ * On exit, length contains the value of this length field.
+ *
+ * Returns a pointer to the first byte after this length
+ * field (aka: the start of the data field).
+ * Returns NULL on any error.
+ */
+unsigned char * asn_parse_length(unsigned char *data,
+ unsigned long *length)
+{
+ unsigned char lengthbyte = *data;
+ *length = 0;
+ if (lengthbyte & ASN_LONG_LEN) {
+ lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
+ if (lengthbyte == 0) {
+ ASNERROR("We don't support indefinite lengths");
+ return NULL;
+ }
+ if (lengthbyte > sizeof(int)) {
+ ASNERROR("we can't support data lengths that long");
+ return NULL;
+ }
+ for (int i=0 ; i < lengthbyte ; i++)
+ {
+ *length = (*length << 8) + *(data + 1 + i);
+ }
+ // check for length greater than 2^31
+ if (*length > 0x80000000ul) {
+ ASNERROR("SNMP does not support data lengths > 2^31");
+ return NULL;
+ }
+ return data + lengthbyte + 1;
+ } else { /* short asnlength */
+ *length = (long)lengthbyte;
+ return data + 1;
+ }
+}
+
+unsigned char *asn_build_length(unsigned char *data,
+ int *datalength,
+ int length)
+{
+ unsigned char *start_data = data;
+
+ /* no indefinite lengths sent */
+ if (length < 0x80) {
+ if (*datalength < 1) {
+ ASNERROR("build_length");
+ return NULL;
+ }
+ *data++ = (unsigned char)length;
+ }
+ else if (length <= 0xFF) {
+ if (*datalength < 2) {
+ ASNERROR("build_length");
+ return NULL;
+ }
+ *data++ = (unsigned char)(0x01 | ASN_LONG_LEN);
+ *data++ = (unsigned char)length;
+ }
+ else if (length <= 0xFFFF) { /* 0xFF < length <= 0xFFFF */
+ if (*datalength < 3) {
+ ASNERROR("build_length");
+ return NULL;
+ }
+ *data++ = (unsigned char)(0x02 | ASN_LONG_LEN);
+ *data++ = (unsigned char)((length >> 8) & 0xFF);
+ *data++ = (unsigned char)(length & 0xFF);
+ }
+ else if (length <= 0xFFFFFF) { /* 0xFF < length <= 0xFFFF */
+ if (*datalength < 4) {
+ ASNERROR("build_length");
+ return NULL;
+ }
+ *data++ = (unsigned char)(0x03 | ASN_LONG_LEN);
+ *data++ = (unsigned char)((length >> 16) & 0xFF);
+ *data++ = (unsigned char)((length >> 8) & 0xFF);
+ *data++ = (unsigned char)(length & 0xFF);
+ }
+ else {
+ if (*datalength < 5) {
+ ASNERROR("build_length");
+ return NULL;
+ }
+ *data++ = (unsigned char)(0x04 | ASN_LONG_LEN);
+ *data++ = (unsigned char)((length >> 24) & 0xFF);
+ *data++ = (unsigned char)((length >> 16) & 0xFF);
+ *data++ = (unsigned char)((length >> 8) & 0xFF);
+ *data++ = (unsigned char)(length & 0xFF);
+ }
+ *datalength -= SAFE_INT_CAST(data - start_data);
+ return data;
+}
+
+/*
+ * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the beginning of the next object.
+ *
+ * "objid" is filled with the object identifier.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_parse_objid(unsigned char *data,
+ int *datalength,
+ unsigned char *type,
+ oid *objid,
+ int *objidlength)
+{
+ /*
+ * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
+ * subidentifier ::= {leadingbyte}* lastbyte
+ * leadingbyte ::= 1 7bitvalue
+ * lastbyte ::= 0 7bitvalue
+ */
+ unsigned char *bufp = data;
+ oid *oidp = objid + 1;
+ unsigned long subidentifier;
+ long length;
+ unsigned long asn_length;
+
+ *type = *bufp++;
+ if (*type != 0x06) {
+ ASNERROR("Wrong Type. Not an oid");
+ return NULL;
+ }
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL)
+ return NULL;
+ if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+ ASNERROR("overflow of message (objid)");
+ return NULL;
+ }
+ *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+
+ /* Handle invalid object identifier encodings of the form 06 00 robustly */
+ if (asn_length == 0)
+ objid[0] = objid[1] = 0;
+
+ length = asn_length;
+ (*objidlength)--; /* account for expansion of first byte */
+ while (length > 0 && (*objidlength)-- > 0) {
+ subidentifier = 0;
+ do { /* shift and add in low order 7 bits */
+ subidentifier = (subidentifier << 7) + (*(unsigned char *)bufp & ~ASN_BIT8);
+ length--;
+ } while (*(unsigned char *)bufp++ & ASN_BIT8); /* last byte has high bit clear */
+ if (subidentifier > (unsigned long)MAX_SUBID) {
+ ASNERROR("subidentifier too long");
+ return NULL;
+ }
+ *oidp++ = (oid)subidentifier;
+ }
+
+ /*
+ * The first two subidentifiers are encoded into the first component
+ * with the value (X * 40) + Y, where:
+ * X is the value of the first subidentifier.
+ * Y is the value of the second subidentifier.
+ */
+ subidentifier = (unsigned long)objid[1];
+ if (subidentifier == 0x2B) {
+ objid[0] = 1;
+ objid[1] = 3;
+ } else {
+ objid[1] = (unsigned char)(subidentifier % 40);
+ objid[0] = (unsigned char)((subidentifier - objid[1]) / 40);
+ }
+
+ *objidlength = (int)(oidp - objid);
+ return bufp;
+}
+
+/*
+ * asn_build_objid - Builds an ASN object identifier object containing the
+ * input string.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the beginning of the next object.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_build_objid(unsigned char *data,
+ int *datalength,
+ unsigned char type,
+ oid *objid,
+ int objidlength)
+{
+ /*
+ * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
+ * subidentifier ::= {leadingbyte}* lastbyte
+ * leadingbyte ::= 1 7bitvalue
+ * lastbyte ::= 0 7bitvalue
+ */
+ // F.Fock correct buffer size must be 5*8bit*MAX_OID_LEN
+ unsigned char buf[MAX_OID_LEN*5];
+ unsigned char *bp = buf;
+ oid *op = objid;
+ int asnlength;
+ unsigned long subid, mask, testmask;
+ int bits, testbits;
+
+ if (objidlength < 2) {
+ *bp++ = 0;
+ objidlength = 0;
+ } else {
+ *bp++ = (unsigned char) (op[1] + (op[0] * 40));
+ objidlength -= 2;
+ op += 2;
+ }
+
+ while(objidlength-- > 0) {
+ subid = *op++;
+ if (subid < 127) { /* off by one? */
+ *bp++ = (unsigned char)subid;
+ } else {
+ mask = 0x7F; /* handle subid == 0 case */
+ bits = 0;
+ /* testmask *MUST* !!!! be of an unsigned type */
+ for(testmask = 0x7F, testbits = 0; testmask != 0;
+ testmask <<= 7, testbits += 7) {
+ if (subid & testmask) { /* if any bits set */
+ mask = testmask;
+ bits = testbits;
+ }
+ }
+ /* mask can't be zero here */
+ for(;mask != 0x7F; mask >>= 7, bits -= 7) {
+ /* fix a mask that got truncated above */
+ if (mask == 0x1E00000)
+ mask = 0xFE00000;
+ *bp++ = (unsigned char)(((subid & mask) >> bits) | ASN_BIT8);
+ }
+ *bp++ = (unsigned char)(subid & mask);
+ }
+ }
+ asnlength = SAFE_INT_CAST(bp - buf);
+ data = asn_build_header(data, datalength, type, asnlength);
+ if (data == NULL) return NULL;
+ if (*datalength < asnlength) return NULL;
+
+ memcpy((char *)data, (char *)buf, asnlength);
+ *datalength -= asnlength;
+ return data + asnlength;
+}
+
+/*
+ * asn_parse_null - Interprets an ASN null type.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the beginning of the next object.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_parse_null(unsigned char *data,
+ int *datalength,
+ unsigned char *type)
+{
+ /*
+ * ASN.1 null ::= 0x05 0x00
+ */
+ unsigned char *bufp = data;
+ unsigned long asn_length;
+
+ *type = *bufp++;
+ if (*type != 0x05) {
+ ASNERROR("Wrong Type. Not a null");
+ return NULL;
+ }
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL)
+ return NULL;
+ if (asn_length != 0) {
+ ASNERROR("Malformed NULL");
+ return NULL;
+ }
+ *datalength -= SAFE_INT_CAST(bufp - data);
+ return bufp + asn_length;
+}
+
+
+/*
+ * asn_build_null - Builds an ASN null object.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the beginning of the next object.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_build_null(unsigned char *data,
+ int *datalength,
+ unsigned char type)
+{
+ /*
+ * ASN.1 null ::= 0x05 0x00
+ */
+ return asn_build_header(data, datalength, type, 0);
+}
+
+/*
+ * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the beginning of the next object.
+ *
+ * "string" is filled with the bit string.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_parse_bitstring(unsigned char *data,
+ int *datalength,
+ unsigned char *type,
+ unsigned char *string,
+ int *strlength)
+{
+ /*
+ * bitstring ::= 0x03 asnlength unused {byte}*
+ */
+ unsigned char *bufp = data;
+ unsigned long asn_length;
+
+ *type = *bufp++;
+ if (*type != 0x03) {
+ ASNERROR("Wrong Type. Not a bitstring");
+ return NULL;
+ }
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL)
+ return NULL;
+ if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+ ASNERROR("overflow of message (bitstring)");
+ return NULL;
+ }
+ if ((int) asn_length > *strlength) {
+ ASNERROR("I don't support such long bitstrings");
+ return NULL;
+ }
+ if (asn_length < 1) {
+ ASNERROR("Invalid bitstring");
+ return NULL;
+ }
+ if (*bufp > 7) {
+ ASNERROR("Invalid bitstring");
+ return NULL;
+ }
+
+ memcpy((char *)string,(char *)bufp, (int)asn_length);
+ *strlength = (int)asn_length;
+ *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+ return bufp + asn_length;
+}
+
+
+/*
+ * asn_build_bitstring - Builds an ASN bit string object containing the
+ * input string.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the beginning of the next object.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_build_bitstring(unsigned char *data,
+ int *datalength,
+ unsigned char type,
+ unsigned char *string,
+ int strlength)
+{
+ /*
+ * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
+ */
+ if (strlength < 1 || *string > 7) {
+ ASNERROR("Building invalid bitstring");
+ return NULL;
+ }
+ data = asn_build_header(data, datalength, type, strlength);
+ if (data == NULL) return NULL;
+ if (*datalength < strlength) return NULL;
+
+ memcpy((char *)data,(char *)string, strlength);
+ *datalength -= strlength;
+ return data + strlength;
+}
+
+
+/*
+ * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
+ * type.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the end of this object.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_parse_unsigned_int64(unsigned char *data,
+ int *datalength,
+ unsigned char *type,
+ struct counter64 *cp)
+{
+ /*
+ * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+ */
+ unsigned char *bufp = data;
+ unsigned long asn_length;
+ unsigned long low = 0, high = 0;
+
+ *type = *bufp++;
+ if ((*type != 0x02) && (*type != 0x46)) {
+ ASNERROR("Wrong Type. Not an integer 64");
+ return NULL;
+ }
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL) {
+ ASNERROR("bad length");
+ return NULL;
+ }
+ if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+ ASNERROR("overflow of message (uint64)");
+ return NULL;
+ }
+ if (((int)asn_length > 9) ||
+ (((int)asn_length == 9) && *bufp != 0x00)) {
+ ASNERROR("I don't support such large integers");
+ return NULL;
+ }
+ *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+ if (*bufp & 0x80) {
+ low = (unsigned long) -1; // integer is negative
+ high = (unsigned long) -1;
+ }
+ while(asn_length--) {
+ high = (high << 8) | ((low & 0xFF000000) >> 24);
+ low = ((low << 8) | *bufp++) & 0xFFFFFFFF;
+ }
+ cp->low = low;
+ cp->high = high;
+
+ return bufp;
+}
+
+
+/*
+ * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
+ * On entry, datalength is input as the number of valid bytes following
+ * "data". On exit, it is returned as the number of valid bytes
+ * following the end of this object.
+ *
+ * Returns a pointer to the first byte past the end
+ * of this object (i.e. the start of the next object).
+ * Returns NULL on any error.
+ */
+unsigned char *asn_build_unsigned_int64(unsigned char *data,
+ int *datalength,
+ unsigned char type,
+ struct counter64 *cp)
+{
+ /*
+ * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+ */
+ unsigned long low = cp->low;
+ unsigned long high = cp->high;
+ unsigned long mask = 0xFF000000ul;
+ int add_null_byte = 0;
+ int intsize = 8;
+
+ if (((high & mask) >> 24) & 0x80) {
+ /* if MSB is set */
+ add_null_byte = 1;
+ intsize++;
+ }
+ else {
+ /*
+ * Truncate "unnecessary" bytes off of the most significant end of this 2's
+ * complement integer.
+ * There should be no sequence of 9 consecutive 1's or 0's at the most
+ * significant end of the integer.
+ */
+ unsigned long mask2 = 0xFF800000ul;
+ while ((((high & mask2) == 0) || ((high & mask2) == mask2)) &&
+ (intsize > 1)) {
+ intsize--;
+ high = (high << 8) | ((low & mask) >> 24);
+ low <<= 8;
+ }
+ }
+ data = asn_build_header(data, datalength, type, intsize);
+ if (data == NULL) return NULL;
+ if (*datalength < intsize) return NULL;
+ *datalength -= intsize;
+ if (add_null_byte == 1) {
+ *data++ = 0;
+ intsize--;
+ }
+ while(intsize--) {
+ *data++ = (unsigned char)((high & mask) >> 24);
+ high = (high << 8) | ((low & mask) >> 24);
+ low <<= 8;
+ }
+ return data;
+}
+
+
+// create a pdu
+struct snmp_pdu *snmp_pdu_create(int command)
+{
+ struct snmp_pdu *pdu;
+
+ pdu = (struct snmp_pdu *)malloc(sizeof(struct snmp_pdu));
+ if (!pdu) return pdu;
+ memset((char *)pdu, 0,sizeof(struct snmp_pdu));
+ pdu->command = command;
+#ifdef _SNMPv3
+ pdu->msgid = 0;
+#endif
+ pdu->errstat = 0;
+ pdu->errindex = 0;
+ pdu->enterprise = NULL;
+ pdu->enterprise_length = 0;
+ pdu->variables = NULL;
+ return pdu;
+}
+
+// free content and clear pointers
+void clear_pdu(struct snmp_pdu *pdu, bool clear_all)
+{
+ struct variable_list *vp, *ovp;
+
+ vp = pdu->variables;
+ while (vp)
+ {
+ if (vp->name) free((char *)vp->name); // free the oid part
+ if (vp->val.string) free((char *)vp->val.string); // free deep data
+ ovp = vp;
+ vp = vp->next_variable; // go to the next one
+ free((char *)ovp); // free up vb itself
+ }
+ pdu->variables = NULL;
+
+ // if enterprise free it up
+ if (pdu->enterprise)
+ free((char *)pdu->enterprise);
+ pdu->enterprise = NULL;
+
+ if (!clear_all) return;
+
+ pdu->command = 0;
+ pdu->reqid = 0;
+#ifdef _SNMPv3
+ pdu->msgid = 0;
+ pdu->maxsize_scopedpdu = 0;
+#endif
+ pdu->errstat = 0;
+ pdu->errindex = 0;
+
+ pdu->enterprise_length = 0;
+ pdu->trap_type = 0;
+ pdu->specific_type = 0;
+ pdu->time = 0;
+}
+
+// free a pdu
+void snmp_free_pdu(struct snmp_pdu *pdu)
+{
+ clear_pdu(pdu); // clear and free content
+ free(pdu); // free up pdu itself
+}
+
+
+// add a null var to a pdu
+void snmp_add_var(struct snmp_pdu *pdu,
+ oid *name,
+ int name_length,
+ SmiVALUE *smival)
+{
+ struct variable_list *vars;
+
+ // if we don't have a vb list ,create one
+ if (pdu->variables == NULL)
+ pdu->variables = vars = (struct variable_list *)malloc(sizeof(struct variable_list));
+ else
+ {
+ // we have one, find the end
+ vars = pdu->variables;
+ while (vars->next_variable) vars = vars->next_variable;
+
+ // create a new one
+ vars->next_variable = (struct variable_list *)malloc(sizeof(struct variable_list));
+ // bump ptr
+ vars = vars->next_variable;
+ }
+
+ // add the oid with no data
+ vars->next_variable = NULL;
+
+ // hook in the Oid portion
+ vars->name = (oid *)malloc(name_length * sizeof(oid));
+
+ memcpy((char *)vars->name,(char *)name, name_length * sizeof(oid));
+ vars->name_length = name_length;
+
+ // hook in the SMI value
+ switch(smival->syntax)
+ {
+ // null , do nothing
+ case sNMP_SYNTAX_NULL:
+ case sNMP_SYNTAX_NOSUCHOBJECT:
+ case sNMP_SYNTAX_NOSUCHINSTANCE:
+ case sNMP_SYNTAX_ENDOFMIBVIEW:
+ {
+ vars->type = (unsigned char) smival->syntax;
+ vars->val.string = NULL;
+ vars->val_len = 0;
+ }
+ break;
+
+ // octects
+ case sNMP_SYNTAX_OCTETS:
+ case sNMP_SYNTAX_OPAQUE:
+ case sNMP_SYNTAX_IPADDR:
+ {
+ vars->type = (unsigned char) smival->syntax;
+ vars->val.string = (unsigned char *)malloc((unsigned)smival->value.string.len);
+ vars->val_len = (int) smival->value.string.len;
+ memcpy((unsigned char *) vars->val.string,
+ (unsigned char *) smival->value.string.ptr,
+ (unsigned) smival->value.string.len);
+ }
+ break;
+
+ // oid
+ case sNMP_SYNTAX_OID:
+ {
+ vars->type = (unsigned char) smival->syntax;
+ vars->val_len = (int) smival->value.oid.len * sizeof(oid);
+ vars->val.objid = (oid *)malloc((unsigned)vars->val_len);
+ memcpy((unsigned long *)vars->val.objid,
+ (unsigned long *)smival->value.oid.ptr,
+ (unsigned) vars->val_len);
+ }
+ break;
+
+
+
+ case sNMP_SYNTAX_TIMETICKS:
+ case sNMP_SYNTAX_CNTR32:
+ case sNMP_SYNTAX_GAUGE32:
+ // case sNMP_SYNTAX_UINT32:
+ {
+ long templong;
+ vars->type = (unsigned char) smival->syntax;
+ vars->val.integer = (long *)malloc(sizeof(long));
+ vars->val_len = sizeof(long);
+ templong = (long) smival->value.uNumber;
+ memcpy((long*) vars->val.integer,
+ (long*) &templong,
+ sizeof(long));
+ }
+ break;
+
+ case sNMP_SYNTAX_INT32:
+ {
+ long templong;
+ vars->type = (unsigned char) smival->syntax;
+ vars->val.integer = (long *)malloc(sizeof(long));
+ vars->val_len = sizeof(long);
+ templong = (long) smival->value.sNumber;
+ memcpy((long*) vars->val.integer,
+ (long*) &templong,
+ sizeof(long));
+ }
+ break;
+
+ // 64 bit counter
+ case sNMP_SYNTAX_CNTR64:
+ {
+ vars->type = (unsigned char) smival->syntax;
+ vars->val.counter64 = (struct counter64 *)malloc(sizeof(struct counter64));
+ vars->val_len = sizeof(struct counter64);
+ memcpy((struct counter64*) vars->val.counter64,
+ (SmiLPCNTR64) &(smival->value.hNumber),
+ sizeof(SmiCNTR64));
+ }
+ break;
+
+ } // end switch
+
+}
+
+// build the authentication, works for v1 or v2c
+static unsigned char *snmp_auth_build(unsigned char *data,
+ int *length,
+ const long int version,
+ const unsigned char *community,
+ const int community_len,
+ const int messagelen)
+{
+ // 5 is 3 octets for version and 2 for community header + len
+ // This assumes that community will not be longer than 0x7f chars.
+ data = asn_build_sequence(data, length, ASN_SEQ_CON,
+ messagelen + community_len + 5);
+ if (data == NULL) {
+ ASNERROR("buildheader");
+ return NULL;
+ }
+ data = asn_build_int(data, length, ASN_UNI_PRIM | ASN_INTEGER, &version);
+ if (data == NULL) {
+ ASNERROR("buildint");
+ return NULL;
+ }
+
+ data = asn_build_string(data, length, ASN_UNI_PRIM | ASN_OCTET_STR,
+ community, community_len);
+ if (data == NULL) {
+ ASNERROR("buildstring");
+ return NULL;
+ }
+
+ return data;
+}
+
+
+// build a variable binding
+unsigned char * snmp_build_var_op(unsigned char *data,
+ oid * var_name,
+ int *var_name_len,
+ unsigned char var_val_type,
+ int var_val_len,
+ unsigned char *var_val,
+ int *listlength)
+{
+ int valueLen;
+ Buffer<unsigned char> buffer(MAX_SNMP_PACKET);
+ unsigned char *buffer_pos = buffer.get_ptr();
+ int bufferLen = MAX_SNMP_PACKET;
+
+ buffer_pos = asn_build_objid(buffer_pos, &bufferLen,
+ ASN_UNI_PRIM | ASN_OBJECT_ID,
+ var_name, *var_name_len);
+ if (buffer_pos == NULL) {
+ ASNERROR("build_var_op: build_objid failed");
+ return NULL;
+ }
+
+ // based on the type...
+ switch(var_val_type) {
+ case ASN_INTEGER:
+ if (var_val_len != sizeof(long))
+ {
+ ASNERROR("build_var_op: Illegal size of integer");
+ return NULL;
+ }
+ buffer_pos = asn_build_int(buffer_pos, &bufferLen,
+ var_val_type, (long *)var_val);
+ break;
+
+ case SMI_GAUGE:
+ case SMI_COUNTER:
+ case SMI_TIMETICKS:
+ case SMI_UINTEGER:
+ if (var_val_len != sizeof(unsigned long))
+ {
+ ASNERROR("build_var_op: Illegal size of unsigned integer");
+ return NULL;
+ }
+ buffer_pos = asn_build_unsigned_int(buffer_pos, &bufferLen,
+ var_val_type, (unsigned long *)var_val);
+ break;
+
+ case SMI_COUNTER64:
+ if (var_val_len != sizeof(counter64))
+ {
+ ASNERROR("build_var_op: Illegal size of counter64");
+ return NULL;
+ }
+ buffer_pos = asn_build_unsigned_int64(buffer_pos, &bufferLen,
+ var_val_type,
+ (struct counter64 *)var_val);
+ break;
+
+ case ASN_OCTET_STR:
+ case SMI_IPADDRESS:
+ case SMI_OPAQUE:
+ case SMI_NSAP:
+ buffer_pos = asn_build_string(buffer_pos, &bufferLen, var_val_type,
+ var_val, var_val_len);
+ break;
+
+ case ASN_OBJECT_ID:
+ buffer_pos = asn_build_objid(buffer_pos, &bufferLen, var_val_type,
+ (oid *)var_val, var_val_len / sizeof(oid));
+ break;
+
+ case ASN_NULL:
+ buffer_pos = asn_build_null(buffer_pos, &bufferLen, var_val_type);
+ break;
+
+ case ASN_BIT_STR:
+ buffer_pos = asn_build_bitstring(buffer_pos, &bufferLen, var_val_type,
+ var_val, var_val_len);
+ break;
+
+ case SNMP_NOSUCHOBJECT:
+ case SNMP_NOSUCHINSTANCE:
+ case SNMP_ENDOFMIBVIEW:
+ buffer_pos = asn_build_null(buffer_pos, &bufferLen, var_val_type);
+ break;
+
+ default:
+ ASNERROR("build_var_op: wrong type");
+ return NULL;
+ }
+ if (buffer_pos == NULL) {
+ ASNERROR("build_var_op: value build failed");
+ return NULL;
+ }
+
+ valueLen = SAFE_INT_CAST(buffer_pos - buffer.get_ptr());
+
+ data = asn_build_sequence(data, listlength, ASN_SEQ_CON, valueLen);
+
+ if(data == NULL || *listlength < valueLen)
+ {
+ ASNERROR("build_var_op");
+ data = NULL;
+ }
+ else
+ {
+ memcpy(data, buffer.get_ptr(), valueLen);
+ data += valueLen;
+ (*listlength)-=valueLen;
+ }
+ return data;
+}
+
+
+unsigned char *build_vb(struct snmp_pdu *pdu,
+ unsigned char *buf, int *buf_len)
+{
+ Buffer<unsigned char> tmp_buf(MAX_SNMP_PACKET);
+ unsigned char *cp = tmp_buf.get_ptr();
+ struct variable_list *vp;
+ int vb_length;
+ int length = MAX_SNMP_PACKET;
+
+ // build varbinds into packet buffer
+ for(vp = pdu->variables; vp; vp = vp->next_variable)
+ {
+ cp = snmp_build_var_op(cp, vp->name, &vp->name_length,
+ vp->type, vp->val_len,
+ (unsigned char *)vp->val.string,
+ &length);
+ if (cp == NULL) return 0;
+ }
+ vb_length = SAFE_INT_CAST(cp - tmp_buf.get_ptr());
+ *buf_len -= vb_length;
+ if (*buf_len <= 0) return 0;
+
+ // encode the length of encoded varbinds into buf
+ cp = asn_build_header(buf, buf_len, ASN_SEQ_CON, vb_length);
+ if (cp == NULL) return 0;
+
+ // copy varbinds from packet behind header in buf
+ memcpy(cp, tmp_buf.get_ptr(), vb_length);
+
+ return (cp + vb_length);
+}
+
+unsigned char *build_data_pdu(struct snmp_pdu *pdu,
+ unsigned char *buf, int *buf_len,
+ unsigned char *vb_buf, int vb_buf_len)
+{
+ Buffer<unsigned char> tmp_buf(MAX_SNMP_PACKET);
+ unsigned char *cp = tmp_buf.get_ptr();
+ int totallength;
+ int length = MAX_SNMP_PACKET;
+
+ // build data of pdu into tmp_buf
+ if (pdu->command != TRP_REQ_MSG)
+ {
+ // request id
+ cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &pdu->reqid);
+ if (cp == NULL) return 0;
+
+ // error status
+ cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &pdu->errstat);
+ if (cp == NULL) return 0;
+
+ // error index
+ cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &pdu->errindex);
+ if (cp == NULL) return 0;
+ }
+ else
+ { // this is a trap message
+ // enterprise
+ cp = asn_build_objid(cp, &length, ASN_UNI_PRIM | ASN_OBJECT_ID,
+ (oid *)pdu->enterprise, pdu->enterprise_length);
+ if (cp == NULL) return 0;
+
+ // agent-addr ; must be IPADDRESS changed by Frank Fock
+ cp = asn_build_string(cp, &length, SMI_IPADDRESS,
+ (unsigned char *)&pdu->agent_addr.sin_addr.s_addr,
+ sizeof(pdu->agent_addr.sin_addr.s_addr));
+ if (cp == NULL) return 0;
+
+ long dummy = pdu->trap_type;
+ // generic trap
+ cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &dummy);
+ if (cp == NULL) return 0;
+
+ dummy = pdu->specific_type;
+ // specific trap
+ cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &dummy);
+ if (cp == NULL) return 0;
+
+ // timestamp
+ cp = asn_build_unsigned_int(cp, &length, SMI_TIMETICKS, &pdu->time);
+ if (cp == NULL) return 0;
+ }
+
+ if (length < vb_buf_len) return 0;
+
+ // save relative position of varbinds
+ int vb_rel_pos = SAFE_INT_CAST(cp - tmp_buf.get_ptr());
+ totallength = SAFE_INT_CAST(cp - tmp_buf.get_ptr()) + vb_buf_len;
+
+ // build header for datapdu into buf
+ cp = asn_build_header(buf, buf_len,
+ (unsigned char)pdu->command, totallength);
+ if (cp == NULL) return 0;
+ if (*buf_len < totallength) return 0;
+
+ // copy data behind header
+ memcpy(cp, tmp_buf.get_ptr(), totallength - vb_buf_len);
+ memcpy((char *)cp + vb_rel_pos, (char *)vb_buf, vb_buf_len);
+ *buf_len -= totallength;
+ return (cp + totallength);
+}
+
+// serialize the pdu
+int snmp_build(struct snmp_pdu *pdu,
+ unsigned char *packet, int *out_length,
+ const long version,
+ const unsigned char* community, const int community_len)
+{
+ Buffer<unsigned char> buf(MAX_SNMP_PACKET);
+ unsigned char *cp;
+ int length;
+ int totallength;
+
+ // encode vbs with header into packet
+ length = *out_length;
+ cp = build_vb(pdu, packet, &length);
+ if (cp == 0) return -1;
+ totallength = SAFE_INT_CAST(cp - packet);
+ if (totallength >= *out_length) return -1;
+
+ // encode datadpu into buf
+ length = MAX_SNMP_PACKET;
+ cp = build_data_pdu(pdu, buf.get_ptr(), &length,
+ packet, totallength);
+ if (cp == 0) return -1;
+ totallength = SAFE_INT_CAST(cp - buf.get_ptr());
+ if (totallength >= *out_length) return -1;
+
+ // build SNMP header
+ length = *out_length;
+ cp = snmp_auth_build(packet, &length, version,
+ community, community_len, totallength);
+ if (cp == NULL) return -1;
+ if ((*out_length - (cp - packet)) < totallength) return -1;
+
+ // copy data
+ memcpy(cp, buf.get_ptr(), totallength);
+ totallength += SAFE_INT_CAST(cp - packet);
+ *out_length = totallength;
+
+ return 0;
+}
+
+// parse the authentication header
+static unsigned char *snmp_auth_parse(unsigned char *data,
+ int *length,
+ unsigned char *community,
+ int *community_len,
+ long *version)
+{
+ unsigned char type;
+
+ // get the type
+ data = asn_parse_header(data, length, &type);
+ if (data == NULL) {
+ ASNERROR("bad header");
+ return NULL;
+ }
+
+ if (type != ASN_SEQ_CON) {
+ ASNERROR("wrong auth header type");
+ return NULL;
+ }
+
+ // get the version
+ data = asn_parse_int(data, length, &type, version);
+ if (data == NULL) {
+ ASNERROR("bad parse of version");
+ return NULL;
+ }
+
+ // get the community name
+ data = asn_parse_string(data, length, &type, community, community_len);
+ if (data == NULL) {
+ ASNERROR("bad parse of community");
+ return NULL;
+ }
+
+ return (unsigned char *)data;
+}
+
+unsigned char *
+snmp_parse_var_op(unsigned char *data, // IN - pointer to the start of object
+ oid *var_name, // OUT - object id of variable
+ int *var_name_len, // IN/OUT - length of variable name
+ unsigned char *var_val_type, // OUT - type of variable (int or octet string) (one byte)
+ int *var_val_len, // OUT - length of variable
+ unsigned char **var_val, // OUT - pointer to ASN1 encoded value of variable
+ int *listlength) // IN/OUT - number of valid bytes left in var_op_list
+{
+ unsigned char var_op_type;
+ int var_op_len = *listlength;
+ unsigned char *var_op_start = data;
+
+ data = asn_parse_header(data, &var_op_len, &var_op_type);
+ if (data == NULL) {
+ ASNERROR("Error snmp_parse_var_op: 1");
+ return NULL;
+ }
+ if (var_op_type != ASN_SEQ_CON)
+ return NULL;
+ data = asn_parse_objid(data, &var_op_len, &var_op_type, var_name, var_name_len);
+ if (data == NULL) {
+ ASNERROR("Error snmp_parse_var_op: 2");
+ return NULL;
+ }
+ if (var_op_type != (ASN_UNI_PRIM | ASN_OBJECT_ID))
+ return NULL;
+ *var_val = data; /* save pointer to this object */
+ /* find out what type of object this is */
+ data = asn_parse_header(data, &var_op_len, var_val_type);
+ if (data == NULL) {
+ ASNERROR("Error snmp_parse_var_op: 3");
+ return NULL;
+ }
+ if (((unsigned long)var_op_len + (data - var_op_start)) > (unsigned long)(*listlength)) {
+ ASNERROR("Error snmp_parse_var_op: 4");
+ return NULL;
+ }
+ *var_val_len = (int)var_op_len;
+ data += var_op_len;
+ *listlength -= (int)(data - var_op_start);
+ return data;
+}
+
+
+int snmp_parse_vb(struct snmp_pdu *pdu, unsigned char *&data, int &data_len)
+{
+ unsigned char *var_val;
+ int len;
+ struct variable_list *vp = 0;
+ oid objid[ASN_MAX_NAME_LEN], *op;
+ unsigned char type;
+
+ // get the vb list from received data
+ data = asn_parse_header(data, &data_len, &type);
+ if (data == NULL)
+ return SNMP_CLASS_ASN1ERROR;
+ if (type != ASN_SEQ_CON)
+ return SNMP_CLASS_ASN1ERROR;
+ pdu->variables = NULL;
+ while(data_len > 0) {
+ if (pdu->variables == NULL) {
+ pdu->variables = vp = (struct variable_list *)malloc(sizeof(struct variable_list));
+ } else {
+ vp->next_variable = (struct variable_list *)malloc(sizeof(struct variable_list));
+ vp = vp->next_variable;
+ }
+ vp->next_variable = NULL;
+ vp->val.string = NULL;
+ vp->name = NULL;
+ vp->name_length = ASN_MAX_NAME_LEN;
+ data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type,
+ &vp->val_len, &var_val, &data_len);
+ if (data == NULL)
+ return SNMP_CLASS_ASN1ERROR;
+ op = (oid *)malloc((unsigned)vp->name_length * sizeof(oid));
+
+ memcpy((char *)op, (char *)objid, vp->name_length * sizeof(oid));
+ vp->name = op;
+
+ len = MAX_SNMP_PACKET;
+ switch((short)vp->type) {
+ case ASN_INTEGER:
+ vp->val.integer = (long *)malloc(sizeof(long));
+ vp->val_len = sizeof(long);
+ asn_parse_int(var_val, &len, &vp->type, vp->val.integer);
+ break;
+
+ case SMI_COUNTER:
+ case SMI_GAUGE:
+ case SMI_TIMETICKS:
+ case SMI_UINTEGER:
+ vp->val.integer = (long *)malloc(sizeof(long));
+ vp->val_len = sizeof(long);
+ asn_parse_unsigned_int(var_val, &len, &vp->type, vp->val.integer);
+ break;
+
+ case SMI_COUNTER64:
+ vp->val.counter64 = (struct counter64 *)malloc(sizeof(struct counter64));
+ vp->val_len = sizeof(struct counter64);
+ asn_parse_unsigned_int64(var_val, &len, &vp->type,
+ vp->val.counter64);
+ break;
+
+ case ASN_OCTET_STR:
+ case SMI_IPADDRESS:
+ case SMI_OPAQUE:
+ case SMI_NSAP:
+ vp->val.string = (unsigned char *)malloc((unsigned)vp->val_len);
+ asn_parse_string(var_val, &len, &vp->type, vp->val.string, &vp->val_len);
+ break;
+
+ case ASN_OBJECT_ID:
+ vp->val_len = ASN_MAX_NAME_LEN;
+ asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
+ //vp->val_len *= sizeof(oid);
+ vp->val.objid = (oid *)malloc((unsigned)vp->val_len * sizeof(oid));
+
+ memcpy((char *)vp->val.objid,
+ (char *)objid,
+ vp->val_len * sizeof(oid));
+ break;
+
+ case SNMP_NOSUCHOBJECT:
+ case SNMP_NOSUCHINSTANCE:
+ case SNMP_ENDOFMIBVIEW:
+ case ASN_NULL:
+ break;
+
+ default:
+ ASNERROR("bad type returned ");
+ return SNMP_CLASS_ASN1ERROR;
+ }
+ }
+ return SNMP_CLASS_SUCCESS;
+}
+
+
+int snmp_parse_data_pdu(snmp_pdu *pdu, unsigned char *&data, int &length)
+{
+ oid objid[ASN_MAX_NAME_LEN];
+ int four = 4;
+ unsigned char type;
+
+ data = asn_parse_header(data, &length, &type);
+ if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+ pdu->command = type;
+
+ if (pdu->command != TRP_REQ_MSG)
+ {
+ // get the rid error status and error index
+ data = asn_parse_int(data, &length, &type, &pdu->reqid);
+ if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+ data = asn_parse_int(data, &length, &type, &pdu->errstat);
+ if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+ data = asn_parse_int(data, &length, &type, &pdu->errindex);
+ if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+ }
+ else
+ { // is a trap
+
+ // get the enterprise
+ pdu->enterprise_length = ASN_MAX_NAME_LEN;
+ data = asn_parse_objid(data, &length, &type,
+ objid, &pdu->enterprise_length);
+ if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+ pdu->enterprise = (oid *)malloc(pdu->enterprise_length * sizeof(oid));
+
+ memcpy((char *)pdu->enterprise,(char *)objid,
+ pdu->enterprise_length * sizeof(oid));
+
+ // get source address
+ data = asn_parse_string(data, &length, &type,
+ (unsigned char *)&pdu->agent_addr.sin_addr.s_addr,
+ &four);
+ if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+ // get trap type
+ long dummy = 0;
+ data = asn_parse_int(data, &length, &type, &dummy);
+ pdu->trap_type = dummy;
+
+ if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+ // trap specific type
+ dummy = 0;
+ data = asn_parse_int(data, &length, &type, &dummy);
+ pdu->specific_type = dummy;
+ if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+ // timestamp
+ data = asn_parse_unsigned_int(data, &length, &type, &pdu->time);
+ if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+ }
+ return SNMP_CLASS_SUCCESS;
+}
+
+
+// parse a pdu
+int snmp_parse(struct snmp_pdu *pdu,
+ unsigned char *data, int data_length,
+ unsigned char *community_name,
+ int &community_len,
+ snmp_version &spp_version)
+{
+ long version = -1;
+
+ // authenticates message and returns length if valid
+ data = snmp_auth_parse(data, &data_length,
+ community_name, &community_len,
+ &version);
+ if (data == NULL)
+ return SNMP_CLASS_ASN1ERROR;
+
+ if(version != SNMP_VERSION_1 && version != SNMP_VERSION_2C) {
+ ASNERROR("Wrong version");
+ return SNMP_CLASS_BADVERSION;
+ }
+
+ spp_version = (snmp_version) version;
+
+ int res = snmp_parse_data_pdu(pdu, data, data_length);
+ if (res != SNMP_CLASS_SUCCESS)
+ return res;
+
+ return snmp_parse_vb(pdu, data, data_length);
+}
+
+
+#ifdef _SNMPv3
+// Parse the field HeaderData of a SNMPv3 message and return the values.
+unsigned char *asn1_parse_header_data(unsigned char *buf, int *buf_len,
+ long *msg_id, long *msg_max_size,
+ unsigned char *msg_flags,
+ long *msg_security_model)
+{
+ unsigned char *buf_ptr = buf;
+ int length = *buf_len;
+ unsigned char type;
+
+ buf = asn_parse_header(buf, &length, &type);
+ if (!buf)
+ {
+ debugprintf(0, "Parse error in header HeaderData");
+ return 0;
+ }
+
+ if (type != ASN_SEQ_CON) {
+ debugprintf(0, "wrong type in header of msgHeaderData");
+ return 0;
+ }
+
+ buf = asn_parse_int(buf, &length, &type, msg_id);
+ if (!buf) {
+ debugprintf(0, "Parse error: msg_id");
+ return 0;
+ }
+
+ buf = asn_parse_int(buf, &length, &type, msg_max_size);
+ if (!buf) {
+ debugprintf(0, "Parse error: msg_max_size");
+ return 0;
+ }
+
+ int dummy = 1;
+ buf = asn_parse_string(buf, &length, &type, msg_flags, &dummy);
+
+ if ((dummy !=1) || (!buf)) {
+ debugprintf(0, "Parse error: msg_flags");
+ return 0;
+ }
+
+ buf = asn_parse_int(buf, &length, &type, msg_security_model);
+ if (!buf) {
+ debugprintf(0, "Parse error: msg_security_model");
+ return 0;
+ }
+
+ if (length) {
+ debugprintf(0, "Parse error: wrong length in header of HeaderData");
+ return 0;
+ }
+
+ debugprintf(3, "Parsed HeaderData: globalDataLength(0x%x), msg_id(%ld), "
+ "msg_max_size(0x%lx), msg_flags(0x%x), msg_security_model(0x%lx)",
+ length, *msg_id, *msg_max_size, *msg_flags, *msg_security_model);
+
+ *buf_len -= SAFE_INT_CAST(buf - buf_ptr);
+ return buf;
+}
+
+// Encode the given values for the HeaderData into the buffer.
+unsigned char *asn1_build_header_data(unsigned char *outBuf, int *maxLength,
+ long msgID,
+ long maxMessageSize,
+ unsigned char msgFlags,
+ long securityModel)
+
+{
+ unsigned char buf[MAXLENGTH_GLOBALDATA];
+ unsigned char *bufPtr = (unsigned char*)&buf;
+ unsigned char *outBufPtr = outBuf;
+ int length = *maxLength;
+ int totalLength;
+
+#ifdef INVALID_MAXMSGSIZE
+ debugprintf(-10, "\nWARNING: Using constant MaxMessageSize!\n");
+ maxMessageSize = 65535;
+#endif
+
+ debugprintf(3, "Coding msgID(%ld), maxMessageSize(0x%lx), "
+ "msgFlags(0x%x), securityModel(0x%lx)",
+ msgID, maxMessageSize, msgFlags, securityModel);
+
+ bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER, &msgID);
+ if (bufPtr == NULL) {
+ debugprintf(0, "asn_build_header_data: Error coding msgID");
+ return NULL;
+ }
+ bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
+ &maxMessageSize);
+ if (bufPtr == NULL) {
+ debugprintf(0, "asn_build_header_data: Error coding maxMessageSize");
+ return NULL;
+ }
+
+ bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
+ &msgFlags, 1);
+ if (bufPtr == NULL) {
+ debugprintf(0, "asn_build_header_data: Error coding msgFlags");
+ return NULL;
+ }
+
+ bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
+ &securityModel);
+ if (bufPtr == NULL) {
+ debugprintf(0, "asn_build_header_data: Error coding securityModel");
+ return NULL;
+ }
+
+ totalLength = SAFE_INT_CAST(bufPtr - (unsigned char*)&buf);
+
+ debugprintf(3, "Coding sequence (headerdata), length = 0x%x", totalLength);
+ outBufPtr = asn_build_sequence(outBufPtr, maxLength, ASN_SEQ_CON,
+ totalLength);
+
+ if (outBufPtr == NULL) {
+ debugprintf(0, "asn_build_header_data: Error coding seq headerdata");
+ return NULL;
+ }
+
+ if (*maxLength < totalLength) {
+ debugprintf(0, "asn_build_header_data: Length error");
+ return NULL;
+ }
+
+ memcpy(outBufPtr, (unsigned char*)&buf, totalLength);
+ outBufPtr += totalLength;
+ *maxLength -= totalLength;
+
+ debugprintf(21, "bufHeaderData:");
+ debughexprintf(21, outBuf, SAFE_INT_CAST(outBufPtr - outBuf));
+
+ return outBufPtr;
+}
+#endif
+
+// Parse the ScopedPDU and return the encoded values.
+unsigned char *asn1_parse_scoped_pdu(
+ unsigned char *scoped_pdu, int *scoped_pdu_len,
+ unsigned char *context_engine_id, int *context_engine_id_len,
+ unsigned char *context_name, int *context_name_len)
+{
+ unsigned char type;
+
+ scoped_pdu = asn_parse_header(scoped_pdu, scoped_pdu_len, &type);
+ if (!scoped_pdu) {
+ debugprintf(0, "Parse error: Wrong header in scoped_pdu.");
+ return 0;
+ }
+
+ if (type != ASN_SEQ_CON) {
+ debugprintf(0, "Parse error: Wrong header type in scoped_pdu.");
+ return 0;
+ }
+
+ scoped_pdu = asn_parse_string(scoped_pdu, scoped_pdu_len, &type,
+ context_engine_id, context_engine_id_len);
+ if (!scoped_pdu) {
+ debugprintf(0, "Parse error: context_engine_id");
+ return 0;
+ }
+
+ scoped_pdu = asn_parse_string(scoped_pdu, scoped_pdu_len, &type,
+ context_name, context_name_len);
+ if (!scoped_pdu) {
+ debugprintf(0, "mpParseScopedPDU: bad parse of context_name");
+ return 0;
+ }
+
+ debugprintf(3, "Parsed scoped_pdu: context_engine_id length(0x%x), "
+ "context_name length(0x%x)",
+ *context_engine_id_len, *context_name_len);
+
+ return scoped_pdu;
+}
+
+// Encode the given values for the scopedPDU into the buffer.
+unsigned char *asn1_build_scoped_pdu(
+ unsigned char *outBuf, int *max_len,
+ unsigned char *contextEngineID, long contextEngineIDLength,
+ unsigned char *contextName, long contextNameLength,
+ unsigned char *data, long dataLength)
+{
+ Buffer<unsigned char> buffer(MAX_SNMP_PACKET);
+ unsigned char *bufPtr = buffer.get_ptr();
+ unsigned char *outBufPtr = outBuf;
+
+ LOG_BEGIN(DEBUG_LOG | 10);
+ LOG("ASN1: coding (context engine id) (context name)");
+ LOG(OctetStr(contextEngineID, contextEngineIDLength).get_printable());
+ LOG(OctetStr(contextName, contextNameLength).get_printable());
+ LOG_END;
+
+ bufPtr = asn_build_string(bufPtr, max_len, ASN_UNI_PRIM | ASN_OCTET_STR,
+ contextEngineID, contextEngineIDLength);
+ if (!bufPtr)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("ASN1: Error encoding contextEngineID");
+ LOG_END;
+
+ return 0;
+ }
+
+ bufPtr = asn_build_string(bufPtr, max_len, ASN_UNI_PRIM | ASN_OCTET_STR,
+ contextName, contextNameLength);
+ if (!bufPtr)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("ASN1: Error encoding contextName");
+ LOG_END;
+
+ return 0;
+ }
+
+ long bufLength = SAFE_INT_CAST(bufPtr - buffer.get_ptr());
+
+ memcpy((char *)bufPtr, (char *)data, dataLength);
+ bufLength += dataLength;
+
+ LOG_BEGIN(DEBUG_LOG | 10);
+ LOG("ASN1: Encoding scoped PDU sequence (len)");
+ LOG(bufLength);
+ LOG_END;
+
+ outBufPtr = asn_build_sequence(outBufPtr, max_len, ASN_SEQ_CON, bufLength);
+ if (!outBufPtr)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("ASN1: Error encoding scopedPDU sequence");
+ LOG_END;
+
+ return 0;
+ }
+
+ memcpy(outBufPtr, buffer.get_ptr(), bufLength);
+ outBufPtr += bufLength;
+
+#ifdef __DEBUG
+ LOG_BEGIN(DEBUG_LOG | 15);
+ LOG("ASN1: Result of build_scoped_pdu (len) (data)");
+ LOG(outBufPtr - outBuf);
+ LOG(OctetStr(outBuf, outBufPtr - outBuf).get_printable_hex());
+ LOG_END;
+#endif
+
+ return outBufPtr;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## auth_priv.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+char auth_priv_version[]="@(#) SNMP++ $Id: auth_priv.cpp 1799 2010-08-14 20:11:45Z katz $";
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+// Only use DES, AES, SHA1 and MD5 from libtomcrypt if openssl is not used
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+#include <tomcrypt.h>
+#endif
+
+// Use DES, AES, SHA and MD5 from openssl
+#ifdef _USE_OPENSSL
+#include <openssl/des.h>
+#include <openssl/aes.h>
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+#endif
+
+// Use internal functions for SHA and MD5 and libdes only
+// if not using libtomcrypt and openssl
+#if !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+#include "snmp_pp/sha.h"
+#ifdef RSAEURO
+#include <rsaeuro.h>
+#else
+#include <des.h>
+#include "snmp_pp/md5.h"
+#endif
+#endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
+// IDEA can only be used with a valid license
+#ifdef _USE_IDEA
+#include "snmp_pp/idea.h"
+#endif
+
+#include "snmp_pp/auth_priv.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/snmperrs.h"
+#include "snmp_pp/address.h"
+#include "snmp_pp/log.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+/*-----------------[ defines for crypto libraries ]------------------*/
+
+#ifdef _USE_OPENSSL
+
+/* -- START: Defines for OpenSSL -- */
+typedef SHA_CTX SHAHashStateType;
+#define SHA1_INIT(s) SHA1_Init(s)
+#define SHA1_PROCESS(s, p, l) SHA1_Update(s, p, l)
+#define SHA1_DONE(s, k) SHA1_Final(k, s)
+
+typedef MD5_CTX MD5HashStateType;
+#define MD5_INIT(s) MD5_Init(s)
+#define MD5_PROCESS(s, p, l) MD5_Update(s, p, l)
+#define MD5_DONE(s, k) MD5_Final(k, s)
+
+typedef des_key_schedule DESCBCType;
+#define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
+ if (des_key_sched((C_Block*)(k), s) < 0) \
+ { \
+ debugprintf(0, "Starting DES encryption failed."); \
+ return SNMPv3_USM_ERROR; \
+ }
+#define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
+ if (des_key_sched((C_Block*)(k), s) < 0) \
+ { \
+ debugprintf(0, "Starting DES decryption failed."); \
+ return SNMPv3_USM_ERROR; \
+ }
+
+#define DES_CBC_ENCRYPT(pt, ct, s, iv, l) \
+ des_ncbc_encrypt(pt, ct, l, \
+ s, (C_Block*)(iv), DES_ENCRYPT)
+#define DES_CBC_DECRYPT(ct, pt, s, iv, l) \
+ des_ncbc_encrypt(ct, pt, l, \
+ s, (C_Block*)(iv), DES_DECRYPT)
+
+#define DES_EDE3_CBC_ENCRYPT(pt, ct, l, k1, k2, k3, iv) \
+ des_ede3_cbc_encrypt(pt, ct, l, \
+ k1, k2, k3, (C_Block*)(iv), DES_ENCRYPT)
+
+#define DES_EDE3_CBC_DECRYPT(ct, pt, l, k1, k2, k3, iv) \
+ des_ede3_cbc_encrypt(ct, pt, l, \
+ k1, k2, k3, (C_Block*)(iv), DES_DECRYPT)
+
+#define DES_MEMSET(s, c, l) memset(&(s), c, l)
+
+/* -- END: Defines for OpenSSL -- */
+
+#else
+
+#ifdef _USE_LIBTOMCRYPT
+
+/* -- START: Defines for LibTomCrypt -- */
+typedef hash_state SHAHashStateType;
+#define SHA1_INIT(s) sha1_init(s)
+#define SHA1_PROCESS(s, p, l) sha1_process(s, p, l)
+#define SHA1_DONE(s, k) sha1_done(s, k)
+
+typedef hash_state MD5HashStateType;
+#define MD5_INIT(s) md5_init(s)
+#define MD5_PROCESS(s, p, l) md5_process(s, p, l)
+#define MD5_DONE(s, k) md5_done(s, k)
+
+typedef symmetric_CBC DESCBCType;
+#define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
+ if (cbc_start(c, iv, k, kl, r, &(s)) != CRYPT_OK) \
+ { \
+ debugprintf(0, "Starting DES encryption failed."); \
+ return SNMPv3_USM_ERROR; \
+ }
+
+#define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
+ if (cbc_start(c, iv, k, kl, r, &(s)) != CRYPT_OK) \
+ { \
+ debugprintf(0, "Starting DES decryption failed."); \
+ return SNMPv3_USM_ERROR; \
+ }
+
+#define DES_CBC_ENCRYPT(pt, ct, s, iv, l) \
+ if (cbc_encrypt(pt, ct, l, &(s)) != CRYPT_OK) \
+ { \
+ debugprintf(0, "Error during DES encryption."); \
+ return SNMPv3_USM_ERROR; \
+ }
+#define DES_CBC_DECRYPT(ct, pt, s, iv, l) \
+ if (cbc_decrypt(ct, pt, l, &(s)) != CRYPT_OK) \
+ { \
+ debugprintf(0, "Error during DES decryption."); \
+ return SNMPv3_USM_ERROR; \
+ }
+#define DES_MEMSET(s, c, l) memset(&(s), c, l)
+/* -- END: Defines for LibTomCrypt -- */
+
+#else // _USE_LIBTOMCRYPT --> libdes
+
+/* -- START: Defines for libdes -- */
+
+typedef SHA_CTX SHAHashStateType;
+#define SHA1_INIT(s) SHAInit(s)
+#define SHA1_PROCESS(s, p, l) SHAUpdate(s, p, l)
+#define SHA1_DONE(s, k) SHAFinal(k, s)
+
+typedef MD5_CTX MD5HashStateType;
+#define MD5_INIT(s) MD5Init(s)
+#define MD5_PROCESS(s, p, l) MD5Update(s, p, l)
+#define MD5_DONE(s, k) MD5Final(k, s)
+
+#define DES_EDE3_CBC_ENCRYPT(pt, ct, l, k1, k2, k3, iv) \
+ des_ede3_cbc_encrypt((C_Block*)(pt), (C_Block*)(ct), l, \
+ k1, k2, k3, (C_Block*)(iv), DES_ENCRYPT)
+
+#define DES_EDE3_CBC_DECRYPT(ct, pt, l, k1, k2, k3, iv) \
+ des_ede3_cbc_encrypt((C_Block*)(ct), (C_Block*)(pt), l, \
+ k1, k2, k3, (C_Block*)(iv), DES_DECRYPT)
+
+#ifdef RSAEURO
+
+#undef MD5_PROCESS
+#define MD5_PROCESS(s, p, l) MD5Update(s, (unsigned char*)(p), l)
+
+typedef DES_CBC_CTX DESCBCType;
+#define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
+ DES_CBCInit(&(s), (unsigned char*)(k), iv, 1)
+#define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
+ DES_CBCInit(&(s),(unsigned char*)(k), iv, 0)
+#define DES_CBC_ENCRYPT(pt, ct, s, iv, l) DES_CBCUpdate(&(s), pt, ct, l)
+#define DES_CBC_DECRYPT(ct, pt, s, iv, l) DES_CBCUpdate(&(s), (unsigned char*)(ct), pt, l)
+#define DES_MEMSET(s, c, l) R_memset((POINTER)&(s), c, l)
+
+#else // RSAEURO
+
+typedef des_key_schedule DESCBCType;
+#define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
+ if (des_key_sched((C_Block*)(k), s) < 0) \
+ { \
+ debugprintf(0, "Starting DES encryption failed."); \
+ return SNMPv3_USM_ERROR; \
+ }
+#define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
+ if (des_key_sched((C_Block*)(k), s) < 0) \
+ { \
+ debugprintf(0, "Starting DES decryption failed."); \
+ return SNMPv3_USM_ERROR; \
+ }
+
+#define DES_CBC_ENCRYPT(pt, ct, s, iv, l) \
+ des_ncbc_encrypt((C_Block*)(pt), (C_Block*)(ct), l, \
+ s, (C_Block*)(iv), DES_ENCRYPT)
+#define DES_CBC_DECRYPT(ct, pt, s, iv, l) \
+ des_ncbc_encrypt((C_Block*)(ct), (C_Block*)(pt), l, \
+ s, (C_Block*)(iv), DES_DECRYPT)
+#define DES_MEMSET(s, c, l) memset(&(s), c, l)
+
+/* -- END: Defines for libdes -- */
+
+#endif // RSAEURO
+
+#endif // _USE_LIBTOMCRYPT
+
+#endif // _USE_OPENSSL
+
+AuthPriv::AuthPriv(int &construct_state)
+{
+ auth = new AuthPtr[10];
+ priv = new PrivPtr[10];
+
+ if (auth)
+ auth_size = 10;
+ else
+ {
+ auth_size = 0;
+
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Error allocating array for authentication.");
+ LOG_END;
+ }
+
+ if (priv)
+ priv_size = 10;
+ else
+ {
+ priv_size = 0;
+
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Error allocating array for privacy.");
+ LOG_END;
+ }
+
+ for (int i = 0; i < auth_size; i++)
+ auth[i] = 0;
+
+ for (int j = 0; j < priv_size; j++)
+ priv[j] = 0;
+
+ /* Check size of salt, has to be 64 bits */
+ if (sizeof(salt) != 8)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: *BUG* sizeof(pp_uint64) is not 8 bytes. snmp++ has to be patched for this system.");
+ LOG_END;
+
+ construct_state = SNMPv3_USM_ERROR;
+ return;
+ }
+
+ /* Initialize salt. srand() has been already done in Snmp::init() */
+ unsigned int *rnd = (unsigned int*)(void *)&salt;
+ for (size_t i = 0; i < sizeof(salt); i += sizeof(unsigned int), rnd++)
+ {
+ *rnd = rand() << 1;
+ if (rand() < (RAND_MAX / 2))
+ *rnd += 1;
+ }
+
+ construct_state = SNMPv3_USM_OK;
+
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+ /* register needed hashes and ciphers in libtomcrypt */
+ if (register_cipher(&rijndael_desc) < 0)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Error registering Rijndael.");
+ LOG_END;
+
+ construct_state = SNMPv3_USM_ERROR;
+ }
+
+ if (register_cipher(&des_desc) < 0)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Error registering DES.");
+ LOG_END;
+
+ construct_state = SNMPv3_USM_ERROR;
+ }
+
+ if (register_cipher(&des3_desc) < 0)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Error registering 3DES.");
+ LOG_END;
+
+ construct_state = SNMPv3_USM_ERROR;
+ }
+
+ if (register_hash(&sha1_desc) < 0)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Error registering SHA1.");
+ LOG_END;
+
+ construct_state = SNMPv3_USM_ERROR;
+ }
+
+ if (register_hash(&md5_desc) < 0)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Error registering MD5.");
+ LOG_END;
+
+ construct_state = SNMPv3_USM_ERROR;
+ }
+#endif // defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+}
+
+AuthPriv::~AuthPriv()
+{
+ for (int i = 0; i < auth_size; i++)
+ if (auth[i])
+ {
+ delete auth[i];
+ auth[i] = 0;
+ }
+
+ for (int j = 0; j < priv_size; j++)
+ if (priv[j])
+ {
+ delete priv[j];
+ priv[j] = 0;
+ }
+
+ delete [] auth;
+ delete [] priv;
+}
+
+int AuthPriv::add_auth(Auth *new_auth)
+{
+ if (!new_auth)
+ {
+ return SNMP_CLASS_ERROR;
+ }
+
+ int id = new_auth->get_id();
+
+ if (id < 0)
+ {
+ return SNMP_CLASS_ERROR;
+ }
+
+ if (id >= auth_size)
+ {
+ AuthPtr *new_array = new AuthPtr[id + 5];
+ if (!new_array)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Could not allocate new auth array.");
+ LOG_END;
+
+ return SNMP_CLASS_ERROR;
+ }
+ for (int i=0 ; i<auth_size; i++)
+ new_array[i] = auth[i];
+
+ for (int j=auth_size ; j<id + 5; j++)
+ new_array[j] = 0;
+
+ AuthPtr *victim = auth;
+ auth = new_array;
+ delete [] victim;
+ auth_size = id + 5;
+ }
+
+ new_auth->set_salt(&salt);
+
+ if (auth[id])
+ {
+ LOG_BEGIN(WARNING_LOG | 4);
+ LOG("AuthPriv: deleting old auth object before adding new one (id)");
+ LOG(id);
+ LOG_END;
+
+ delete auth[id];
+ }
+
+ auth[id] = new_auth;
+
+ LOG_BEGIN(INFO_LOG | 6);
+ LOG("AuthPriv: Added auth protocol (id)");
+ LOG(id);
+ LOG_END;
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+int AuthPriv::del_auth(const int auth_id)
+{
+ if ((auth_id < 0) || (auth_id >= auth_size) || (auth[auth_id] == 0))
+ {
+ LOG_BEGIN(WARNING_LOG | 4);
+ LOG("AuthPriv: Request to delete non existing auth protocol (id)");
+ LOG(auth_id);
+ LOG_END;
+
+ return SNMP_CLASS_ERROR;
+ }
+
+ delete auth[auth_id];
+ auth[auth_id] = 0;
+
+ LOG_BEGIN(INFO_LOG | 6);
+ LOG("AuthPriv: Removed auth protocol (id)");
+ LOG(auth_id);
+ LOG_END;
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+
+int AuthPriv::add_priv(Priv *new_priv)
+{
+ if (!new_priv)
+ {
+ return SNMP_CLASS_ERROR;
+ }
+
+ int id = new_priv->get_id();
+
+ if (id < 0)
+ {
+ return SNMP_CLASS_ERROR;
+ }
+
+ if (id >= priv_size)
+ {
+ PrivPtr *new_array = new PrivPtr[id + 5];
+ if (!new_array)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Could not allocate new priv array.");
+ LOG_END;
+
+ return SNMP_CLASS_ERROR;
+ }
+ for (int i=0 ; i<priv_size; i++)
+ new_array[i] = priv[i];
+
+ for (int j=priv_size ; j<id + 5; j++)
+ new_array[j] = 0;
+
+ PrivPtr *victim = priv;
+ priv = new_array;
+ delete [] victim;
+ priv_size = id + 5;
+ }
+
+ new_priv->set_salt(&salt);
+
+ if (priv[id])
+ {
+ LOG_BEGIN(WARNING_LOG | 4);
+ LOG("AuthPriv: deleting old priv object before adding new one (id)");
+ LOG(id);
+ LOG_END;
+
+ delete priv[id];
+ }
+
+ priv[id] = new_priv;
+
+ LOG_BEGIN(INFO_LOG | 6);
+ LOG("AuthPriv: Added priv protocol (id)");
+ LOG(id);
+ LOG_END;
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+int AuthPriv::del_priv(const int priv_id)
+{
+ if ((priv_id < 0) || (priv_id >= priv_size) || (priv[priv_id] == 0))
+ {
+ LOG_BEGIN(WARNING_LOG | 4);
+ LOG("AuthPriv: Request to delete non existing priv protocol (id)");
+ LOG(priv_id);
+ LOG_END;
+
+ return SNMP_CLASS_ERROR;
+ }
+
+ delete priv[priv_id];
+ priv[priv_id] = 0;
+
+ LOG_BEGIN(INFO_LOG | 6);
+ LOG("AuthPriv: Removed priv protocol (id)");
+ LOG(priv_id);
+ LOG_END;
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+Auth *AuthPriv::get_auth(const int auth_prot)
+{
+ if ((auth_prot >= 0) && (auth_prot < auth_size))
+ return auth[auth_prot];
+ return 0;
+}
+
+Priv *AuthPriv::get_priv(const int priv_prot)
+{
+ if ((priv_prot >= 0) && (priv_prot < priv_size))
+ return priv[priv_prot];
+ return 0;
+}
+
+// Get the unique id for the given auth protocol.
+int AuthPriv::get_auth_id(const char *string_id) const
+{
+ for (int i = 0; i < auth_size; ++i)
+ if ((auth[i]) && (strcmp(string_id, auth[i]->get_id_string()) == 0))
+ return i;
+ return -1;
+}
+
+// Get the unique id for the given priv protocol.
+int AuthPriv::get_priv_id(const char *string_id) const
+{
+ for (int i = 0; i < priv_size; ++i)
+ if ((priv[i]) && (strcmp(string_id, priv[i]->get_id_string()) == 0))
+ return i;
+ return -1;
+}
+
+int AuthPriv::get_keychange_value(const int auth_prot,
+ const OctetStr& old_key,
+ const OctetStr& new_key,
+ OctetStr& keychange_value)
+{
+
+ // uses fixed key length determined from oldkey!
+ // works with SHA and MD5
+ // modifications needed to support variable length keys
+ // algorithm according to USM-document textual convention KeyChange
+
+ keychange_value.clear();
+ int key_len = old_key.len();
+
+ Auth *a = get_auth(auth_prot);
+
+ if (!a)
+ return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
+
+ // compute random value
+ OctetStr random = "";
+
+ for (int i=0; i<key_len; i++) {
+#ifdef _TEST
+ // do not use random values for testing
+ random += OctetStr((unsigned char*)"\0",1);
+#else
+ char tmprand = rand();
+ random += tmprand;
+#endif
+ }
+
+#ifdef __DEBUG
+ debugprintf(21, "Values for keyChange:");
+ debughexcprintf(21, "old_key", old_key.data(), old_key.len());
+ debughexcprintf(21, "new_key", new_key.data(), new_key.len());
+ debughexcprintf(21, "random value", random.data(), random.len());
+#endif
+
+ int iterations = (key_len - 1) / a->get_hash_len();
+ OctetStr tmp = old_key;
+ OctetStr delta;
+
+ for (int k = 0; k < iterations; k++)
+ {
+ unsigned char digest[SNMPv3_USM_MAX_KEY_LEN];
+ memset((char*)digest, 0, SNMPv3_USM_MAX_KEY_LEN);
+ tmp += random;
+ debughexcprintf(21, "loop tmp1", tmp.data(), tmp.len());
+ a->hash(tmp.data(), tmp.len(), digest);
+ tmp.set_data(digest, a->get_hash_len());
+ debughexcprintf(21, "loop tmp2", tmp.data(), tmp.len());
+ delta.set_len(delta.len() + a->get_hash_len());
+ for (int kk=0; kk < a->get_hash_len(); kk++)
+ delta[k * a->get_hash_len() + kk]
+ = tmp[kk] ^ new_key[k * a->get_hash_len() + kk];
+ debughexcprintf(21, "loop delta", delta.data(), delta.len());
+ }
+
+ unsigned char digest[SNMPv3_USM_MAX_KEY_LEN];
+ memset((char*)digest, 0, SNMPv3_USM_MAX_KEY_LEN);
+ tmp += random;
+ debughexcprintf(21, " tmp1", tmp.data(), tmp.len());
+ a->hash(tmp.data(), tmp.len(), digest);
+ tmp.set_data(digest, key_len - delta.len());
+ debughexcprintf(21, " tmp2", tmp.data(), tmp.len());
+ for (unsigned int j = 0; j < tmp.len(); j++)
+ tmp[j] = tmp[j] ^ new_key[iterations * a->get_hash_len() + j];
+ debughexcprintf(21, " tmp3", tmp.data(), tmp.len());
+
+ keychange_value = random;
+ keychange_value += delta;
+ keychange_value += tmp;
+
+#ifdef __DEBUG
+ debughexcprintf(21, "keychange_value",
+ keychange_value.data(), keychange_value.len());
+#endif
+
+ return SNMPv3_USM_OK;
+}
+
+int AuthPriv::password_to_key_auth(const int auth_prot,
+ const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len)
+{
+ if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
+ {
+ *key_len = 0;
+ return SNMPv3_USM_OK;
+ }
+
+ if (!password || (password_len == 0))
+ {
+ LOG_BEGIN(WARNING_LOG | 2);
+ LOG("AuthPriv: Password to key auth needs a non empty password");
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+ }
+
+ Auth *a = get_auth(auth_prot);
+
+ if (!a)
+ return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
+
+ int res = a->password_to_key(password, password_len,
+ engine_id, engine_id_len,
+ key, key_len);
+
+ return res;
+}
+
+
+int AuthPriv::password_to_key_priv(const int auth_prot,
+ const int priv_prot,
+ const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len)
+{
+ /* check for priv protocol */
+ if (priv_prot == SNMP_PRIVPROTOCOL_NONE)
+ {
+ *key_len = 0;
+ return SNMPv3_USM_OK;
+ }
+
+ if (!password || (password_len == 0))
+ {
+ LOG_BEGIN(WARNING_LOG | 2);
+ LOG("AuthPriv: Password to key priv needs a non empty password");
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+ }
+
+ Priv *p = get_priv(priv_prot);
+ Auth *a = get_auth(auth_prot);
+
+ if (!p) return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
+ if (!a) return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
+
+ unsigned int max_key_len = *key_len; /* save length of buffer! */
+ unsigned int min_key_len = p->get_min_key_len();
+
+ /* check if buffer for key is long enough */
+ if (min_key_len > max_key_len)
+ return SNMPv3_USM_ERROR; // TODO: better error code!
+
+ int res = password_to_key_auth(auth_prot,
+ password, password_len,
+ engine_id, engine_id_len,
+ key, key_len);
+ if (res != SNMPv3_USM_OK)
+ return res;
+
+ /* We have a too short key: Call priv protocoll to extend it */
+ if (*key_len < min_key_len)
+ {
+ res = p->extend_short_key(password, password_len,
+ engine_id, engine_id_len,
+ key, key_len, max_key_len, a);
+ if (res != SNMPv3_USM_OK)
+ return res;
+ }
+
+ /* make sure key length is valid */
+ p->fix_key_len(*key_len);
+
+ return SNMPv3_USM_OK;
+}
+
+
+
+
+int AuthPriv::encrypt_msg(const int priv_prot,
+ const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ unsigned char *privacy_params,
+ unsigned int *privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time)
+{
+ /* check for priv protocol */
+ Priv *p = get_priv(priv_prot);
+
+ if (!p)
+ return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
+
+ return p->encrypt(key, key_len, buffer, buffer_len,
+ out_buffer, out_buffer_len,
+ privacy_params, privacy_params_len,
+ engine_boots, engine_time);
+}
+
+int AuthPriv::decrypt_msg(const int priv_prot,
+ const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ const unsigned char *privacy_params,
+ const unsigned int privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time)
+{
+ /* check for priv protocol */
+ Priv *p = get_priv(priv_prot);
+
+ if (!p)
+ return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
+
+ return p->decrypt(key, key_len, buffer, buffer_len,
+ out_buffer, out_buffer_len,
+ privacy_params, privacy_params_len,
+ engine_boots, engine_time);
+}
+
+
+int AuthPriv::add_default_modules()
+{
+ int ret = SNMP_CLASS_SUCCESS;
+
+ if (add_auth(new AuthSHA()) != SNMP_ERROR_SUCCESS)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Could not add default protocol AuthSHA.");
+ LOG_END;
+
+ ret = SNMP_CLASS_ERROR;
+ }
+
+ if (add_auth(new AuthMD5()) != SNMP_ERROR_SUCCESS)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Could not add default protocol AuthMD5.");
+ LOG_END;
+
+ ret = SNMP_CLASS_ERROR;
+ }
+
+ if (add_priv(new PrivDES()) != SNMP_ERROR_SUCCESS)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Could not add default protocol PrivDES.");
+ LOG_END;
+
+ ret = SNMP_CLASS_ERROR;
+ }
+
+#ifdef _USE_IDEA
+ if (add_priv(new PrivIDEA()) != SNMP_ERROR_SUCCESS)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Could not add default protocol PrivIDEA.");
+ LOG_END;
+
+ ret = SNMP_CLASS_ERROR;
+ }
+#endif
+
+#if defined(_USE_LIBTOMCRYPT) || defined(_USE_OPENSSL)
+ if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES128)) != SNMP_ERROR_SUCCESS)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Could not add default protocol PrivAES 128.");
+ LOG_END;
+
+ ret = SNMP_CLASS_ERROR;
+ }
+
+ if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES192)) != SNMP_ERROR_SUCCESS)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Could not add default protocol PrivAES 192.");
+ LOG_END;
+
+ ret = SNMP_CLASS_ERROR;
+ }
+
+ if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES256)) != SNMP_ERROR_SUCCESS)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Could not add default protocol PrivAES 256.");
+ LOG_END;
+
+ ret = SNMP_CLASS_ERROR;
+ }
+#endif
+
+#ifdef _USE_3DES_EDE
+ if (add_priv(new Priv3DES_EDE()) != SNMP_ERROR_SUCCESS)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("AuthPriv: Could not add default protocol Priv3DES_EDE.");
+ LOG_END;
+
+ ret = SNMP_CLASS_ERROR;
+ }
+#endif
+
+
+ if (ret == SNMP_CLASS_SUCCESS)
+ {
+ LOG_BEGIN(INFO_LOG | 3);
+ LOG("AuthPriv: Added default Auth and Priv protocols.");
+ LOG_END;
+ }
+
+ return ret;
+}
+
+int AuthPriv::get_auth_params_len(const int auth_prot)
+{
+ Auth *a = get_auth(auth_prot);
+
+ if (!a)
+ return 0;
+
+ return a->get_auth_params_len();
+}
+
+int AuthPriv::get_priv_params_len(const int priv_prot)
+{
+ Priv *p = get_priv(priv_prot);
+
+ if (!p)
+ return 0;
+
+ return p->get_priv_params_len();
+}
+
+int AuthPriv::auth_out_msg(const int auth_prot,
+ const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr)
+{
+ if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
+ return SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
+
+ Auth *a = get_auth(auth_prot);
+
+ if (!a)
+ return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
+
+ return a->auth_out_msg(key, msg, msg_len, auth_par_ptr);
+}
+
+int AuthPriv::auth_inc_msg(const int auth_prot,
+ const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr,
+ const int auth_par_len)
+{
+ if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
+ return SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
+
+ Auth *a = get_auth(auth_prot);
+
+ if (!a)
+ return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
+
+ /* @todo check if auth par is inside msg
+ if ((auth_par_ptr < msg) ||
+ (msg + msg_len < auth_par_ptr + auth_par_len))
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("AuthPriv: Authentication data is not within message (msg start) (len) (auth start) (len)");
+ LOG(msg);
+ LOG(msg_len);
+ LOG(auth_par_ptr);
+ LOG(auth_par_len);
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+ }
+ */
+
+ return a->auth_inc_msg(key, msg, msg_len, auth_par_ptr, auth_par_len);
+}
+
+/* ========================================================== */
+
+/* ----------------------- AuthSHA ---------------------------------------*/
+
+int AuthSHA::password_to_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len)
+{
+ *key_len = 20; /* All SHA keys have 20 bytes length */
+
+#ifdef __DEBUG
+ debugprintf(5,"password_to_key SHA: password: (%s).",
+ OctetStr(password, password_len).get_printable());
+ debugprintf(5,"password_to_key SHA: engine_id: (%s).",
+ OctetStr(engine_id, engine_id_len).get_printable());
+#endif
+
+ SHAHashStateType sha_hash_state;
+ unsigned char *cp, password_buf[72];
+ unsigned long password_index = 0;
+ unsigned long count = 0, i;
+
+ SHA1_INIT(&sha_hash_state); /* initialize SHA */
+
+ /**********************************************/
+ /* Use while loop until we've done 1 Megabyte */
+ /**********************************************/
+ while (count < 1048576) {
+ cp = password_buf;
+ for (i = 0; i < 64; i++) {
+ /*************************************************/
+ /* Take the next octet of the password, wrapping */
+ /* to the beginning of the password as necessary.*/
+ /*************************************************/
+ *cp++ = password[password_index++ % password_len];
+ }
+
+ SHA1_PROCESS(&sha_hash_state, password_buf, 64);
+ count += 64;
+ }
+
+ SHA1_DONE(&sha_hash_state, key); /* tell SHA we're done */
+
+#ifdef __DEBUG
+ debughexcprintf(21, "key", key, *key_len);
+#endif
+
+ /*****************************************************/
+ /* Now localize the key with the engine_id and pass */
+ /* through SHA to produce final key */
+ /* May want to ensure that engine_id_len <= 32, */
+ /* otherwise need to use a buffer larger than 72 */
+ /*****************************************************/
+ memcpy(password_buf, key, *key_len);
+ memcpy(password_buf + *key_len, engine_id, engine_id_len);
+ memcpy(password_buf + *key_len + engine_id_len, key, *key_len);
+
+ SHA1_INIT(&sha_hash_state);
+ SHA1_PROCESS(&sha_hash_state, password_buf, (2 * *key_len) + engine_id_len);
+ SHA1_DONE(&sha_hash_state, key);
+
+#ifdef __DEBUG
+ debughexcprintf(21, "localized key", key, *key_len);
+#endif
+
+ return SNMPv3_USM_OK;
+}
+
+int AuthSHA::hash(const unsigned char *data,
+ const unsigned int data_len,
+ unsigned char *digest) const
+{
+ SHAHashStateType sha_hash_state;
+
+ SHA1_INIT(&sha_hash_state);
+ SHA1_PROCESS(&sha_hash_state, data, data_len);
+ SHA1_DONE(&sha_hash_state, digest);
+
+ return SNMPv3_USM_OK;
+}
+
+int AuthSHA::auth_out_msg(const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr)
+{
+ SHAHashStateType sha_hash_state;
+ int key_len = 20; /* We use only 20 Byte Key! */
+ unsigned char digest[20];
+ unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */
+ unsigned char k_opad[65]; /* outer padding - key XORd with opad */
+
+ memset((char*)(auth_par_ptr), 0, 12);
+
+#ifdef __DEBUG
+ debughexcprintf(21, "key", key, 16);
+#endif
+
+ /*
+ * the HMAC_SHA transform looks like:
+ *
+ * SHA(K XOR opad, SHA(K XOR ipad, msg))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing ipads and opads in pads */
+ memset( (char*)k_ipad, 0x36, sizeof k_ipad);
+ memset( (char*)k_opad, 0x5c, sizeof k_opad);
+
+ /* XOR pads with key */
+ for (int i=0; i < key_len; ++i) {
+ k_ipad[i] ^= key[i];
+ k_opad[i] ^= key[i];
+ }
+
+ /* perform inner SHA */
+ SHA1_INIT(&sha_hash_state); /* init sha_hash_state for 1st pass */
+ SHA1_PROCESS(&sha_hash_state, k_ipad, 64); /* start with inner pad */
+ SHA1_PROCESS(&sha_hash_state, msg, msg_len); /* then text of datagram */
+ SHA1_DONE(&sha_hash_state, digest); /* finish up 1st pass */
+ /* perform outer SHA */
+ SHA1_INIT(&sha_hash_state); /* init sha_hash_state for 2nd pass */
+ SHA1_PROCESS(&sha_hash_state, k_opad, 64); /* start with outer pad */
+ SHA1_PROCESS(&sha_hash_state, digest, 20); /* then results of 1st hash */
+ SHA1_DONE(&sha_hash_state, digest); /* finish up 2nd pass */
+
+#ifdef __DEBUG
+ debughexcprintf(21,"digest", digest, 160 / 8);
+#endif
+
+ memcpy(auth_par_ptr, digest, 12);
+
+ return SNMPv3_USM_OK;
+}
+
+
+int AuthSHA::auth_inc_msg(const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr,
+ const int auth_par_len)
+{
+ unsigned char receivedDigest[20];
+
+ if (auth_par_len != 12)
+ {
+ debugprintf(4, "SHA illegal digest length (%d), authentication FAILED.",
+ auth_par_len);
+ return SNMPv3_USM_AUTHENTICATION_FAILURE;
+ }
+
+#ifdef __DEBUG
+ debughexcprintf(21, "digest in Message", auth_par_ptr, 12);
+ debughexcprintf(21, "key", key, 20);
+#endif
+
+ /* Save received digest */
+ memcpy(receivedDigest, auth_par_ptr, 12);
+
+ if (SNMPv3_USM_OK != auth_out_msg(key, msg, msg_len, auth_par_ptr))
+ {
+ /* copy digest back into message and return error */
+ memcpy(auth_par_ptr, receivedDigest, 12);
+ debugprintf(4, "SHA authentication FAILED (1).");
+ return SNMPv3_USM_AUTHENTICATION_FAILURE;
+ }
+
+ /* compare digest to received digest */
+ for (int i=0; i < 12 ; ++i)
+ {
+ if (auth_par_ptr[i] != receivedDigest[i])
+ {
+ /* copy digest back into message and return error */
+ memcpy(auth_par_ptr, receivedDigest, 12);
+ debugprintf(4, "SHA authentication FAILED.");
+ return SNMPv3_USM_AUTHENTICATION_FAILURE;
+ }
+ }
+ debugprintf(4, "SHA authentication OK.");
+ return SNMPv3_USM_OK;
+}
+
+
+/* ----------------------- AuthMD5 ---------------------------------------*/
+
+int AuthMD5::password_to_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len)
+{
+ *key_len = 16; /* All MD5 keys have 16 bytes length */
+
+#ifdef __DEBUG
+ debugprintf(5,"password: %s.",
+ OctetStr(password, password_len).get_printable());
+ debugprintf(5,"engineID: %s.",
+ OctetStr(engine_id, engine_id_len).get_printable());
+#endif
+
+ MD5HashStateType md5_hash_state;
+ unsigned char *cp, password_buf[65];
+ unsigned long password_index = 0;
+ unsigned long count = 0, i;
+
+ MD5_INIT(&md5_hash_state); /* initialize MD5 */
+
+ /**********************************************/
+ /* Use while loop until we've done 1 Megabyte */
+ /**********************************************/
+ while (count < 1048576) {
+ cp = password_buf;
+ for (i = 0; i < 64; i++) {
+ /*************************************************/
+ /* Take the next octet of the password, wrapping */
+ /* to the beginning of the password as necessary.*/
+ /*************************************************/
+ *cp++ = password[password_index++ % password_len];
+ }
+ MD5_PROCESS(&md5_hash_state, password_buf, 64);
+ count += 64;
+ }
+ MD5_DONE(&md5_hash_state, key); /* tell MD5 we're done */
+
+#ifdef __DEBUG
+ debughexcprintf(21, "key", key, *key_len);
+#endif
+
+ /*****************************************************/
+ /* Now localize the key with the engine_id and pass */
+ /* through MD5 to produce final key */
+ /* May want to ensure that engine_id_len <= 32, */
+ /* otherwise need to use a buffer larger than 64 */
+ /*****************************************************/
+ memcpy(password_buf, key, *key_len);
+ memcpy(password_buf + *key_len, engine_id, engine_id_len);
+ memcpy(password_buf + *key_len + engine_id_len, key, *key_len);
+
+ MD5_INIT(&md5_hash_state);
+ MD5_PROCESS(&md5_hash_state, password_buf, (2 * *key_len) + engine_id_len);
+ MD5_DONE(&md5_hash_state, key);
+
+#ifdef __DEBUG
+ debughexcprintf(21, "localized key", key, *key_len);
+#endif
+
+ return SNMPv3_USM_OK;
+}
+
+int AuthMD5::hash(const unsigned char *data,
+ const unsigned int data_len,
+ unsigned char *digest) const
+{
+ MD5HashStateType md5_hash_state;
+
+ MD5_INIT(&md5_hash_state);
+ MD5_PROCESS(&md5_hash_state, data, data_len);
+ MD5_DONE(&md5_hash_state, digest);
+
+ return SNMPv3_USM_OK;
+}
+
+int AuthMD5::auth_out_msg(const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr)
+{
+ MD5HashStateType md5_hash_state;
+ int key_len = 16; /* We use only 16 Byte Key! */
+ unsigned char digest[16];
+ unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */
+ unsigned char k_opad[65]; /* outer padding - key XORd with opad */
+
+ memset((char*)(auth_par_ptr), 0, 12);
+
+#ifdef __DEBUG
+ debughexcprintf(21, "key", key, 16);
+#endif
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, msg))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ memset( (char*)k_ipad, 0, sizeof k_ipad);
+ memset( (char*)k_opad, 0, sizeof k_opad);
+ memcpy( (char*)k_ipad, (char*)key, key_len);
+ memcpy( (char*)k_opad, (char*)key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (int i=0; i<64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ /* perform inner MD5 */
+ MD5_INIT(&md5_hash_state); /* init md5_hash_state for 1st pass */
+ MD5_PROCESS(&md5_hash_state, k_ipad, 64); /* start with inner pad */
+ MD5_PROCESS(&md5_hash_state, msg, msg_len); /* then text of datagram */
+ MD5_DONE(&md5_hash_state, digest); /* finish up 1st pass */
+ /* perform outer MD5 */
+ MD5_INIT(&md5_hash_state); /* init md5_hash_state for 2nd pass */
+ MD5_PROCESS(&md5_hash_state, k_opad, 64); /* start with outer pad */
+ MD5_PROCESS(&md5_hash_state, digest, 16); /* then results of 1st hash */
+ MD5_DONE(&md5_hash_state, digest); /* finish up 2nd pass */
+
+#ifdef __DEBUG
+ debughexcprintf(21, "digest", digest, 128 / 8);
+#endif
+
+ memcpy(auth_par_ptr, digest, 12);
+
+ return SNMPv3_USM_OK;
+}
+
+int AuthMD5::auth_inc_msg(const unsigned char *key,
+ unsigned char *msg,
+ const int msg_len,
+ unsigned char *auth_par_ptr,
+ const int auth_par_len)
+{
+ unsigned char receivedDigest[16];
+
+ if (auth_par_len != 12)
+ {
+ debugprintf(4, "MD5 illegal digest length (%d), authentication FAILED.",
+ auth_par_len);
+ return SNMPv3_USM_AUTHENTICATION_FAILURE;
+ }
+
+#ifdef __DEBUG
+ debughexcprintf(21, "digest in Message", auth_par_ptr, 12);
+ debughexcprintf(21, "key", key, 16);
+#endif
+
+ memcpy(receivedDigest, auth_par_ptr, 12);
+
+ if (SNMPv3_USM_OK != auth_out_msg(key, msg, msg_len, auth_par_ptr))
+ {
+ /* copy digest back into message and return error */
+ memcpy(auth_par_ptr, receivedDigest, 12);
+ debugprintf(4, "MD5 authentication FAILED (1).");
+ return SNMPv3_USM_AUTHENTICATION_FAILURE;
+ }
+
+ /* compare digest to received digest */
+ for (int i=0; i < 12 ; ++i)
+ {
+ if (auth_par_ptr[i] != receivedDigest[i])
+ {
+ /* copy digest back into message and return error */
+ memcpy(auth_par_ptr, receivedDigest, 12);
+ debugprintf(4, "MD5 authentication FAILED.");
+ return SNMPv3_USM_AUTHENTICATION_FAILURE;
+ }
+ }
+ debugprintf(4, "MD5 authentication OK.");
+ return SNMPv3_USM_OK;
+}
+
+/* ========================= PRIV ================================*/
+
+/* ----------------------- PrivDES ---------------------------------------*/
+
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+PrivDES::PrivDES()
+{
+ cipher = find_cipher("des");
+}
+#endif
+
+int PrivDES::encrypt(const unsigned char *key,
+ const unsigned int /*key_len*/,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ unsigned char *privacy_params,
+ unsigned int *privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long /*engine_time*/)
+{
+ unsigned char initVect[8];
+ pp_uint64 my_salt = (*salt)++;
+
+#ifdef INVALID_ENCRYPTION
+ debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
+ my_salt = 0;
+#endif
+
+ /* check space in privacy_params buffer */
+ if (*privacy_params_len < 8)
+ {
+ debugprintf(4, "Buffer too small: should be 8, is (%i).",
+ *privacy_params_len);
+ return SNMPv3_USM_ENCRYPTION_ERROR;
+ }
+ /* Length is always 8 */
+ *privacy_params_len = 8;
+
+ // last 8 bytes of key are used as base for initialization vector
+ memcpy((char*)initVect, key+8, 8);
+
+ // put salt in privacy_params
+ for (int j=0; j<4; j++)
+ {
+ privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
+ privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
+ }
+
+ // xor initVect with salt
+ for (int i=0; i<8; i++)
+ initVect[i] ^= privacy_params[i];
+
+#ifdef __DEBUG
+ debughexcprintf(21, "apDESEncryptData: Data to encrypt",
+ buffer, buffer_len);
+ debughexcprintf(21, "apDESEncryptData: used key (only 8 bytes used)",
+ key, 16);
+ debughexcprintf(21, "apDESEncryptData: used iv",
+ initVect, 8);
+#endif
+
+ DESCBCType symcbc;
+ DES_CBC_START_ENCRYPT(cipher, initVect, key, 8, 16, symcbc);
+
+ for(unsigned int k = 0; k <= buffer_len - 8; k += 8) {
+ DES_CBC_ENCRYPT(buffer + k, out_buffer + k, symcbc, initVect, 8);
+ }
+
+ /* last part of buffer */
+ if (buffer_len % 8)
+ {
+ unsigned char tmp_buf[8];
+ unsigned char *tmp_buf_ptr = tmp_buf;
+ int start = buffer_len - (buffer_len % 8);
+ memset(tmp_buf, 0, 8);
+ for (unsigned int l = start; l < buffer_len; l++)
+ *tmp_buf_ptr++ = buffer[l];
+ DES_CBC_ENCRYPT(tmp_buf, out_buffer + start, symcbc, initVect, 8);
+ *out_buffer_len = buffer_len + 8 - (buffer_len % 8);
+ }
+ else
+ *out_buffer_len = buffer_len;
+
+ /* Clear context buffer (paranoia!)*/
+ DES_MEMSET(symcbc, 0, sizeof(symcbc));
+
+#ifdef __DEBUG
+ debughexcprintf(21, "apDESEncryptData: created privacy_params",
+ privacy_params, 8);
+ debughexcprintf(21, "apDESEncryptData: encrypted Data",
+ out_buffer, *out_buffer_len);
+#endif
+
+ return SNMPv3_USM_OK;
+}
+
+
+
+int PrivDES::decrypt(const unsigned char *key,
+ const unsigned int /*key_len*/,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *outBuffer,
+ unsigned int *outBuffer_len,
+ const unsigned char *privacy_params,
+ const unsigned int privacy_params_len,
+ const unsigned long /*engine_boots*/,
+ const unsigned long /*engine_time*/)
+{
+ unsigned char initVect[8];
+
+ /* Privacy params length has to be 8 && Length has to be a multiple of 8 */
+ if (( buffer_len % 8 ) || (privacy_params_len != 8))
+ return SNMPv3_USM_DECRYPTION_ERROR;
+
+ for (int i=0; i<8; i++)
+ initVect[i] = privacy_params[i] ^ key[i+8];
+
+ memset((char*)outBuffer, 0, *outBuffer_len);
+
+#ifdef __DEBUG
+ debughexcprintf(21, "apDESDecryptData: Data to decrypt",
+ buffer, buffer_len);
+ debughexcprintf(21, "apDESDecryptData: used key (only 8 bytes used)",
+ key, 16);
+ debughexcprintf(21, "apDESDecryptData: used privacy_params",
+ privacy_params, 8);
+ debughexcprintf(21, "apDESDecryptData: used iv",
+ initVect, 8);
+#endif
+
+ DESCBCType symcbc;
+ DES_CBC_START_DECRYPT(cipher, initVect, key, 8, 16, symcbc);
+ for(unsigned int j=0; j<buffer_len; j+=8 ) {
+ DES_CBC_DECRYPT(buffer + j, outBuffer + j, symcbc, initVect, 8);
+ }
+ /* Clear context (paranoia!) */
+ DES_MEMSET(symcbc, 0, sizeof(symcbc));
+
+ *outBuffer_len = buffer_len;
+
+#ifdef __DEBUG
+ debughexcprintf(21, "apDESDecryptData: decrypted Data",
+ outBuffer, *outBuffer_len);
+#endif
+
+ return SNMPv3_USM_OK;
+}
+
+
+/* ----------------------- PrivIDEA --------------------------------------*/
+
+#ifdef _USE_IDEA
+
+int PrivIDEA::encrypt(const unsigned char *key,
+ const unsigned int /*key_len*/,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ unsigned char *privacy_params,
+ unsigned int *privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long /*engine_time*/)
+{
+ IDEAContext CFB_Context;
+ pp_uint64 my_salt = (*salt)++;
+
+#ifdef INVALID_ENCRYPTION
+ debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
+ my_salt = 0;
+#endif
+
+ /* check space in privacy_params buffer */
+ if (*privacy_params_len < 8)
+ {
+ debugprintf(4, "Buffer too small: should be 8, is (%i).", *privacy_params_len);
+ return SNMPv3_USM_ENCRYPTION_ERROR;
+ }
+ /* Length is always 8 */
+ *privacy_params_len = 8;
+
+ // last 8 bytes of key are used as base for initialization vector
+ unsigned char iv[8];
+
+ memcpy((char*)iv, key+8, 8);
+
+ // put salt in privacy_params
+ for (int j=0; j<4; j++)
+ {
+ privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
+ privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
+ }
+ // xor iv with privacy_params
+ for (int i=0; i<8; i++)
+ iv[i] ^= privacy_params[i];
+
+ idea_set_key(&CFB_Context, key);
+
+ idea_cfb_encrypt(&CFB_Context, iv, out_buffer,
+ buffer, buffer_len);
+
+ /* Clear context (paranoia!) */
+ idea_destroy_context(&CFB_Context);
+
+ *out_buffer_len = buffer_len;
+
+#ifdef __DEBUG
+ debughexcprintf(21, "apIDEAEncryptData: Data to encrypt",
+ buffer, buffer_len);
+ debughexcprintf(21, "apIDEAEncryptData: key",
+ key, 16);
+ debughexcprintf(21, "apIDEAEncryptData: privacy_params",
+ privacy_params, 8);
+ debughexcprintf(21, "apIDEAEncryptData: encrypted Data",
+ out_buffer, *out_buffer_len);
+#endif
+
+ return SNMPv3_USM_OK;
+}
+
+int PrivIDEA::decrypt(const unsigned char *key,
+ const unsigned int /*key_len*/,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ const unsigned char *privacy_params,
+ const unsigned int privacy_params_len,
+ const unsigned long /*engine_boots*/,
+ const unsigned long /*engine_time*/)
+{
+ unsigned char iv[8];
+ IDEAContext CFB_Context;
+
+ /* privacy params length has to be 8 */
+ if (privacy_params_len != 8)
+ return SNMPv3_USM_DECRYPTION_ERROR;
+
+ idea_set_key(&CFB_Context, key);
+
+ memset((char*)out_buffer, 0, *out_buffer_len);
+
+ /* Initialize iv with last 8 bytes of key and xor with privacy_params */
+ memcpy((char*)iv, key+8, 8);
+ for (int i=0; i<8; i++)
+ iv[i] ^= privacy_params[i];
+
+ idea_cfb_decrypt(&CFB_Context, iv, out_buffer,
+ buffer, buffer_len);
+
+ /* Clear context (paranoia!) */
+ idea_destroy_context(&CFB_Context);
+ memset((char*)iv, 0, 8);
+
+ *out_buffer_len = buffer_len;
+
+#ifdef __DEBUG
+ debughexcprintf(21, "apIDEADecryptData: Data to decrypt",
+ buffer, buffer_len);
+ debughexcprintf(21, "apIDEADecryptData: key", key, 16);
+ debughexcprintf(21, "apIDEAEncryptData: privacy_params", privacy_params, 8);
+ debughexcprintf(21, "apIDEADecryptData: decrypted Data",
+ out_buffer, *out_buffer_len);
+#endif
+
+ return SNMPv3_USM_OK;
+}
+
+#endif // _USE_IDEA
+
+#if defined(_USE_LIBTOMCRYPT) || defined(_USE_OPENSSL)
+
+PrivAES::PrivAES(const int aes_type_)
+ : aes_type(aes_type_)
+{
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+ cipher = find_cipher("rijndael");
+#endif
+
+ switch (aes_type)
+ {
+ case SNMP_PRIVPROTOCOL_AES128:
+ key_bytes = 16;
+ rounds = 10;
+ break;
+ case SNMP_PRIVPROTOCOL_AES192:
+ key_bytes = 24;
+ rounds = 12;
+ break;
+ case SNMP_PRIVPROTOCOL_AES256:
+ key_bytes = 32;
+ rounds = 14;
+ break;
+ default:
+ debugprintf(0, "Wrong AES type: %i.", aes_type);
+ key_bytes = 0;
+ rounds = 0;
+ aes_type = -1; // will cause an error in AuthPriv::add_priv()
+ }
+
+ unsigned int testswap = htonl(0x01020304);
+ if (testswap == 0x01020304)
+ need_byteswap = FALSE;
+ else
+ need_byteswap = TRUE;
+}
+
+const char *PrivAES::get_id_string() const
+{
+ switch (aes_type)
+ {
+ case SNMP_PRIVPROTOCOL_AES128: return "AES128"; break;
+ case SNMP_PRIVPROTOCOL_AES192: return "AES192"; break;
+ case SNMP_PRIVPROTOCOL_AES256: return "AES256"; break;
+ default: return "error"; break;
+ }
+};
+
+int PrivAES::encrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ unsigned char *privacy_params,
+ unsigned int *privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time)
+{
+ unsigned char initVect[16];
+ pp_uint64 my_salt = (*salt)++;
+
+#ifdef INVALID_ENCRYPTION
+ debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
+ my_salt = 0;
+#endif
+
+ /* check space in privacy_params buffer */
+ if (*privacy_params_len < 8)
+ {
+ debugprintf(4, "Buffer too small: should be 8, is (%i).",
+ *privacy_params_len);
+ return SNMPv3_USM_ENCRYPTION_ERROR;
+ }
+ /* Length is always 8 */
+ *privacy_params_len = 8;
+
+ /* Set IV as engine_boots + engine_time + salt */
+ unsigned int *tmpi = (unsigned int *)initVect;
+ *tmpi++ = htonl(engine_boots);
+ *tmpi++ = htonl(engine_time);
+ if (need_byteswap)
+ {
+ *tmpi++ = htonl(my_salt & 0xFFFFFFFF);
+ *tmpi = htonl((my_salt >> 32) & 0xFFFFFFFF);
+ }
+ else
+ memcpy(tmpi, &my_salt, 8);
+
+ /* put byteswapped salt in privacy_params */
+ memcpy(privacy_params, initVect + 8, 8);
+ debughexcprintf(21, "aes initVect:", initVect, 16);
+
+#ifdef _USE_OPENSSL
+ AES_KEY symcfb;
+ int dummy = 0;
+
+ if (AES_set_encrypt_key(key, key_len * 8, &symcfb) < 0)
+ {
+
+ debugprintf(1, "AES_set_encrypt_key(%p, %d, %p) failed.",
+ key, key_len * 8, &symcfb);
+ return SNMPv3_USM_ERROR;
+ }
+
+ AES_cfb128_encrypt(buffer, out_buffer, buffer_len,
+ &symcfb, initVect, &dummy, AES_ENCRYPT);
+#else
+ symmetric_CFB symcfb;
+
+ cfb_start(cipher, initVect, key, key_bytes, rounds, &symcfb);
+ cfb_encrypt((unsigned char*)buffer, out_buffer, buffer_len, &symcfb);
+#endif
+
+ /* Clear context and plaintext buffer (paranoia!)*/
+ memset(&symcfb, 0, sizeof(symcfb));
+
+ *out_buffer_len = buffer_len;
+
+#ifdef __DEBUG
+ debughexcprintf(21, "aes EncryptData: Data to encrypt", buffer, buffer_len);
+ debughexcprintf(21, "aes EncryptData: used key", key, key_len);
+ debughexcprintf(21, "aes EncryptData: created privacy_params",
+ privacy_params, 8);
+ debughexcprintf(21, "aes EncryptData: encrypted Data",
+ out_buffer, *out_buffer_len);
+#endif
+
+ return SNMPv3_USM_OK;
+}
+
+int PrivAES::decrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ const unsigned char *privacy_params,
+ const unsigned int privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time)
+{
+ unsigned char initVect[16];
+
+ /* Privacy params length has to be 8 */
+ if (privacy_params_len != 8)
+ return SNMPv3_USM_DECRYPTION_ERROR;
+
+ /* build IV */
+ unsigned int *tmp;
+ tmp = (unsigned int *)initVect;
+ *tmp++ = htonl(engine_boots);
+ *tmp = htonl(engine_time);
+ memcpy(initVect + 8, privacy_params, 8);
+ debughexcprintf(21, "aes initVect:", initVect, 16);
+
+#ifdef _USE_OPENSSL
+ int dummy = 0;
+ AES_KEY symcfb;
+
+ AES_set_encrypt_key(key, key_len * 8, &symcfb);
+ AES_cfb128_encrypt(buffer, out_buffer, buffer_len,
+ &symcfb, initVect, &dummy, AES_DECRYPT);
+#else
+ symmetric_CFB symcfb;
+
+ cfb_start(cipher, initVect, key, key_bytes, rounds, &symcfb);
+ cfb_decrypt((unsigned char*)buffer, out_buffer, buffer_len, &symcfb);
+#endif
+
+ /* Clear context and plaintext buffer (paranoia!)*/
+ memset(&symcfb, 0, sizeof(symcfb));
+
+ *out_buffer_len = buffer_len;
+
+#ifdef __DEBUG
+ debughexcprintf(21, "aes DecryptData: Data to decrypt", buffer, buffer_len);
+ debughexcprintf(21, "aes DecryptData: used key", key, key_len);
+ debughexcprintf(21, "aes DecryptData: used privacy_params",
+ privacy_params, 8);
+ debughexcprintf(21, "aes DecryptData: decrypted Data",
+ out_buffer, *out_buffer_len);
+#endif
+
+ return SNMPv3_USM_OK;
+}
+
+int PrivAES::extend_short_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len,
+ const unsigned int max_key_len,
+ Auth *auth)
+{
+ if (max_key_len < (unsigned)key_bytes)
+ return SNMPv3_USM_ERROR;
+
+ int res = 0;
+ unsigned char *hash_buf = new unsigned char[auth->get_hash_len()];
+
+ if (!hash_buf)
+ {
+ debugprintf(0, "Out of mem. Did not get %i bytes.", auth->get_hash_len());
+ return SNMPv3_USM_ERROR;
+ }
+
+ while (*key_len < (unsigned)key_bytes)
+ {
+ res = auth->hash(key, *key_len, hash_buf);
+ if (res != SNMPv3_USM_OK)
+ break;
+
+ int copy_bytes = key_bytes - *key_len;
+ if (copy_bytes > auth->get_hash_len())
+ copy_bytes = auth->get_hash_len();
+ if (*key_len + copy_bytes > max_key_len)
+ copy_bytes = max_key_len - *key_len;
+ memcpy(key + *key_len, hash_buf, copy_bytes);
+ *key_len += copy_bytes;
+ }
+
+ if (hash_buf) delete [] hash_buf;
+
+ return res;
+}
+
+
+#endif // _USE_LIBTOMCRYPT or _USE_OPENSSL
+
+
+#ifdef _USE_3DES_EDE
+
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+Priv3DES_EDE::Priv3DES_EDE()
+{
+ cipher = find_cipher("3des");
+ debugprintf(10, "tomcrypt returned cipher %d", cipher);
+}
+#endif
+
+
+int
+Priv3DES_EDE::encrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ unsigned char *privacy_params,
+ unsigned int *privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time)
+{
+ unsigned char initVect[8];
+ pp_uint64 my_salt = (*salt)++;
+
+#ifdef INVALID_ENCRYPTION
+ debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
+ my_salt = 0;
+#endif
+
+ /* check space in privacy_params buffer */
+ if (*privacy_params_len < 8)
+ {
+ debugprintf(4, "Buffer too small: should be 8, is (%i).",
+ *privacy_params_len);
+ return SNMPv3_USM_ENCRYPTION_ERROR;
+ }
+ /* Length is always 8 */
+ *privacy_params_len = 8;
+
+ /* check key length */
+ if (key_len < TRIPLEDES_EDE_KEY_LEN)
+ {
+ debugprintf(4, "Key too small: should be %d, is (%d).",
+ TRIPLEDES_EDE_KEY_LEN, key_len);
+ return SNMPv3_USM_ENCRYPTION_ERROR;
+ }
+
+ /* TODO: check if K1 != K2 != K3 */
+
+ // last 8 bytes of key are used as base for initialization vector
+ memcpy((char*)initVect, key+24, 8);
+
+ /* TODO: generate salt as specified in draft */
+
+ // put salt in privacy_params
+ for (int j=0; j<4; j++)
+ {
+ privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
+ privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
+ }
+
+ // xor initVect with salt
+ for (int i=0; i<8; i++)
+ initVect[i] ^= privacy_params[i];
+
+
+#ifdef __DEBUG
+ debughexcprintf(21, "3DES Data to encrypt", buffer, buffer_len);
+ debughexcprintf(21, "3DES used iv", initVect, 8);
+ debughexcprintf(21, "3DES key", key, key_len);
+#endif
+
+ // The first 24 octets of the 32-octet secret are used as a 3DES-EDE
+ // key. Since 3DES-EDE uses only 168 bits the least significant bit
+ // in each octet is disregarded
+
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+ DESCBCType symcbc;
+ DES_CBC_START_ENCRYPT(cipher, initVect, key, 24, 16, symcbc);
+
+ for(unsigned int k = 0; k <= buffer_len - 8; k += 8) {
+ DES_CBC_ENCRYPT(buffer + k, out_buffer + k, symcbc, initVect, 8);
+ }
+
+ /* last part of buffer */
+ if (buffer_len % 8)
+ {
+ unsigned char tmp_buf[8];
+ unsigned char *tmp_buf_ptr = tmp_buf;
+ int start = buffer_len - (buffer_len % 8);
+ memset(tmp_buf, 0, 8);
+ for (unsigned int l = start; l < buffer_len; l++)
+ *tmp_buf_ptr++ = buffer[l];
+ DES_CBC_ENCRYPT(tmp_buf, out_buffer + start, symcbc, initVect, 8);
+ *out_buffer_len = buffer_len + 8 - (buffer_len % 8);
+ }
+ else
+ *out_buffer_len = buffer_len;
+
+ /* Clear context buffer (paranoia!)*/
+ DES_MEMSET(symcbc, 0, sizeof(symcbc));
+
+#else
+ DESCBCType ks1, ks2, ks3;
+
+ if ((des_key_sched((C_Block*)(key), ks1) < 0) ||
+ (des_key_sched((C_Block*)(key +8), ks2) < 0) ||
+ (des_key_sched((C_Block*)(key +16), ks3) < 0))
+ {
+ debugprintf(0, "Starting 3DES-EDE encryption failed.");
+ return SNMPv3_USM_ERROR;
+ }
+
+ if (buffer_len >= 8)
+ for(unsigned int k = 0; k <= (buffer_len - 8); k += 8)
+ {
+ DES_EDE3_CBC_ENCRYPT(buffer+k, out_buffer+k, 8,
+ ks1, ks2, ks3, initVect);
+ }
+
+ // Last part
+ if (buffer_len % 8)
+ {
+ unsigned char tmp_buf[8];
+ unsigned char *tmp_buf_ptr = tmp_buf;
+ int start = buffer_len - (buffer_len % 8);
+ memset(tmp_buf, 0, 8);
+ for (unsigned int l = start; l < buffer_len; l++)
+ *tmp_buf_ptr++ = buffer[l];
+ DES_EDE3_CBC_ENCRYPT(tmp_buf, out_buffer + start, 8,
+ ks1, ks2, ks3, initVect);
+
+ *out_buffer_len = buffer_len + 8 - (buffer_len % 8);
+ }
+ else
+ *out_buffer_len = buffer_len;
+
+ /* Clear context buffer (paranoia!)*/
+ DES_MEMSET(ks1, 0, sizeof(ks1));
+ DES_MEMSET(ks2, 0, sizeof(ks2));
+ DES_MEMSET(ks3, 0, sizeof(ks3));
+#endif
+
+#ifdef __DEBUG
+ debughexcprintf(21, "3DES created privacy_params", privacy_params, 8);
+ debughexcprintf(21, "3DES encrypted Data", out_buffer, *out_buffer_len);
+#endif
+
+ return SNMPv3_USM_OK;
+}
+
+
+int
+Priv3DES_EDE::decrypt(const unsigned char *key,
+ const unsigned int key_len,
+ const unsigned char *buffer,
+ const unsigned int buffer_len,
+ unsigned char *out_buffer,
+ unsigned int *out_buffer_len,
+ const unsigned char *privacy_params,
+ const unsigned int privacy_params_len,
+ const unsigned long engine_boots,
+ const unsigned long engine_time)
+{
+ unsigned char initVect[8];
+
+ /* Privacy params length has to be 8 && Length has to be a multiple of 8 */
+ if (( buffer_len % 8 ) || (privacy_params_len != 8))
+ return SNMPv3_USM_DECRYPTION_ERROR;
+
+ for (int i=0; i<8; i++)
+ initVect[i] = privacy_params[i] ^ key[i+24];
+
+ memset((char*)out_buffer, 0, *out_buffer_len);
+
+#ifdef __DEBUG
+ debughexcprintf(21, "3DES Data to decrypt", buffer, buffer_len);
+ debughexcprintf(21, "3DES privacy_params", privacy_params, 8);
+ debughexcprintf(21, "3DES used iv", initVect, 8);
+ debughexcprintf(21, "3DES key", key, key_len);
+#endif
+
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+ DESCBCType symcbc;
+ DES_CBC_START_DECRYPT(cipher, initVect, key, 24, 16, symcbc);
+ for(unsigned int j=0; j<buffer_len; j+=8 ) {
+ DES_CBC_DECRYPT(buffer + j, out_buffer + j, symcbc, initVect, 8);
+ }
+ /* Clear context (paranoia!) */
+ DES_MEMSET(symcbc, 0, sizeof(symcbc));
+
+#else
+ DESCBCType ks1, ks2, ks3;
+
+ if ((des_key_sched((C_Block*)(key), ks1) < 0) ||
+ (des_key_sched((C_Block*)(key+8), ks2) < 0) ||
+ (des_key_sched((C_Block*)(key+16), ks3) < 0))
+ {
+ debugprintf(0, "Starting 3DES-EDE decryption failed.");
+ return SNMPv3_USM_ERROR;
+ }
+
+ for(unsigned int k=0; k<buffer_len; k+=8 )
+ {
+ DES_EDE3_CBC_DECRYPT(buffer+k, out_buffer+k, 8,
+ ks1, ks2, ks3, initVect);
+ }
+ /* Clear context (paranoia!) */
+ DES_MEMSET(ks1, 0, sizeof(ks1));
+ DES_MEMSET(ks2, 0, sizeof(ks2));
+ DES_MEMSET(ks3, 0, sizeof(ks3));
+#endif
+
+ *out_buffer_len = buffer_len;
+
+#ifdef __DEBUG
+ debughexcprintf(21, "3DES decrypted Data", out_buffer, *out_buffer_len);
+#endif
+
+ return SNMPv3_USM_OK;
+}
+
+
+int
+Priv3DES_EDE::extend_short_key(const unsigned char *password,
+ const unsigned int password_len,
+ const unsigned char *engine_id,
+ const unsigned int engine_id_len,
+ unsigned char *key,
+ unsigned int *key_len,
+ const unsigned int max_key_len,
+ Auth *auth)
+{
+ if (max_key_len < TRIPLEDES_EDE_KEY_LEN)
+ return SNMPv3_USM_ERROR;
+
+ unsigned int p2k_output_len = *key_len;
+ unsigned char *p2k_buf = new unsigned char[p2k_output_len];
+ int res = 0;
+
+ if (!p2k_buf) return SNMPv3_USM_ERROR;
+
+ while (*key_len < TRIPLEDES_EDE_KEY_LEN)
+ {
+ unsigned int p2k_buf_len = p2k_output_len;
+
+ res = auth->password_to_key(key, *key_len,
+ engine_id, engine_id_len,
+ p2k_buf, &p2k_buf_len);
+
+ if (res != SNMPv3_USM_OK)
+ break;
+
+ unsigned int copy_bytes = TRIPLEDES_EDE_KEY_LEN - *key_len;
+
+ if (copy_bytes > p2k_buf_len)
+ copy_bytes = p2k_buf_len;
+
+ if (*key_len + copy_bytes > max_key_len)
+ copy_bytes = max_key_len - *key_len;
+
+ memcpy(key + *key_len, p2k_buf, copy_bytes);
+
+ *key_len += copy_bytes;
+ }
+
+ if (p2k_buf) delete [] p2k_buf;
+
+ return res;
+}
+
+#ifdef _TEST
+bool Priv3DES_EDE::test()
+{
+ int status;
+ AuthPriv ap(status);
+ if (status != SNMPv3_USM_OK)
+ return false;
+
+ if (ap.add_auth(new AuthSHA()) != SNMP_ERROR_SUCCESS)
+ {
+ debugprintf(0, "Error: could not add AuthSHA.");
+ return false;
+ }
+
+ if (ap.add_auth(new AuthMD5()) != SNMP_ERROR_SUCCESS)
+ {
+ debugprintf(0, "Error: could not add AuthMD5.");
+ return false;
+ }
+
+ if (ap.add_priv(new Priv3DES_EDE()) != SNMP_ERROR_SUCCESS)
+ {
+ debugprintf(0, "Error: could not add Priv3DES_EDE.");
+ return false;
+ }
+
+ unsigned char password[11] = "maplesyrup";
+ unsigned char engine_id[12];
+
+ memset(engine_id, 0, 11);
+ engine_id[11] = 2;
+
+ unsigned char key[TRIPLEDES_EDE_KEY_LEN];
+ unsigned int key_len = TRIPLEDES_EDE_KEY_LEN;
+
+ status = ap.password_to_key_priv(SNMP_AUTHPROTOCOL_HMACSHA,
+ SNMP_PRIVPROTOCOL_3DESEDE,
+ password, 10,
+ engine_id, 12,
+ key, &key_len);
+
+ debughexcprintf(1, "result key 3DES SHA",
+ key, key_len);
+
+ key_len = TRIPLEDES_EDE_KEY_LEN;
+ status = ap.password_to_key_priv(SNMP_AUTHPROTOCOL_HMACMD5,
+ SNMP_PRIVPROTOCOL_3DESEDE,
+ password, 10,
+ engine_id, 12,
+ key, &key_len);
+
+ debughexcprintf(1, "result key 3DES MD5",
+ key, key_len);
+
+ unsigned char msg[80] = "This is the secret message, that has to be encrypted!";
+ unsigned char enc_buffer[80];
+ unsigned int enc_buffer_len = 80;
+ unsigned char dec_buffer[80];
+ unsigned int dec_buffer_len = 80;
+ unsigned char priv_params[64];
+ unsigned int priv_params_len = 64;
+
+
+ status = ap.encrypt_msg(SNMP_PRIVPROTOCOL_3DESEDE,
+ key, key_len, msg, 53,
+ enc_buffer, &enc_buffer_len,
+ priv_params, &priv_params_len, 0x5abc, 0x6def);
+
+ debughexcprintf(1, "encrypted text",
+ enc_buffer, enc_buffer_len);
+
+ status = ap.decrypt_msg(SNMP_PRIVPROTOCOL_3DESEDE,
+ key, key_len, enc_buffer, enc_buffer_len,
+ dec_buffer, &dec_buffer_len,
+ priv_params, priv_params_len, 0x5abc, 0x6def);
+
+ dec_buffer[dec_buffer_len] = 0;
+ debugprintf(1, "decrypted text: %s",
+ dec_buffer);
+ // TODO: check keys and return real value
+ return true;
+}
+#endif
+
+#endif // _USE_3DES_EDE
+
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
+
+#endif // _SNMPv3
--- /dev/null
+/*_############################################################################
+ _##
+ _## counter.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ C O U N T E R. C P P
+
+ COUNTER32 CLASS IMPLEMENTATION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ Class implementation for SMI Counter32 class.
+=====================================================================*/
+char counter_cpp_version[]="@(#) SNMP++ $Id: counter.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+#include "snmp_pp/counter.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// copy constructor
+Counter32::Counter32(const Counter32 &c)
+{
+ smival.value.uNumber = c.smival.value.uNumber;
+ smival.syntax = sNMP_SYNTAX_CNTR32;
+ m_changed = true;
+ valid_flag = true;
+}
+
+// general assignment from any Value
+SnmpSyntax& Counter32::operator=(const SnmpSyntax &in_val)
+{
+ if (this == &in_val) return *this; // handle assignement from itself
+
+ valid_flag = false; // will get set true if really valid
+ if (in_val.valid())
+ {
+ switch (in_val.get_syntax())
+ {
+ case sNMP_SYNTAX_UINT32:
+ // case sNMP_SYNTAX_GAUGE32: .. indistinquishable from UINT32
+ case sNMP_SYNTAX_CNTR32:
+ case sNMP_SYNTAX_TIMETICKS:
+ case sNMP_SYNTAX_INT32: // implied cast int -> uint
+ smival.value.uNumber = ((Counter32 &)in_val).smival.value.uNumber;
+ valid_flag = true;
+ break;
+ }
+ }
+ m_changed = true;
+ return *this;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## ctr64.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ C O U N T E R 6 4. C P P
+
+ COUNTER64 CLASS IMPLEMENTATION
+
+ DESIGN + AUTHOR: Peter E. Mellquist
+
+ DESCRIPTION: Implementation for Counter64 (64 bit counter class).
+=====================================================================*/
+char counter64_cpp_version[]="@(#) SNMP++ $Id: ctr64.cpp 1558 2009-07-03 20:16:53Z katz $";
+
+#include "snmp_pp/ctr64.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/v3.h"
+
+#include <stdio.h> // for pretty printing...
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define MAX32 4294967295u
+
+
+//------------------[ constructor with no value ]------------------------
+Counter64::Counter64() : m_changed(true)
+{
+ smival.syntax = sNMP_SYNTAX_CNTR64;
+ smival.value.hNumber.hipart = 0;
+ smival.value.hNumber.lopart = 0;
+}
+
+//------------------[ constructor with values ]--------------------------
+Counter64::Counter64(unsigned long hi, unsigned long lo) : m_changed(true)
+{
+ smival.syntax = sNMP_SYNTAX_CNTR64;
+ smival.value.hNumber.hipart = hi;
+ smival.value.hNumber.lopart = lo;
+}
+
+//------------------[ constructor with low value only ]------------------
+Counter64::Counter64(unsigned long lo) : m_changed(true)
+{
+ smival.syntax = sNMP_SYNTAX_CNTR64;
+ smival.value.hNumber.hipart = 0;
+ smival.value.hNumber.lopart = lo;
+}
+
+//------------------[ copy constructor ]---------------------------------
+Counter64::Counter64(const Counter64 &ctr64 ) : m_changed(true)
+{
+ smival.syntax = sNMP_SYNTAX_CNTR64;
+ smival.value.hNumber.hipart = ctr64.high();
+ smival.value.hNumber.lopart = ctr64.low();
+}
+
+//------------------[ operator=(const Counter64 &ctr64) ]-------------
+// assign a ctr64 to a ctr64
+Counter64& Counter64::operator=(const Counter64 &ctr64)
+{
+ if (this == &ctr64) return *this; // check for self assignment
+ smival.value.hNumber.hipart = ctr64.high();
+ smival.value.hNumber.lopart = ctr64.low();
+ m_changed = true;
+ return *this;
+}
+
+//-------------------[ operator=(const unsigned long int i) ]---------
+// assign a ul to a ctr64, clears the high part
+// and assugns the low part
+Counter64& Counter64::operator=(const unsigned long i)
+{
+ smival.value.hNumber.hipart = 0;
+ smival.value.hNumber.lopart = i;
+ m_changed = true;
+ return *this;
+}
+
+//-----------[ c64_to_ll(Counter64 c64) ]-----------------------------
+// convert a Counter 64 to a 64 bit integer
+pp_uint64 Counter64::c64_to_ll(const Counter64 &c64)
+{
+ pp_uint64 ll = c64.high();
+ ll *= (pp_uint64)MAX32 + (pp_uint64)1; // gotta be MAX32 + 1 to move it to next pos
+ ll += c64.low();
+ return ll;
+}
+
+//-----------[ c64_to_ll( ) ]------------------------------------------
+pp_uint64 Counter64::c64_to_ll() const
+{
+ pp_uint64 ll = high();
+ ll *= (pp_uint64)MAX32 + (pp_uint64)1; // gotta be MAX32 + 1 to move it to next pos
+ ll += low();
+ return ll;
+}
+
+//-----------[ ll_to_c64(pp_uint64 ll) ]----------------------------
+// convert a 64 bit integer to a Counter64
+Counter64 Counter64::ll_to_c64(const pp_uint64 &ll)
+{
+ pp_uint64 high = (pp_uint64)MAX32 + (pp_uint64)1; // look above
+ unsigned long h = (unsigned long)(ll / high);
+ return Counter64(h, (unsigned long)(ll - (h * high)));
+}
+
+//----------[ Counter64::operator+(const Counter64 &c) ]---------------
+// add two Counter64s
+Counter64 Counter64::operator+(const Counter64 &c) const
+{
+ pp_uint64 llsum = c64_to_ll() + c.c64_to_ll();
+ return ll_to_c64(llsum);
+}
+
+//------------[ Counter64::operator-(const Counter64 &c) ]-------------
+// subtract two Counter64s
+Counter64 Counter64::operator-(const Counter64 &c) const
+{
+ pp_uint64 lldiff = c64_to_ll() - c.c64_to_ll();
+ return ll_to_c64(lldiff);
+}
+
+//------------[ Counter64::operator*(const Counter64 &c) ]-------------
+// multiply two Counter64s
+Counter64 Counter64::operator*(const Counter64 &c) const
+{
+ pp_uint64 llmult = c64_to_ll() * c.c64_to_ll();
+ return ll_to_c64(llmult);
+}
+
+//------------[ Counter64::operator/(const Counter64 &c) ]--------------
+// divide two Counter64s
+Counter64 Counter64::operator/(const Counter64 &c) const
+{
+ pp_uint64 lldiv = c64_to_ll() / c.c64_to_ll();
+ return ll_to_c64(lldiv);
+}
+
+//-------[ overloaded equivlence test ]----------------------------------
+bool operator==(const Counter64 &lhs, const Counter64 &rhs)
+{
+ return ((lhs.high() == rhs.high()) && (lhs.low() == rhs.low()));
+}
+
+//-------[ overloaded not equal test ]-----------------------------------
+bool operator!=(const Counter64 &lhs, const Counter64 &rhs)
+{
+ return ((lhs.high() != rhs.high()) || (lhs.low() != rhs.low()));
+}
+
+//--------[ overloaded less than ]---------------------------------------
+bool operator<(const Counter64 &lhs, const Counter64 &rhs)
+{
+ return ( (lhs.high() < rhs.high()) ||
+ ((lhs.high() == rhs.high()) && (lhs.low() < rhs.low())));
+}
+
+//---------[ overloaded less than or equal ]-----------------------------
+bool operator<=(const Counter64 &lhs, const Counter64 &rhs)
+{
+ return ( (lhs.high() < rhs.high()) ||
+ ((lhs.high() == rhs.high()) && (lhs.low() <= rhs.low())));
+}
+
+//---------[ overloaded greater than ]-----------------------------------
+bool operator>(const Counter64 &lhs, const Counter64 &rhs)
+{
+ return ( (lhs.high() > rhs.high()) ||
+ ((lhs.high() == rhs.high()) && (lhs.low() > rhs.low())));
+}
+
+//----------[ overloaded greater than or equal ]-------------------------
+bool operator>=(const Counter64 &lhs, const Counter64 &rhs)
+{
+ return ( (lhs.high() > rhs.high()) ||
+ ((lhs.high() == rhs.high()) && (lhs.low() >= rhs.low())));
+}
+
+//----------[ return ASCII format ]-------------------------
+// TODO: Fix up to do real 64bit decimal value printing...
+// For now, print > 32-bit values in hex
+// 26Nov2002 M.Evstiounin - this method is not thread safe!
+const char *Counter64::get_printable() const
+{
+ if (m_changed == false)
+ return output_buffer;
+
+ char *buf = PP_CONST_CAST(char*, output_buffer);
+ if ( high() != 0 )
+ sprintf(buf, "0x%lX%08lX", high(), low());
+ else
+ sprintf(buf, "%lu", low());
+
+ Counter64 *nc_this = PP_CONST_CAST(Counter64*, this);
+ nc_this->m_changed = false;
+
+ return output_buffer;
+}
+
+
+//----------------[ general Value = operator ]---------------------
+SnmpSyntax& Counter64::operator=(const SnmpSyntax &val)
+{
+ if (this == &val) return *this; // protect against assignment from itself
+
+ smival.value.hNumber.lopart = 0; // pessimsitic - assume no mapping
+ smival.value.hNumber.hipart = 0;
+
+ // try to make assignment valid
+ if (val.valid())
+ {
+ switch (val.get_syntax())
+ {
+ case sNMP_SYNTAX_CNTR64:
+ smival.value.hNumber.hipart =
+ ((Counter64 &)val).smival.value.hNumber.hipart;
+ smival.value.hNumber.lopart =
+ ((Counter64 &)val).smival.value.hNumber.lopart;
+ break;
+
+ case sNMP_SYNTAX_CNTR32:
+ case sNMP_SYNTAX_TIMETICKS:
+ case sNMP_SYNTAX_GAUGE32:
+ // case sNMP_SYNTAX_UINT32: .. indistinguishable from GAUGE32
+ case sNMP_SYNTAX_INT32:
+ // take advantage of union...
+ smival.value.hNumber.lopart = ((Counter64 &)val).smival.value.uNumber;
+ smival.value.hNumber.hipart = 0;
+ break;
+ }
+ }
+ m_changed = true;
+ return *this;
+}
+
+// Return the space needed for serialization
+int Counter64::get_asn1_length() const
+{
+ if (smival.value.hNumber.hipart == 0)
+ {
+ if (smival.value.hNumber.lopart < 0x80)
+ return 3;
+ else if (smival.value.hNumber.lopart < 0x8000)
+ return 4;
+ else if (smival.value.hNumber.lopart < 0x800000)
+ return 5;
+ else if (smival.value.hNumber.lopart < 0x80000000)
+ return 6;
+ return 7;
+ }
+ if (smival.value.hNumber.hipart < 0x80)
+ return 7;
+ else if (smival.value.hNumber.hipart < 0x8000)
+ return 8;
+ else if (smival.value.hNumber.hipart < 0x800000)
+ return 9;
+ else if (smival.value.hNumber.hipart < 0x80000000)
+ return 10;
+ return 11;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## eventlist.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ E V E N T L I S T . C P P
+
+ CEventList CLASS DEFINITION
+
+ COPYRIGHT HEWLETT PACKARD COMPANY 1999
+
+ INFORMATION NETWORKS DIVISION
+
+ NETWORK MANAGEMENT SECTION
+
+ DESIGN + AUTHOR: Tom Murray
+
+ DESCRIPTION:
+ Queue for holding all event sources (snmp messages, user
+ defined input sources, user defined timeouts, etc)
+=====================================================================*/
+char event_list_version[]="@(#) SNMP++ $Id: eventlist.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+//----[ snmp++ includes ]----------------------------------------------
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/eventlist.h" // queue for holding all event sources
+#include "snmp_pp/msgqueue.h" // queue for holding snmp event sources
+#include "snmp_pp/notifyqueue.h" // queue for holding trap callbacks
+#include "snmp_pp/snmperrs.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//----[ CSNMPMessageQueueElt class ]--------------------------------------
+
+CEventList::CEventListElt::CEventListElt(CEvents *events,
+ CEventListElt *next,
+ CEventListElt *previous):
+ m_events(events), m_Next(next), m_previous(previous)
+{
+ /* Finish insertion into doubly linked list */
+ if (m_Next) m_Next->m_previous = this;
+ if (m_previous) m_previous->m_Next = this;
+}
+
+CEventList::CEventListElt::~CEventListElt()
+{
+ /* Do deletion form doubly linked list */
+ if (m_Next) m_Next->m_previous = m_previous;
+ if (m_previous) m_previous->m_Next = m_Next;
+ if (m_events) delete m_events;
+}
+
+
+//----[ CEventList class ]--------------------------------------
+
+
+CEventList::~CEventList()
+{
+ CEventListElt *leftOver;
+
+ /* walk the list deleting any elements still on the queue */
+ lock();
+ while ((leftOver = m_head.GetNext()))
+ delete leftOver;
+ unlock();
+}
+
+CEvents * CEventList::AddEntry(CEvents *events) REENTRANT ({
+ /*---------------------------------------------------------*/
+ /* Insert entry at head of list, done automagically by the */
+ /* constructor function, so don't use the return value. */
+ /*---------------------------------------------------------*/
+ (void) new CEventListElt(events, m_head.GetNext(), &m_head);
+ m_msgCount++;
+
+ return events;
+})
+
+int CEventList::GetNextTimeout(msec &sendTime) REENTRANT ({
+
+ CEventListElt *msgEltPtr = m_head.GetNext();
+ msec tmpTime(sendTime);
+
+ sendTime.SetInfinite(); // set sendtime out into future
+ while (msgEltPtr) {
+ if (msgEltPtr->GetEvents()->GetCount() &&
+ !msgEltPtr->GetEvents()->GetNextTimeout(tmpTime)) {
+ if (sendTime > tmpTime)
+ sendTime = tmpTime;
+ }
+
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ return 0;
+})
+
+#ifdef HAVE_POLL_SYSCALL
+
+int CEventList::GetFdCount()
+{
+ SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+ int count = 0;
+ CEventListElt *msgEltPtr = m_head.GetNext();
+
+ while (msgEltPtr)
+ {
+ count += msgEltPtr->GetEvents()->GetFdCount();
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ return count;
+}
+
+bool CEventList::GetFdArray(struct pollfd *readfds, int &remaining)
+{
+ SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+ CEventListElt *msgEltPtr = m_head.GetNext();
+
+ while (msgEltPtr)
+ {
+ int old_remaining = remaining;
+ if (msgEltPtr->GetEvents()->GetFdArray(readfds, remaining) == false)
+ return false;
+ readfds += (old_remaining - remaining);
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ return true;
+}
+
+int CEventList::HandleEvents(const struct pollfd *readfds, const int fds)
+{
+ lock();
+ CEventListElt *msgEltPtr = m_head.GetNext();
+ int status = SNMP_CLASS_SUCCESS;
+ while (msgEltPtr)
+ {
+ if (msgEltPtr->GetEvents()->GetCount())
+ {
+ unlock();
+ status = msgEltPtr->GetEvents()->HandleEvents(readfds, fds);
+ lock();
+ }
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ unlock();
+ return status;
+}
+
+#else
+
+void CEventList::GetFdSets(int &maxfds, fd_set &readfds, fd_set &writefds,
+ fd_set &exceptfds) REENTRANT ({
+
+ CEventListElt *msgEltPtr = m_head.GetNext();
+
+ maxfds = 0;
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&exceptfds);
+ while (msgEltPtr) {
+ if (msgEltPtr->GetEvents()->GetCount()) {
+ msgEltPtr->GetEvents()->GetFdSets(maxfds, readfds, writefds, exceptfds);
+ }
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+})
+
+int CEventList::HandleEvents(const int maxfds,
+ const fd_set &readfds,
+ const fd_set &writefds,
+ const fd_set &exceptfds)
+{
+ lock();
+ CEventListElt *msgEltPtr = m_head.GetNext();
+ int status = SNMP_CLASS_SUCCESS;
+ while (msgEltPtr){
+ if (msgEltPtr->GetEvents()->GetCount()) {
+ unlock();
+ status = msgEltPtr->GetEvents()->HandleEvents(maxfds, readfds, writefds,
+ exceptfds);
+ lock();
+ }
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ unlock();
+ return status;
+}
+
+#endif // HAVE_POLL_SYSCALL
+
+int CEventList::DoRetries(const msec &sendtime) REENTRANT ({
+
+ CEventListElt *msgEltPtr = m_head.GetNext();
+ int status = SNMP_CLASS_SUCCESS;
+ while (msgEltPtr){
+ if (msgEltPtr->GetEvents()->GetCount()) {
+ status = msgEltPtr->GetEvents()->DoRetries(sendtime);
+ }
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ return status;
+})
+
+int CEventList::Done() REENTRANT ({
+
+ CEventListElt *msgEltPtr = m_head.GetNext();
+ int status = SNMP_CLASS_SUCCESS;
+
+ if (m_done) {
+ m_done--;
+ return 1;
+ }
+
+ while (msgEltPtr){
+ if (msgEltPtr->GetEvents()->GetCount()) {
+ status = msgEltPtr->GetEvents()->Done();
+ if (status)
+ break;
+ }
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ return status;
+})
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## eventlistholder.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+
+char event_list_holder_version[]="@(#) SNMP++ $Id: eventlistholder.cpp 342 2008-08-29 22:00:19Z katz $";
+
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/eventlist.h"
+#include "snmp_pp/msgqueue.h"
+#include "snmp_pp/notifyqueue.h"
+#include "snmp_pp/mp_v3.h"
+#include "snmp_pp/v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+EventListHolder::EventListHolder(Snmp *snmp_session)
+{
+ // Automaticly add the SNMP message queue
+ m_snmpMessageQueue = new CSNMPMessageQueue(this, snmp_session);
+ m_eventList.AddEntry(m_snmpMessageQueue);
+
+ // Automatically add the SNMP notification queue
+ m_notifyEventQueue = new CNotifyEventQueue(this, snmp_session);
+ m_eventList.AddEntry(m_notifyEventQueue);
+}
+
+//---------[ Block For Response ]-----------------------------------
+// Wait for the completion of an outstanding SNMP event (msg).
+// Handle any other events as they occur.
+int EventListHolder::SNMPBlockForResponse(const unsigned long req_id,
+ Pdu &pdu)
+{
+ CSNMPMessage *msg;
+ int status;
+
+ do {
+ SNMPProcessEvents(1000);
+ } while (!m_snmpMessageQueue->Done(req_id));
+
+ m_snmpMessageQueue->lock();
+ msg = m_snmpMessageQueue->GetEntry(req_id);
+ if (msg) {
+ // we found our response
+ msg->GetPdu(status, pdu);
+
+ // Dequeue the message
+ m_snmpMessageQueue->DeleteEntry(req_id);
+ m_snmpMessageQueue->unlock();
+ return status;
+ }
+ else {
+ // not in the send queue...must have timed out
+ m_snmpMessageQueue->unlock();
+ return SNMP_CLASS_TIMEOUT;
+ }
+}
+
+//---------[ Process Pending Events ]-------------------------------
+#ifdef HAVE_POLL_SYSCALL
+// Pull all available events out of their sockets - do not block
+int EventListHolder::SNMPProcessPendingEvents()
+{
+ int fdcount;
+ int remaining;
+ struct pollfd *pollfds = 0;
+ int nfound = 0;
+ int timeout;
+ msec now(0, 0);
+ int status;
+
+ pevents_mutex.lock();
+
+ timeout = 1; // chosen a very small timeout
+ // in order to avoid busy looping but keep overall performance
+
+ do
+ {
+ do
+ {
+ fdcount = m_eventList.GetFdCount();
+ if (pollfds) delete [] pollfds;
+ pollfds = new struct pollfd[fdcount + 1];
+ memset(pollfds, 0, (fdcount + 1) * sizeof(struct pollfd));
+ remaining = fdcount + 1;
+ } while (m_eventList.GetFdArray(pollfds, remaining) == false);
+
+ nfound = poll(pollfds, fdcount, timeout);
+
+ now.refresh();
+
+ if (nfound > 0)
+ {
+ status = m_eventList.HandleEvents(pollfds, fdcount);
+ // TM should we do anything with bad status?
+ }
+#ifdef WIN32
+ /* On Win32 select immediately returns -1 if all fd_sets are empty */
+ if (maxfds == 0)
+ Sleep(1); /* prevent 100% CPU utilization */
+#endif
+ } while (nfound > 0);
+
+ // go through the message queue and resend any messages
+ // which are past the timeout.
+ status = m_eventList.DoRetries(now);
+
+ pevents_mutex.unlock();
+
+ if (pollfds) delete [] pollfds;
+
+ return status;
+}
+
+// Block until an event shows up - then handle the event(s)
+int EventListHolder::SNMPProcessEvents(const int max_block_milliseconds)
+{
+ int fdcount;
+ int remaining;
+ struct pollfd *pollfds = 0;
+ struct timeval fd_timeout;
+ int timeout;
+ msec now; // automatcally calls msec::refresh()
+ msec sendTime;
+ int status = 0;
+
+ m_eventList.GetNextTimeout(sendTime);
+ now.GetDelta(sendTime, fd_timeout);
+
+ do
+ {
+ fdcount = m_eventList.GetFdCount();
+ if (pollfds) delete [] pollfds;
+ pollfds = new struct pollfd[fdcount + 1];
+ memset(pollfds, 0, (fdcount + 1) * sizeof(struct pollfd));
+ remaining = fdcount + 1;
+ } while (m_eventList.GetFdArray(pollfds, remaining) == false);
+
+ if ((max_block_milliseconds > 0) &&
+ ((fd_timeout.tv_sec > max_block_milliseconds / 1000) ||
+ ((fd_timeout.tv_sec == max_block_milliseconds / 1000) &&
+ (fd_timeout.tv_usec > (max_block_milliseconds % 1000) * 1000))))
+ {
+ fd_timeout.tv_sec = max_block_milliseconds / 1000;
+ fd_timeout.tv_usec = (max_block_milliseconds % 1000) * 1000;
+ }
+
+ /* Prevent endless sleep in case no fd is open */
+ if ((fdcount == 0) && (fd_timeout.tv_sec > 5))
+ fd_timeout.tv_sec = 5; /* sleep at max 5.99 seconds */
+
+ timeout = fd_timeout.tv_sec * 1000 + fd_timeout.tv_usec / 1000;
+
+ poll(pollfds, fdcount, timeout);
+
+ status = SNMPProcessPendingEvents();
+
+ if (pollfds) delete [] pollfds;
+
+ return status;
+}
+
+#else
+
+int EventListHolder::SNMPProcessPendingEvents()
+{
+ int maxfds;
+ fd_set readfds;
+ fd_set writefds;
+ fd_set exceptfds;
+ int nfound = 0;
+ struct timeval fd_timeout;
+ msec now(0, 0);
+ int status;
+
+ pevents_mutex.lock();
+
+ // do not allow select to block
+ fd_timeout.tv_sec = 0;
+ fd_timeout.tv_usec = 10; // chosen a very small timeout
+ // in order to avoid busy looping but keep overall performance
+
+ do {
+
+ // Set up Select
+ m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
+
+ nfound = select(maxfds, &readfds, &writefds, &exceptfds, &fd_timeout);
+
+ now.refresh();
+
+ if (nfound > 0)
+ { // found something on select
+ status = m_eventList.HandleEvents(maxfds, readfds, writefds, exceptfds);
+ // TM should we do anything with bad status?
+ }
+#ifdef WIN32
+ /* On Win32 select immediately returns -1 if all fd_sets are empty */
+ if (maxfds == 0)
+ Sleep(1); /* prevent 100% CPU utilization */
+#endif
+ } while (nfound > 0);
+
+ // go through the message queue and resend any messages
+ // which are past the timeout.
+ status = m_eventList.DoRetries(now);
+
+ pevents_mutex.unlock();
+
+ return status;
+}
+
+//---------[ Process Events ]------------------------------------------
+// Block until an event shows up - then handle the event(s)
+int EventListHolder::SNMPProcessEvents(const int max_block_milliseconds)
+{
+ int maxfds;
+ fd_set readfds;
+ fd_set writefds;
+ fd_set exceptfds;
+ struct timeval fd_timeout;
+ msec now; // automatcally calls msec::refresh()
+ msec sendTime;
+ int status = 0;
+
+ m_eventList.GetNextTimeout(sendTime);
+ now.GetDelta(sendTime, fd_timeout);
+
+ m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
+
+ if ((max_block_milliseconds > 0) &&
+ ((fd_timeout.tv_sec > max_block_milliseconds / 1000) ||
+ ((fd_timeout.tv_sec == max_block_milliseconds / 1000) &&
+ (fd_timeout.tv_usec > (max_block_milliseconds % 1000) * 1000))))
+ {
+ fd_timeout.tv_sec = max_block_milliseconds / 1000;
+ fd_timeout.tv_usec = (max_block_milliseconds % 1000) * 1000;
+ }
+
+ /* Prevent endless sleep in case no fd is open */
+ if ((maxfds == 0) && (fd_timeout.tv_sec > 5))
+ fd_timeout.tv_sec = 5; /* sleep at max 5.99 seconds */
+
+ select(maxfds, &readfds, &writefds, &exceptfds, &fd_timeout);
+
+ status = SNMPProcessPendingEvents();
+
+ return status;
+}
+
+#endif
+
+//---------[ Main Loop ]------------------------------------------
+// Infinite loop which blocks when there is nothing to do and handles
+// any events as they occur.
+void EventListHolder::SNMPMainLoop(const int max_block_milliseconds)
+{
+ do {
+ SNMPProcessEvents(max_block_milliseconds);
+ } while (!m_eventList.Done());
+}
+
+//---------[ Exit Main Loop ]---------------------------------------
+// Force the SNMP Main Loop to terminate immediately
+void EventListHolder::SNMPExitMainLoop()
+{
+ m_eventList.SetDone();
+}
+
+#ifdef HAVE_POLL_SYSCALL
+
+int EventListHolder::GetFdCount()
+{
+ return m_eventList.GetFdCount();
+}
+
+bool EventListHolder::GetFdArray(struct pollfd *readfds, int &remaining)
+{
+ return m_eventList.GetFdArray(readfds, remaining);
+}
+
+#else
+
+void EventListHolder::SNMPGetFdSets(int &maxfds,
+ fd_set &readfds,
+ fd_set &writefds,
+ fd_set &exceptfds)
+{
+ m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
+}
+
+#endif // HAVE_POLL_SYSCALL
+
+Uint32 EventListHolder::SNMPGetNextTimeout()
+{
+ msec now;
+ msec sendTime(now);
+
+//TM: This function used to have an argument of sendTime and
+// would simply call eventList.GetNextTimeout(sendTime) and
+// return the status. However, to avoid exposing the msec
+// class we now convert the msec to hundreths of seconds
+// and return that as a unsigned long.
+// 25-Jan-96 TM
+
+ m_eventList.GetNextTimeout(sendTime);
+ if (sendTime.IsInfinite()) {
+ return UINT_MAX;
+ }
+ else {
+
+ // Kludge: When this was first designed the units were millisecs
+ // However, later on the units for the target class were changed
+ // to hundreths of secs. Divide millisecs by 10 to create the
+ // hundreths of secs which the rest of the objects use.
+ // 25-Jan-96 TM
+
+ // 21-May-02 DLD: Add check to avoid returning a negative interval
+ // Long eventlists seem to end up with events that are greater
+ // than the time when the event loop is started, but less than the
+ // time when this function is called. This check is analagous to
+ // what is done in msec::GetDelta() which is used in
+ // SNMPProcessEvents(), the library main loop.
+
+ // 21-May-02 DLD: Add 1/100 sec to time out to avoid returning a
+ // short time out interval. A short interval can result due to
+ // truncation of the millisec value when dividing by 10.
+
+ if (sendTime > now)
+ {
+ sendTime -= now;
+ return ((((unsigned long) sendTime) / 10) + 1);
+ }
+ else
+ return 0;
+ }
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## gauge.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ G A U G E. C P P
+
+ GAUGE32 CLASS IMPLEMTATION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ Class implemtation for SMI Gauge32 class.
+=====================================================================*/
+char gauge_cpp_version[]="@(#) SNMP++ $Id: gauge.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+#include "snmp_pp/gauge.h" // header file for gauge class
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// copy constructor
+Gauge32::Gauge32(const Gauge32 &g32)
+ : SnmpUInt32()
+{
+ smival.value.uNumber = g32.smival.value.uNumber;
+ smival.syntax = sNMP_SYNTAX_GAUGE32;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## idea.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+char idea_cpp_version[]="#(@) SNMP++ $Id: idea.cpp 43 2004-03-03 23:11:21Z katz $";
+/*
+
+idea.c
+
+Author: Tatu Ylonen <ylo@cs.hut.fi>
+
+Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ All rights reserved
+
+Created: Sun Jun 25 02:59:39 1995 ylo
+
+This code is based on Xuejia Lai: On the Design and Security of Block
+Ciphers, ETH Series in Information Processing, vol. 1, Hartung-Gorre
+Verlag, Konstanz, Switzerland, 1992. Another source was Bruce
+Schneier: Applied Cryptography, John Wiley & Sons, 1994.
+
+The IDEA mathematical formula may be covered by one or more of the
+following patents: PCT/CH91/00117, EP 0 482 154 B1, US Pat. 5,214,703.
+
+*/
+
+//#include "snmp_pp/includes.h"
+//#include "snmp_pp/getput.h"
+#include "snmp_pp/idea.h"
+#include <string.h>
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifdef _USE_IDEA
+
+/* Sets idea key for encryption. */
+
+void idea_set_key(IDEAContext *c, const unsigned char key[16])
+{
+ int i;
+ word16 *keys;
+
+ /* Get pointer to the keys. */
+ keys = c->key_schedule;
+
+ /* Keys for the first round are directly taken from the user-supplied key. */
+ for (i = 0; i < 8; i++)
+ keys[i] = (word16)GET_16BIT(key + 2 * i);
+
+ /* Each round uses the key of the previous key, rotated to the left by 25
+ bits. The last four keys (output transform) are the first four keys
+ from what would be the ninth round. */
+ for (i = 8; i < 52; i++)
+ {
+ if ((i & 7) == 0)
+ keys += 8;
+ keys[i & 7] = ((keys[((i + 1) & 7) - 8] << 9) |
+ (keys[((i + 2) & 7) - 8] >> 7)) & 0xffff;
+ }
+}
+
+/* Destroys any sensitive data in the context. */
+
+void idea_destroy_context(IDEAContext *c)
+{
+ memset(&c, 0, sizeof(c));
+}
+
+/* Performs the "multiplication" operation of IDEA: returns a*b mod 65537,
+ where a and b are first converted to 65536 if they are zero, and result
+ 65536 is converted to zero. Both inputs should be less than 65536.
+ Only the lower 16 bits of result are significant; other bits are garbage.
+ */
+
+static inline word32 mulop(word32 a, word32 b)
+{
+ word32 ab = a * b;
+ if (ab != 0)
+ {
+ word32 lo = ab & 0xffff;
+ word32 hi = (ab >> 16) & 0xffff;
+ return (lo - hi) + (lo < hi);
+ }
+ if (a == 0)
+ return 1 - b;
+ return 1 - a;
+}
+
+/* Performs the IDEA cipher transform on a block of data. */
+
+void idea_transform(IDEAContext *c, word32 l, word32 r, word32 *output)
+{
+ unsigned int round;
+ word16 *keys;
+ word32 t1, t2, x1, x2, x3, x4;
+
+ keys = c->key_schedule;
+ x1 = l >> 16;
+ x2 = l;
+ x3 = r >> 16;
+ x4 = r;
+ for (round = 0; round < 8; round++)
+ {
+ x1 = mulop(x1 & 0xffff, keys[0]);
+ x3 = x3 + keys[2];
+ x4 = mulop(x4 & 0xffff, keys[3]);
+ x2 = x2 + keys[1];
+ t1 = x1 ^ x3;
+ t2 = x2 ^ x4;
+ t1 = mulop(t1 & 0xffff, keys[4]);
+ t2 = t1 + t2;
+ t2 = mulop(t2 & 0xffff, keys[5]);
+ t1 = t1 + t2;
+ x1 = x1 ^ t2;
+ x4 = x4 ^ t1;
+ t1 = t1 ^ x2;
+ x2 = t2 ^ x3;
+ x3 = t1;
+ keys += 6;
+ }
+
+ x1 = mulop(x1 & 0xffff, keys[0]);
+ x3 = (x2 + keys[2]) & 0xffff;
+ x2 = t1 + keys[1]; /* t1 == old x3 */
+ x4 = mulop(x4 & 0xffff, keys[3]);
+ output[0] = (x1 << 16) | (x2 & 0xffff);
+ output[1] = (x3 << 16) | (x4 & 0xffff);
+}
+
+/* Encrypts len bytes from src to dest in CFB mode. Len need not be a multiple
+ of 8; if it is not, iv at return will contain garbage.
+ Otherwise, iv will be modified at end to a value suitable for continuing
+ encryption. */
+
+void idea_cfb_encrypt(IDEAContext *c, unsigned char *iv, unsigned char *dest,
+ const unsigned char *src, unsigned int len)
+{
+ word32 iv0, iv1, out[2];
+ unsigned int i;
+
+ iv0 = GET_32BIT(iv);
+ iv1 = GET_32BIT(iv + 4);
+
+ for (i = 0; i < len; i += 8)
+ {
+ idea_transform(c, iv0, iv1, out);
+ iv0 = out[0] ^ GET_32BIT(src + i);
+ iv1 = out[1] ^ GET_32BIT(src + i + 4);
+ if (i + 8 <= len)
+ {
+ PUT_32BIT(dest + i, iv0);
+ PUT_32BIT(dest + i + 4, iv1);
+ }
+ else
+ {
+ switch (len - i)
+ {
+ case 7:
+ dest[i + 6] = iv1 >> 8;
+ /*FALLTHROUGH*/
+ case 6:
+ dest[i + 5] = iv1 >> 16;
+ /*FALLTHROUGH*/
+ case 5:
+ dest[i + 4] = iv1 >> 24;
+ /*FALLTHROUGH*/
+ case 4:
+ dest[i + 3] = iv0;
+ /*FALLTHROUGH*/
+ case 3:
+ dest[i + 2] = iv0 >> 8;
+ /*FALLTHROUGH*/
+ case 2:
+ dest[i + 1] = iv0 >> 16;
+ /*FALLTHROUGH*/
+ case 1:
+ dest[i] = iv0 >> 24;
+ /*FALLTHROUGH*/
+ }
+ }
+ }
+ PUT_32BIT(iv, iv0);
+ PUT_32BIT(iv + 4, iv1);
+}
+
+/* Decrypts len bytes from src to dest in CFB mode. Len need not be a multiple
+ of 8; if it is not, iv at return will contain garbage.
+ Otherwise, iv will be modified at end to a value suitable for continuing
+ decryption. */
+
+void idea_cfb_decrypt(IDEAContext *c, unsigned char *iv, unsigned char *dest,
+ const unsigned char *src, unsigned int len)
+{
+ word32 iv0, iv1, out[2], plain0, plain1;
+ unsigned int i;
+
+ iv0 = GET_32BIT(iv);
+ iv1 = GET_32BIT(iv + 4);
+
+ for (i = 0; i < len; i += 8)
+ {
+ idea_transform(c, iv0, iv1, out);
+ iv0 = GET_32BIT(src + i);
+ iv1 = GET_32BIT(src + i + 4);
+ plain0 = out[0] ^ iv0;
+ plain1 = out[1] ^ iv1;
+ if (i + 8 <= len)
+ {
+ PUT_32BIT(dest + i, plain0);
+ PUT_32BIT(dest + i + 4, plain1);
+ }
+ else
+ {
+ switch (len - i)
+ {
+ case 7:
+ dest[i + 6] = plain1 >> 8;
+ /*FALLTHROUGH*/
+ case 6:
+ dest[i + 5] = plain1 >> 16;
+ /*FALLTHROUGH*/
+ case 5:
+ dest[i + 4] = plain1 >> 24;
+ /*FALLTHROUGH*/
+ case 4:
+ dest[i + 3] = plain0;
+ /*FALLTHROUGH*/
+ case 3:
+ dest[i + 2] = plain0 >> 8;
+ /*FALLTHROUGH*/
+ case 2:
+ dest[i + 1] = plain0 >> 16;
+ /*FALLTHROUGH*/
+ case 1:
+ dest[i] = plain0 >> 24;
+ /*FALLTHROUGH*/
+ }
+ }
+ }
+ PUT_32BIT(iv, iv0);
+ PUT_32BIT(iv + 4, iv1);
+}
+
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## integer.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ I N T E G E R . C P P
+
+ SMI INTEGER CLASS IMPLEMTATION
+
+ DESIGN + AUTHOR: Jeff Meyer
+
+ DESCRIPTION:
+ Class implemtation for SMI Integer classes.
+=====================================================================*/
+char integer_cpp_version[]="#(@) SNMP++ $Id: integer.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+#include <stdio.h> // for sprintf()
+#include "snmp_pp/integer.h" // header file for gauge class
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// constructor no value
+SnmpUInt32::SnmpUInt32() : valid_flag(true), m_changed(true)
+{
+ smival.value.uNumber = 0;
+ smival.syntax = sNMP_SYNTAX_UINT32;
+}
+
+// constructor with value
+SnmpUInt32::SnmpUInt32 (const unsigned long i)
+ : valid_flag(true), m_changed(true)
+{
+ smival.value.uNumber = i;
+ smival.syntax = sNMP_SYNTAX_UINT32;
+}
+
+// copy constructor
+SnmpUInt32::SnmpUInt32(const SnmpUInt32 &c) : valid_flag(true), m_changed(true)
+{
+ smival.value.uNumber=c.smival.value.uNumber;
+ smival.syntax = sNMP_SYNTAX_UINT32;
+}
+
+// overloaded assignment
+SnmpUInt32& SnmpUInt32::operator=(const unsigned long i)
+{
+ smival.value.uNumber = i;
+ valid_flag = true;
+ m_changed = true;
+ return *this;
+}
+
+// general assignment from any Value
+SnmpSyntax& SnmpUInt32::operator=(const SnmpSyntax &in_val)
+{
+ if (this == &in_val) return *this; // handle assignement from itself
+
+ valid_flag = false; // will get set true if really valid
+ if (in_val.valid())
+ {
+ switch (in_val.get_syntax())
+ {
+ case sNMP_SYNTAX_UINT32:
+ // case sNMP_SYNTAX_GAUGE32: .. indistinquishable from UINT32
+ case sNMP_SYNTAX_CNTR32:
+ case sNMP_SYNTAX_TIMETICKS:
+ case sNMP_SYNTAX_INT32: // implied cast int -> uint
+ smival.value.uNumber =
+ ((SnmpUInt32 &)in_val).smival.value.uNumber;
+ valid_flag = true;
+ break;
+ }
+ }
+ m_changed = true;
+ return *this;
+}
+
+// overloaded assignment
+SnmpUInt32& SnmpUInt32::operator=(const SnmpUInt32 &uli)
+{
+ if (this == &uli) return *this; // check for self assignment
+
+ smival.value.uNumber = uli.smival.value.uNumber;
+ valid_flag = uli.valid_flag;
+ m_changed = true;
+ return *this;
+}
+
+// ASCII format return
+const char *SnmpUInt32::get_printable() const
+{
+ if (m_changed == false) return output_buffer;
+
+ SnmpUInt32 *nc_this = PP_CONST_CAST(SnmpUInt32*, this);
+ sprintf(nc_this->output_buffer, "%lu", smival.value.uNumber);
+
+ nc_this->m_changed = false;
+
+ return output_buffer;
+}
+
+// Return the space needed for serialization
+int SnmpUInt32::get_asn1_length() const
+{
+ if (smival.value.uNumber < 0x80)
+ return 3;
+ else if (smival.value.uNumber < 0x8000)
+ return 4;
+ else if (smival.value.uNumber < 0x800000)
+ return 5;
+ else if (smival.value.uNumber < 0x80000000)
+ return 6;
+ return 7;
+}
+
+//====================================================================
+// INT 32 Implementation
+//====================================================================
+
+// constructor no value
+SnmpInt32::SnmpInt32() : valid_flag(true), m_changed(true)
+{
+ smival.value.sNumber = 0;
+ smival.syntax = sNMP_SYNTAX_INT32;
+}
+
+// constructor with value
+SnmpInt32::SnmpInt32(const long i) : valid_flag(true), m_changed(true)
+{
+ smival.value.sNumber = i;
+ smival.syntax = sNMP_SYNTAX_INT32;
+}
+
+// constructor with value
+SnmpInt32::SnmpInt32(const SnmpInt32 &c) : valid_flag(true), m_changed(true)
+{
+ smival.value.sNumber = c.smival.value.sNumber;
+ smival.syntax = sNMP_SYNTAX_INT32;
+}
+
+// overloaded assignment
+SnmpInt32& SnmpInt32::operator=(const long i)
+{
+ smival.value.sNumber = (unsigned long) i;
+ valid_flag = true;
+ m_changed = true;
+ return *this;
+}
+
+// overloaded assignment
+SnmpInt32& SnmpInt32::operator=(const SnmpInt32 &uli)
+{
+ if (this == &uli) return *this; // check for self assignment
+
+ smival.value.sNumber = uli.smival.value.sNumber;
+ valid_flag = uli.valid_flag;
+ m_changed = true;
+ return *this;
+}
+
+// general assignment from any Value
+SnmpSyntax& SnmpInt32::operator=(const SnmpSyntax &in_val)
+{
+ if (this == &in_val) return *this; // handle assignement from itself
+
+ valid_flag = false; // will get set true if really valid
+ if (in_val.valid())
+ {
+ switch (in_val.get_syntax())
+ {
+ case sNMP_SYNTAX_INT32:
+ case sNMP_SYNTAX_UINT32: // implied cast uint -> int
+ // case sNMP_SYNTAX_GAUGE32: .. indistinquishable from UINT32
+ case sNMP_SYNTAX_CNTR32: // implied cast uint -> int
+ case sNMP_SYNTAX_TIMETICKS: // implied cast uint -> int
+ smival.value.sNumber =
+ ((SnmpInt32 &)in_val).smival.value.sNumber;
+ valid_flag = true;
+ break;
+ }
+ }
+ m_changed = true;
+ return *this;
+}
+
+// ASCII format return
+const char *SnmpInt32::get_printable() const
+{
+ if (m_changed == false) return output_buffer;
+
+ SnmpInt32 *nc_this = PP_CONST_CAST(SnmpInt32*, this);
+ sprintf(nc_this->output_buffer, "%ld", (long)smival.value.sNumber);
+
+ nc_this->m_changed = false;
+
+ return output_buffer;
+}
+
+// Return the space needed for serialization
+int SnmpInt32::get_asn1_length() const
+{
+ if ((smival.value.sNumber < 0x80) &&
+ (smival.value.sNumber >= -0x80))
+ return 3;
+ else if ((smival.value.sNumber < 0x8000) &&
+ (smival.value.sNumber >= -0x8000))
+ return 4;
+ else if ((smival.value.sNumber < 0x800000) &&
+ (smival.value.sNumber >= -0x800000))
+ return 5;
+ return 6;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## log.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <process.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <signal.h>
+#include <string.h>
+
+#include <snmp_pp/log.h>
+
+#ifdef WIN32
+#ifdef __BCPLUSPLUS__
+#define _getpid getpid
+#endif
+#endif
+
+#if defined (CPU) && CPU == PPC603
+#include <taskLib.h>
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+using namespace Snmp_pp;
+#endif
+
+// default log filter: logs with level less or equal filter value are logged
+// error, warning, event, info, debug:
+static unsigned char default_logfilter[] = { 9, 9, 4, 6, 7, 15};
+
+#undef LOG_INDENT
+
+
+/*--------------------------- class LogEntry --------------------------*/
+
+ /**
+ * Initialize a log entry, showing timestamp, class, and level.
+ *
+ */
+void LogEntry::init(void)
+{
+#ifdef WIN32
+ int pid = _getpid();
+#elif defined (CPU) && CPU == PPC603
+ int pid = taskIdSelf();
+#else
+ int pid = getpid();
+#endif
+
+ add_timestamp();
+ add_string(": ");
+ add_integer(pid);
+ add_string(": ");
+
+ char buf[20];
+ sprintf(buf, "(%X)", get_level());
+ add_string(buf);
+
+ switch (type & 0xF0) {
+ case DEBUG_LOG: add_string("DEBUG : "); break;
+ case INFO_LOG: add_string("INFO : "); break;
+ case WARNING_LOG: add_string("WARNING: "); break;
+ case ERROR_LOG: add_string("ERROR : "); break;
+ case EVENT_LOG: add_string("EVENT : "); break;
+ case USER_LOG: add_string("USER : "); break;
+ }
+
+#ifdef LOG_INDENT
+ // indent log by level
+ for (int i=0; i<(type & 0x0F); i++)
+ add_string(" ");
+#endif
+}
+
+/**
+ * Add a string value to the log entry.
+ *
+ * @param l - A numeric value.
+ */
+LogEntry& LogEntry::operator+=(const char* s)
+{
+ // The convention for Agent++ log messages is that the
+ // timestamp, etc. is followed by the class and method name,
+ // then by the list of arguments.
+ if (count == 0)
+ add_string(s);
+ else {
+ if (count == 1)
+ add_string(": ");
+ else
+ add_string(", ");
+
+ add_string("(");
+ add_string(s);
+ add_string(")");
+ }
+ count++;
+ return *this;
+}
+
+/**
+ * Add a numeric value to the log entry.
+ *
+ * @param l - A numeric value.
+ */
+LogEntry& LogEntry::operator+=(const long l)
+{
+ if (count == 1)
+ add_string(": ");
+ else
+ add_string(", ");
+
+ count++;
+ add_string("(");
+ add_integer(l);
+ add_string(")");
+ return *this;
+}
+
+/**
+ * Add an integer to the log.
+ *
+ * @param s - An integer value.
+ * @return TRUE if the value has been added and FALSE if the log
+ * entry is full.
+ */
+bool LogEntry::add_integer(long l)
+{
+ char buf[40];
+ sprintf(buf, "%ld", l);
+ return add_string(buf);
+}
+
+/**
+ * Add the current time to the log entry.
+ */
+bool LogEntry::add_timestamp(void)
+{
+ return add_string(DefaultLog::log()->now());
+}
+
+
+/*------------------------- class LogEntryImpl ------------------------*/
+
+/**
+ * Constructor for the standard log entry implementation.
+ */
+LogEntryImpl::LogEntryImpl(unsigned char t) : LogEntry(t)
+{
+ value = new char[MAX_LOG_SIZE];
+ value[0] = '\0';
+ ptr = value;
+ output_stopped = FALSE;
+}
+
+/**
+ * Destructor for the standard log entry implementation.
+ */
+LogEntryImpl::~LogEntryImpl()
+{
+ delete [] value;
+}
+
+/**
+ * Add a string to the log.
+ *
+ * @param s - A string value.
+ * @return TRUE if the value has been added and FALSE if the log
+ * entry is full.
+ */
+bool LogEntryImpl::add_string(const char* s)
+{
+ if (output_stopped)
+ return FALSE;
+
+ size_t len = strlen(s);
+ if (len <= bytes_left()) {
+ strcat(ptr, s);
+ ptr += len;
+ return TRUE;
+ }
+
+ if (bytes_left() >= 3) {
+ strcat(ptr, "...");
+ ptr += 3;
+ }
+ output_stopped = TRUE;
+ return FALSE;
+}
+
+
+/*-------------------------- class AgentLog ---------------------------*/
+
+/**
+ * Default constructor.
+ */
+AgentLog::AgentLog()
+{
+ for (int i=0; i<LOG_TYPES; i++)
+ logfilter[i] = default_logfilter[i];
+}
+
+void AgentLog::set_filter(int logclass, unsigned char filter)
+{
+ int idx = (logclass/16)-1;
+ if ((idx >=0) && (idx < LOG_TYPES) && (filter<16))
+ logfilter[idx] = filter;
+}
+
+unsigned char AgentLog::get_filter(int logclass) const
+{
+ int idx = (logclass/16)-1;
+ if ((idx >= 0) && (idx < LOG_TYPES)) {
+ return logfilter[idx];
+ }
+ return 0;
+}
+
+const char* AgentLog::now(char* buf)
+{
+ if (buf == NULL) buf = static_buf;
+
+ time_t t;
+ time(&t);
+ struct tm *stm = localtime(&t);
+ if (stm)
+ strftime(buf, 18, "%Y%m%d.%H:%M:%S", localtime(&t));
+ else
+ buf[0] = 0;
+ return buf;
+}
+
+/*static*/ const char* AgentLog::get_current_time()
+{
+ char* buf = new char[18];
+ strcpy(buf, DefaultLog::log()->now());
+ return buf;
+}
+
+
+/*------------------------ class AgentLogImpl -------------------------*/
+
+/**
+ * Default constructor. Log is directed to stdout.
+ */
+AgentLogImpl::AgentLogImpl(FILE* fp) : AgentLog()
+{
+ set_dest(fp);
+}
+
+/**
+ * Constructor with file name of a log file. Log is directed
+ * to the given file.
+ *
+ * @param fname - The file name of a log file.
+ */
+AgentLogImpl::AgentLogImpl(const char* fname) : AgentLog()
+{
+ set_dest(fname);
+}
+
+/**
+ * Destructor.
+ */
+AgentLogImpl::~AgentLogImpl()
+{
+ if (close_needed) fclose(logfile);
+}
+
+/**
+ * Set destination of logs to a given file.
+ *
+ * @param fname - A file name. "" directs logs to stdout.
+ */
+void AgentLogImpl::set_dest(const char* fname)
+{
+ close_needed = FALSE;
+ if ((!fname) || (strlen(fname) == 0))
+ logfile = stdout;
+ else {
+ logfile = fopen(fname, "a");
+ if (logfile == NULL)
+ logfile = stdout;
+ else
+ close_needed = TRUE;
+ }
+}
+
+/**
+ * Set destination of logs to a given file.
+ *
+ * @param fname - A pointer to an open log file. 0 directs logs to stdout.
+ */
+void AgentLogImpl::set_dest(FILE* fp)
+{
+ logfile = fp ? fp : stdout;
+ close_needed = FALSE;
+}
+
+/**
+ * Create a new LogEntry.
+ *
+ * @param t - The type of the log entry.
+ * @return A new instance of LogEntry (or of a derived class).
+ */
+LogEntry* AgentLogImpl::create_log_entry(unsigned char t) const
+{
+ return new LogEntryImpl(t);
+}
+
+/**
+ * Add a LogEntry to the receiver Log.
+ *
+ * @param log - A log entry.
+ * @return The receiver log itself.
+ */
+AgentLog& AgentLogImpl::operator+=(const LogEntry* log)
+{
+ fprintf(logfile, "%s\n", log->get_value());
+
+ // check if critical error
+ if ((log->get_class() == ERROR_LOG) && (log->get_level() == 0))
+ {
+ fprintf(logfile, "Exiting now\n");
+ raise(SIGTERM);
+ }
+
+ return *this;
+}
+
+
+// define the default logs
+
+#ifdef _THREADS
+#ifndef _WIN32THREADS
+#if !(defined (CPU) && CPU == PPC603)
+pthread_mutex_t logmutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+#endif
+#endif
+
+AgentLog* DefaultLog::instance = 0;
+LogEntry* DefaultLog::entry = 0;
+SnmpSynchronized DefaultLog::mutex;
+
+/*------------------------ class DefaultLog -------------------------*/
+
+void DefaultLog::cleanup()
+{
+ mutex.lock();
+ if (instance) delete instance;
+ instance = 0;
+ mutex.unlock();
+}
+
+AgentLog* DefaultLog::init_ts(AgentLog* logger)
+{
+ AgentLog* r = instance;
+ if (!instance) {
+ mutex.lock();
+ if (!instance) {
+ instance = logger;
+ r = instance;
+ }
+ mutex.unlock();
+ }
+ return r;
+}
+
+AgentLog* DefaultLog::log()
+{
+ AgentLog* r = instance;
+ if (!r) {
+ r = new AgentLogImpl();
+ AgentLog* l = init_ts(r);
+ if (r != l) delete r;
+ r = l;
+ }
+ return r;
+}
--- /dev/null
+/*_############################################################################
+ _##
+ _## md5c.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+char md5c_cpp_version[]="#(@) SNMP++ $Id: md5c.cpp 43 2004-03-03 23:11:21Z katz $";
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm */
+
+/* Copyright (C) 1991, RSA Data Security, Inc. All rights reserved.
+
+ License to copy and use this software is granted provided that it
+ is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ License is also granted to make and use derivative works provided
+ that such works are identified as "derived from the RSA Data
+ Security, Inc. MD5 Message-Digest Algorithm" in all material
+ mentioning or referencing the derived work.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#include "snmp_pp/md5.h"
+
+#if !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], const unsigned char [64]));
+static void Encode PROTO_LIST ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST ((UINT4 *, const unsigned char *, unsigned int));
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (MD5_CTX *context)
+{
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants.
+ */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest operation,
+ processing another message block, and updating the context.
+ */
+void MD5Update (MD5_CTX *context, /* context */
+ const unsigned char *input, /* input block */
+ const unsigned int inputLen) /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+ */
+ if (inputLen >= partLen) {
+ MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (
+unsigned char digest[16], /* message digest */
+MD5_CTX *context) /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+ */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (
+UINT4 state[4],
+const unsigned char block[64])
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF ( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF ( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF ( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF ( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF ( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF ( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF ( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF ( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF ( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF ( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF ( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF ( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF ( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF ( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF ( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF ( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG ( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG ( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG ( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG ( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG ( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG ( d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG ( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG ( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG ( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG ( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG ( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG ( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG ( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG ( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG ( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG ( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH ( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH ( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH ( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH ( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH ( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH ( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH ( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH ( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH ( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH ( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH ( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH ( b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH ( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH ( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH ( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH ( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II ( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II ( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II ( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II ( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II ( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II ( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II ( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II ( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II ( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II ( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II ( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II ( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II ( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II ( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II ( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II ( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (
+ unsigned char *output,
+ UINT4 *input,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (
+ UINT4 *output,
+ const unsigned char *input,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+static void MD5_memcpy (
+ POINTER output,
+ POINTER input,
+ unsigned int len)
+{
+ memcpy(output, input, len);
+}
+
+static void MD5_memset (
+ POINTER output,
+ int value,
+ unsigned int len)
+{
+ memset(output, value, len);
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
--- /dev/null
+/*_############################################################################
+ _##
+ _## mp_v3.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+char mp_v3_cpp_version[]="@(#) SNMP++ $Id: mp_v3.cpp 1686 2009-11-24 13:47:44Z katz $";
+
+#include <stdlib.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+#include "snmp_pp/v3.h"
+#include "snmp_pp/mp_v3.h"
+#include "snmp_pp/usm_v3.h"
+#include "snmp_pp/notifyqueue.h"
+#include "snmp_pp/snmpmsg.h"
+#include "snmp_pp/uxsnmp.h"
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/vb.h"
+#include "snmp_pp/log.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define MAX_MPMSGID 2147483647
+
+#define CACHE_LOCAL_REQ true
+#define CACHE_REMOTE_REQ false
+
+v3MP *v3MP::I = 0;
+
+// Use locking on access methods in an multithreaded environment.
+#ifdef _THREADS
+#define BEGIN_REENTRANT_CODE_BLOCK SnmpSynchronize auto_lock(lock)
+#define BEGIN_REENTRANT_CODE_BLOCK_CONST \
+ SnmpSynchronize auto_lock(*(PP_CONST_CAST(SnmpSynchronized*, &lock)))
+#else
+#define BEGIN_REENTRANT_CODE_BLOCK
+#define BEGIN_REENTRANT_CODE_BLOCK_CONST
+#endif
+
+// ========================[ Engine id table ]=============================
+
+// Construct engine id table
+v3MP::EngineIdTable::EngineIdTable(int initial_size)
+{
+ if (initial_size < 1)
+ initial_size = 10;
+
+ if (!initialize_table(initial_size))
+ {
+ LOG_BEGIN(ERROR_LOG | 0);
+ LOG("v3MP::EngineIdTable: Error creating empty table.");
+ LOG_END;
+ }
+}
+
+// Destruct enigne id table
+v3MP::EngineIdTable::~EngineIdTable()
+{
+ if (table)
+ delete [] table;
+ table = 0;
+}
+
+// Add an entry to the table.
+int v3MP::EngineIdTable::add_entry(const OctetStr &engine_id,
+ const OctetStr &host, int port)
+{
+ if (!table)
+ return SNMPv3_MP_NOT_INITIALIZED;
+
+ LOG_BEGIN(INFO_LOG | 9);
+ LOG("v3MP::EngineIdTable: adding new entry (id) (host) (port)");
+ LOG(engine_id.get_printable());
+ LOG(host.get_printable());
+ LOG(port);
+ LOG_END;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i = 0; i < entries; i++)
+ if (((table[i].port == port) &&
+ (table[i].host == host)) ||
+ (table[i].engine_id == engine_id))
+ {
+ LOG_BEGIN(INFO_LOG | 2);
+ LOG("v3MP::EngineIdTable: replace entry (old id) (old host) (old port) (id) (host) (port)");
+ LOG(table[i].engine_id.get_printable());
+ LOG(table[i].host.get_printable());
+ LOG(table[i].port);
+ LOG(engine_id.get_printable());
+ LOG(host.get_printable());
+ LOG(port);
+ LOG_END;
+
+ table[i].engine_id = engine_id;
+ table[i].host = host;
+ table[i].port = port;
+
+ return SNMPv3_MP_OK; // host is in table
+ }
+
+ table[entries].engine_id = engine_id;
+ table[entries].host = host;
+ table[entries].port = port;
+
+ entries++;
+ if (entries == max_entries)
+ {
+ // resize Table
+ struct Entry_T *tmp;
+ tmp = new struct Entry_T[2 * max_entries];
+ if (!tmp)
+ {
+ entries--;
+ return SNMPv3_MP_ERROR;
+ }
+ for (int i = 0; i < entries; i++)
+ tmp[i] = table[i];
+
+ delete [] table;
+ table = tmp;
+ max_entries *= 2;
+ }
+
+ return SNMPv3_MP_OK;
+}
+
+// Get the engine_id of the SNMP entity at the given host/port.
+int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
+ const OctetStr &hostport) const
+{
+ int port;
+ char host[MAX_HOST_NAME_LENGTH + 1];
+ char *ptr;
+
+ /* Check length */
+ if (hostport.len() > MAX_HOST_NAME_LENGTH)
+ return SNMPv3_MP_ERROR;
+
+ /* split up port from hostport */
+ strcpy(host, hostport.get_printable());
+
+ ptr = strstr((char*)host,"/");
+ if (!ptr)
+ return SNMPv3_MP_ERROR;
+
+ *ptr = '\0';
+ port = atol(ptr + 1);
+
+ /* Check for IPv6 address with [] */
+ if (host[0] == '[')
+ {
+ if (*(ptr -1) == ']')
+ {
+ *(ptr-1) = '\0';
+ return get_entry(engine_id, &(host[1]), port);
+ }
+ else
+ return SNMPv3_MP_ERROR;
+ }
+ return get_entry(engine_id, host, port);
+}
+
+// Get the engineID of the SNMP entity at the given host/port.
+int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
+ const OctetStr &host, int port) const
+{
+ if (!table)
+ return SNMPv3_MP_NOT_INITIALIZED;
+
+ BEGIN_REENTRANT_CODE_BLOCK_CONST;
+
+ int i, found = 0;
+
+ for (i = 0; i < entries; i++)
+ if ((table[i].port == port) &&
+ (table[i].host == host))
+ {
+ found=1;
+ break;
+ }
+ if (!found)
+ {
+ LOG_BEGIN(INFO_LOG | 4);
+ LOG("v3MP::EngineIdTable: Dont know engine id for (host) (port)");
+ LOG(host.get_printable());
+ LOG(port);
+ LOG_END;
+
+ return SNMPv3_MP_ERROR;
+ }
+
+ engine_id = table[i].engine_id;
+
+ return SNMPv3_MP_OK;
+}
+
+// Remove all entries from the engine id table.
+int v3MP::EngineIdTable::reset()
+{
+ if (!table)
+ return SNMPv3_MP_NOT_INITIALIZED;
+
+ LOG_BEGIN(INFO_LOG | 1);
+ LOG("v3MP::EngineIdTable: Resetting table.");
+ LOG_END;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ entries = 0;
+
+ return SNMPv3_MP_OK;
+}
+
+// Remove the given engine id from the table.
+int v3MP::EngineIdTable::delete_entry(const OctetStr &engine_id)
+{
+ if (!table)
+ return SNMPv3_MP_NOT_INITIALIZED;
+
+ int i, found = 0;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (i = 0; i < entries; i++)
+ if (table[i].engine_id == engine_id)
+ {
+ found=1;
+ break;
+ }
+ if (!found)
+ {
+ LOG_BEGIN(WARNING_LOG | 4);
+ LOG("v3MP::EngineIdTable: cannot remove nonexisting entry (engine id)");
+ LOG(engine_id.get_printable());
+ LOG_END;
+
+ return SNMPv3_MP_ERROR;
+ }
+
+ /* i is the entry to remove */
+ if (i != entries - 1)
+ table[i] = table[entries-1];
+
+ entries--;
+
+ return SNMPv3_MP_OK;
+}
+
+// Remove the entry for the given address/port from the table.
+int v3MP::EngineIdTable::delete_entry(const OctetStr &host, int port)
+{
+ if (!table)
+ return SNMPv3_MP_NOT_INITIALIZED;
+
+ int i, found = 0;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (i = 0; i < entries; i++)
+ if ((table[i].port == port) &&
+ (table[i].host == host))
+ {
+ found=1;
+ break;
+ }
+ if (!found)
+ {
+ LOG_BEGIN(WARNING_LOG | 4);
+ LOG("v3MP::EngineIdTable: cannot remove nonexisting entry (host) (port)");
+ LOG(host.get_printable());
+ LOG(port);
+ LOG_END;
+
+ return SNMPv3_MP_ERROR;
+ }
+
+ /* i is the entry to remove */
+ if (i != entries - 1)
+ table[i] = table[entries-1];
+
+ entries--;
+
+ return SNMPv3_MP_OK;
+}
+
+int v3MP::EngineIdTable::initialize_table(const int size)
+{
+ table = new struct Entry_T[size];
+ entries = 0;
+ if (!table)
+ {
+ max_entries = 0;
+ return FALSE;
+ }
+ max_entries = size;
+ return TRUE;
+}
+
+// ===============================[ Cache ]==================================
+
+v3MP::Cache::Cache()
+{
+ // init cache
+ table = new struct Entry_T[5];
+ if (!table)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("v3MP::Cache: could not create empty table.");
+ LOG_END;
+
+ max_entries = 0;
+ }
+ else
+ max_entries = 5;
+
+ entries = 0;
+}
+
+v3MP::Cache::~Cache()
+{
+ if (table)
+ {
+ for (int i = 0; i < entries; i++)
+ usm->delete_sec_state_reference(table[i].sec_state_ref);
+ entries = 0;
+ delete [] table;
+ table = 0;
+ max_entries = 0;
+ }
+}
+
+// Add an entry to the cache.
+int v3MP::Cache::add_entry(int msg_id, unsigned long req_id,
+ const OctetStr &sec_engine_id,
+ int sec_model,
+ const OctetStr &sec_name,
+ int sec_level,
+ const OctetStr &context_engine_id,
+ const OctetStr &context_name,
+ struct SecurityStateReference *sec_state_ref,
+ int error_code, bool local_request)
+{
+ if (!table)
+ return SNMPv3_MP_ERROR;
+
+ LOG_BEGIN(INFO_LOG | 8);
+ LOG("v3MP::Cache: adding new entry (n) (msg id) (req id) (type)");
+ LOG(entries);
+ LOG(msg_id);
+ LOG(req_id);
+ LOG(local_request ? "local" : "remote");
+ LOG_END;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i = 0; i < entries; i++)
+ if ((table[i].msg_id == msg_id) &&
+ (table[i].req_id == req_id) &&
+ (table[i].local_request == local_request) &&
+ (table[i].sec_engine_id == sec_engine_id) &&
+ (table[i].sec_model == sec_model) &&
+ (table[i].sec_name == sec_name) &&
+ (table[i].sec_level == sec_level) &&
+ (table[i].context_engine_id == context_engine_id) &&
+ (table[i].context_name == context_name))
+ {
+ LOG_BEGIN(WARNING_LOG | 3);
+ LOG("v3MP::Cache: Dont add doubled entry (msg id) (req id)");
+ LOG(msg_id);
+ LOG(req_id);
+ LOG_END;
+
+ return SNMPv3_MP_DOUBLED_MESSAGE;
+ }
+
+ table[entries].msg_id = msg_id;
+ table[entries].req_id = req_id;
+ table[entries].local_request = local_request;
+ table[entries].sec_engine_id = sec_engine_id;
+ table[entries].sec_model = sec_model;
+ table[entries].sec_name = sec_name;
+ table[entries].sec_level = sec_level;
+ table[entries].context_engine_id = context_engine_id;
+ table[entries].context_name = context_name;
+ table[entries].sec_state_ref = sec_state_ref;
+ table[entries].error_code = error_code;
+
+ entries++;
+ if (entries == max_entries)
+ {
+ // resize Table
+ struct Entry_T *tmp;
+ tmp = new struct Entry_T[2 * max_entries];
+ if (!tmp)
+ {
+ entries--;
+ return SNMPv3_MP_ERROR;
+ }
+ for (int i=0; i<entries;i++)
+ tmp[i] = table[i];
+ delete [] table;
+ table = tmp;
+ max_entries *= 2;
+ }
+ return SNMPv3_MP_OK;
+}
+
+// Search the cache for a message id, return the error code and
+int v3MP::Cache::get_entry(int msg_id, bool local_request, int *error_code,
+ struct SecurityStateReference **sec_state_ref)
+{
+ if (!table) return SNMPv3_MP_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i=0; i < entries; i++)
+ {
+ if ((msg_id == table[i].msg_id) &&
+ (local_request == table[i].local_request))
+ {
+ *error_code = table[i].error_code;
+ *sec_state_ref = table[i].sec_state_ref;
+ entries--;
+
+ LOG_BEGIN(INFO_LOG | 8);
+ LOG("v3MP::Cache: Found entry (n) (msg id) (type)");
+ LOG(i);
+ LOG(msg_id);
+ LOG(local_request ? "local" : "remote");
+ LOG_END;
+
+ if (entries > i)
+ {
+ table[i] = table[entries];
+
+ LOG_BEGIN(INFO_LOG | 10);
+ LOG("v3MP::Cache: Moving entry (from) (to)");
+ LOG(entries);
+ LOG(i);
+ LOG_END;
+ }
+ return SNMPv3_MP_OK;
+ }
+ }
+
+ LOG_BEGIN(WARNING_LOG | 5);
+ LOG("v3MP::Cache: Entry not found (msg id) (type)");
+ LOG(msg_id);
+ LOG(local_request ? "local" : "remote");
+ LOG_END;
+
+ return SNMPv3_MP_ERROR;
+}
+
+// Delete the entry with the given request id from the cache.
+void v3MP::Cache::delete_entry(unsigned long req_id, bool local_request)
+{
+ if (!table) return;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i=0; i<entries; i++)
+ if ((table[i].req_id == req_id) &&
+ (table[i].local_request == local_request))
+ {
+ LOG_BEGIN(INFO_LOG | 8);
+ LOG("v3MP::Cache: Delete unprocessed entry (n) (req id) (type)");
+ LOG(i);
+ LOG(req_id);
+ LOG(local_request ? "local" : "remote");
+ LOG_END;
+
+ usm->delete_sec_state_reference(table[i].sec_state_ref);
+ entries--;
+ if (entries > i)
+ {
+ table[i] = table[entries];
+
+ LOG_BEGIN(INFO_LOG | 10);
+ LOG("v3MP::Cache: Moving entry (from) (to)");
+ LOG(entries);
+ LOG(i);
+ LOG_END;
+ }
+ return;
+ }
+
+ LOG_BEGIN(INFO_LOG | 8);
+ LOG("v3MP::Cache: Entry to delete not found (req id) (type)");
+ LOG(req_id);
+ LOG(local_request ? "local" : "remote");
+ LOG_END;
+
+ return;
+}
+
+// Delete the entry with the given request ans message id from the cache.
+void v3MP::Cache::delete_entry(unsigned long req_id, int msg_id,
+ bool local_request)
+{
+ if (!table) return;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i=0; i<entries; i++)
+ if ((table[i].req_id == req_id) &&
+ (table[i].msg_id == msg_id) &&
+ (table[i].local_request == local_request))
+ {
+ LOG_BEGIN(INFO_LOG | 8);
+ LOG("v3MP::Cache: Delete unprocessed entry (n) (req id) (msg id) (type)");
+ LOG(i);
+ LOG(req_id);
+ LOG(msg_id);
+ LOG(local_request ? "local" : "remote");
+ LOG_END;
+
+ usm->delete_sec_state_reference(table[i].sec_state_ref);
+ entries--;
+ if (entries > i)
+ {
+ table[i] = table[entries];
+
+ LOG_BEGIN(INFO_LOG | 10);
+ LOG("v3MP::Cache: Moving entry (from) (to)");
+ LOG(entries);
+ LOG(i);
+ LOG_END;
+ }
+ return;
+ }
+
+ LOG_BEGIN(INFO_LOG | 8);
+ LOG("v3MP::Cache: Entry to delete not found (req id) (msg id) (type)");
+ LOG(req_id);
+ LOG(msg_id);
+ LOG(local_request ? "local" : "remote");
+ LOG_END;
+
+ return;
+}
+
+// Search the cache for a message id, return it and remove it from the cache
+int v3MP::Cache::get_entry(int searchedID, bool local_request,
+ struct Cache::Entry_T *res)
+{
+ if ((!table) || (!res)) return SNMPv3_MP_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i=0; i < entries; i++)
+ if ((table[i].msg_id == searchedID) &&
+ (table[i].local_request == local_request))
+ {
+ res->msg_id = table[i].msg_id;
+ res->req_id = table[i].req_id;
+ res->local_request = table[i].local_request;
+ res->sec_engine_id = table[i].sec_engine_id;
+ res->sec_model = table[i].sec_model;
+ res->sec_name = table[i].sec_name;
+ res->sec_level = table[i].sec_level;
+ res->context_engine_id = table[i].context_engine_id;
+ res->context_name = table[i].context_name;
+ res->sec_state_ref = table[i].sec_state_ref;
+ res->error_code = table[i].error_code;
+
+ LOG_BEGIN(INFO_LOG | 8);
+ LOG("v3MP::Cache: Found entry (n) (msg id) (type)");
+ LOG(i);
+ LOG(searchedID);
+ LOG(local_request ? "local" : "remote");
+ LOG_END;
+
+ entries--;
+
+ if (entries > i)
+ {
+ table[i] = table[entries];
+
+ LOG_BEGIN(INFO_LOG | 10);
+ LOG("v3MP::Cache: Moving entry (from) (to)");
+ LOG(entries);
+ LOG(i);
+ LOG_END;
+ }
+ return SNMPv3_MP_OK;
+ }
+
+ LOG_BEGIN(WARNING_LOG | 5);
+ LOG("v3MP::Cache: Entry not found (msg id) (type)");
+ LOG(searchedID);
+ LOG(local_request ? "local" : "remote");
+ LOG_END;
+
+ return SNMPv3_MP_ERROR;
+}
+
+void v3MP::Cache::delete_content(struct v3MP::Cache::Entry_T &ce)
+{
+ if (ce.sec_state_ref)
+ usm->delete_sec_state_reference(ce.sec_state_ref);
+}
+
+// ==========================[ class v3MP ]===============================
+
+// Initialize the v3MP.
+v3MP::v3MP(const OctetStr& snmpEngineID,
+ unsigned int engineBoots, int &construct_status)
+ : own_engine_id(0), usm(0)
+{
+ if (I)
+ {
+ debugprintf(0, "v3MP: You must not create two objects of this class!");
+ construct_status = SNMPv3_MP_ERROR;
+ return;
+ }
+
+ I = this;
+
+ snmpUnknownSecurityModels = 0;
+ snmpInvalidMsgs = 0;
+ snmpUnknownPDUHandlers = 0;
+
+ int length = snmpEngineID.len();
+ if (length > MAXLENGTH_ENGINEID)
+ length = MAXLENGTH_ENGINEID;
+
+ own_engine_id = v3strcpy(snmpEngineID.data(), length);
+ own_engine_id_len = length;
+ own_engine_id_oct = snmpEngineID;
+
+ int result;
+ usm = new USM(engineBoots, snmpEngineID, this, &cur_msg_id, result);
+
+ if (cur_msg_id >= MAX_MPMSGID)
+ cur_msg_id = 1;
+
+ if ((!own_engine_id) || (!usm) || (result != SNMPv3_USM_OK))
+ {
+ construct_status = SNMPv3_MP_ERROR;
+ return;
+ }
+
+ cache.set_usm(usm);
+ construct_status = SNMPv3_MP_OK;
+}
+
+// Free all allocated ressources of the v3MP.
+v3MP::~v3MP()
+{
+ if (own_engine_id)
+ delete [] own_engine_id;
+ own_engine_id = 0;
+
+ if (usm)
+ {
+ delete usm;
+ usm = 0;
+ }
+
+ I = 0;
+}
+
+// Remove all occurences of this engine id from v3MP and USM.
+int v3MP::remove_engine_id(const OctetStr &engine_id)
+{
+ int retval1, retval2;
+
+ retval1 = engine_id_table.delete_entry(engine_id);
+
+ retval2 = usm->remove_engine_id(engine_id);
+
+ if ((retval1 == SNMPv3_MP_NOT_INITIALIZED) ||
+ (retval2 == SNMPv3_USM_ERROR))
+ return SNMPv3_MP_NOT_INITIALIZED;
+
+ return SNMPv3_MP_OK;
+}
+
+// Send a report message.
+int v3MP::send_report(unsigned char* scopedPDU, int scopedPDULength,
+ struct snmp_pdu *pdu, int errorCode, int sLevel,
+ int sModel, OctetStr &sName,
+ UdpAddress &destination, Snmp *snmp_session)
+{
+ debugprintf(2, "v3MP::send_report: Sending report message.");
+
+ unsigned char *data;
+ int dataLength;
+ int pdu_type = 0;
+ unsigned char cEngineID[MAXLENGTH_ENGINEID+1];
+ unsigned char cName[MAXLENGTH_CONTEXT_NAME+1];
+ int cEngineIDLength = MAXLENGTH_ENGINEID+1;
+ int cNameLength = MAXLENGTH_CONTEXT_NAME+1;
+
+ if (scopedPDULength != MAX_SNMP_PACKET)
+ {
+ // try to get scopedPDU and PDU
+ data = asn1_parse_scoped_pdu(scopedPDU, &scopedPDULength,
+ cEngineID, &cEngineIDLength,
+ cName, &cNameLength);
+ if (data == NULL) {
+ debugprintf(1, "mp: Error while trying to parse scopedPDU!");
+ cEngineID[0] = '\0';
+ cEngineIDLength = 0;
+ cName[0] = '\0';
+ cNameLength = 0;
+ // Dont send encrypted report if decryption failed:
+ if (sLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
+ sLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV;
+ }
+ else { // data != NULL
+ dataLength = scopedPDULength;
+
+ // parse data of scopedPDU
+ snmp_parse_data_pdu(pdu, data, dataLength);
+ pdu_type = pdu->command;
+
+ if (!data) {
+ debugprintf(0, "mp: Error while trying to parse PDU!");
+ }
+ } // end of: if (data == NULL)
+ } // end if (scopedPDULength != MAX_SNMP_PACKET)
+ else { // scopedPDULength == MAX_SNMP_PACKET
+ cEngineID[0] = '\0';
+ cEngineIDLength = 0;
+ cName[0] = '\0';
+ cNameLength = 0;
+ pdu->reqid = 0;
+ }
+
+ clear_pdu(pdu); // Clear pdu and free all content
+
+ debugprintf(4, "pdu->reqid = %ld",pdu->reqid);
+ pdu->errstat = 0;
+ pdu->errindex = 0;
+ pdu->command = REPORT_MSG;
+
+ Vb counterVb;
+ Oid counterOid;
+ SmiLPOID smioid;
+ SmiVALUE smival;
+
+ switch (errorCode) {
+ case SNMPv3_MP_INVALID_MESSAGE:
+ case SNMPv3_USM_PARSE_ERROR: {
+ counterVb.set_oid(oidSnmpInvalidMsgs);
+ counterVb.set_value(Counter32(get_stats_invalid_msgs()));
+ break;
+ }
+ case SNMPv3_USM_NOT_IN_TIME_WINDOW:
+ case SNMPv3_MP_NOT_IN_TIME_WINDOW: {
+ counterVb.set_oid(oidUsmStatsNotInTimeWindows);
+ counterVb.set_value(Counter32(usm->get_stats_not_in_time_windows()));
+ break;
+ }
+ case SNMPv3_USM_DECRYPTION_ERROR: {
+ counterVb.set_oid(oidUsmStatsDecryptionErrors);
+ counterVb.set_value(Counter32(usm->get_stats_decryption_errors()));
+ sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ break;
+ }
+ case SNMPv3_USM_AUTHENTICATION_ERROR:
+ case SNMPv3_USM_AUTHENTICATION_FAILURE: {
+ counterVb.set_oid(oidUsmStatsWrongDigests);
+ counterVb.set_value(Counter32(usm->get_stats_wrong_digests()));
+ sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ break;
+ }
+ case SNMPv3_USM_UNKNOWN_ENGINEID:
+ case SNMPv3_MP_INVALID_ENGINEID: {
+ sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ counterVb.set_oid(oidUsmStatsUnknownEngineIDs);
+ counterVb.set_value(Counter32(usm->get_stats_unknown_engine_ids()));
+ break;
+ }
+ case SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL: {
+ counterVb.set_oid(oidSnmpUnknownSecurityModels);
+ counterVb.set_value(Counter32(get_stats_unknown_security_models()));
+ sModel = SNMP_SECURITY_MODEL_USM;
+ sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ break;
+ }
+ case SNMPv3_USM_UNKNOWN_SECURITY_NAME: {
+ counterVb.set_oid(oidUsmStatsUnknownUserNames);
+ counterVb.set_value(Counter32(usm->get_stats_unknown_user_names()));
+ sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ debugprintf(2, "Report: SecurityName: %s",sName.get_printable());
+ break;
+ }
+ case SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL: {
+ counterVb.set_oid(oidUsmStatsUnsupportedSecLevels);
+ counterVb.set_value(Counter32(usm->get_stats_unsupported_sec_levels()));
+ sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ break;
+ }
+ default: {
+ counterVb.set_oid(oidSnmpInvalidMsgs);
+ counterVb.set_value(Counter32(get_stats_invalid_msgs()));
+ sModel = SNMP_SECURITY_MODEL_USM;
+ sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ sName.set_data(0, 0);
+
+ debugprintf(2, "ErrorCode was %i in snmp_parse", errorCode);
+ }
+ } // end switch
+
+ counterVb.get_oid(counterOid);
+ smioid = counterOid.oidval();
+
+ int status = convertVbToSmival(counterVb, &smival);
+ if (status != SNMP_CLASS_SUCCESS) {
+ return SNMPv3_MP_ERROR;
+ }
+ snmp_add_var(pdu, smioid->ptr,
+ (int) smioid->len, &smival);
+ freeSmivalDescriptor(&smival);
+
+ Buffer<unsigned char> sendbuffer(MAX_SNMP_PACKET);
+ int sendbufferlen= MAX_SNMP_PACKET;
+ status = snmp_build( pdu, sendbuffer.get_ptr(), &sendbufferlen,
+ own_engine_id_oct, sName, sModel, sLevel,
+ OctetStr(cEngineID, cEngineIDLength),
+ OctetStr(cName, cNameLength));
+ if (status != SNMPv3_MP_OK) {
+ debugprintf(2, "v3MP::send_report: error serializing message (mpSnmpBuild returns: %i).", status);
+ return SNMPv3_MP_ERROR;
+ }
+ SnmpSocket send_fd = INVALID_SOCKET;
+ if (pdu_type == sNMP_PDU_INFORM)
+ {
+ debugprintf(4, "Received a snmpInform pdu.");
+ if (snmp_session->get_eventListHolder()->notifyEventList())
+ send_fd = snmp_session->get_eventListHolder()->notifyEventList()->get_notify_fd();
+ }
+
+ status = snmp_session->send_raw_data(sendbuffer.get_ptr(),
+ (size_t)sendbufferlen,// pdu to send
+ destination, // target address
+ send_fd); // the fd to use
+ if ( status != 0)
+ {
+ debugprintf(1, "v3MP::send_report: error sending message (%i)", status);
+ return SNMPv3_MP_ERROR;
+ }
+ debugprintf(3, "v3MP::send_report: Report sent.");
+ return SNMPv3_MP_OK;
+}
+
+// Parse the given buffer as a SNMPv3-Message.
+int v3MP::snmp_parse(Snmp *snmp_session,
+ struct snmp_pdu *pdu,
+ unsigned char *inBuf,
+ int inBufLength,
+ OctetStr &securityEngineID,
+ OctetStr &securityName,
+ OctetStr &contextEngineID,
+ OctetStr &contextName,
+ long &securityLevel,
+ long &msgSecurityModel,
+ snmp_version &spp_version,
+ UdpAddress from_address)
+{
+ debugprintf(3, "mp is parsing incoming message:");
+ debughexprintf(25, inBuf, inBufLength);
+
+ if (inBufLength > MAX_SNMP_PACKET)
+ return SNMPv3_MP_ERROR;
+
+ unsigned char type;
+ long version;
+ int origLength = inBufLength;
+ unsigned char *inBufPtr = inBuf;
+ long msgID, msgMaxSize;
+ unsigned char msgFlags;
+ Buffer<unsigned char> msgSecurityParameters(MAX_SNMP_PACKET);
+ Buffer<unsigned char> msgData(MAX_SNMP_PACKET);
+ int msgSecurityParametersLength = inBufLength, msgDataLength = inBufLength;
+ Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
+ int scopedPDULength = MAX_SNMP_PACKET;
+ long maxSizeResponseScopedPDU = 0;
+ struct SecurityStateReference *securityStateReference = NULL;
+ int securityParametersPosition;
+ int rc;
+ int errorCode = 0;
+
+ // get the type
+ inBuf = asn_parse_header( inBuf, &inBufLength, &type);
+ if (inBuf == NULL){
+ debugprintf(0, "snmp_parse: bad header");
+ return SNMPv3_MP_PARSE_ERROR;
+ }
+
+ if (type != (ASN_SEQ_CON)){
+ debugprintf(0, "snmp_parse: wrong auth header type");
+ return SNMPv3_MP_PARSE_ERROR;
+ }
+
+ if (origLength != inBufLength + (inBuf - inBufPtr)) {
+ debugprintf(0, "snmp_parse: wrong length of received packet");
+ return SNMPv3_MP_PARSE_ERROR;
+ }
+
+ // get the version
+ inBuf = asn_parse_int(inBuf, &inBufLength, &type, &version);
+ if (inBuf == NULL){
+ debugprintf(0, "snmp_parse: bad parse of version");
+ return SNMPv3_MP_PARSE_ERROR;
+ }
+
+ debugprintf(3, "Parsed length(%x), version(0x%lx)", inBufLength, version);
+
+ if ( version != SNMP_VERSION_3 )
+ return SNMPv3_MP_PARSE_ERROR;
+
+ spp_version = (snmp_version) version;
+
+ inBuf = asn1_parse_header_data(inBuf, &inBufLength,
+ &msgID, &msgMaxSize,
+ &msgFlags, &msgSecurityModel);
+
+ if (inBuf == NULL){
+ debugprintf(0, "snmp_parse: bad parse of msgHeaderData");
+ return SNMPv3_MP_PARSE_ERROR;
+ }
+
+ pdu->msgid = msgID;
+ if ((msgMaxSize < 484) || (msgMaxSize > 0x7FFFFFFF)) {
+ debugprintf(0, "snmp_parse: bad parse of msgMaxSize");
+ return SNMPv3_MP_PARSE_ERROR;
+ }
+
+ // do not allow larger messages than this entity can handle
+ if (msgMaxSize > MAX_SNMP_PACKET) msgMaxSize = MAX_SNMP_PACKET;
+ pdu->maxsize_scopedpdu = msgMaxSize;
+
+ inBuf = asn_parse_string( inBuf, &inBufLength, &type,
+ msgSecurityParameters.get_ptr(),
+ &msgSecurityParametersLength);
+
+ if (inBuf == NULL){
+ debugprintf(0, "snmp_parse: bad parse of msgSecurityParameters");
+ return SNMPv3_MP_PARSE_ERROR;
+ }
+
+ securityParametersPosition= SAFE_INT_CAST(inBuf - inBufPtr) - msgSecurityParametersLength;
+
+ // the rest of the message is passed directly to the security module
+
+ msgDataLength = origLength - SAFE_INT_CAST(inBuf - inBufPtr);
+ memcpy(msgData.get_ptr(), inBuf, msgDataLength);
+
+ debugprintf(3, "Parsed msgdata length(0x%x), "
+ "msgSecurityParameters length(0x%x)", msgDataLength,
+ msgSecurityParametersLength);
+
+ switch (msgFlags & 0x03) {
+ case 3: { securityLevel = SNMP_SECURITY_LEVEL_AUTH_PRIV; break;}
+ case 0: { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV; break;}
+ case 1: { securityLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV; break;}
+ default: { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ snmpInvalidMsgs++;
+ // do not send back report
+ return SNMPv3_MP_INVALID_MESSAGE;
+ break;
+ }
+ }
+
+ bool reportableFlag;
+
+ if (msgFlags & 0x04) reportableFlag = TRUE;
+ else reportableFlag = FALSE;
+
+ securityStateReference = usm->get_new_sec_state_reference();
+ if (!securityStateReference)
+ return SNMPv3_MP_ERROR;
+
+ switch (msgSecurityModel) {
+ case SNMP_SECURITY_MODEL_USM:
+ {
+ rc = usm->process_msg(
+ msgMaxSize,
+ msgSecurityParameters.get_ptr(),
+ msgSecurityParametersLength,
+ securityParametersPosition,
+ securityLevel,
+ inBufPtr, origLength, //wholeMsg
+ msgData.get_ptr(), msgDataLength,
+ securityEngineID,
+ securityName,
+ scopedPDU.get_ptr(), &scopedPDULength,
+ &maxSizeResponseScopedPDU,
+ securityStateReference,
+ from_address);
+ pdu->maxsize_scopedpdu = maxSizeResponseScopedPDU;
+ if (rc != SNMPv3_USM_OK) {
+ if (rc == SNMPv3_USM_NOT_IN_TIME_WINDOW) {
+ errorCode = SNMPv3_MP_NOT_IN_TIME_WINDOW;
+ }
+ else {
+ // error handling! rfc2262 page 31
+ debugprintf(0, "mp: error while executing USM::process_msg");
+ errorCode = rc;
+ }
+ }
+ if (errorCode != SNMPv3_USM_PARSE_ERROR)
+ if (securityEngineID.len() == 0)
+ errorCode = SNMPv3_MP_INVALID_ENGINEID;
+ break;
+ }
+ default: {
+ snmpUnknownSecurityModels++;
+ usm->delete_sec_state_reference(securityStateReference);
+ debugprintf(0, "SecurityModel of incomming Message not supported!");
+ // Message should be dropped without a report
+ return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
+ }
+ }
+ // process scopedPDU
+ debughexcprintf(21, "scoped PDU", scopedPDU.get_ptr(), scopedPDULength);
+
+ unsigned char *scopedPDUPtr= scopedPDU.get_ptr();
+ unsigned char tmp_contextEngineID[MAXLENGTH_ENGINEID];
+ unsigned char tmp_contextName[MAXLENGTH_CONTEXT_NAME];
+ int tmp_contextEngineIDLength = MAXLENGTH_ENGINEID;
+ int tmp_contextNameLength = MAXLENGTH_CONTEXT_NAME;
+
+ unsigned char *data;
+ int dataLength;
+
+ debugprintf(1,"ErrorCode is %i",errorCode);
+
+ if (!errorCode) {
+ data = asn1_parse_scoped_pdu(scopedPDUPtr, &scopedPDULength,
+ tmp_contextEngineID,
+ &tmp_contextEngineIDLength,
+ tmp_contextName, &tmp_contextNameLength);
+ if (data == NULL) {
+ debugprintf(0, "mp: Error Parsing scopedPDU!");
+ usm->delete_sec_state_reference(securityStateReference);
+ return SNMPv3_MP_PARSE_ERROR;
+ }
+ dataLength = scopedPDULength;
+ contextEngineID.set_data(tmp_contextEngineID, tmp_contextEngineIDLength);
+ contextName.set_data(tmp_contextName, tmp_contextNameLength);
+
+ // parse data of scopedPDU
+ if (snmp_parse_data_pdu(pdu, data, dataLength) != SNMP_CLASS_SUCCESS) {
+ debugprintf(0, "mp: Error parsing PDU!");
+ usm->delete_sec_state_reference(securityStateReference);
+ return SNMPv3_MP_PARSE_ERROR;
+ }
+ if (SNMP_CLASS_SUCCESS != snmp_parse_vb(pdu, data, dataLength)) {
+ debugprintf(0, "mp: Error parsing Vb");
+ usm->delete_sec_state_reference(securityStateReference);
+ return SNMPv3_MP_PARSE_ERROR;
+ }
+ if ((tmp_contextEngineIDLength == 0) &&
+ ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
+ (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
+ (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG) ||
+ (pdu->command == TRP2_REQ_MSG)))
+ {
+ // RFC 2572 � 4.2.2.1 (2a)
+ debugprintf(2, "mp: received request message with zero length"
+ " contextEngineID -> unknownPduHandlers.");
+ inc_stats_unknown_pdu_handlers();
+ errorCode = SNMPv3_MP_UNKNOWN_PDU_HANDLERS;
+ }
+ }
+ if (errorCode) {
+ if ((reportableFlag) && (errorCode != SNMPv3_USM_PARSE_ERROR)) {
+ // error occured: prepare reportpdu in agent
+ cache.add_entry(msgID, pdu->reqid, securityEngineID,
+ msgSecurityModel,
+ securityName, securityLevel, "", "",
+ securityStateReference, errorCode, CACHE_REMOTE_REQ);
+
+ send_report(scopedPDUPtr, scopedPDULength, pdu, errorCode,
+ securityLevel, msgSecurityModel, securityName,
+ from_address, snmp_session);
+ clear_pdu(pdu, true); // Clear pdu and free all content AND IDs!
+ }
+ else {
+ usm->delete_sec_state_reference(securityStateReference);
+ }
+ return errorCode;
+ }
+
+ struct Cache::Entry_T centry;
+
+ if ((pdu->command == GET_RSP_MSG) || (pdu->command == REPORT_MSG)) {
+ rc = cache.get_entry(msgID, true, ¢ry);
+ if (rc != SNMPv3_MP_OK) {
+ // RFC 2572 � 4
+ debugprintf(2, "Received rspMsg without outstanding request."
+ " -> SnmpUnknownPduHandler");
+ usm->delete_sec_state_reference(securityStateReference);
+ inc_stats_unknown_pdu_handlers();
+ return SNMPv3_MP_UNKNOWN_PDU_HANDLERS;
+ }
+ if (((pdu->reqid == 0) || (pdu->reqid == 0x7fffffff))
+ && (pdu->command == REPORT_MSG))
+ pdu->reqid = centry.req_id;
+#ifdef BUGGY_REPORT_REQID
+ if ((pdu->reqid != centry.req_id) && (pdu->command == REPORT_MSG))
+ {
+ debugprintf(0, "WARNING: setting reqid of REPORT PDU (from) (to): (%ld) (%ld)", pdu->reqid, centry.req_id);
+ pdu->reqid = centry.req_id;
+ }
+#endif
+ }
+
+ if (pdu->command == REPORT_MSG) {
+ // !! rfc2262 page 33
+
+ debugprintf(2, "*** Receiving a ReportPDU ***");
+ if (/*((securityEngineID != centry.sec_engine_id)
+ && (centry.sec_engine_id.len() != 0)) ||*/
+ ((msgSecurityModel != centry.sec_model)
+ && (msgSecurityModel != SNMP_SECURITY_MODEL_USM)) ||
+ ((securityName != centry.sec_name)
+ && (securityName.len() != 0)))
+ {
+ debugprintf(0, "Received report message doesn't match sent message!");
+ usm->delete_sec_state_reference(securityStateReference);
+ return SNMPv3_MP_MATCH_ERROR;
+ }
+ usm->delete_sec_state_reference(securityStateReference);
+ cache.delete_content(centry);
+ debugprintf(1, "mp finished (OK)");
+ return SNMPv3_MP_OK;
+ }
+
+ if (pdu->command == GET_RSP_MSG) {
+ if (((securityEngineID != centry.sec_engine_id)
+ && (centry.sec_engine_id.len() != 0)) ||
+ (msgSecurityModel != centry.sec_model) ||
+ (securityName != centry.sec_name) ||
+ (securityLevel != centry.sec_level) ||
+ ((contextEngineID != centry.context_engine_id)
+ && (centry.context_engine_id.len() != 0))||
+ ((contextName != centry.context_name)
+ && (centry.context_name.len() != 0))) {
+ debugprintf(0, "Received response message doesn't match sent message!");
+ usm->delete_sec_state_reference(securityStateReference);
+ cache.delete_content(centry);
+ return SNMPv3_MP_MATCH_ERROR;
+ }
+ usm->delete_sec_state_reference(securityStateReference);
+ cache.delete_content(centry);
+ debugprintf(1, "mp finished (OK)");
+ return SNMPv3_MP_OK;
+ }
+
+ if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
+ (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
+ (pdu->command == INFORM_REQ_MSG)) {
+ if (securityEngineID.len() == 0) {
+ debugprintf(2, "Received Message with engineID = 0.");
+ }
+ else {
+ if (!(unsignedCharCompare(securityEngineID.data(), securityEngineID.len(),
+ own_engine_id, own_engine_id_len))) {
+ debugprintf(0, "snmp_parse: securityEngineID doesn't match own_engine_id.");
+ /* we are authoritative but engine id of message is wrong
+ if discovery in USM is enabled:
+ - remove automatically added illegal engine id from USM tables
+ - send a report
+ */
+ if (usm->is_discovery_enabled())
+ {
+ // TODO: try to remove engine id from USM
+ if (reportableFlag)
+ {
+ cache.add_entry(msgID, pdu->reqid, securityEngineID,
+ msgSecurityModel,
+ securityName, securityLevel, "", "",
+ securityStateReference,
+ SNMPv3_MP_INVALID_ENGINEID,
+ CACHE_REMOTE_REQ);
+
+ send_report(0, MAX_SNMP_PACKET, pdu, SNMPv3_MP_INVALID_ENGINEID,
+ SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV, msgSecurityModel,
+ securityName, from_address, snmp_session);
+ clear_pdu(pdu, true); // Clear pdu and free all content AND IDs!
+ }
+ else
+ {
+ usm->delete_sec_state_reference(securityStateReference);
+ }
+ return SNMPv3_MP_INVALID_ENGINEID;
+ }
+
+ usm->delete_sec_state_reference(securityStateReference);
+ return SNMPv3_MP_MATCH_ERROR;
+ }
+ }
+ int ret = cache.add_entry(msgID, pdu->reqid, securityEngineID,
+ msgSecurityModel, securityName,
+ securityLevel, contextEngineID,
+ contextName, securityStateReference,
+ SNMPv3_MP_OK, CACHE_REMOTE_REQ);
+ if (ret == SNMPv3_MP_DOUBLED_MESSAGE) {
+ debugprintf(0, "*** received doubled message ***");
+ // message will be ignored so return OK
+ usm->delete_sec_state_reference(securityStateReference);
+ }
+
+ debugprintf(1, "mp: parsing finished (ok).");
+ return SNMPv3_MP_OK;
+ }
+
+ if ((pdu->command == TRP_REQ_MSG) || (pdu->command == TRP2_REQ_MSG))
+ {
+ usm->delete_sec_state_reference(securityStateReference);
+ return SNMPv3_MP_OK;
+ }
+
+ debugprintf(0, "mp error: This line should not be executed.");
+ usm->delete_sec_state_reference(securityStateReference);
+ return SNMPv3_MP_ERROR;
+}
+
+
+// Tests if the given buffer contains a SNMPv3-Message.
+bool v3MP::is_v3_msg(unsigned char *buffer, int length)
+{
+ unsigned char type;
+ long version;
+
+ // get the type
+ buffer = asn_parse_header(buffer, &length, &type);
+ if (!buffer)
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("Testing for v3 message: Bad header");
+ LOG_END;
+
+ return FALSE;
+ }
+
+ if (type != ASN_SEQ_CON)
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("Testing for v3 message: Wrong auth header type");
+ LOG((int)type);
+ LOG_END;
+
+ return FALSE;
+ }
+
+ // get the version
+ buffer = asn_parse_int(buffer, &length, &type, &version);
+ if (!buffer)
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("Testing for v3 message: Bad parse of version");
+ LOG_END;
+
+ return 0;
+ }
+
+ return (version == SNMP_VERSION_3);
+}
+
+
+
+// Do the complete process of encoding the given values into the buffer
+// ready to send to the target.
+int v3MP::snmp_build(struct snmp_pdu *pdu,
+ unsigned char *packet,
+ int *out_length, // maximum Bytes in packet
+ const OctetStr &securityEngineID,
+ const OctetStr &securityName,
+ int securityModel,
+ int securityLevel,
+ const OctetStr &contextEngineID,
+ const OctetStr &contextName)
+{
+ Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
+ unsigned char *scopedPDUPtr = scopedPDU.get_ptr();
+ unsigned char globalData[MAXLENGTH_GLOBALDATA];
+ int globalDataLength = MAXLENGTH_GLOBALDATA;
+ int scopedPDULength, maxLen = *out_length;
+ Buffer<unsigned char> buf(MAX_SNMP_PACKET);
+ unsigned char *bufPtr = buf.get_ptr();
+ long bufLength = 0, rc;
+ int msgID;
+ int cachedErrorCode = SNMPv3_MP_OK;
+ struct SecurityStateReference *securityStateReference = NULL;
+ int isRequestMessage = 0;
+
+ if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
+ (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
+ (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG) ||
+ (pdu->command == TRP2_REQ_MSG))
+ isRequestMessage = 1;
+
+ if (isRequestMessage) {
+ if (securityEngineID.len() == 0) {
+ // First Contact => use user noAuthNoPriv and USM
+ securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ securityModel = SNMP_SECURITY_MODEL_USM;
+ }
+
+ cur_msg_id_lock.lock();
+ msgID = cur_msg_id;
+ cur_msg_id++;
+ if (cur_msg_id >= MAX_MPMSGID)
+ cur_msg_id = 1;
+ cur_msg_id_lock.unlock();
+
+#ifdef INVALID_MSGID
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("*** WARNING: Using constant MessageID! ***");
+ LOG_END;
+
+ msgID = 0xdead;
+#endif
+
+ if (securityEngineID.len() == 0) {
+ // length==0 => SecurityLevel == noAuthNoPriv
+ // => we do not send any management information
+ // => delete VariableBinding
+ clear_pdu(pdu);
+ }
+ }
+ else {
+ // it is a response => search for request
+ debugprintf(3, "Looking up cache");
+ msgID = pdu->msgid;
+ rc = cache.get_entry(msgID, CACHE_REMOTE_REQ,
+ &cachedErrorCode, &securityStateReference);
+
+ if (rc != SNMPv3_MP_OK) {
+
+ debugprintf(0, "mp: Cache lookup error");
+ return SNMPv3_MP_MATCH_ERROR;
+ }
+ }
+
+ LOG_BEGIN(DEBUG_LOG | 5);
+ LOG("v3MP: Building message with (SecurityEngineID) (securityName) (securityLevel) (contextEngineID) (contextName)");
+ LOG(securityEngineID.get_printable());
+ LOG(securityName.get_printable());
+ LOG(securityLevel);
+ LOG(contextEngineID.get_printable());
+ LOG(contextName.get_printable());
+ LOG_END;
+
+ // encode vb in buf
+ scopedPDUPtr = build_vb(pdu, scopedPDUPtr, &maxLen);
+ if (!scopedPDUPtr)
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("v3MP: Error encoding vbs into buffer");
+ LOG_END;
+
+ return SNMPv3_MP_BUILD_ERROR;
+ }
+ scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());
+
+ //build dataPDU in buf
+ maxLen = *out_length;
+ scopedPDUPtr = scopedPDU.get_ptr();
+ bufPtr = build_data_pdu(pdu, bufPtr, &maxLen, scopedPDUPtr, scopedPDULength);
+
+ if (!bufPtr)
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("v3MP: Error encoding data pdu into buffer");
+ LOG_END;
+
+ return SNMPv3_MP_BUILD_ERROR;
+ }
+
+ bufLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());
+
+ // serialize scopedPDU
+ maxLen = *out_length;
+ scopedPDUPtr = asn1_build_scoped_pdu(scopedPDUPtr, &maxLen,
+ contextEngineID.data(),
+ contextEngineID.len(),
+ contextName.data(), contextName.len(),
+ buf.get_ptr(), bufLength);
+
+ if (!scopedPDUPtr)
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("v3MP: Error encoding scoped pdu into buffer");
+ LOG_END;
+
+ return SNMPv3_MP_BUILD_ERROR;
+ }
+
+ scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());
+
+ // build msgGlobalData
+ unsigned char *globalDataPtr = (unsigned char *)&globalData;
+ unsigned char msgFlags;
+ switch (securityLevel) {
+ case SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV:
+ { msgFlags = 0 ; break;}
+ case SNMP_SECURITY_LEVEL_AUTH_NOPRIV:
+ { msgFlags = SNMPv3_AUTHFLAG; break;}
+ case SNMP_SECURITY_LEVEL_AUTH_PRIV:
+ { msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG; break;}
+ default:
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("v3MP: Unknown security level requested, will use authPriv");
+ LOG(securityLevel);
+ LOG_END;
+
+ msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG;
+ }
+ }
+
+ if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
+ (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
+ (pdu->command == INFORM_REQ_MSG))
+ msgFlags = msgFlags | SNMPv3_REPORTABLEFLAG;
+
+ globalDataPtr = asn1_build_header_data(globalDataPtr, &globalDataLength,
+ msgID, *out_length, // maxMessageSize
+ msgFlags, securityModel);
+ if (!globalDataPtr)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("v3MP: Error building header data");
+ LOG_END;
+
+ return SNMPv3_MP_BUILD_ERROR;
+ }
+ globalDataLength = SAFE_INT_CAST(globalDataPtr - (unsigned char *)&globalData);
+
+ switch (securityModel) {
+ case SNMP_SECURITY_MODEL_USM: {
+ int use_own_engine_id = 0;
+ if ((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
+ (pdu->command == REPORT_MSG) || (pdu->command == TRP2_REQ_MSG)) {
+ use_own_engine_id = 1;
+ }
+
+ rc = usm->generate_msg(globalData, globalDataLength, *out_length,
+ (use_own_engine_id ?
+ own_engine_id_oct : securityEngineID),
+ securityName, securityLevel,
+ scopedPDU.get_ptr(), scopedPDULength,
+ securityStateReference, packet, out_length);
+
+ if ( rc == SNMPv3_USM_OK ) {
+ // build cache
+ if (!((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
+ (pdu->command == REPORT_MSG) || (pdu->command == TRP2_REQ_MSG)))
+ cache.add_entry(msgID, pdu->reqid, securityEngineID,
+ securityModel, securityName, securityLevel,
+ contextEngineID, contextName, securityStateReference,
+ SNMPv3_MP_OK, CACHE_LOCAL_REQ);
+
+ LOG_BEGIN(INFO_LOG | 3);
+ LOG("v3MP: Message built OK");
+ LOG_END;
+
+ return SNMPv3_MP_OK;
+ }
+ else
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("v3MP: Returning error for building message");
+ LOG(rc);
+ LOG_END;
+
+ return rc;
+ }
+ }
+ default:
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("v3MP: Should build message with unsupported securityModel");
+ LOG(securityModel);
+ LOG_END;
+
+ return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
+ }
+ }
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
+
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## msec.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+*/
+char msec_cpp_version[]="@(#) SNMP++ $Id: msec.cpp 318 2007-11-02 19:25:56Z katz $";
+
+#include "snmp_pp/msec.h"
+#include "snmp_pp/smival.h"
+#include "snmp_pp/config_snmp_pp.h"
+
+#include <stdio.h> // for sprintf
+#include <string.h> // for strcat
+
+#ifdef WIN32
+#include <sys/types.h> // for _timeb
+#include <sys/timeb.h> // and _ftime
+
+#ifdef __BCPLUSPLUS__
+#define _timeb timeb
+#define _ftime ftime
+#endif
+
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#if !defined HAVE_LOCALTIME_R && !defined HAVE_REENTRANT_LOCALTIME
+#ifdef _THREADS
+SnmpSynchronized msec::m_localtime_mutex;
+#endif
+#endif
+
+int operator==(const msec &t1, const msec &t2)
+{
+ return((t1.m_time.tv_sec == t2.m_time.tv_sec) &&
+ (t1.m_time.tv_usec == t2.m_time.tv_usec));
+}
+
+int operator!=(const msec &t1, const msec &t2)
+{
+ return((t1.m_time.tv_sec != t2.m_time.tv_sec) ||
+ (t1.m_time.tv_usec != t2.m_time.tv_usec));
+}
+
+int operator<(const msec &t1, const msec &t2)
+{
+ if (t1.IsInfinite()) return 0;
+ if (t2.IsInfinite()) return 1;
+ if ((t1.m_time.tv_sec < t2.m_time.tv_sec) ||
+ ((t1.m_time.tv_sec == t2.m_time.tv_sec) &&
+ (t1.m_time.tv_usec < t2.m_time.tv_usec)))
+ return 1;
+ return 0;
+}
+
+int operator>(const msec &t1, const msec &t2)
+{
+ if (t2.IsInfinite()) return 0;
+ if (t1.IsInfinite()) return 1;
+ if ((t1.m_time.tv_sec > t2.m_time.tv_sec) ||
+ ((t1.m_time.tv_sec == t2.m_time.tv_sec) &&
+ (t1.m_time.tv_usec > t2.m_time.tv_usec)))
+ return 1;
+ return 0;
+}
+
+msec &msec::operator-=(const long millisec)
+{
+ timeval t1;
+
+ // create a timeval
+ t1.tv_sec = millisec / 1000;
+ t1.tv_usec = (millisec % 1000) * 1000;
+ // subtract it from this
+ *this -= t1; // add m_changed = true if this line is removed!
+ return *this;
+}
+
+msec &msec::operator-=(const timeval &t1)
+{
+ long tmp_usec = t1.tv_usec/1000;// convert usec to millisec
+ if (!this->IsInfinite())
+ {
+ if (m_time.tv_usec < t1.tv_usec) {
+ // borrow
+ m_time.tv_sec--;
+ m_time.tv_usec += 1000;
+ }
+ m_time.tv_usec -= tmp_usec;
+ m_time.tv_sec -= t1.tv_sec;
+ }
+ m_changed = true;
+ return *this;
+}
+
+msec &msec::operator+=(const long millisec)
+{
+ timeval t1;
+
+ // create a timeval
+ t1.tv_sec = millisec / 1000;
+ t1.tv_usec = (millisec % 1000) * 1000;
+ // add it to this
+ *this += t1; // add m_changed = true if this line is removed!
+ return *this;
+}
+
+msec &msec::operator+=(const timeval &t1)
+{
+ long tmp_usec = t1.tv_usec/1000;// convert usec to millisec
+ if (!this->IsInfinite())
+ {
+ m_time.tv_usec += tmp_usec;
+ if (m_time.tv_usec > 1000) {
+ // carry
+ m_time.tv_sec += m_time.tv_usec / 1000;
+ m_time.tv_usec = m_time.tv_usec % 1000;
+ }
+ m_time.tv_sec += t1.tv_sec;
+ }
+ m_changed = true;
+ return *this;
+}
+
+msec &msec::operator=(const timeval &t1)
+{
+ m_time.tv_sec = t1.tv_sec;
+ m_time.tv_usec = t1.tv_usec/1000; // convert usec to millisec
+ m_changed = true;
+ return *this;
+}
+
+#if defined (CPU) && CPU == PPC603
+
+ struct SCommTimer
+ {
+ unsigned long NumMS;
+ unsigned long FractMS;
+ };
+
+ extern "C"
+ {
+ // The GetTime call is not part of the VxWorks library!
+ // If it is not already available in your environment,
+ // you will need to implement it!
+ void GetTime (struct SCommTimer * Time);
+ }
+#endif
+
+void msec::refresh()
+{
+#ifdef WIN32
+ struct _timeb timebuffer;
+ _ftime( &timebuffer );
+ m_time.tv_usec = timebuffer.millitm;
+ m_time.tv_sec = SAFE_ULONG_CAST(timebuffer.time);
+#elif defined (CPU) && CPU == PPC603
+
+ SCommTimer theTime;
+
+ GetTime(&theTime);
+
+ m_time.tv_sec = theTime.NumMS/1000;
+ m_time.tv_usec = theTime.NumMS % 1000;
+
+#else
+ class timezone tzone;
+ gettimeofday((timeval *)&m_time, &tzone);
+ m_time.tv_usec /= 1000; // convert usec to millisec
+#endif
+ m_changed = true;
+}
+
+#ifndef MAX_ALARM
+#define MAX_ALARM 1000000000L
+#endif
+
+void msec::GetDelta(const msec &future, timeval &timeout) const
+{
+ if (future.IsInfinite())
+ {
+ timeout.tv_sec = MAX_ALARM; // max allowable select timeout
+ timeout.tv_usec = 0;
+ }
+ else if (future > *this)
+ {
+ if (future.m_time.tv_usec < m_time.tv_usec)
+ {
+ timeout.tv_sec = future.m_time.tv_sec - 1 - m_time.tv_sec;
+ timeout.tv_usec = future.m_time.tv_usec + 1000 - m_time.tv_usec;
+ }
+ else
+ {
+ timeout.tv_sec = future.m_time.tv_sec - m_time.tv_sec;
+ timeout.tv_usec = future.m_time.tv_usec - m_time.tv_usec;
+ }
+ timeout.tv_usec *= 1000 ;// convert back to usec
+ }
+ else // Never give back negative timeval's they make select() hurl
+ {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ }
+}
+
+// FIXME: does not print years and days!
+const char *msec::get_printable() const
+{
+ if (m_changed == false) return m_output_buffer;
+
+ char msec_buffer[5];
+ msec *nc_this = PP_CONST_CAST(msec*, this);
+
+#ifdef HAVE_LOCALTIME_R
+ struct tm stm;
+ localtime_r((const time_t *)&m_time.tv_sec, &stm);
+ strftime(nc_this->m_output_buffer, sizeof(m_output_buffer),
+ "%H:%M:%S.", &stm);
+#else
+#if defined _THREADS && !defined HAVE_REENTRANT_LOCALTIME
+ SnmpSynchronize s(m_localtime_mutex); // Serialize all calls to localtime!
+#endif
+ struct tm *tmptr;
+ tmptr = localtime((time_t *)&m_time.tv_sec);
+ strftime(nc_this->m_output_buffer, sizeof(m_output_buffer),
+ "%H:%M:%S.", tmptr);
+#endif
+
+ sprintf(msec_buffer, "%.3ld", (long)m_time.tv_usec);
+ strcat(nc_this->m_output_buffer, msec_buffer);
+
+ nc_this->m_changed = false;
+
+ return m_output_buffer;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## msgqueue.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ M S G Q U E U E . C P P
+
+ MSG QUEUE CLASS DECLARATION
+
+ Author: Peter E Mellquist
+
+=====================================================================*/
+char msgqueue_version[]="#(@) SNMP++ $Id: msgqueue.cpp 1826 2010-08-29 20:19:59Z katz $";
+
+//-----[ includes ]----------------------------------------------------
+
+//----[ snmp++ includes ]----------------------------------------------
+
+#include "snmp_pp/msgqueue.h" // queue for holding outstanding messages
+#include "snmp_pp/snmpmsg.h"
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/log.h"
+#include "snmp_pp/vb.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+#define SNMP_PORT 161
+
+//--------[ externs ]---------------------------------------------------
+extern int send_snmp_request(SnmpSocket sock, unsigned char *send_buf,
+ size_t send_len, Address &address);
+extern int receive_snmp_response(SnmpSocket sock, Snmp &snmp_session,
+ Pdu &pdu, UdpAddress &fromaddress,
+ OctetStr &engine_id, bool process_msg = true);
+
+//----[ CSNMPMessage class ]-------------------------------------------
+
+CSNMPMessage::CSNMPMessage(unsigned long id,
+ Snmp * snmp,
+ SnmpSocket socket,
+ const SnmpTarget &target,
+ Pdu &pdu,
+ unsigned char * rawPdu,
+ size_t rawPduLen,
+ const Address & address,
+ snmp_callback callBack,
+ void * callData):
+ m_uniqueId(id), m_snmp(snmp), m_socket(socket), m_pdu(pdu),
+ m_rawPduLen(rawPduLen), m_callBack(callBack), m_callData(callData),
+ m_reason(0), m_received(0)
+{
+ // reset pdu mvs
+ m_pdu.set_error_index(0);
+ m_pdu.set_error_status(0);
+ m_pdu.set_request_id(m_uniqueId);
+
+ m_rawPdu = new unsigned char [rawPduLen];
+ memcpy(m_rawPdu, rawPdu, rawPduLen);
+ m_address = (Address *)address.clone();
+ m_target = target.clone();
+
+ SetSendTime();
+}
+
+CSNMPMessage::~CSNMPMessage()
+{
+ delete [] m_rawPdu;
+ delete m_address;
+ delete m_target;
+}
+
+void CSNMPMessage::SetSendTime()
+{
+ m_sendTime.refresh();
+
+ // Kludge: When this was first designed the units were millisecs
+ // However, later on the units for the target class were changed
+ // to hundreths of secs. Multiply the hundreths of secs by 10
+ // to create the millisecs which the rest of the objects use.
+ // 11-Dec-95 TM
+ m_sendTime += (m_target->get_timeout() * 10);
+}
+
+int CSNMPMessage::SetPdu(const int reason, const Pdu &pdu,
+ const UdpAddress &fromaddress)
+{
+ if (Pdu::match_type(m_pdu.get_type(), pdu.get_type()) == false)
+ {
+ LOG_BEGIN(INFO_LOG | 1);
+ LOG("MsgQueue: Response pdu type does not match, pdu is ignored: (id) (type1) (type2)");
+ LOG(m_uniqueId);
+ LOG(m_pdu.get_type());
+ LOG(pdu.get_type());
+ LOG_END;
+
+ return -1;
+ }
+
+ unsigned short orig_type = m_pdu.get_type();
+ if (m_received)
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("MsgQueue: Message is already marked as received (id) (reason) (new reason)");
+ LOG(m_uniqueId);
+ LOG(reason);
+ LOG(m_reason);
+ LOG_END;
+
+ // TODO: better check based on error codes
+ if (reason || !m_reason)
+ {
+ LOG_BEGIN(WARNING_LOG | 1);
+ LOG("MsgQueue: ignoring the second pdu");
+ LOG_END;
+
+ return 0;
+ }
+ }
+ m_received = 1;
+ m_pdu = pdu;
+ m_reason = reason;
+
+ LOG_BEGIN(DEBUG_LOG | 10);
+ LOG("MsgQueue: Response received (req id) (status) (msg id)");
+ LOG(pdu.get_request_id());
+ LOG(reason);
+#ifdef _SNMPv3
+ LOG(pdu.get_message_id());
+#endif
+ LOG_END;
+
+ if ((orig_type == sNMP_PDU_INFORM) &&
+ (m_pdu.get_type() == sNMP_PDU_RESPONSE))
+ {
+ // remove the first two vbs of the pdu if sysUpTime and notify_id
+ if (m_pdu.get_vb_count() < 2)
+ return 0;
+
+ const Vb &vb1 = m_pdu.get_vb(0);
+ if (vb1.get_syntax() != sNMP_SYNTAX_TIMETICKS) return 0;
+ if (vb1.get_oid() != SNMP_MSG_OID_SYSUPTIME) return 0;
+
+ const Vb &vb2 = m_pdu.get_vb(1);
+ if (vb2.get_syntax() != sNMP_SYNTAX_OID) return 0;
+ if (vb2.get_oid() != SNMP_MSG_OID_TRAPID) return 0;
+
+ TimeTicks timeticks;
+ Oid oid;
+
+ vb1.get_value(timeticks);
+ m_pdu.set_notify_timestamp(timeticks);
+
+ vb2.get_value(oid);
+ m_pdu.set_notify_id(oid);
+
+ m_pdu.delete_vb(1);
+ m_pdu.delete_vb(0);
+ }
+ return 0;
+}
+
+int CSNMPMessage::ResendMessage()
+{
+ if (m_received)
+ {
+ // Don't bother to resend if we already have the response
+ SetSendTime();
+ return SNMP_CLASS_SUCCESS;
+ }
+
+ LOG_BEGIN(DEBUG_LOG | 10);
+ LOG("MsgQueue: Message (msg id) (req id) (info)");
+#ifdef _SNMPv3
+ LOG(m_pdu.get_message_id());
+#endif
+ LOG(m_pdu.get_request_id());
+ LOG((m_target->get_retry() <= 0) ? "TIMEOUT" : "RESEND");
+ LOG_END;
+
+ if (m_target->get_retry() <= 0)
+ {
+ // This message has timed out
+ Callback(SNMP_CLASS_TIMEOUT); // perform callback with the error
+
+ return SNMP_CLASS_TIMEOUT;
+ }
+
+ m_target->set_retry(m_target->get_retry() - 1);
+ SetSendTime();
+ int status = send_snmp_request(m_socket, m_rawPdu, m_rawPduLen, *m_address);
+ if (status != 0)
+ return SNMP_CLASS_TL_FAILED;
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+int CSNMPMessage::Callback(const int reason)
+{
+ snmp_callback tmp_callBack;
+ if (m_callBack) {
+ // prevent callbacks from using this message
+ tmp_callBack = m_callBack;
+ m_callBack = NULL;
+
+ tmp_callBack(reason, m_snmp, m_pdu, *m_target, m_callData);
+ return 0;
+ }
+ return 1;
+}
+
+//----[ CSNMPMessageQueueElt class ]--------------------------------------
+
+CSNMPMessageQueue::CSNMPMessageQueueElt::CSNMPMessageQueueElt(
+ CSNMPMessage *message,
+ CSNMPMessageQueueElt *next,
+ CSNMPMessageQueueElt *previous):
+ m_message(message), m_Next(next), m_previous(previous)
+{
+ /* Finish insertion into doubly linked list */
+ if (m_Next) m_Next->m_previous = this;
+ if (m_previous) m_previous->m_Next = this;
+}
+
+CSNMPMessageQueue::CSNMPMessageQueueElt::~CSNMPMessageQueueElt()
+{
+ /* Do deletion form doubly linked list */
+ if (m_Next) m_Next->m_previous = m_previous;
+ if (m_previous) m_previous->m_Next = m_Next;
+ if (m_message) delete m_message;
+}
+
+CSNMPMessage *CSNMPMessageQueue::CSNMPMessageQueueElt::TestId(const unsigned long uniqueId)
+{
+ if (m_message && (m_message->GetId() == uniqueId))
+ return m_message;
+ return 0;
+}
+
+
+
+//----[ CSNMPMessageQueue class ]--------------------------------------
+
+CSNMPMessageQueue::CSNMPMessageQueue(EventListHolder *holder, Snmp *session)
+ : m_head(0, 0, 0), m_msgCount(0), my_holder(holder), m_snmpSession(session)
+{
+}
+
+CSNMPMessageQueue::~CSNMPMessageQueue()
+{
+ CSNMPMessageQueueElt *leftOver;
+ lock();
+ /*--------------------------------------------------------*/
+ /* walk the list deleting any elements still on the queue */
+ /*--------------------------------------------------------*/
+ while ((leftOver = m_head.GetNext()))
+ delete leftOver;
+
+ unlock();
+}
+
+CSNMPMessage * CSNMPMessageQueue::AddEntry(unsigned long id,
+ Snmp * snmp,
+ SnmpSocket socket,
+ const SnmpTarget &target,
+ Pdu &pdu,
+ unsigned char * rawPdu,
+ size_t rawPduLen,
+ const Address & address,
+ snmp_callback callBack,
+ void * callData)
+{
+ if (snmp != m_snmpSession)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("MsgQueue: Adding message for other Snmp object.");
+ LOG_END;
+ }
+
+ CSNMPMessage *newMsg = new CSNMPMessage(id, snmp, socket, target, pdu,
+ rawPdu, rawPduLen, address,
+ callBack, callData);
+
+ lock();
+ /*---------------------------------------------------------*/
+ /* Insert entry at head of list, done automagically by the */
+ /* constructor function, so don't use the return value. */
+ /*---------------------------------------------------------*/
+ (void) new CSNMPMessageQueueElt(newMsg, m_head.GetNext(), &m_head);
+ ++m_msgCount;
+
+ LOG_BEGIN(DEBUG_LOG | 10);
+ LOG("MsgQueue: Adding entry (req id) (count)");
+ LOG(id);
+ LOG(m_msgCount);
+ LOG_END;
+
+ unlock();
+ return newMsg;
+}
+
+
+CSNMPMessage *CSNMPMessageQueue::GetEntry(const unsigned long uniqueId)
+{
+ CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+ CSNMPMessage *returnVal = NULL;
+
+ while (msgEltPtr){
+ if ((returnVal = msgEltPtr->TestId(uniqueId)))
+ return returnVal;
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ return 0;
+}
+
+int CSNMPMessageQueue::DeleteEntry(const unsigned long uniqueId)
+{
+ CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+
+ while (msgEltPtr){
+ if (msgEltPtr->TestId(uniqueId)) {
+ delete msgEltPtr;
+ m_msgCount--;
+ LOG_BEGIN(DEBUG_LOG | 10);
+ LOG("MsgQueue: Removed entry (req id)");
+ LOG(uniqueId);
+ LOG_END;
+ return SNMP_CLASS_SUCCESS;
+ }
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ return SNMP_CLASS_INVALID_REQID;
+}
+
+void CSNMPMessageQueue::DeleteSocketEntry(const SnmpSocket socket)
+REENTRANT({
+ CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+ CSNMPMessageQueueElt *tmp_msgEltPtr;
+ CSNMPMessage *msg = NULL;
+
+ while (msgEltPtr){
+ msg = msgEltPtr->GetMessage();
+ if (socket == msg->GetSocket()) {
+ // Make a callback with an error
+ (void) msg->Callback(SNMP_CLASS_SESSION_DESTROYED);
+ tmp_msgEltPtr = msgEltPtr;
+ msgEltPtr = tmp_msgEltPtr->GetNext();
+ // delete the entry
+ delete tmp_msgEltPtr;
+ }
+ else
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+})
+
+CSNMPMessage * CSNMPMessageQueue::GetNextTimeoutEntry()
+{
+ CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+ msec bestTime;
+ msec sendTime(bestTime);
+ CSNMPMessage *msg;
+ CSNMPMessage *bestmsg = NULL;
+
+ if (msgEltPtr) {
+ bestmsg = msgEltPtr->GetMessage();
+ bestmsg->GetSendTime(bestTime);
+ }
+
+ // This would be much simpler if the queue was an ordered list!
+ while (msgEltPtr){
+ msg = msgEltPtr->GetMessage();
+ msg->GetSendTime(sendTime);
+ if (bestTime > sendTime) {
+ bestTime = sendTime;
+ bestmsg = msg;
+ }
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ return bestmsg;
+}
+
+int CSNMPMessageQueue::GetNextTimeout(msec &sendTime)
+{
+ CSNMPMessage *msg = GetNextTimeoutEntry();
+
+ if (!msg) return 1; // nothing in the queue...
+
+ msg->GetSendTime(sendTime);
+ return 0;
+}
+
+#ifdef HAVE_POLL_SYSCALL
+
+int CSNMPMessageQueue::GetFdCount()
+{
+ SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+
+ CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+
+ if (!msgEltPtr) return 0;
+
+#ifndef SNMP_PP_IPv6
+ // we have at least one message in the queue and Snmp class
+ // can only have one socket, so
+ return 1;
+#else
+ // we can have max 2 sockets
+ SnmpSocket firstSocket = msgEltPtr->GetMessage()->GetSocket();
+
+ msgEltPtr = msgEltPtr->GetNext();
+
+ while (msgEltPtr)
+ {
+ if (msgEltPtr->GetMessage()->GetSocket() != firstSocket)
+ return 2;
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ return 1;
+#endif
+}
+
+bool CSNMPMessageQueue::GetFdArray(struct pollfd *readfds, int &remaining)
+{
+ SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+
+ CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+ if (!msgEltPtr) return true;
+
+ if (remaining <= 0) return false;
+
+ SnmpSocket firstSocket = msgEltPtr->GetMessage()->GetSocket();
+ readfds[0].fd = firstSocket;
+ readfds[0].events = POLLIN;
+ remaining--;
+
+#ifndef SNMP_PP_IPv6
+ // we have at least one message in the queue and Snmp class
+ // can only have one socket, so we are done
+ return true;
+#else
+ // we can have max 2 sockets
+ msgEltPtr = msgEltPtr->GetNext();
+
+ while (msgEltPtr)
+ {
+ if (msgEltPtr->GetMessage()->GetSocket() != firstSocket)
+ {
+ if (remaining <= 0) return false;
+ readfds[1].fd = msgEltPtr->GetMessage()->GetSocket();
+ readfds[1].events = POLLIN;
+ remaining--;
+
+ return true;
+ }
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ return true;
+#endif
+}
+
+int CSNMPMessageQueue::HandleEvents(const struct pollfd *readfds,
+ const int fds)
+{
+ for (int i=0; i < fds ; i++)
+ {
+ if (readfds[i].revents & POLLIN)
+ {
+ CSNMPMessage *msg;
+ UdpAddress fromaddress;
+ Pdu tmppdu;
+ unsigned long temp_req_id;
+ int status;
+ int recv_status;
+ OctetStr engine_id;
+
+ tmppdu.set_request_id(0);
+
+ // get the response and put it into a Pdu
+ recv_status = receive_snmp_response(readfds[i].fd, *m_snmpSession,
+ tmppdu, fromaddress, engine_id);
+
+ lock();
+ // find the corresponding msg in the message queue
+ temp_req_id = tmppdu.get_request_id();
+ msg = GetEntry(temp_req_id);
+ if (!msg)
+ {
+ unlock();
+ LOG_BEGIN(INFO_LOG | 7);
+ LOG("MsgQueue: Ignore received message without outstanding request (req id)");
+ LOG(tmppdu.get_request_id());
+ LOG_END;
+ // the sent message is gone! probably was canceled, ignore it
+ continue;
+ }
+
+ if (tmppdu.get_request_id())
+ {
+ // we correctly received the pdu
+
+ // save it back into the message
+ status = msg->SetPdu(recv_status, tmppdu, fromaddress);
+
+ if (status != 0)
+ {
+ // received pdu does not match
+ // @todo if version is SNMPv3 we must return a report
+ // unknown pdu handler!
+ unlock();
+ continue;
+ }
+
+#ifdef _SNMPv3
+ if (engine_id.len() > 0)
+ {
+ SnmpTarget *target = msg->GetTarget();
+ if ((target->get_type() == SnmpTarget::type_utarget) &&
+ (target->get_version() == version3))
+ {
+ UdpAddress addr = target->get_address();
+
+ LOG_BEGIN(DEBUG_LOG | 14);
+ LOG("MsgQueue: Adding engine id to table (addr) (id)");
+ LOG(addr.get_printable());
+ LOG(engine_id.get_printable());
+ LOG_END;
+
+ v3MP::I->add_to_engine_id_table(engine_id,
+ (char*)addr.IpAddress::get_printable(),
+ addr.get_port());
+ }
+ }
+#endif
+
+ // Do the callback
+ unlock();
+ status = msg->Callback(SNMP_CLASS_ASYNC_RESPONSE);
+ lock();
+
+ if (!status)
+ {
+ // this is an asynch response and the callback is done.
+ // no need to keep this message around;
+ // Dequeue the message
+ DeleteEntry(temp_req_id);
+ }
+ }
+ unlock();
+ }
+ }
+ return SNMP_CLASS_SUCCESS;
+}
+
+#else // HAVE_POLL_SYSCALL
+
+void CSNMPMessageQueue::GetFdSets(int &maxfds, fd_set &readfds,
+ fd_set &, fd_set &)
+{
+ SnmpSynchronize _synchronize(*this); // REENTRANT
+ CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+ SnmpSocket sock;
+
+ while (msgEltPtr){
+ sock = msgEltPtr->GetMessage()->GetSocket();
+ FD_SET(sock, &readfds);
+ if (maxfds < SAFE_INT_CAST(sock+1))
+ maxfds = SAFE_INT_CAST(sock+1);
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+}
+
+int CSNMPMessageQueue::HandleEvents(const int maxfds,
+ const fd_set &readfds,
+ const fd_set &,
+ const fd_set &)
+{
+ CSNMPMessage *msg;
+ UdpAddress fromaddress;
+ Pdu tmppdu;
+ unsigned long temp_req_id;
+ int status;
+ int recv_status;
+ fd_set snmp_readfds, snmp_writefds, snmp_errfds;
+ int tmp_maxfds = maxfds;
+
+ // Only read from our own fds
+ FD_ZERO(&snmp_readfds);
+ FD_ZERO(&snmp_writefds);
+ FD_ZERO(&snmp_errfds);
+ GetFdSets(tmp_maxfds, snmp_readfds, snmp_writefds, snmp_errfds);
+
+ for (int fd = 0; fd < maxfds; fd++)
+ {
+ if ((FD_ISSET(fd, &snmp_readfds)) &&
+ (FD_ISSET(fd, (fd_set*)&readfds)))
+ {
+ OctetStr engine_id;
+
+ tmppdu.set_request_id(0);
+
+ // get the response and put it into a Pdu
+ recv_status = receive_snmp_response(fd, *m_snmpSession,
+ tmppdu, fromaddress, engine_id);
+
+ lock();
+ // find the corresponding msg in the message queue
+ temp_req_id = tmppdu.get_request_id();
+ msg = GetEntry(temp_req_id);
+ if (!msg) {
+ unlock();
+ LOG_BEGIN(INFO_LOG | 7);
+ LOG("MsgQueue: Ignore received message without outstanding "
+ "request (req id)");
+ LOG(tmppdu.get_request_id());
+ LOG_END;
+ // the sent message is gone! probably was canceled, ignore it
+ continue;
+ }
+
+ if (tmppdu.get_request_id()) {
+ // we correctly received the pdu
+
+ // save it back into the message
+ status = msg->SetPdu(recv_status, tmppdu, fromaddress);
+
+ if (status != 0)
+ {
+ // received pdu does not match
+ // @todo if version is SNMPv3 we must return a report
+ // unknown pdu handler!
+ unlock();
+ continue;
+ }
+
+#ifdef _SNMPv3
+ if (engine_id.len() > 0)
+ {
+ SnmpTarget *target = msg->GetTarget();
+ if ((target->get_type() == SnmpTarget::type_utarget) &&
+ (target->get_version() == version3))
+ {
+ UdpAddress addr = target->get_address();
+
+ LOG_BEGIN(DEBUG_LOG | 14);
+ LOG("MsgQueue: Adding engine id to table (addr) (id)");
+ LOG(addr.get_printable());
+ LOG(engine_id.get_printable());
+ LOG_END;
+
+ v3MP::I->add_to_engine_id_table(engine_id,
+ (char*)addr.IpAddress::get_printable(),
+ addr.get_port());
+ }
+ }
+#endif
+
+ // Do the callback
+ unlock();
+ status = msg->Callback(SNMP_CLASS_ASYNC_RESPONSE);
+ lock();
+
+ if (!status) {
+ // this is an asynch response and the callback is done.
+ // no need to keep this message around;
+ // Dequeue the message
+ DeleteEntry(temp_req_id);
+ }
+ }
+ unlock();
+ } // if socket has data
+ } // for all sockets
+ return SNMP_CLASS_SUCCESS;
+}
+
+#endif // HAVE_POLL_SYSCALL
+
+int CSNMPMessageQueue::DoRetries(const msec &now)
+{
+ CSNMPMessage *msg;
+ msec sendTime(0, 0);
+ int status = SNMP_CLASS_SUCCESS;
+ lock();
+ while ((msg = GetNextTimeoutEntry())) {
+
+ msg->GetSendTime(sendTime);
+
+ if (sendTime <= now)
+ {
+ // send out the message again
+ unlock();
+ status = msg->ResendMessage();
+ lock();
+ if (status != 0)
+ {
+ if (status == SNMP_CLASS_TIMEOUT)
+ {
+ unsigned long req_id = msg->GetId();
+
+ // Dequeue the message
+ DeleteEntry(req_id);
+#ifdef _SNMPv3
+ // delete entry in cache
+ if (v3MP::I)
+ v3MP::I->delete_from_cache(req_id);
+
+ LOG_BEGIN(INFO_LOG | 6);
+ LOG("MsgQueue: Message timed out, removed id from v3MP cache (rid)");
+ LOG(req_id);
+ LOG_END;
+#endif
+ }
+ else {
+ // Some other send error, should we dequeue the message?
+ // do we really want to return without processing the rest?
+ unlock();
+ return status;
+ }
+ }
+ }
+ else {
+ break; // the next timeout is still in the future...so we are done
+ }
+ }
+ unlock();
+ return status;
+}
+
+
+int CSNMPMessageQueue::Done()
+{
+ return 0;
+}
+
+int CSNMPMessageQueue::Done(unsigned long id) REENTRANT ({
+ // FF: This is much more efficient than the above
+ CSNMPMessage *msg = GetEntry(id);
+
+ if (!msg) return 1; // the message is not in the queue...must have timed out
+
+ if (msg->GetReceived())
+ return 1;
+
+ return 0;
+})
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## notifyqueue.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ N O T I F Y Q U E U E . C P P
+
+ CNotifyEventQueue CLASS DEFINITION
+
+ COPYRIGHT HEWLETT PACKARD COMPANY 1999
+
+ INFORMATION NETWORKS DIVISION
+
+ NETWORK MANAGEMENT SECTION
+
+ DESIGN + AUTHOR: Tom Murray
+
+ DESCRIPTION:
+ Queue for holding callback associated with user defined
+ timeouts
+
+=====================================================================*/
+char notifyqueue_version[]="#(@) SNMP++ $Id: notifyqueue.cpp 1826 2010-08-29 20:19:59Z katz $";
+
+//-----[ includes ]----------------------------------------------------
+#include <errno.h>
+
+#if defined (CPU) && CPU == PPC603
+#include <sockLib.h>
+#endif
+
+#if defined(__APPLE__)
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+
+//----[ snmp++ includes ]----------------------------------------------
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/notifyqueue.h" // queue for holding sessions waiting for async notifications
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/uxsnmp.h"
+#include "snmp_pp/snmperrs.h"
+#include "snmp_pp/pdu.h"
+#include "snmp_pp/log.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//--------[ externs ]---------------------------------------------------
+extern int receive_snmp_notification(SnmpSocket sock, Snmp &snmp_session,
+ Pdu &pdu, SnmpTarget **target);
+
+//-----[ macros ]------------------------------------------------------
+// should be in snmp.h...
+#define SNMP_PORT 161 // standard port # for SNMP
+#define SNMP_TRAP_PORT 162 // standard port # for SNMP traps
+
+#ifdef WIN32
+#define close closesocket
+#elif defined(_AIX)
+#include <unistd.h>
+#endif
+
+//----[ CNotifyEvent class ]------------------------------------------------
+
+CNotifyEvent::CNotifyEvent(Snmp *snmp,
+ const OidCollection &trapids,
+ const TargetCollection &targets)
+ : m_snmp(snmp)
+{
+ // create new collections using parms passed in
+ notify_ids = new OidCollection(trapids);
+ notify_targets = new TargetCollection(targets);
+}
+
+CNotifyEvent::~CNotifyEvent()
+{
+ // free up local collections
+ if (notify_ids) { delete notify_ids; notify_ids = 0; }
+ if (notify_targets) { delete notify_targets; notify_targets = 0; }
+}
+
+int CNotifyEvent::notify_filter(const Oid &trapid, SnmpTarget &target) const
+{
+ int target_count, has_target = FALSE, target_matches = FALSE;
+ int trapid_count, has_trapid = FALSE, trapid_matches = FALSE;
+ GenAddress targetaddr, tmpaddr;
+
+ // figure out how many targets, handle empty case as all targets
+ if ((notify_targets) && ((target_count = notify_targets->size())))
+ {
+ SnmpTarget *tmptarget = 0;
+ has_target = TRUE;
+
+ target.get_address(targetaddr);
+
+ if (targetaddr.valid()) {
+ // loop through all targets in the collection
+ SnmpTarget::target_type target_type = target.get_type();
+ SnmpTarget::target_type tmptarget_type;
+
+ for ( int x = 0; x < target_count; x++) // for all targets
+ {
+ if (notify_targets->get_element(tmptarget, x))
+ continue;
+
+ tmptarget->get_address(tmpaddr);
+ if ((tmpaddr.valid())) {
+ int addr_equal = 0;
+
+ /* check for types of Address */
+ if ((tmpaddr.get_type() == Address::type_ip) &&
+ (targetaddr.get_type() == Address::type_udp))
+ {
+ /* special case that works for UdpAddress == IpAddress */
+ IpAddress ip1(targetaddr);
+ IpAddress ip2(tmpaddr);
+
+ addr_equal = (ip1.valid() && ip2.valid() && (ip1 == ip2));
+ }
+ else
+ {
+ addr_equal = (targetaddr == tmpaddr);
+ }
+
+ if (addr_equal) {
+ tmptarget_type = tmptarget->get_type();
+ if (target_type == SnmpTarget::type_utarget) {
+ // target is a UTarget
+ if (tmptarget_type == SnmpTarget::type_utarget) {
+ // both are UTarget
+ if ((((UTarget*)(&target))->get_security_name() ==
+ ((UTarget*)tmptarget)->get_security_name()) &&
+ (((UTarget*)(&target))->get_security_model() ==
+ ((UTarget*)tmptarget)->get_security_model())) {
+ target_matches = TRUE;
+ break;
+ }
+ }
+ else
+ if (tmptarget_type == SnmpTarget::type_ctarget)
+ // in case utarget is used with v1 or v2:
+ if ((tmptarget->get_version() == target.get_version()) &&
+ (((UTarget*)(&target))->get_security_name() ==
+ OctetStr(((CTarget*)tmptarget)->
+ get_readcommunity()))) {
+ target_matches = TRUE;
+ break;
+ }
+ }
+ else {
+ if (target_type == SnmpTarget::type_ctarget) {
+ // target is a CTarget
+ if (tmptarget_type == SnmpTarget::type_ctarget) {
+ // both are CTarget
+ if (!strcmp(((CTarget*)(&target))->get_readcommunity(),
+ ((CTarget*)tmptarget)->get_readcommunity())) {
+ target_matches = TRUE;
+ break;
+ }
+ }
+ else
+ if (tmptarget_type == SnmpTarget::type_utarget) {
+ if ((tmptarget->get_version() == target.get_version()) &&
+ (OctetStr(((CTarget*)(&target))->get_readcommunity()) ==
+ ((UTarget*)tmptarget)->get_security_name())) {
+ target_matches = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ } // end if (add_equal)
+ } // end if tmpaddr.valid()...
+ }
+ }
+ }
+ // else no targets means all targets
+
+ // figure out how many trapids, handle empty case as all trapids
+ if ((notify_ids) && ((trapid_count = notify_ids->size()))) {
+ Oid tmpoid;
+ has_trapid = TRUE;
+ // loop through all trapids in the collection
+ for (int y=0; y < trapid_count; y++) // for all trapids
+ {
+ if (notify_ids->get_element(tmpoid, y))
+ continue;
+ if (trapid == tmpoid) {
+ trapid_matches = TRUE;
+ break;
+ }
+ }
+ }
+ // else no trapids means all traps
+
+ // Make the callback if the trap passed the filters
+ if ((has_target && !target_matches) || (has_trapid && !trapid_matches))
+ return FALSE;
+ return TRUE;
+}
+
+
+int CNotifyEvent::Callback(SnmpTarget &target, Pdu &pdu, SnmpSocket fd, int status)
+{
+ Oid trapid;
+ pdu.get_notify_id(trapid);
+
+ // Make the callback if the trap passed the filters
+ if ((m_snmp) && (notify_filter(trapid, target)))
+ {
+ int reason;
+
+ if (SNMP_CLASS_TL_FAILED == status)
+ reason = SNMP_CLASS_TL_FAILED;
+ else
+ reason = SNMP_CLASS_NOTIFICATION;
+
+ //------[ call into the callback function ]-------------------------
+ if (m_snmp->get_notify_callback())
+ (m_snmp->get_notify_callback())(
+ reason,
+ m_snmp, // snmp++ session who owns the req
+ pdu, // trap pdu
+ target, // target
+ m_snmp->get_notify_callback_data()); // callback data
+ }
+ return SNMP_CLASS_SUCCESS;
+}
+
+
+//----[ CNotifyEventQueueElt class ]--------------------------------------
+
+CNotifyEventQueue::CNotifyEventQueueElt::CNotifyEventQueueElt(
+ CNotifyEvent *notifyevent,
+ CNotifyEventQueueElt *next,
+ CNotifyEventQueueElt *previous)
+ : m_notifyevent(notifyevent), m_Next(next), m_previous(previous)
+{
+ /* Finish insertion into doubly linked list */
+ if (m_Next) m_Next->m_previous = this;
+ if (m_previous) m_previous->m_Next = this;
+}
+
+CNotifyEventQueue::CNotifyEventQueueElt::~CNotifyEventQueueElt()
+{
+ /* Do deletion form doubly linked list */
+ if (m_Next) m_Next->m_previous = m_previous;
+ if (m_previous) m_previous->m_Next = m_Next;
+ if (m_notifyevent) delete m_notifyevent;
+}
+
+CNotifyEvent *CNotifyEventQueue::CNotifyEventQueueElt::TestId(Snmp *snmp)
+{
+ if (m_notifyevent && (m_notifyevent->GetId() == snmp))
+ return m_notifyevent;
+ return 0;
+}
+
+
+//----[ CNotifyEventQueue class ]--------------------------------------
+CNotifyEventQueue::CNotifyEventQueue(EventListHolder *holder, Snmp *session)
+ : m_head(NULL,NULL,NULL), m_msgCount(0), m_notify_fd(INVALID_SOCKET),
+ m_listen_port(SNMP_TRAP_PORT),
+ my_holder(holder), m_snmpSession(session)
+{
+//TM: could do the trap registration setup here but seems better to
+//wait until the app actually requests trap receives by calling
+//notify_register().
+}
+
+CNotifyEventQueue::~CNotifyEventQueue()
+{
+ CNotifyEventQueueElt *leftOver;
+
+ /* walk the list deleting any elements still on the queue */
+ lock();
+ while ((leftOver = m_head.GetNext()))
+ delete leftOver;
+ unlock();
+}
+
+SnmpSocket CNotifyEventQueue::get_notify_fd() const
+{
+ return m_notify_fd;
+}
+
+int CNotifyEventQueue::AddEntry(Snmp *snmp,
+ const OidCollection &trapids,
+ const TargetCollection &targets)
+{
+ SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+
+ if (snmp != m_snmpSession)
+ {
+ debugprintf(0, "WARNING: Adding notification event for other Snmp object");
+ }
+
+ if (!m_msgCount)
+ {
+ m_notify_addr = snmp->get_listen_address();
+ m_notify_addr.set_port(m_listen_port);
+
+ int status = SNMP_CLASS_SUCCESS;
+
+ // This is the first request to receive notifications
+ // Set up the socket for the snmp trap port (162) or the
+ // specified port through set_listen_port()
+ bool is_v4_address = (m_notify_addr.get_ip_version() == Address::version_ipv4);
+ if (is_v4_address)
+ {
+ struct sockaddr_in mgr_addr;
+
+ // open a socket to be used for the session
+ if ((m_notify_fd = socket(AF_INET, SOCK_DGRAM,0)) < 0)
+ {
+#ifdef WIN32
+ int werr = WSAGetLastError();
+ if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (WSAEHOSTDOWN == werr)
+ status = SNMP_CLASS_TL_FAILED;
+ else
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+#else
+ if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (EHOSTDOWN == errno)
+ status = SNMP_CLASS_TL_FAILED;
+ else
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+#endif
+ cleanup();
+ return status;
+ }
+
+ // set up the manager socket attributes
+ unsigned long inaddr = inet_addr(IpAddress(m_notify_addr).get_printable());
+ memset(&mgr_addr, 0, sizeof(mgr_addr));
+ mgr_addr.sin_family = AF_INET;
+ mgr_addr.sin_addr.s_addr = inaddr; // was htonl( INADDR_ANY);
+ mgr_addr.sin_port = htons(m_notify_addr.get_port());
+#ifdef CYGPKG_NET_OPENBSD_STACK
+ mgr_addr.sin_len = sizeof(mgr_addr);
+#endif
+
+ // bind the socket
+ if (bind(m_notify_fd, (struct sockaddr *) &mgr_addr,
+ sizeof(mgr_addr)) < 0)
+ {
+#ifdef WIN32
+ int werr = WSAGetLastError();
+ if (WSAEADDRINUSE == werr)
+ status = SNMP_CLASS_TL_IN_USE;
+ else if (WSAENOBUFS == werr)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (werr == WSAEAFNOSUPPORT)
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+ else if (werr == WSAENETUNREACH)
+ status = SNMP_CLASS_TL_FAILED;
+ else if (werr == EACCES)
+ status = SNMP_CLASS_TL_ACCESS_DENIED;
+ else
+ status = SNMP_CLASS_INTERNAL_ERROR;
+#else
+ if (EADDRINUSE == errno)
+ status = SNMP_CLASS_TL_IN_USE;
+ else if (ENOBUFS == errno)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (errno == EAFNOSUPPORT)
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+ else if (errno == ENETUNREACH)
+ status = SNMP_CLASS_TL_FAILED;
+ else if (errno == EACCES)
+ status = SNMP_CLASS_TL_ACCESS_DENIED;
+ else
+ {
+ debugprintf(0, "Uncatched errno value %d, returning internal error.",
+ errno);
+ status = SNMP_CLASS_INTERNAL_ERROR;
+ }
+#endif
+ debugprintf(0, "Fatal: could not bind to %s",
+ m_notify_addr.get_printable());
+ cleanup();
+ return status;
+ }
+
+ debugprintf(3, "Bind to %s for notifications, fd %d.",
+ m_notify_addr.get_printable(), m_notify_fd);
+ } // is_v4_address
+ else
+ {
+ // not is_v4_address
+#ifdef SNMP_PP_IPv6
+ // open a socket to be used for the session
+ if ((m_notify_fd = socket(AF_INET6, SOCK_DGRAM,0)) < 0)
+ {
+#ifdef WIN32
+ int werr = WSAGetLastError();
+ if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (WSAEHOSTDOWN == werr)
+ status = SNMP_CLASS_TL_FAILED;
+ else
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+#else
+ if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (EHOSTDOWN == errno)
+ status = SNMP_CLASS_TL_FAILED;
+ else
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+#endif
+ cleanup();
+ return status;
+ }
+
+ // set up the manager socket attributes
+ struct sockaddr_in6 mgr_addr;
+ memset(&mgr_addr, 0, sizeof(mgr_addr));
+
+ unsigned int scope = 0;
+
+ OctetStr addrstr = ((IpAddress &)m_notify_addr).IpAddress::get_printable();
+
+ if (m_notify_addr.has_ipv6_scope())
+ {
+ scope = m_notify_addr.get_scope();
+
+ int y = addrstr.len() - 1;
+ while ((y>0) && (addrstr[y] != '%'))
+ {
+ addrstr.set_len(addrstr.len() - 1);
+ y--;
+ }
+ if (addrstr[y] == '%')
+ addrstr.set_len(addrstr.len() - 1);
+ }
+
+ if (inet_pton(AF_INET6, addrstr.get_printable(),
+ &mgr_addr.sin6_addr) < 0)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("Notify transport: inet_pton returns (errno) (str)");
+ LOG(errno);
+ LOG(strerror(errno));
+ LOG_END;
+ cleanup();
+ return SNMP_CLASS_INVALID_ADDRESS;
+ }
+
+ mgr_addr.sin6_family = AF_INET6;
+ mgr_addr.sin6_port = htons(m_notify_addr.get_port());
+ mgr_addr.sin6_scope_id = scope;
+
+ // bind the socket
+ if (bind(m_notify_fd, (struct sockaddr *) &mgr_addr,
+ sizeof(mgr_addr)) < 0)
+ {
+#ifdef WIN32
+ int werr = WSAGetLastError();
+ if (WSAEADDRINUSE == werr)
+ status = SNMP_CLASS_TL_IN_USE;
+ else if (WSAENOBUFS == werr)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (werr == WSAEAFNOSUPPORT)
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+ else if (werr == WSAENETUNREACH)
+ status = SNMP_CLASS_TL_FAILED;
+ else if (werr == EACCES)
+ status = SNMP_CLASS_TL_ACCESS_DENIED;
+ else
+ status = SNMP_CLASS_INTERNAL_ERROR;
+#else
+ if (EADDRINUSE == errno)
+ status = SNMP_CLASS_TL_IN_USE;
+ else if (ENOBUFS == errno)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (errno == EAFNOSUPPORT)
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+ else if (errno == ENETUNREACH)
+ status = SNMP_CLASS_TL_FAILED;
+ else if (errno == EACCES)
+ status = SNMP_CLASS_TL_ACCESS_DENIED;
+ else
+ {
+ debugprintf(0, "Uncatched errno value %d, returning internal error.",
+ errno);
+ status = SNMP_CLASS_INTERNAL_ERROR;
+ return status;
+ }
+#endif
+ debugprintf(0, "Fatal: could not bind to %s",
+ m_notify_addr.get_printable());
+ cleanup();
+ return status;
+ }
+ debugprintf(3, "Bind to %s for notifications, fd %d.",
+ m_notify_addr.get_printable(), m_notify_fd);
+#else
+ debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
+ cleanup();
+ return SNMP_CLASS_TL_UNSUPPORTED;
+#endif
+ } // not is_v4_address
+ }
+
+ CNotifyEvent *newEvent = new CNotifyEvent(snmp, trapids, targets);
+
+ /*---------------------------------------------------------*/
+ /* Insert entry at head of list, done automagically by the */
+ /* constructor function, so don't use the return value. */
+ /*---------------------------------------------------------*/
+ (void) new CNotifyEventQueueElt(newEvent, m_head.GetNext(), &m_head);
+ m_msgCount++;
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+void CNotifyEventQueue::cleanup()
+{
+ if (m_notify_fd != INVALID_SOCKET)
+ {
+ close(m_notify_fd);
+ m_notify_fd = INVALID_SOCKET;
+ }
+ m_notify_addr.clear();
+}
+
+CNotifyEvent *CNotifyEventQueue::GetEntry(Snmp * snmp) REENTRANT ({
+ CNotifyEventQueueElt *msgEltPtr = m_head.GetNext();
+ CNotifyEvent *returnVal = NULL;
+
+ while (msgEltPtr){
+ if ((returnVal = msgEltPtr->TestId(snmp)))
+ return returnVal;
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+ return 0;
+})
+
+void CNotifyEventQueue::DeleteEntry(Snmp *snmp)
+{
+ lock();
+ CNotifyEventQueueElt *msgEltPtr = m_head.GetNext();
+
+ while (msgEltPtr){
+ if (msgEltPtr->TestId(snmp)){
+ delete msgEltPtr;
+ m_msgCount--;
+ break;
+ }
+ msgEltPtr = msgEltPtr->GetNext();
+ }
+
+ if (m_msgCount <= 0)
+ {
+ // shut down the trap socket (if valid) if not using it.
+ if (m_notify_fd != INVALID_SOCKET)
+ {
+ debugprintf(3, "Closing notifications port %s, fd %d.",
+ m_notify_addr.get_printable(), m_notify_fd);
+ close(m_notify_fd);
+ m_notify_fd = INVALID_SOCKET;
+ }
+ m_notify_addr.clear();
+ }
+ unlock();
+}
+
+#ifdef HAVE_POLL_SYSCALL
+int CNotifyEventQueue::GetFdCount()
+{
+ SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+ if (m_notify_fd == INVALID_SOCKET)
+ return 0;
+ return 1;
+}
+
+bool CNotifyEventQueue::GetFdArray(struct pollfd *readfds,
+ int &remaining)
+{
+ SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+
+ if (m_notify_fd != INVALID_SOCKET)
+ {
+ if (remaining == 0)
+ return false;
+ readfds[0].fd = m_notify_fd;
+ readfds[0].events = POLLIN;
+ remaining--;
+ }
+ return true;
+}
+
+int CNotifyEventQueue::HandleEvents(const struct pollfd *readfds,
+ const int fds)
+{
+ SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+
+ int status = SNMP_CLASS_SUCCESS;
+
+ if (m_notify_fd == INVALID_SOCKET)
+ return status;
+
+ for (int i=0; i < fds; i++)
+ {
+ Pdu pdu;
+ SnmpTarget *target = NULL;
+
+ if ((readfds[i].revents & POLLIN) == 0)
+ continue; // nothing to receive
+
+ if (readfds[i].fd != m_notify_fd)
+ continue; // not our socket
+
+ status = receive_snmp_notification(m_notify_fd, *m_snmpSession,
+ pdu, &target);
+
+ if ((SNMP_CLASS_SUCCESS == status) ||
+ (SNMP_CLASS_TL_FAILED == status))
+ {
+ // If we have transport layer failure, the app will want to
+ // know about it.
+ // Go through each snmp object and check the filters, making
+ // callbacks as necessary
+ if (!target) target = new SnmpTarget();
+
+ CNotifyEventQueueElt *notifyEltPtr = m_head.GetNext();
+ while (notifyEltPtr)
+ {
+ notifyEltPtr->GetNotifyEvent()->Callback(*target, pdu,
+ m_notify_fd, status);
+ notifyEltPtr = notifyEltPtr->GetNext();
+ } // for each snmp object
+ }
+ if (target) // receive_snmp_notification calls new
+ delete target;
+ }
+
+ return status;
+}
+
+#else
+
+void CNotifyEventQueue::GetFdSets(int &maxfds, fd_set &readfds,
+ fd_set &/*writefds*/,
+ fd_set &/*exceptfds*/)
+{
+ SnmpSynchronize _synchronize(*this); // REENTRANT
+ if (m_notify_fd != INVALID_SOCKET)
+ {
+ FD_SET(m_notify_fd, &readfds);
+ if (maxfds < SAFE_INT_CAST(m_notify_fd + 1))
+ maxfds = SAFE_INT_CAST(m_notify_fd + 1);
+ }
+ return;
+}
+
+int CNotifyEventQueue::HandleEvents(const int /*maxfds*/,
+ const fd_set &readfds,
+ const fd_set &/*writefds*/,
+ const fd_set &/*exceptfds*/)
+{
+ SnmpSynchronize _synchronize(*this); // REENTRANT
+ int status = SNMP_CLASS_SUCCESS;
+
+ if (m_notify_fd == INVALID_SOCKET)
+ return status;
+
+ Pdu pdu;
+ SnmpTarget *target = NULL;
+
+ // pull the notifiaction off the socket
+ if (FD_ISSET(m_notify_fd, (fd_set*)&readfds)) {
+ status = receive_snmp_notification(m_notify_fd, *m_snmpSession,
+ pdu, &target);
+
+ if ((SNMP_CLASS_SUCCESS == status) ||
+ (SNMP_CLASS_TL_FAILED == status))
+ {
+ // If we have transport layer failure, the app will want to
+ // know about it.
+ // Go through each snmp object and check the filters, making
+ // callbacks as necessary
+
+ // On failure target will be NULL
+ if (!target)
+ target = new SnmpTarget();
+
+ CNotifyEventQueueElt *notifyEltPtr = m_head.GetNext();
+ while (notifyEltPtr)
+ {
+ notifyEltPtr->GetNotifyEvent()->Callback(*target, pdu,
+ m_notify_fd, status);
+ notifyEltPtr = notifyEltPtr->GetNext();
+ } // for each snmp object
+ }
+ if (target) // receive_snmp_notification calls new
+ delete target;
+ }
+ return status;
+}
+
+#endif // HAVE_POLL_SYSCALL
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## octet.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ O C T E T . C P P
+
+ OCTETSTR CLASS IMPLEMENTATION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ This class is fully contained and does not rely on or any other
+ SNMP libraries. This class is portable across any platform
+ which supports C++.
+=====================================================================*/
+char octet_cpp_version[]="@(#) SNMP++ $Id: octet.cpp 1824 2010-08-29 19:47:08Z katz $";
+
+#include "snmp_pp/octet.h" // include definition for octet class
+#include <ctype.h> // for isprint() used by get_printable()
+#include <stdio.h> // for sprintf() used by get_printable_hex()
+#include <string.h> // for strlen() and memcpy()
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+enum OctetStr::OutputType OctetStr::hex_output_type
+ = OctetStr::OutputHexAndClear;
+char OctetStr::nonprintable_char = '.';
+
+#ifdef __unix
+ char OctetStr::linefeed_chars[3] = "\n";
+#else
+ char OctetStr::linefeed_chars[3] = "\r\n";
+#endif // __unix
+
+
+//============[ constructor using no arguments ]======================
+OctetStr::OctetStr()
+ : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
+{
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.ptr = 0;
+ smival.value.string.len = 0;
+}
+
+//============[ constructor using a string ]=========================
+OctetStr::OctetStr(const char *str)
+ : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
+{
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.ptr = 0;
+ smival.value.string.len = 0;
+
+ size_t z;
+
+ // check for null string
+ if (!str || !((z = strlen(str))))
+ return;
+
+ // get mem needed
+ smival.value.string.ptr = (SmiLPBYTE) new unsigned char[z];
+
+ if (smival.value.string.ptr)
+ {
+ MEMCPY(smival.value.string.ptr, str, z);
+ smival.value.string.len = SAFE_INT_CAST(z);
+ }
+ else
+ validity = false;
+}
+
+
+//============[ constructor using an unsigned char * ]================
+OctetStr::OctetStr(const unsigned char *str, unsigned long len)
+ : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
+{
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.ptr = 0;
+ smival.value.string.len = 0;
+
+ if (!str || !len) return; // check for zero len
+
+ // get the mem needed
+ smival.value.string.ptr = (SmiLPBYTE) new unsigned char[len];
+
+ if (smival.value.string.ptr)
+ {
+ MEMCPY(smival.value.string.ptr, str, (size_t) len);
+ smival.value.string.len = len;
+ }
+ else
+ validity = false;
+}
+
+//============[ constructor using another octet object ]==============
+OctetStr::OctetStr (const OctetStr &octet)
+ : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
+{
+ smival.syntax = sNMP_SYNTAX_OCTETS;
+ smival.value.string.ptr = 0;
+ smival.value.string.len = 0;
+
+ if (octet.smival.value.string.len == 0) return; // check for zero len case
+
+ // must be a valid object
+ if (!octet.validity)
+ {
+ validity = false;
+ return;
+ }
+
+ // get the mem needed
+ smival.value.string.ptr = (SmiLPBYTE) new unsigned char[octet.smival.value.string.len];
+
+ if (smival.value.string.ptr)
+ {
+ MEMCPY(smival.value.string.ptr,
+ octet.smival.value.string.ptr,
+ (size_t) octet.smival.value.string.len);
+ smival.value.string.len = octet.smival.value.string.len;
+ }
+ else
+ validity = false;
+}
+
+//=============[ destructor ]=========================================
+OctetStr::~OctetStr()
+{
+ // if not empty, free it up
+ if (smival.value.string.ptr) delete [] smival.value.string.ptr;
+ smival.value.string.len = 0;
+ smival.value.string.ptr = 0;
+ if (output_buffer) delete [] output_buffer;
+ output_buffer = 0;
+ output_buffer_len = 0;
+}
+
+
+//============[ set the data on an already constructed Octet ]============
+void OctetStr::set_data(const unsigned char *str, unsigned long len)
+{
+ // free up already used space
+ if (smival.value.string.ptr)
+ {
+ delete [] smival.value.string.ptr;
+ smival.value.string.ptr = 0;
+ }
+ smival.value.string.len = 0;
+ m_changed = true;
+
+ // check for zero len
+ if (!str || !len)
+ {
+ validity = true;
+ return;
+ }
+
+ // get the mem needed
+ smival.value.string.ptr = (SmiLPBYTE) new unsigned char[len];
+
+ if (smival.value.string.ptr)
+ {
+ MEMCPY(smival.value.string.ptr, str, len);
+ smival.value.string.len = len;
+ validity = true;
+ }
+ else
+ validity = false;
+}
+
+//=============[ assignment to a string operator overloaded ]=========
+OctetStr& OctetStr::operator=(const char *str)
+{
+ size_t nz;
+
+ // free up previous memory if needed
+ if (smival.value.string.ptr)
+ {
+ delete [] smival.value.string.ptr;
+ smival.value.string.ptr = 0;
+ smival.value.string.len = 0;
+ }
+
+ m_changed = true;
+
+ // if empty then we are done; get the string size
+ if (!str || !((nz = strlen(str))))
+ {
+ validity = true;
+ return *this;
+ }
+
+ // get memory needed
+ smival.value.string.ptr = (SmiLPBYTE) new unsigned char[nz];
+
+ if (smival.value.string.ptr)
+ {
+ MEMCPY(smival.value.string.ptr, str, nz);
+ smival.value.string.len = SAFE_INT_CAST(nz);
+ validity = true;
+ }
+ else
+ validity = false;
+
+ return *this; // return self reference
+}
+
+//=============[ assignment to another oid object overloaded ]========
+OctetStr& OctetStr::operator=(const OctetStr &octet)
+{
+ if (this == &octet) return *this; // protect against assignment from self
+
+ if (!octet.validity) return *this; // don't assign from invalid objs
+
+ set_data(octet.smival.value.string.ptr, octet.smival.value.string.len);
+
+ return *this; // return self reference
+}
+
+//==============[ equivlence operator overloaded ]====================
+int operator==(const OctetStr &lhs, const OctetStr &rhs)
+{
+ if (lhs.smival.value.string.len != rhs.smival.value.string.len)
+ return false;
+ return (lhs.nCompare(rhs.smival.value.string.len, rhs) == 0);
+}
+
+//==============[ not equivlence operator overloaded ]================
+int operator!=(const OctetStr &lhs, const OctetStr &rhs)
+{
+ if (lhs.smival.value.string.len != rhs.smival.value.string.len)
+ return true;
+ return (lhs.nCompare(rhs.smival.value.string.len, rhs) != 0);
+}
+
+//==============[ less than < overloaded ]============================
+int operator<(const OctetStr &lhs, const OctetStr &rhs)
+{
+ int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
+ ? lhs.smival.value.string.len : rhs.smival.value.string.len;
+ return (lhs.nCompare(maxlen, rhs) < 0);
+}
+
+//==============[ less than <= overloaded ]===========================
+int operator<=(const OctetStr &lhs, const OctetStr &rhs)
+{
+ int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
+ ? lhs.smival.value.string.len : rhs.smival.value.string.len;
+ return (lhs.nCompare(maxlen, rhs) <= 0);
+}
+
+//===============[ greater than > overloaded ]========================
+int operator>(const OctetStr &lhs, const OctetStr &rhs)
+{
+ int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
+ ? lhs.smival.value.string.len : rhs.smival.value.string.len;
+ return (lhs.nCompare(maxlen, rhs) > 0);
+}
+
+//===============[ greater than >= overloaded ]=======================
+int operator>=(const OctetStr &lhs, const OctetStr &rhs)
+{
+ int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
+ ? lhs.smival.value.string.len : rhs.smival.value.string.len;
+ return (lhs.nCompare(maxlen, rhs) >=0);
+}
+
+//===============[ equivlence operator overloaded ]===================
+int operator==(const OctetStr &lhs, const char *rhs)
+{
+ OctetStr to(rhs);
+ if (lhs.smival.value.string.len != to.smival.value.string.len)
+ return false;
+ return (lhs.nCompare(to.smival.value.string.len, to) == 0);
+}
+
+//===============[ not equivlence operator overloaded ]===============
+int operator!=(const OctetStr &lhs, const char *rhs)
+{
+ OctetStr to(rhs);
+ if (lhs.smival.value.string.len != to.smival.value.string.len)
+ return true;
+ return (lhs.nCompare(to.smival.value.string.len, to) != 0);
+}
+
+//===============[ less than < operator overloaded ]==================
+int operator<(const OctetStr &lhs, const char *rhs)
+{
+ OctetStr to(rhs);
+ int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
+ ? lhs.smival.value.string.len : to.smival.value.string.len;
+ return (lhs.nCompare(maxlen,to) < 0);
+}
+
+//===============[ less than <= operator overloaded ]=================
+int operator<=(const OctetStr &lhs, const char *rhs)
+{
+ OctetStr to(rhs);
+ int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
+ ? lhs.smival.value.string.len : to.smival.value.string.len;
+ return (lhs.nCompare(maxlen, to) <= 0);
+}
+
+//===============[ greater than > operator overloaded ]===============
+int operator>(const OctetStr &lhs, const char *rhs)
+{
+ OctetStr to(rhs);
+ int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
+ ? lhs.smival.value.string.len : to.smival.value.string.len;
+ return (lhs.nCompare(maxlen, to) > 0);
+}
+
+//===============[ greater than >= operator overloaded ]==============
+int operator>=(const OctetStr &lhs, const char *rhs)
+{
+ OctetStr to(rhs);
+ int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
+ ? lhs.smival.value.string.len : to.smival.value.string.len;
+ return (lhs.nCompare(maxlen, to) >= 0);
+}
+
+//===============[ append operator, appends a string ]================
+OctetStr& OctetStr::operator+=(const char *a)
+{
+ unsigned char *tmp;
+ size_t slen, nlen;
+
+ // get len of string
+ if (!a || ((slen = strlen(a)) == 0))
+ return *this;
+
+ nlen = slen + (size_t) smival.value.string.len; // total len of new octet
+ tmp = (SmiLPBYTE) new unsigned char[nlen]; // get mem needed
+
+ if (tmp)
+ {
+ // copy in the original 1st
+ MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
+ // copy in the string
+ MEMCPY(tmp + smival.value.string.len, a, slen);
+ // delete the original
+ if (smival.value.string.ptr)
+ delete [] smival.value.string.ptr;
+ // point to the new one
+ smival.value.string.ptr = tmp;
+ smival.value.string.len = SAFE_INT_CAST(nlen);
+
+ m_changed = true;
+ }
+ return *this;
+}
+
+//================[ append one OctetStr to another ]==================
+OctetStr& OctetStr::operator+=(const OctetStr& octet)
+{
+ unsigned char *tmp;
+ size_t slen, nlen;
+
+ if (!octet.validity || !((slen = (size_t)octet.len())))
+ return *this;
+
+ nlen = slen + (size_t) smival.value.string.len; // total len of new octet
+ tmp = (SmiLPBYTE) new unsigned char[nlen]; // get mem needed
+
+ if (tmp)
+ {
+ // copy in the original 1st
+ MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
+ // copy in the string
+ MEMCPY(tmp + smival.value.string.len, octet.data(), slen);
+ // delete the original
+ if (smival.value.string.ptr )
+ delete [] smival.value.string.ptr;
+ // point to the new one
+ smival.value.string.ptr = tmp;
+ smival.value.string.len = SAFE_INT_CAST(nlen);
+
+ m_changed = true;
+ }
+ return *this;
+}
+
+//================[ appends a char ]==================================
+OctetStr& OctetStr::operator+=(const unsigned char c)
+{
+ unsigned char *tmp;
+
+ // get the memory needed plus one extra byte
+ tmp = (SmiLPBYTE) new unsigned char[smival.value.string.len + 1];
+
+ if (tmp)
+ {
+ MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
+ tmp[smival.value.string.len] = c; // assign in new byte
+
+ if (smival.value.string.ptr) // delete the original
+ delete [] smival.value.string.ptr;
+
+ smival.value.string.ptr = tmp; // point to new one
+ smival.value.string.len++; // up the len
+
+ m_changed = true;
+ }
+ return *this; // return self reference
+}
+
+//================[ compare n elements of an Octet ]==================
+int OctetStr::nCompare(const unsigned long n, const OctetStr &o) const
+{
+ unsigned long n_max;
+ unsigned long w,str_len;
+
+ if (n == 0) return 0; // Nothing to compare, strings are equal
+
+ // both are empty, they are equal
+ if ((smival.value.string.len == 0) && (o.smival.value.string.len == 0))
+ return 0; // equal
+
+ // self is empty and param has something
+ if ((smival.value.string.len == 0) && (o.smival.value.string.len > 0))
+ return -1;
+
+ // self has something and param has nothing
+ if ((smival.value.string.len > 0) && (o.smival.value.string.len == 0))
+ return 1;
+
+ // now: n > 0; this.len > 0; o.len > 0 !!!
+
+ // pick the Min of n, this and the param len
+ // this is the maximum # to iterate a search
+ str_len = smival.value.string.len < o.smival.value.string.len
+ ? smival.value.string.len : o.smival.value.string.len;
+ w = (n <= str_len) ? n : str_len;
+
+ unsigned long z = 0;
+ while (z < w)
+ {
+ if (smival.value.string.ptr[z] < o.smival.value.string.ptr[z])
+ return -1; // less than
+ if (smival.value.string.ptr[z] > o.smival.value.string.ptr[z])
+ return 1; // greater than
+ z++;
+ }
+
+ // now: z == w > 0
+ // set n_max to min(n, max(len of strings))
+ n_max = smival.value.string.len > o.smival.value.string.len
+ ? smival.value.string.len : o.smival.value.string.len;
+ if (n< n_max) n_max = n;
+
+ if (w < n_max) // ==> we have compared too few bytes
+ {
+ if (smival.value.string.len < o.smival.value.string.len)
+ return -1;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+//================[ ASCII format return ]=============================
+const char *OctetStr::get_printable() const
+{
+ if ((m_changed == false) &&
+ (output_last_function == OutputFunctionDefault))
+ return output_buffer;
+
+ for (unsigned long i=0; i < smival.value.string.len; i++)
+ {
+ if ((smival.value.string.ptr[i] != '\r')&&
+ (smival.value.string.ptr[i] != '\n')&&
+ (isprint((int) (smival.value.string.ptr[i]))==0))
+ switch (hex_output_type)
+ {
+ case OutputClear: return get_printable_clear();
+ case OutputHexAndClear:
+ case OutputHex:
+ default: return get_printable_hex();
+ }
+ }
+
+ OctetStr *ncthis = PP_CONST_CAST(OctetStr*, this);
+ if (output_buffer_len < smival.value.string.len + 1)
+ {
+ if (output_buffer) delete [] ncthis->output_buffer;
+
+ ncthis->output_buffer = new char[smival.value.string.len + 1];
+ if (!ncthis->output_buffer)
+ {
+ ncthis->output_buffer_len = 0;
+ return output_buffer;
+ }
+ ncthis->output_buffer_len = smival.value.string.len + 1;
+ }
+ if (smival.value.string.len)
+ MEMCPY(ncthis->output_buffer,
+ smival.value.string.ptr, (unsigned int) smival.value.string.len);
+ ncthis->output_buffer[smival.value.string.len] = '\0';
+
+ ncthis->m_changed = false;
+ ncthis->output_last_function = OutputFunctionDefault;
+
+ return output_buffer;
+}
+
+//================[ ASCII format return ]=============================
+const char *OctetStr::get_printable_clear() const
+{
+ if ((m_changed == false) &&
+ (output_last_np_char == nonprintable_char) &&
+ (output_last_function == OutputFunctionClear))
+ return output_buffer;
+
+ OctetStr *ncthis = PP_CONST_CAST(OctetStr*, this);
+ if (output_buffer_len < smival.value.string.len + 1)
+ {
+ if (output_buffer) delete [] ncthis->output_buffer;
+
+ ncthis->output_buffer = new char[smival.value.string.len + 1];
+ if (!ncthis->output_buffer)
+ {
+ ncthis->output_buffer_len = 0;
+ return output_buffer;
+ }
+ ncthis->output_buffer_len = smival.value.string.len + 1;
+ }
+
+ if (smival.value.string.len)
+ {
+ for (unsigned long i=0; i < smival.value.string.len; i++)
+ {
+ if (isprint((int) (smival.value.string.ptr[i]))==0)
+ ncthis->output_buffer[i] = nonprintable_char;
+ else
+ ncthis->output_buffer[i] = smival.value.string.ptr[i];
+ }
+ }
+
+ ncthis->output_buffer[smival.value.string.len] = '\0';
+
+ ncthis->output_last_np_char = nonprintable_char;
+ ncthis->m_changed = false;
+ ncthis->output_last_function = OutputFunctionClear;
+
+ return output_buffer;
+}
+
+
+//================[ general Value = operator ]========================
+SnmpSyntax& OctetStr::operator=(const SnmpSyntax &val)
+{
+ if (this == &val) return *this; // protect against assignment from self
+
+ // blow away the old value
+ if (smival.value.string.ptr)
+ {
+ delete [] smival.value.string.ptr;
+ smival.value.string.ptr = 0;
+ }
+ smival.value.string.len = 0;
+ validity = false;
+
+ if (val.valid()){
+ switch (val.get_syntax()){
+ case sNMP_SYNTAX_OPAQUE:
+ case sNMP_SYNTAX_BITS:
+ case sNMP_SYNTAX_OCTETS:
+ case sNMP_SYNTAX_IPADDR:
+ set_data(((OctetStr &)val).smival.value.string.ptr,
+ ((OctetStr &)val).smival.value.string.len);
+ break;
+ }
+ }
+ m_changed = true;
+ return *this;
+}
+
+#define ATOI(x) if ((x >= 48) && (x <= 57)) x = x-48; /* 0-9 */ \
+ else if ((x >= 65) && (x <= 70)) x = x-55; /* A-F */ \
+ else if ((x >= 97) && (x <=102)) x = x-87; /* a-f */ \
+ else x = 0
+
+//=======[ create an octet string from a hex string ]===================
+OctetStr OctetStr::from_hex_string(const OctetStr &hex_string)
+{
+ OctetStr val;
+ unsigned int p;
+ unsigned int hex_len = 0;
+
+ // make sure the string has at least one byte
+ if (hex_string.len() == 0) return val;
+
+ // allocate max needed space for copy without spaces
+ unsigned char *hex, *hex_ptr;
+ hex = hex_ptr = new unsigned char[hex_string.len()];
+ if (!hex) return val;
+
+ // delete spaces
+ const unsigned char *ptr = hex_string.smival.value.string.ptr;
+ for (p = hex_string.len(); p > 0; p--)
+ {
+ unsigned char c = *ptr++;
+ if (c != ' ')
+ {
+ *hex_ptr++ = c;
+ ++hex_len;
+ }
+ }
+
+ // leading 0 may be omitted
+ if (hex_len % 2)
+ {
+ unsigned char c = hex[0];
+ ATOI(c);
+ val += c;
+ p = 1;
+ }
+ else
+ {
+ p = 0;
+ }
+
+ while (p < hex_len)
+ {
+ unsigned char c = hex[p++];
+ unsigned char d = hex[p++];
+
+ ATOI(c);
+ ATOI(d);
+ val += (c*16 + d);
+ }
+ delete[] hex;
+ return val;
+}
+
+#undef ATOI
+
+//================[ format the output into hex ]========================
+const char *OctetStr::get_printable_hex() const
+{
+ if ((m_changed == false) && (output_last_type == hex_output_type) &&
+ (output_last_np_char == nonprintable_char) &&
+ (output_last_function == OutputFunctionHex))
+ return output_buffer;
+
+ int cnt;
+ char char_buf[80]; // holds ASCII representation of data
+ char *buf_ptr; // pointer into ASCII listing
+ char *line_ptr; // pointer into Hex listing
+ unsigned int storageNeeded; // how much space do we need ?
+ int local_len = (int) smival.value.string.len;
+ unsigned char *bytes = smival.value.string.ptr;
+
+ storageNeeded = (unsigned int) ((smival.value.string.len/16)+1) * 72 + 1;
+ OctetStr *ncthis = PP_CONST_CAST(OctetStr*, this);
+
+ if (output_buffer_len < storageNeeded)
+ {
+ if (output_buffer) delete [] ncthis->output_buffer;
+
+ ncthis->output_buffer = new char[storageNeeded];
+ if (!ncthis->output_buffer)
+ {
+ ncthis->output_buffer_len = 0;
+ return output_buffer;
+ }
+ ncthis->output_buffer_len = storageNeeded;
+ }
+
+ line_ptr = ncthis->output_buffer;
+
+ /*----------------------------------------*/
+ /* processing loop for entire data buffer */
+ /*----------------------------------------*/
+ while (local_len > 0)
+ {
+ cnt = 16; /* print 16 bytes per line */
+ buf_ptr = char_buf;
+ sprintf(line_ptr, " ");
+ line_ptr += 2; /* indent */
+
+ /*-----------------------*/
+ /* process a single line */
+ /*-----------------------*/
+ while (cnt-- > 0 && local_len-- > 0)
+ {
+ sprintf(line_ptr, "%2.2X ", *bytes);
+
+ line_ptr +=3; /* the display of a byte always 3 chars long */
+ if (isprint(*bytes))
+ *buf_ptr++ = *bytes;
+ else
+ *buf_ptr++ = nonprintable_char;
+ ++bytes;
+ }
+ ++cnt;
+ *buf_ptr = 0; // null terminate string
+
+ /*----------------------------------------------------------*/
+ /* this is to make sure that the ASCII displays line up for */
+ /* incomplete lines of hex */
+ /*----------------------------------------------------------*/
+ while (cnt-- > 0)
+ {
+ *line_ptr++ = ' ';
+ *line_ptr++ = ' ';
+ *line_ptr++ = ' ';
+ }
+
+ /*------------------------------------------*/
+ /* append the ASCII display to the Hex line */
+ /*------------------------------------------*/
+ if (hex_output_type == OutputHex)
+ char_buf[0] = 0;
+
+ sprintf(line_ptr," %s%s", char_buf, linefeed_chars);
+ line_ptr += 3 + strlen(char_buf) + strlen(linefeed_chars);
+ }
+
+ ncthis->output_last_type = hex_output_type;
+ ncthis->output_last_np_char = nonprintable_char;
+ ncthis->m_changed = false;
+ ncthis->output_last_function = OutputFunctionHex;
+
+ return output_buffer;
+}
+
+
+//==============[ Null out the contents of the string ]===================
+void OctetStr::clear()
+{
+ if (smival.value.string.len > 0)
+ {
+ memset(smival.value.string.ptr, 0, smival.value.string.len);
+ smival.value.string.len = 0;
+ }
+
+ if (output_buffer)
+ memset(output_buffer, 0, output_buffer_len);
+ m_changed = true;
+}
+
+//============[Return the space needed for serialization]=================
+int OctetStr::get_asn1_length() const
+{
+ if (smival.value.string.len < 0x80)
+ return smival.value.string.len + 2;
+ else if (smival.value.string.len < 0x100)
+ return smival.value.string.len + 3;
+ else if (smival.value.string.len < 0x10000)
+ return smival.value.string.len + 4;
+ else if (smival.value.string.len < 0x1000000)
+ return smival.value.string.len + 5;
+ return smival.value.string.len + 6; // should be safe for some time...
+}
+
+//========[Set the character for linefeeds in get_printable() functions]====
+bool OctetStr::set_linefeed_chars(const char* lf_chars)
+{
+ if (!lf_chars) return false;
+ if (strlen(lf_chars) > 2) return false;
+
+ linefeed_chars[2] = 0;
+ linefeed_chars[1] = lf_chars[1];
+ linefeed_chars[0] = lf_chars[0];
+
+ return true;
+}
+
+//===============[ append or shorten the data buffer ]================
+bool OctetStr::set_len(const unsigned long new_len)
+{
+ unsigned char *tmp;
+
+ if (new_len <= smival.value.string.len)
+ {
+ smival.value.string.len = new_len;
+ m_changed = true;
+
+ if (new_len == 0)
+ {
+ if (smival.value.string.ptr) delete [] smival.value.string.ptr;
+ smival.value.string.ptr = 0;
+ }
+
+ return true;
+ }
+
+ tmp = (SmiLPBYTE) new unsigned char[new_len]; // get mem needed
+
+ if (!tmp) return false;
+
+ if (smival.value.string.ptr)
+ MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
+ memset(tmp + smival.value.string.len, 0, new_len - smival.value.string.len);
+ if (smival.value.string.ptr)
+ delete [] smival.value.string.ptr;
+ smival.value.string.ptr = tmp;
+ smival.value.string.len = new_len;
+
+ m_changed = true;
+
+ return true;
+}
+
+
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## oid.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ O I D. C P P
+
+ OID CLASS IMPLEMENTATION
+
+ DESIGN + AUTHOR: Peter E. Mellquist
+
+ DESCRIPTION:
+ This module contains the implementation of the oid class. This
+ includes all protected and public member functions. The oid class
+ may be compiled stand alone without the use of any other library.
+=====================================================================*/
+char oid_cpp_version[]="#(@) SNMP++ $Id: oid.cpp 1742 2010-04-29 19:08:54Z katz $";
+
+//---------[ external C libaries used ]--------------------------------
+#include <stdio.h> // standard io
+#if !(defined (CPU) && CPU == PPC603)
+#include <memory.h> // memcpy's
+#endif
+#include <string.h> // strlen, etc..
+#include <stdlib.h> // standard library
+#include <ctype.h> // isdigit
+#include <stdlib.h> // malloc, free
+
+#include "snmp_pp/oid.h" // include def for oid class
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define SNMPBUFFSIZE 11 // size of scratch buffer
+#define SNMPCHARSIZE 11 // an individual oid instance as a string
+
+/* Borlands isdigit has a bug */
+#ifdef __BCPLUSPLUS__
+#define my_isdigit(c) ((c) >= '0' && (c) <= '9')
+#else
+#define my_isdigit isdigit
+#endif
+
+//=============[Oid::Oid(void)]============================================
+// constructor using no arguments
+// initialize octet ptr and string
+// ptr to null
+Oid::Oid() : iv_str(0), iv_part_str(0), m_changed(true)
+{
+ smival.syntax = sNMP_SYNTAX_OID;
+ smival.value.oid.len = 0;
+ smival.value.oid.ptr = 0;
+}
+
+
+//=============[Oid::Oid(const char *dotted_string ]=====================
+// constructor using a dotted string
+//
+// do a string to oid using the string passed in
+Oid::Oid(const char *oid_string, const bool is_dotted_oid_string)
+ : iv_str(0), iv_part_str(0), m_changed(true)
+{
+ smival.syntax = sNMP_SYNTAX_OID;
+ smival.value.oid.len = 0;
+ smival.value.oid.ptr = 0;
+
+ if (is_dotted_oid_string)
+ StrToOid(oid_string, &smival.value.oid);
+ else
+ set_data(oid_string, oid_string ? strlen(oid_string) : 0);
+}
+
+
+//=============[Oid::Oid(const Oid &oid) ]================================
+// constructor using another oid object
+//
+// do an oid copy using the oid object passed in
+Oid::Oid(const Oid &oid)
+ : iv_str(0), iv_part_str(0), m_changed(true)
+{
+ smival.syntax = sNMP_SYNTAX_OID;
+ smival.value.oid.len = 0;
+ smival.value.oid.ptr = 0;
+
+ // allocate some memory for the oid
+ // in this case the size to allocate is the same size as the source oid
+ if (oid.smival.value.oid.len)
+ {
+ smival.value.oid.ptr = (SmiLPUINT32) new unsigned long[oid.smival.value.oid.len];
+ if (smival.value.oid.ptr)
+ OidCopy((SmiLPOID)&(oid.smival.value.oid), (SmiLPOID)&smival.value.oid);
+ }
+}
+
+
+//=============[Oid::Oid(const unsigned long *raw_oid, int oid_len) ]====
+// constructor using raw numeric form
+//
+// copy the integer values into the private member
+Oid::Oid(const unsigned long *raw_oid, int oid_len)
+ : iv_str(0), iv_part_str(0), m_changed(true)
+{
+ smival.syntax = sNMP_SYNTAX_OID;
+ smival.value.oid.len = 0;
+ smival.value.oid.ptr = 0;
+
+ if (raw_oid && (oid_len > 0))
+ {
+ smival.value.oid.ptr = (SmiLPUINT32) new unsigned long[oid_len];
+ if (smival.value.oid.ptr)
+ {
+ smival.value.oid.len = oid_len;
+ for (int i=0; i < oid_len; i++)
+ smival.value.oid.ptr[i] = raw_oid[i];
+ }
+ }
+}
+
+//=============[Oid::~Oid]==============================================
+Oid::~Oid()
+{
+ delete_oid_ptr();
+ if (iv_str) delete [] iv_str; // free up the output string
+ if (iv_part_str) delete [] iv_part_str; // free up the output string
+}
+
+
+//=============[Oid::operator = const char * dotted_string ]==============
+// assignment to a string operator overloaded
+//
+// free the existing oid
+// create the new oid from the string
+// return this object
+Oid& Oid::operator=(const char *dotted_oid_string)
+{
+ delete_oid_ptr();
+
+ // assign the new value
+ StrToOid(dotted_oid_string, &smival.value.oid);
+ return *this;
+}
+
+
+//=============[Oid:: operator = const Oid &oid ]==========================
+// assignment to another oid object overloaded
+//
+// free the existing oid
+// create a new one from the object passed in
+Oid& Oid::operator=(const Oid &oid)
+{
+ if (this == &oid) return *this; // protect against assignment from self
+
+ delete_oid_ptr();
+
+ // check for zero len on source
+ if (oid.smival.value.oid.len == 0)
+ return *this;
+
+ // allocate some memory for the oid
+ smival.value.oid.ptr = (SmiLPUINT32) new unsigned long[oid.smival.value.oid.len];
+ if (smival.value.oid.ptr)
+ OidCopy((SmiLPOID)&(oid.smival.value.oid), (SmiLPOID)&smival.value.oid);
+ return *this;
+}
+
+
+//==============[Oid:: operator += const char *a ]=========================
+// append operator, appends a string
+//
+// allocate some space for a max oid string
+// extract current string into space
+// concat new string
+// free up existing oid
+// make a new oid from string
+// delete allocated space
+Oid& Oid::operator+=(const char *a)
+{
+ unsigned int n;
+
+ if (!a) return *this;
+
+ if (*a == '.') ++a;
+
+ n = (smival.value.oid.len * SNMPCHARSIZE) + (smival.value.oid.len)
+ + 1 + SAFE_UINT_CAST(strlen(a));
+ char *ptr = new char[n];
+ if (ptr)
+ {
+ /// @todo optimze this function (avoid conversion to string)
+ OidToStr(&smival.value.oid, n, ptr);
+ if (ptr[0])
+ STRCAT(ptr,".");
+ STRCAT(ptr,a);
+
+ delete_oid_ptr();
+
+ StrToOid(ptr, &smival.value.oid);
+ delete [] ptr;
+ }
+ return *this;
+}
+
+//=============[ int operator == oid,oid ]=================================
+// equivlence operator overloaded
+int operator==(const Oid &lhs, const Oid &rhs)
+{
+ // ensure same len, then use nCompare
+ if (rhs.len() != lhs.len()) return 0;
+ return (lhs.nCompare(rhs.len(), rhs) == 0);
+}
+
+//==============[ operator<(Oid &x,Oid &y) ]=============================
+// less than < overloaded
+int operator<(const Oid &lhs, const Oid &rhs)
+{
+ int result;
+ // call nCompare with the current
+ // Oidx, Oidy and len of Oidx
+ if((result = lhs.nCompare(rhs.len(), rhs))<0) return 1;
+ if (result > 0) return 0;
+
+ // if here, equivalent substrings, call the shorter one <
+ return (lhs.len() < rhs.len());
+}
+
+//==============[ operator==(Oid &x,char *) ]=============================
+// equivlence operator overloaded
+int operator==(const Oid &x, const char *dotted_oid_string)
+{
+ Oid to(dotted_oid_string); // create a temp oid object
+ return (x == to); // compare using existing operator
+}
+
+//==============[ operator!=(Oid &x,char*) ]=============================
+// not equivlence operator overloaded
+int operator!=(const Oid &x, const char *dotted_oid_string)
+{
+ Oid to(dotted_oid_string); // create a temp oid object
+ return (x != to); // compare using existing operator
+}
+
+//==============[ operator<(Oid &x,char*) ]=============================
+// less than < operator overloaded
+int operator<(const Oid &x, const char *dotted_oid_string)
+{
+ Oid to(dotted_oid_string); // create a temp oid object
+ return (x < to); // compare using existing operator
+}
+
+//==============[ operator<=(Oid &x,char *) ]=============================
+// less than <= operator overloaded
+int operator<=(const Oid &x,char *dotted_oid_string)
+{
+ Oid to(dotted_oid_string); // create a temp oid object
+ return (x <= to); // compare using existing operator
+}
+
+//==============[ operator>(Oid &x,char* ]=============================
+// greater than > operator overloaded
+int operator>(const Oid &x,const char *dotted_oid_string)
+{
+ Oid to(dotted_oid_string); // create a temp oid object
+ return (x > to); // compare using existing operator
+}
+
+//==============[ operator>=(Oid &x,char*) ]=============================
+// greater than >= operator overloaded
+int operator>=(const Oid &x,const char *dotted_oid_string)
+{
+ Oid to(dotted_oid_string); // create a temp oid object
+ return (x >= to); // compare using existing operator
+}
+
+//===============[Oid::set_data ]==---=====================================
+// copy data from raw form...
+void Oid::set_data(const unsigned long *raw_oid,
+ const unsigned int oid_len)
+{
+ if (smival.value.oid.len < oid_len)
+ {
+ delete_oid_ptr();
+
+ smival.value.oid.ptr = (SmiLPUINT32) new unsigned long[oid_len];
+ if (!smival.value.oid.ptr) return;
+ }
+ MEMCPY((SmiLPBYTE) smival.value.oid.ptr,
+ (SmiLPBYTE) raw_oid,
+ (size_t) (oid_len*sizeof(SmiUINT32)));
+ smival.value.oid.len = oid_len;
+ m_changed = true;
+}
+
+// Set the data from raw form.
+void Oid::set_data(const char *str, const unsigned int str_len)
+{
+ if (smival.value.oid.len < str_len)
+ {
+ delete_oid_ptr();
+
+ smival.value.oid.ptr = (SmiLPUINT32) new unsigned long[str_len];
+ if (!smival.value.oid.ptr) return;
+ }
+
+ if ((!str) || (str_len == 0))
+ return;
+
+ for (unsigned int i=0; i<str_len; i++)
+ smival.value.oid.ptr[i] = str[i];
+
+ smival.value.oid.len = str_len;
+ m_changed = true;
+}
+
+//===============[Oid::trim(unsigned int) ]============================
+// trim off the n leftmost values of an oid
+// Note!, does not adjust actual space for
+// speed
+void Oid::trim(const unsigned long n)
+{
+ // verify that n is legal
+ if ((n <= smival.value.oid.len) && (n > 0))
+ {
+ smival.value.oid.len -= n;
+ if (smival.value.oid.len == 0)
+ delete_oid_ptr();
+ m_changed = true;
+ }
+}
+
+//===============[Oid::operator += const unsigned int) ]====================
+// append operator, appends an int
+//
+Oid& Oid::operator+=(const unsigned long i)
+{
+ Oid other(&i, 1);
+ (*this) += other;
+ return *this;
+}
+
+//===============[Oid::operator += const Oid) ]========================
+// append operator, appends an Oid
+//
+// allocate some space for a max oid string
+// extract current string into space
+// concat new string
+// free up existing oid
+// make a new oid from string
+// delete allocated space
+Oid& Oid::operator+=(const Oid &o)
+{
+ SmiLPUINT32 new_oid;
+
+ if (o.smival.value.oid.len == 0)
+ return *this;
+
+ new_oid = (SmiLPUINT32) new unsigned long[smival.value.oid.len + o.smival.value.oid.len];
+ if (new_oid == 0)
+ {
+ delete_oid_ptr();
+ return *this;
+ }
+
+ if (smival.value.oid.ptr)
+ {
+ MEMCPY((SmiLPBYTE) new_oid,
+ (SmiLPBYTE) smival.value.oid.ptr,
+ (size_t) (smival.value.oid.len*sizeof(SmiUINT32)));
+
+ delete [] smival.value.oid.ptr;
+ }
+
+ // out with the old, in with the new...
+ smival.value.oid.ptr = new_oid;
+
+ MEMCPY((SmiLPBYTE) &new_oid[smival.value.oid.len],
+ (SmiLPBYTE) o.smival.value.oid.ptr,
+ (size_t) (o.smival.value.oid.len*sizeof(SmiUINT32)));
+
+ smival.value.oid.len += o.smival.value.oid.len;
+
+ m_changed = true;
+ return *this;
+}
+
+//==============[Oid::get_printable(unsigned int start, n) ]=============
+// return a dotted string starting at start,
+// going n positions to the left
+// NOTE, start is 1 based (the first id is at position #1)
+const char *Oid::get_printable(const unsigned long start,
+ const unsigned long n,
+ char *&buffer) const
+{
+ if (!m_changed && (buffer == iv_str)) return buffer;
+
+ unsigned long nz;
+ unsigned long my_start = start - 1;
+ unsigned long my_end = my_start + n;
+
+ nz = (smival.value.oid.len * (SNMPCHARSIZE + 1)) + 1;
+
+ if (buffer) delete [] buffer; // delete the previous output string
+
+ buffer = new char[nz]; // allocate some space for the output string
+ if (buffer == 0)
+ return 0;
+
+ buffer[0] = 0; // init the string
+
+ // cannot ask for more than there is..
+ if ((start == 0) || (my_end > smival.value.oid.len))
+ return buffer;
+
+ char *cur_ptr = buffer;
+ bool first = true;
+
+ // loop through and build up a string
+ for (unsigned long index = my_start; index < my_end; ++index)
+ {
+ // if not at begin, pad with a dot
+ if (first)
+ first = false;
+ else
+ *cur_ptr++ = '.';
+
+ // convert data element to a string
+ cur_ptr += sprintf(cur_ptr, "%lu", smival.value.oid.ptr[index]);
+ }
+
+ if (buffer == iv_str)
+ {
+ Oid *nc_this = PP_CONST_CAST(Oid*, this);
+ nc_this->m_changed = false;
+ }
+
+ return buffer;
+}
+
+
+//=============[Oid::StrToOid(char *string, SmiLPOID dst) ]==============
+// convert a string to an oid
+int Oid::StrToOid(const char *str, SmiLPOID dstOid) const
+{
+ unsigned int index = 0;
+
+ // make a temp buffer to copy the data into first
+ SmiLPUINT32 temp;
+ unsigned int nz;
+
+ if (str && *str)
+ {
+ nz = SAFE_UINT_CAST(strlen(str));
+ }
+ else
+ {
+ dstOid->len = 0;
+ dstOid->ptr = 0;
+ return -1;
+ }
+ temp = (SmiLPUINT32) new unsigned long[nz];
+
+ if (temp == 0) return -1; // return if can't get the mem
+
+ while ((*str) && (index < nz))
+ {
+ // skip over the dot
+ if (*str == '.') ++str;
+
+ // convert digits
+ if (my_isdigit(*str))
+ {
+ unsigned long number = 0;
+
+ // grab a digit token and convert it to a long int
+ while (my_isdigit(*str))
+ number = (number * 10) + *(str++) - '0';
+
+ // stuff the value into the array and bump the counter
+ temp[index++] = number;
+
+ // there must be a dot or end of string now
+ if ((*str) && (*str != '.'))
+ {
+ delete [] temp;
+ return -1;
+ }
+ }
+
+ // check for other chars
+ if ((*str) && (*str != '.'))
+ {
+ // found String -> converting it into an oid
+ if (*str != '$')
+ {
+ delete [] temp;
+ return -1;
+ }
+
+ // skip $
+ ++str;
+
+ // copy until second $
+ while ((*str) && (*str != '$'))
+ {
+ temp[index] = (unsigned char)*str;
+ ++str;
+ ++index;
+ }
+
+ if (*str != '$')
+ {
+ delete [] temp;
+ return -1;
+ }
+
+ // skip over the $
+ ++str;
+
+ // there must be a dot or end of string now
+ if ((*str) && (*str != '.'))
+ {
+ delete [] temp;
+ return -1;
+ }
+ }
+ }
+
+ // get some space for the real oid
+ dstOid->ptr = (SmiLPUINT32) new unsigned long[index];
+ // return if can't get the mem needed
+ if(dstOid->ptr == 0)
+ {
+ delete [] temp;
+ return -1;
+ }
+
+ // copy in the temp data
+ MEMCPY((SmiLPBYTE) dstOid->ptr,
+ (SmiLPBYTE) temp,
+ (size_t) (index*sizeof(SmiUINT32)));
+
+ // set the len of the oid
+ dstOid->len = index;
+
+ // free up temp data
+ delete [] temp;
+
+ return (int) index;
+}
+
+
+//===============[Oid::OidCopy(source, destination) ]====================
+// Copy an oid
+int Oid::OidCopy(SmiLPOID srcOid, SmiLPOID dstOid) const
+{
+ // check source len ! zero
+ if (srcOid->len == 0) return -1;
+
+ // copy source to destination
+ MEMCPY((SmiLPBYTE) dstOid->ptr,
+ (SmiLPBYTE) srcOid->ptr,
+ (size_t) (srcOid->len*sizeof(SmiUINT32)));
+
+ //set the new len
+ dstOid->len = srcOid->len;
+ return (int) srcOid->len;
+}
+
+
+//===============[Oid::nCompare(n, Oid) ]=================================
+// compare the n leftmost values of two oids (left-to_right )
+//
+// self == Oid then return 0, they are equal
+// self < Oid then return -1, <
+// self > Oid then return 1, >
+int Oid::nCompare(const unsigned long n,
+ const Oid &o) const
+{
+ unsigned long length = n;
+ bool reduced_len = false;
+
+ // If both oids are too short, decrease len
+ while ((smival.value.oid.len < length) && (o.smival.value.oid.len < length))
+ length--;
+
+ if (length == 0) return 0; // equal
+
+ // only compare for the minimal length
+ if (length > smival.value.oid.len)
+ {
+ length = smival.value.oid.len;
+ reduced_len = true;
+ }
+ if (length > o.smival.value.oid.len)
+ {
+ length = o.smival.value.oid.len;
+ reduced_len = true;
+ }
+
+ unsigned long z = 0;
+ while (z < length)
+ {
+ if (smival.value.oid.ptr[z] < o.smival.value.oid.ptr[z])
+ return -1; // less than
+ if (smival.value.oid.ptr[z] > o.smival.value.oid.ptr[z])
+ return 1; // greater than
+ ++z;
+ }
+
+ // if we truncated the len then these may not be equal
+ if (reduced_len)
+ {
+ if (smival.value.oid.len < o.smival.value.oid.len) return -1;
+ if (smival.value.oid.len > o.smival.value.oid.len) return 1;
+ }
+ return 0; // equal
+}
+
+//================[Oid::OidToStr ]=========================================
+// convert an oid to a string
+int Oid::OidToStr(const SmiOID *srcOid,
+ SmiUINT32 size,
+ char *str) const
+{
+ unsigned totLen = 0;
+ char szNumber[SNMPBUFFSIZE];
+ int cur_len;
+
+ str[0] = 0; // init the string
+
+ // verify there is something to copy
+ if (srcOid->len == 0)
+ return -1;
+
+ // loop through and build up a string
+ for (unsigned long index = 0; index < srcOid->len; ++index)
+ {
+ // convert data element to a string
+ cur_len = sprintf(szNumber, "%lu", srcOid->ptr[index]);
+
+ // verify len is not over
+ if (totLen + cur_len + 1 >= size)
+ return -2;
+
+ // if not at begin, pad with a dot
+ if (totLen)
+ str[totLen++] = '.';
+
+ // copy the string token into the main string
+ STRCPY(str + totLen, szNumber);
+
+ // adjust the total len
+ totLen += cur_len;
+ }
+ return totLen+1;
+}
+
+
+//================[ general Value = operator ]========================
+SnmpSyntax& Oid::operator=(const SnmpSyntax &val)
+{
+ if (this == &val) return *this; // protect against assignment from self
+
+ delete_oid_ptr();
+
+ // assign new value
+ if (val.valid())
+ {
+ switch (val.get_syntax())
+ {
+ case sNMP_SYNTAX_OID:
+ set_data(((Oid &)val).smival.value.oid.ptr,
+ (unsigned int)((Oid &)val).smival.value.oid.len);
+ break;
+ }
+ }
+ return *this;
+}
+
+int Oid::get_asn1_length() const
+{
+ int length = 1; // for first 2 subids
+
+ for (unsigned int i = 2; i < smival.value.oid.len; ++i)
+ {
+ unsigned long v = smival.value.oid.ptr[i];
+
+ if (v < 0x80) // 7 bits long subid
+ length += 1;
+ else if (v < 0x4000) // 14 bits long subid
+ length += 2;
+ else if (v < 0x200000) // 21 bits long subid
+ length += 3;
+ else if (v < 0x10000000) // 28 bits long subid
+ length += 4;
+ else // 32 bits long subid
+ length += 5;
+ }
+
+ if (length < 128)
+ return length + 2;
+ else if (length < 256)
+ return length + 3;
+ return length + 4;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## pdu.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ P D U . C P P
+
+ PDU CLASS IMPLEMENTATION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ Pdu class implementation. Encapsulation of an SMI Protocol
+ Data Unit (PDU) in C++.
+
+=====================================================================*/
+char pdu_cpp_version[]="@(#) SNMP++ $Id: pdu.cpp 209 2006-01-07 20:02:34Z katz $";
+
+#include "snmp_pp/pdu.h" // include Pdu class definition
+#include "snmp_pp/usm_v3.h"
+#include "snmp_pp/vb.h"
+#include "snmp_pp/v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define PDU_INITIAL_SIZE 25
+
+//=====================[ constructor no args ]=========================
+Pdu::Pdu()
+ : vbs(0), vbs_size(0), vb_count(0), error_status(0), error_index(0),
+ validity(true), request_id(0), pdu_type(0), notify_timestamp(0),
+ v1_trap_address_set(false)
+#ifdef _SNMPv3
+ , security_level(SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV),
+ message_id(0), maxsize_scopedpdu(0)
+#endif
+{
+}
+
+//=====================[ constructor with vbs and count ]==============
+Pdu::Pdu(Vb* pvbs, const int pvb_count)
+ : vbs(0), vbs_size(0), vb_count(0), error_status(0), error_index(0),
+ validity(true), request_id(0), pdu_type(0), notify_timestamp(0),
+ v1_trap_address_set(false)
+#ifdef _SNMPv3
+ , security_level(SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV),
+ message_id(0), maxsize_scopedpdu(0)
+#endif
+{
+ if (pvb_count == 0) return; // zero is ok
+
+ vbs = new Vb*[pvb_count];
+ if (vbs)
+ vbs_size = pvb_count;
+ else
+ {
+ vbs_size = 0;
+ validity = false;
+ return;
+ }
+
+ // loop through and assign internal vbs
+ for (int z = 0; z < pvb_count; ++z)
+ {
+ if (pvbs[z].valid())
+ vbs[z] = new Vb(pvbs[z]);
+ else
+ vbs[z] = 0;
+
+ if ((vbs[z]) && !vbs[z]->valid())
+ {
+ delete vbs[z];
+ vbs[z] = 0;
+ }
+
+ if (vbs[z] == 0) // check for new fail
+ {
+ for (int y = 0; y < z; ++y) delete vbs[y]; // free vbs
+ validity = false;
+ return;
+ }
+ }
+
+ vb_count = pvb_count; // assign the vb count
+}
+
+//=====================[ destructor ]====================================
+Pdu::~Pdu()
+{
+ for (int z = 0; z < vb_count; ++z)
+ {
+ delete vbs[z];
+ vbs[z] = 0;
+ }
+
+ if (vbs)
+ {
+ delete [] vbs;
+ vbs = 0;
+ vbs_size = 0;
+ }
+}
+
+//=====================[ assignment to another Pdu object overloaded ]===
+Pdu& Pdu::operator=(const Pdu &pdu)
+{
+ if (this == &pdu) return *this; // check for self assignment
+
+ // Initialize all mv's
+ error_status = pdu.error_status;
+ error_index = pdu.error_index;
+ request_id = pdu.request_id;
+ pdu_type = pdu.pdu_type;
+ notify_id = pdu.notify_id;
+ notify_timestamp = pdu.notify_timestamp;
+ notify_enterprise = pdu.notify_enterprise;
+#ifdef _SNMPv3
+ security_level = pdu.security_level;
+ message_id = pdu.message_id;
+ context_name = pdu.context_name;
+ context_engine_id = pdu.context_engine_id;
+ maxsize_scopedpdu = pdu.maxsize_scopedpdu;
+#endif
+ if (pdu.v1_trap_address_set)
+ {
+ v1_trap_address = pdu.v1_trap_address;
+ v1_trap_address_set = true;
+ }
+ else
+ v1_trap_address_set = false;
+
+ validity = true;
+
+ // free up old vbs
+ for (int z = 0; z < vb_count; ++z) delete vbs[z];
+ vb_count = 0;
+
+ // check for zero case
+ if (pdu.vb_count == 0) return *this;
+
+ // allocate array
+ if (vbs_size < pdu.vb_count)
+ {
+ delete [] vbs;
+ vbs = new Vb*[pdu.vb_count];
+ if (vbs)
+ vbs_size = pdu.vb_count;
+ else
+ {
+ vbs_size = 0;
+ validity = false;
+ return *this;
+ }
+ }
+
+ // loop through and fill em up
+ for (int y = 0; y < pdu.vb_count; ++y)
+ {
+ vbs[y] = new Vb(*(pdu.vbs[y]));
+
+ if ((vbs[y]) && !vbs[y]->valid())
+ {
+ delete vbs[y];
+ vbs[y] = 0;
+ }
+
+ if (!vbs[y])
+ {
+ for (int x = 0; x < y; ++x) delete vbs[x]; // free vbs
+ validity = false;
+ return *this;
+ }
+ }
+
+ vb_count = pdu.vb_count;
+ return *this;
+}
+
+// append operator, appends a variable binding
+Pdu& Pdu::operator+=(const Vb &vb)
+{
+ if (!vb.valid()) return *this; // dont add invalid Vbs
+
+ if (vb_count + 1 > vbs_size)
+ {
+ if (!extend_vbs()) return *this;
+ }
+
+ vbs[vb_count] = new Vb(vb); // add the new one
+
+ if (vbs[vb_count]) // up the vb count on success
+ {
+ if (vbs[vb_count]->valid())
+ {
+ ++vb_count;
+ validity = true; // set up validity
+ }
+ else
+ {
+ delete vbs[vb_count];
+ vbs[vb_count] = 0;
+ }
+ }
+
+ return *this; // return self reference
+}
+
+//=====================[ extract Vbs from Pdu ]==========================
+int Pdu::get_vblist(Vb* pvbs, const int pvb_count) const
+{
+ if ((!pvbs) || (pvb_count < 0) || (pvb_count > vb_count))
+ return false;
+
+ // loop through all vbs and assign to params
+ for (int z = 0; z < pvb_count; ++z)
+ {
+ pvbs[z] = *vbs[z];
+ if (!pvbs[z].valid())
+ return false;
+ }
+
+ return true;
+}
+
+//=====================[ deposit Vbs ]===================================
+int Pdu::set_vblist(Vb* pvbs, const int pvb_count)
+{
+ // if invalid then don't destroy
+ if (((!pvbs) && (pvb_count > 0)) ||
+ (pvb_count < 0))
+ return false;
+
+ // free up current vbs
+ for (int z = 0; z < vb_count; ++z) delete vbs[z];
+ vb_count = 0;
+
+ // check for zero case
+ if (pvb_count == 0)
+ {
+ validity = true;
+ error_status = 0;
+ error_index = 0;
+ request_id = 0;
+ return false;
+ }
+
+ // allocate array
+ if (vbs_size < pvb_count)
+ {
+ delete [] vbs;
+ vbs = new Vb*[pvb_count];
+ if (vbs)
+ vbs_size = pvb_count;
+ else
+ {
+ vbs_size = 0;
+ validity = false;
+ return false;
+ }
+ }
+
+ // loop through all vbs and reassign them
+ for (int y = 0; y < pvb_count; ++y)
+ {
+ if (pvbs[y].valid())
+ {
+ vbs[y] = new Vb(pvbs[y]);
+ if ((vbs[y]) && !vbs[y]->valid())
+ {
+ delete vbs[y];
+ vbs[y] = 0;
+ }
+ }
+ else
+ vbs[y] = 0;
+
+ // check for errors
+ if (!vbs[y])
+ {
+ for (int x = 0; x < y; ++x) delete vbs[x]; // free vbs
+ validity = false;
+ return false;
+ }
+ }
+
+ vb_count = pvb_count;
+
+ // clear error status and index since no longer valid
+ // request id may still apply so don't reassign it
+ error_status = 0;
+ error_index = 0;
+ validity = true;
+
+ return true;
+}
+
+//===================[ get a particular vb ]=============================
+// here the caller has already instantiated a vb object
+// index is zero based
+int Pdu::get_vb(Vb &vb, const int index) const
+{
+ if (index < 0) return false; // can't have an index less than 0
+ if (index >= vb_count) return false; // can't ask for something not there
+
+ vb = *vbs[index]; // asssign it
+
+ return vb.valid();
+}
+
+//===================[ set a particular vb ]=============================
+int Pdu::set_vb(Vb &vb, const int index)
+{
+ if (index < 0) return false; // can't have an index less than 0
+ if (index >= vb_count) return false; // can't ask for something not there
+ if (!vb.valid()) return false; // don't set invalid vbs
+
+ Vb *victim = vbs[index]; // save in case new fails
+ vbs[index] = new Vb(vb);
+ if (vbs[index])
+ {
+ if (vbs[index]->valid())
+ {
+ delete victim;
+ }
+ else
+ {
+ delete vbs[index];
+ vbs[index] = victim;
+ return false;
+ }
+ }
+ else
+ {
+ vbs[index] = victim;
+ return false;
+ }
+ return true;
+}
+
+// trim off the last vb
+int Pdu::trim(const int count)
+{
+ // verify that count is legal
+ if ((count < 0) || (count > vb_count)) return false;
+
+ int lp = count;
+
+ while (lp != 0)
+ {
+ if (vb_count > 0)
+ {
+ delete vbs[vb_count-1];
+ vbs[vb_count-1] = 0;
+ vb_count--;
+ }
+ lp--;
+ }
+ return true;
+}
+
+// delete a Vb anywhere within the Pdu
+int Pdu::delete_vb(const int p)
+{
+ // position has to be in range
+ if ((p<0) || (p > vb_count - 1)) return false;
+
+ delete vbs[p]; // safe to remove it
+
+ for (int z = p; z < vb_count - 1; ++z)
+ vbs[z] = vbs[z+1];
+
+ vb_count--;
+
+ return true;
+}
+
+
+// Get the SNMPv1 trap address
+int Pdu::get_v1_trap_address(GenAddress &address) const
+{
+ if (v1_trap_address_set == false)
+ return false;
+
+ address = v1_trap_address;
+ return true;
+}
+
+// Set the SNMPv1 trap address
+int Pdu::set_v1_trap_address(const Address &address)
+{
+ v1_trap_address = address;
+ v1_trap_address_set = (v1_trap_address.valid() == true);
+
+ return v1_trap_address_set;
+}
+
+int Pdu::get_asn1_length() const
+{
+ int length = 0;
+
+ // length for all vbs
+ for (int i = 0; i < vb_count; ++i)
+ length += vbs[i]->get_asn1_length();
+
+ // header for vbs
+ if (length < 0x80) length += 2;
+ else if (length <= 0xFF) length += 3;
+ else if (length <= 0xFFFF) length += 4;
+ else if (length <= 0xFFFFFF) length += 5;
+ else length += 6;
+
+ // req id, error status, error index
+ SnmpInt32 i32(request_id ? request_id : PDU_MAX_RID);
+ length += i32.get_asn1_length();
+ i32 = error_status;
+ length += i32.get_asn1_length();
+ i32 = error_index;
+ length += i32.get_asn1_length();
+
+ // header for data_pdu
+ if (length < 0x80) length += 2;
+ else if (length <= 0xFF) length += 3;
+ else if (length <= 0xFFFF) length += 4;
+ else if (length <= 0xFFFFFF) length += 5;
+ else length += 6;
+
+#ifdef _SNMPv3
+ // now the scopedpdu part sequence (4), context engine, id context name
+ length += 4 + 2 + context_engine_id.len() + 2 + context_name.len();
+
+ // An encrypted message is transported as an octet string
+ if (security_level == SNMP_SECURITY_LEVEL_AUTH_PRIV)
+ {
+ // assume that encryption increases the data to a multiple of 16
+ int mod = length % 16;
+ if (mod) length += 16 - mod;
+
+ length += 4;
+ }
+#endif
+
+ return length;
+}
+
+// extend the vbs array
+bool Pdu::extend_vbs()
+{
+ if (vbs_size == 0)
+ {
+ vbs = new Vb*[PDU_INITIAL_SIZE];
+ if (vbs)
+ {
+ vbs_size = PDU_INITIAL_SIZE;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ Vb **tmp = vbs;
+ vbs = new Vb*[vbs_size * 2];
+ if (!vbs)
+ {
+ vbs = tmp;
+ return false;
+ }
+
+ for (int y = 0; y < vb_count; ++y)
+ vbs[y] = tmp[y];
+ vbs_size *= 2;
+ delete [] tmp;
+ return true;
+}
+
+// Clear all members of the object
+void Pdu::clear()
+{
+ error_status = 0;
+ error_index = 0;
+ request_id = 0;
+ pdu_type = 0;
+ notify_timestamp = 0;
+ notify_id.clear();
+ notify_enterprise.clear();
+ v1_trap_address_set = false;
+ validity = true;
+
+ for (int z = 0; z < vb_count; ++z) delete vbs[z];
+ vb_count = 0;
+
+#ifdef _SNMPv3
+ security_level = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ message_id = 0;
+ maxsize_scopedpdu = 0;
+ context_name.clear();
+ context_engine_id.clear();
+#endif // _SNMPv3
+}
+
+// Does the type of response match the type of request
+bool Pdu::match_type(const int request, const int response)
+{
+ switch (request)
+ {
+ case sNMP_PDU_GET:
+ case sNMP_PDU_GETNEXT:
+ case sNMP_PDU_SET:
+ case sNMP_PDU_GETBULK:
+ case sNMP_PDU_INFORM:
+ {
+ if ((response == sNMP_PDU_RESPONSE) ||
+ (response == sNMP_PDU_REPORT))
+ return true;
+ if ((response == sNMP_PDU_GET) ||
+ (response == sNMP_PDU_GETNEXT) ||
+ (response == sNMP_PDU_SET) ||
+ (response == sNMP_PDU_GETBULK) ||
+ (response == sNMP_PDU_INFORM) ||
+ (response == sNMP_PDU_V1TRAP) ||
+ (response == sNMP_PDU_TRAP))
+ {
+ debugprintf(0, "Unknown response pdu type (%d).", response);
+ }
+ return false;
+ }
+ case sNMP_PDU_REPORT:
+ case sNMP_PDU_RESPONSE:
+ case sNMP_PDU_V1TRAP:
+ case sNMP_PDU_TRAP:
+ {
+ return false;
+ }
+ default:
+ {
+ debugprintf(0, "Unknown request pdu type (%d).", request);
+ return false;
+ }
+ }
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## reentrant.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+char reentrant_cpp_version[]="#(@) SNMP++ $Id: reentrant.cpp 179 2005-09-19 19:59:36Z fock $";
+
+#include "snmp_pp/reentrant.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+SnmpSynchronized::SnmpSynchronized()
+{
+#ifdef _THREADS
+#ifdef WIN32
+ InitializeCriticalSection(&_mutex);
+#elif defined (CPU) && CPU == PPC603
+ _mutex = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE );
+#else
+ pthread_mutex_init(&_mutex, 0);
+#endif
+#endif
+}
+
+SnmpSynchronized::~SnmpSynchronized()
+{
+#ifdef _THREADS
+#ifdef WIN32
+ DeleteCriticalSection(&_mutex);
+#elif defined (CPU) && CPU == PPC603
+ semTake(_mutex, WAIT_FOREVER);
+ semDelete(_mutex);
+#else
+ pthread_mutex_destroy(&_mutex);
+#endif
+#endif
+}
+
+void SnmpSynchronized::lock()
+{
+#ifdef _THREADS
+#ifdef WIN32
+ EnterCriticalSection(&_mutex);
+#elif defined (CPU) && CPU == PPC603
+ semTake(_mutex, WAIT_FOREVER);
+#else
+ pthread_mutex_lock(&_mutex);
+#endif
+#endif
+}
+
+void SnmpSynchronized::unlock()
+{
+#ifdef _THREADS
+#ifdef WIN32
+ LeaveCriticalSection(&_mutex);
+#elif defined (CPU) && CPU == PPC603
+ semGive(_mutex);
+#else
+ pthread_mutex_unlock(&_mutex);
+#endif
+#endif
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
+
--- /dev/null
+/*_############################################################################
+ _##
+ _## sha.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+char sha_cpp_version[]="#(@) SNMP++ $Id: sha.cpp 1549 2009-06-26 19:42:55Z katz $";
+
+#include "snmp_pp/sha.h"
+
+#if !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
+/*****************************************************************
+ * SHS.c - Secure Hash Standard (draft) FIPS 180-1 *
+ * *
+ * Copyright (C) 1994 Uri Blumenthal, uri@watson.ibm.com *
+ * Copyright (C) 1994 IBM T. J. Watson esearch Center *
+ * *
+ * Feel free to use this code, as long as you acknowledge the *
+ * ownership by U. Blumenthal and IBM Corp. and agree to hold *
+ * both harmless in case of ANY problem you may have with this *
+ * code. *
+ *****************************************************************/
+
+#if !(defined (CPU) && CPU == PPC603)
+#include <memory.h>
+#else
+#include <string.h>
+#endif
+#include <stdio.h>
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define K1 0x5A827999
+#define K2 0x6ED9EBA1
+#define K3 0x8F1BBCDC
+#define K4 0xCA62C1D6
+
+#define F1(B, C, D) ((B & C) | (~B & D))
+#define F2(B, C, D) (B ^ C ^ D)
+#define F3(B, C, D) ((B & C) | (B & D) | (C & D))
+#define F4(B, C, D) (B ^ C ^ D)
+
+#define ROL(A, K) ((A << K) | (A >> (32 - K)))
+
+#if !defined(i386) && !defined(_IBMR2)
+static int msb_flag = 0; /* ENDIAN-ness of CPU */
+#endif
+
+static void SHATransform(SHA_CTX *ctx, const unsigned char *X)
+{
+ unsigned /* long */ int a, b, c, d, e, temp = 0;
+ unsigned /* long */ int W[80]; /* Work array for SHS */
+ int i;
+
+#ifdef _IBMR2
+ unsigned long int *p = (unsigned long int *)X;
+ memcpy((char *)&W[0], p, 64);
+#else
+#ifndef i386
+ unsigned long int *p = (unsigned long int *)X;
+ if (msb_flag)
+ memcpy((char *)&W[0], p, 64);
+ else
+#endif /* ~i386 */
+ for (i = 0; i < 64; i += 4)
+ W[(i/4)] = X[i+3] | (X[i+2] << 8) |
+ (X[i+1] << 16) | (X[i] << 24);
+#endif /* _IBMR2 */
+
+ for (i = 16; i < 80; i++)
+ W[i] = ROL((W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]), 1);
+
+ a = ctx->h[0];
+ b = ctx->h[1];
+ c = ctx->h[2];
+ d = ctx->h[3];
+ e = ctx->h[4];
+
+ for (i = 0; i <= 19; i++) {
+ temp = ROL(a, 5) + F1(b, c, d) + e + K1 + W[i];
+ e = d; d = c; c = ROL(b, 30); b = a; a = temp;
+ }
+
+ for (i = 20; i <= 39; i++) {
+ temp = ROL(a, 5) + F2(b, c, d) + e + K2 + W[i];
+ e = d; d = c; c = ROL(b, 30); b = a; a = temp;
+ }
+
+ for (i = 40; i <= 59; i++) {
+ temp = ROL(a, 5) + F3(b, c, d) + e + K3 + W[i];
+ e = d; d = c; c = ROL(b, 30); b = a; a = temp;
+ }
+
+ for (i = 60; i <= 79; i++) {
+ temp = ROL(a, 5) + F4(b, c, d) + e + K4 + W[i];
+ e = d; d = c; c = ROL(b, 30); b = a; a = temp;
+ }
+
+ ctx->h[0] += a;
+ ctx->h[1] += b;
+ ctx->h[2] += c;
+ ctx->h[3] += d;
+ ctx->h[4] += e;
+}
+
+
+void SHAInit(SHA_CTX *ctx)
+{
+#if !defined(i386) && !defined(_IBMR2)
+ union z_test {
+ unsigned char ch[4];
+ unsigned long ll;
+ } z_t;
+#endif
+ /* Zero the SHS Context */
+ memset((char *)ctx, 0, sizeof(*ctx));
+
+ /* Prime the SHS with "magic" init constants */
+ ctx->h[0] = 0x67452301;
+ ctx->h[1] = 0xEFCDAB89;
+ ctx->h[2] = 0x98BADCFE;
+ ctx->h[3] = 0x10325476;
+ ctx->h[4] = 0xC3D2E1F0;
+
+#if !defined(i386) && !defined(_IBMR2)
+ /* Determine the ENDIAN-ness of the CPU */
+ z_t.ll = 0;
+
+ z_t.ch[0] = 0x01;
+
+ if (z_t.ll == 0x01000000)
+ msb_flag = 1;
+ else {
+ if (z_t.ll == 0x00000001)
+ msb_flag = 0;
+ else
+ printf("ENDIAN-ness is SCREWED! (%0#lx)\n", z_t.ll);
+ }
+#endif /* ~_IBMR2 & ~i386 */
+}
+
+
+void SHAUpdate(SHA_CTX *ctx, const unsigned char *buf, unsigned int lenBuf)
+{
+ /* Do we have any bytes? */
+ if (lenBuf == 0) return;
+
+ /* Calculate buf len in bits and update the len count */
+ ctx->count[0] += (lenBuf << 3);
+ if (ctx->count[0] < (lenBuf << 3))
+ ctx->count[1] += 1;
+ ctx->count[1] += (lenBuf >> 29);
+
+ /* Fill the hash working buffer for the first run, if */
+ /* we have enough data... */
+ int i = 64 - ctx->index; /* either fill it up to 64 bytes */
+ if ((int)lenBuf < i) i = lenBuf; /* or put the whole data...*/
+
+ lenBuf -= i; /* Reflect the data we'll put in the buf */
+
+ /* Physically put the data in the hash workbuf */
+ memcpy((char *)&(ctx->X[ctx->index]), buf, i);
+ buf += i; ctx->index += i;
+
+ /* Adjust the buf index */
+ if (ctx->index == 64)
+ ctx->index = 0;
+
+ /* Let's see whether we're equal to 64 bytes in buf */
+ if (ctx->index == 0)
+ SHATransform(ctx, ctx->X);
+
+ /* Process full 64-byte blocks */
+ while(lenBuf >= 64) {
+ lenBuf -= 64;
+ SHATransform(ctx, buf);
+ buf += 64;
+ }
+
+ /* Put the rest of data in the hash buf for next run */
+ if (lenBuf > 0) {
+ memcpy(ctx->X, buf, lenBuf);
+ ctx->index = lenBuf;
+ }
+}
+
+
+void SHAFinal(unsigned char *digest, SHA_CTX *ctx)
+{
+ int i;
+ unsigned long int c0, c1;
+ unsigned char truelen[8];
+ static unsigned char padding[64] = {
+ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 8 */
+ 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 16 */
+ 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 24 */
+ 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 32 */
+ 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 40 */
+ 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 48 */
+ 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 56 */
+ 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; /* 64 */
+
+ /* Store the message length to append after */
+ /* padding is done... */
+
+#ifdef _IBMR2
+ memcpy(truelen, (char *) &(ctx->count[1]), 4);
+ memcpy(&truelen[4], (char *) &(ctx->count[0]), 4);
+#else
+#ifndef i386
+ if (msb_flag) {
+ memcpy(truelen, (char *) &(ctx->count[1]), 4);
+ memcpy(&truelen[4], (char *) &(ctx->count[0]), 4);
+ } else
+#endif /* ~i386 */
+ {
+ c0 = ctx->count[0]; c1 = ctx->count[1];
+ for (i = 7; i >=0; i--) {
+ truelen[i] = (unsigned char) (c0 & 0xff);
+ c0 = (c0 >> 8) | (((c1 >> 8) & 0xff) << 24);
+ c1 = (c1 >> 8);
+ }
+ }
+#endif /* _IBMR2 */
+
+ /* How many padding bytes do we need? */
+ i = (ctx->count[0] >> 3) & 0x3f; /* # of bytes mod 64 */
+ if (i >= 56) i = 120 - i; /* # of padding bytes needed */
+ else i = 56 - i;
+
+
+ SHAUpdate(ctx, padding, i); /* Append the padding */
+ SHAUpdate(ctx, truelen, 8); /* Append the length */
+
+#ifdef _IBMR2
+ memcpy(digest, (char *)&ctx->h[0], 20);
+#else
+#ifndef i386
+ if (msb_flag)
+ memcpy(digest, (char *)&ctx->h[0], 20);
+ else
+#endif /* ~i386 */
+ for (i = 0; i < 4; i++) {
+ digest[3-i] = (unsigned char) (ctx->h[0] & 0xff);
+ ctx->h[0] >>= 8;
+ digest[7-i] = (unsigned char) (ctx->h[1] & 0xff);
+ ctx->h[1] >>= 8;
+ digest[11-i] = (unsigned char) (ctx->h[2] & 0xff);
+ ctx->h[2] >>= 8;
+ digest[15-i] = (unsigned char) (ctx->h[3] & 0xff);
+ ctx->h[3] >>= 8;
+ digest[19-i] = (unsigned char) (ctx->h[4] & 0xff);
+ ctx->h[4] >>= 8;
+ }
+#endif /* _IBMR2 */
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
+
+#endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
--- /dev/null
+/*_############################################################################
+ _##
+ _## snmpmsg.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1996
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ SNMP++ S N M P M S G . C P P
+
+ SNMPMESSAGE CLASS DEFINITION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION: ASN.1 encoding / decoding class
+=====================================================================*/
+char snmpmsg_cpp_version[]="#(@) SNMP++ $Id: snmpmsg.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+#if defined(_AIX)
+#include <unistd.h>
+#endif
+#if defined(__APPLE__)
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <stdio.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/snmpmsg.h" // header file for SnmpMessage
+#include "snmp_pp/oid_def.h" // changed (Frank Fock)
+#include "snmp_pp/log.h"
+#include "snmp_pp/vb.h"
+#include "snmp_pp/usm_v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define MAX_LEN_COMMUNITY 254
+
+const coldStartOid coldStart;
+const warmStartOid warmStart;
+const linkDownOid linkDown;
+const linkUpOid linkUp;
+const authenticationFailureOid authenticationFailure;
+const egpNeighborLossOid egpNeighborLoss;
+const snmpTrapEnterpriseOid snmpTrapEnterprise;
+
+//------------[ convert SNMP++ VB to WinSNMP smiVALUE ]----------------
+int convertVbToSmival( const Vb &tempvb, SmiVALUE *smival )
+{
+ smival->syntax = tempvb.get_syntax();
+ switch ( smival->syntax ) {
+
+ // case sNMP_SYNTAX_NULL
+ case sNMP_SYNTAX_NULL:
+ case sNMP_SYNTAX_NOSUCHOBJECT:
+ case sNMP_SYNTAX_NOSUCHINSTANCE:
+ case sNMP_SYNTAX_ENDOFMIBVIEW:
+ break;
+
+ // case sNMP_SYNTAX_INT32:
+ case sNMP_SYNTAX_INT:
+ tempvb.get_value(smival->value.sNumber);
+ break;
+
+ // case sNMP_SYNTAX_UINT32:
+ case sNMP_SYNTAX_GAUGE32:
+ case sNMP_SYNTAX_CNTR32:
+ case sNMP_SYNTAX_TIMETICKS:
+ // case sNMP_SYNTAX_UINT32:
+ tempvb.get_value(smival->value.uNumber);
+ break;
+
+ // case Counter64
+ case sNMP_SYNTAX_CNTR64:
+ {
+ Counter64 c64;
+ tempvb.get_value(c64);
+ smival->value.hNumber.hipart = c64.high();
+ smival->value.hNumber.lopart = c64.low();
+ }
+ break;
+
+ case sNMP_SYNTAX_BITS:
+ case sNMP_SYNTAX_OCTETS:
+ case sNMP_SYNTAX_OPAQUE:
+ case sNMP_SYNTAX_IPADDR:
+ {
+ OctetStr os;
+ tempvb.get_value(os);
+ smival->value.string.ptr = NULL;
+ smival->value.string.len = os.len();
+ if ( smival->value.string.len > 0 )
+ {
+ smival->value.string.ptr
+ = (SmiLPBYTE) new unsigned char [smival->value.string.len];
+ if ( smival->value.string.ptr )
+ {
+ for (int i=0; i<(int) smival->value.string.len ; i++)
+ smival->value.string.ptr[i] = os[i];
+ }
+ else
+ {
+ smival->syntax = sNMP_SYNTAX_NULL; // invalidate the smival
+ return SNMP_CLASS_RESOURCE_UNAVAIL;
+ }
+ }
+ }
+ break;
+
+ case sNMP_SYNTAX_OID:
+ {
+ Oid oid;
+ tempvb.get_value(oid);
+ smival->value.oid.ptr = NULL;
+ smival->value.oid.len = oid.len();
+ if ( smival->value.oid.len > 0 )
+ {
+ smival->value.oid.ptr
+ = (SmiLPUINT32) new unsigned long [ smival->value.oid.len];
+ if ( smival->value.oid.ptr )
+ {
+ for (int i=0; i<(int)smival->value.oid.len ; i++)
+ smival->value.oid.ptr[i] = oid[i];
+ }
+ else
+ {
+ smival->syntax = sNMP_SYNTAX_NULL; // invalidate the smival
+ return SNMP_CLASS_RESOURCE_UNAVAIL;
+ }
+ }
+ }
+ break;
+
+ default:
+ return SNMP_CLASS_INTERNAL_ERROR;
+ }
+ return SNMP_CLASS_SUCCESS;
+}
+
+// free a SMI value
+void freeSmivalDescriptor( SmiVALUE *smival )
+{
+ switch ( smival->syntax ) {
+ case sNMP_SYNTAX_OCTETS:
+ case sNMP_SYNTAX_OPAQUE:
+ case sNMP_SYNTAX_IPADDR:
+ case sNMP_SYNTAX_BITS: // obsoleted in SNMPv2 Draft Std
+ delete [] smival->value.string.ptr;
+ break;
+
+ case sNMP_SYNTAX_OID:
+ delete [] smival->value.oid.ptr;
+ break;
+ }
+ smival->syntax = sNMP_SYNTAX_NULL;
+}
+
+#ifdef _SNMPv3
+
+int SnmpMessage::unloadv3( Pdu &pdu, // Pdu returned
+ snmp_version &version, // version
+ OctetStr &engine_id, // optional v3
+ OctetStr &security_name, // optional v3
+ long int &security_model,
+ UdpAddress &from_addr,
+ Snmp &snmp_session)
+{
+ OctetStr tmp;
+ return unload(pdu, tmp, version, &engine_id,
+ &security_name, &security_model, &from_addr, &snmp_session);
+}
+
+#endif
+
+int SnmpMessage::load(const Pdu &cpdu,
+ const OctetStr &community,
+ const snmp_version version,
+ const OctetStr* engine_id,
+ const OctetStr* security_name,
+ const int security_model)
+{
+ int status;
+ const Pdu *pdu = &cpdu;
+ Pdu temppdu;
+
+ // make sure pdu is valid
+ if ( !pdu->valid())
+ return SNMP_CLASS_INVALID_PDU;
+
+ // create a raw pdu
+ snmp_pdu *raw_pdu;
+ raw_pdu = snmp_pdu_create( (int) pdu->get_type());
+
+ Oid enterprise;
+
+ // load it up
+ raw_pdu->reqid = pdu->get_request_id();
+#ifdef _SNMPv3
+ raw_pdu->msgid = pdu->get_message_id();
+#endif
+ raw_pdu->errstat= (unsigned long) pdu->get_error_status();
+ raw_pdu->errindex= (unsigned long) pdu->get_error_index();
+
+ // if its a V1 trap then load up other values
+ // for v2, use normal pdu format
+ if (raw_pdu->command == sNMP_PDU_V1TRAP)
+ {
+ // DON'T forget about the v1 trap agent address (changed by Frank Fock)
+ GenAddress gen_addr;
+ IpAddress ip_addr;
+ int addr_set = FALSE;
+
+ if (pdu->get_v1_trap_address(gen_addr))
+ {
+ /* User did set the v1 trap address */
+ if ((gen_addr.get_type() != Address::type_ip) &&
+ (gen_addr.get_type() != Address::type_udp) )
+ {
+ LOG_BEGIN(ERROR_LOG | 4);
+ LOG("SNMPMessage: Bad v1 trap address type in pdu");
+ LOG(gen_addr.get_type());
+ LOG_END;
+
+ snmp_free_pdu( raw_pdu);
+ return SNMP_CLASS_INVALID_PDU;
+ }
+
+ ip_addr = gen_addr;
+ if (!ip_addr.valid())
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("SNMPMessage: Copied v1 trap address not valid");
+ LOG_END;
+
+ snmp_free_pdu( raw_pdu);
+ return SNMP_CLASS_RESOURCE_UNAVAIL;
+ }
+ addr_set = TRUE;
+ }
+ else
+ {
+ /* User did not set the v1 trap address */
+ char addrString[256];
+ if (gethostname(addrString, 255) == 0)
+ {
+ ip_addr = addrString;
+ addr_set = TRUE;
+ }
+ }
+ struct sockaddr_in agent_addr; // agent address socket struct
+ // prepare the agent address
+ memset(&agent_addr, 0, sizeof(agent_addr));
+ agent_addr.sin_family = AF_INET;
+ if (addr_set)
+ {
+ agent_addr.sin_addr.s_addr
+ = inet_addr(((IpAddress &)ip_addr).IpAddress::get_printable());
+ LOG_BEGIN(INFO_LOG | 7);
+ LOG("SNMPMessage: Setting v1 trap address");
+ LOG(((IpAddress &)ip_addr).IpAddress::get_printable());
+ LOG_END;
+ }
+ raw_pdu->agent_addr = agent_addr;
+
+ //-----[ compute generic trap value ]-------------------------------
+ // determine the generic value
+ // 0 - cold start
+ // 1 - warm start
+ // 2 - link down
+ // 3 - link up
+ // 4 - authentication failure
+ // 5 - egpneighborloss
+ // 6 - enterprise specific
+ Oid trapid;
+ pdu->get_notify_id( trapid);
+ if ( !trapid.valid() || trapid.len() < 2 )
+ {
+ snmp_free_pdu( raw_pdu);
+ return SNMP_CLASS_INVALID_NOTIFYID;
+ }
+ raw_pdu->specific_type=0;
+ if ( trapid == coldStart)
+ raw_pdu->trap_type = 0; // cold start
+ else if ( trapid == warmStart)
+ raw_pdu->trap_type = 1; // warm start
+ else if( trapid == linkDown)
+ raw_pdu->trap_type = 2; // link down
+ else if ( trapid == linkUp)
+ raw_pdu->trap_type = 3; // link up
+ else if ( trapid == authenticationFailure )
+ raw_pdu->trap_type = 4; // authentication failure
+ else if ( trapid == egpNeighborLoss)
+ raw_pdu->trap_type = 5; // egp neighbor loss
+ else {
+ raw_pdu->trap_type = 6; // enterprise specific
+ // last oid subid is the specific value
+ // if 2nd to last subid is "0", remove it
+ // enterprise is always the notify oid prefix
+ raw_pdu->specific_type = (int) trapid[(int) (trapid.len()-1)];
+
+ trapid.trim(1);
+ if ( trapid[(int)(trapid.len()-1)] == 0 )
+ trapid.trim(1);
+ enterprise = trapid;
+ }
+
+ if ( raw_pdu->trap_type !=6)
+ pdu->get_notify_enterprise( enterprise);
+ if ( enterprise.len() >0) {
+ // note!!
+ // these are hooks into an SNMP++ oid
+ // and therefor the raw_pdu enterprise
+ // should not free them. null them out!!
+ SmiLPOID rawOid;
+ rawOid = enterprise.oidval();
+ raw_pdu->enterprise = rawOid->ptr;
+ raw_pdu->enterprise_length = (int) rawOid->len;
+ }
+
+ // timestamp
+ TimeTicks timestamp;
+ pdu->get_notify_timestamp( timestamp);
+ raw_pdu->time = ( unsigned long) timestamp;
+
+ }
+
+ // if its a v2 trap then we need to make a few adjustments
+ // vb #1 is the timestamp
+ // vb #2 is the id, represented as an Oid
+ if (( raw_pdu->command == sNMP_PDU_TRAP) ||
+ ( raw_pdu->command == sNMP_PDU_INFORM))
+ {
+ Vb tempvb;
+
+ temppdu = *pdu;
+ temppdu.trim(temppdu.get_vb_count());
+
+ // vb #1 is the timestamp
+ TimeTicks timestamp;
+ tempvb.set_oid(SNMP_MSG_OID_SYSUPTIME); // sysuptime
+ pdu->get_notify_timestamp( timestamp);
+ tempvb.set_value ( timestamp);
+ temppdu += tempvb;
+
+ // vb #2 is the id
+ Oid trapid;
+ tempvb.set_oid(SNMP_MSG_OID_TRAPID);
+ pdu->get_notify_id( trapid);
+ tempvb.set_value( trapid);
+ temppdu += tempvb;
+
+ // append the remaining vbs
+ for (int z=0; z<pdu->get_vb_count(); z++) {
+ pdu->get_vb( tempvb,z);
+ temppdu += tempvb;
+ }
+
+ pdu = &temppdu; // reassign the pdu to the temp one
+ }
+ // load up the payload
+ // for all Vbs in list, add them to the pdu
+ int vb_count;
+ Vb tempvb;
+ Oid tempoid;
+ SmiLPOID smioid;
+ SmiVALUE smival;
+
+ vb_count = pdu->get_vb_count();
+ for (int z=0;z<vb_count;z++) {
+ pdu->get_vb( tempvb,z);
+ tempvb.get_oid( tempoid);
+ smioid = tempoid.oidval();
+ // clear the value portion, in case its
+ // not already been done so by the app writer
+ // only do it in the case its a get,next or bulk
+ if ((raw_pdu->command == sNMP_PDU_GET) ||
+ (raw_pdu->command == sNMP_PDU_GETNEXT) ||
+ (raw_pdu->command == sNMP_PDU_GETBULK))
+ tempvb.set_null();
+ status = convertVbToSmival( tempvb, &smival );
+ if ( status != SNMP_CLASS_SUCCESS) {
+ snmp_free_pdu( raw_pdu);
+ return status;
+ }
+ // add the vb to the raw pdu
+ snmp_add_var( raw_pdu, smioid->ptr, (int) smioid->len, &smival);
+
+ freeSmivalDescriptor( &smival);
+ }
+
+ // ASN1 encode the pdu
+#ifdef _SNMPv3
+ if (version == version3)
+ {
+ if ((!engine_id) || (!security_name))
+ {
+ LOG_BEGIN(ERROR_LOG | 4);
+ LOG("SNMPMessage: Need security name and engine id for v3 message");
+ LOG_END;
+
+ // prevention of SNMP++ Enterprise Oid death
+ if ( enterprise.len() >0) {
+ raw_pdu->enterprise = 0;
+ raw_pdu->enterprise_length=0;
+ }
+ snmp_free_pdu( raw_pdu);
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+
+ status = v3MP::I->snmp_build(raw_pdu, databuff, (int *)&bufflen,
+ *engine_id, *security_name, security_model,
+ pdu->get_security_level(),
+ pdu->get_context_engine_id(),
+ pdu->get_context_name());
+ if (status == SNMPv3_MP_OK) {
+ if ((pdu->get_type() == sNMP_PDU_RESPONSE) &&
+ ((int)pdu->get_maxsize_scopedpdu() < pdu->get_asn1_length())) {
+
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("SNMPMessage: *BUG*: Serialized response pdu is too big (len) (max)");
+ LOG(pdu->get_asn1_length());
+ LOG(pdu->get_maxsize_scopedpdu());
+ LOG_END;
+
+ // prevention of SNMP++ Enterprise Oid death
+ if ( enterprise.len() >0) {
+ raw_pdu->enterprise = 0;
+ raw_pdu->enterprise_length=0;
+ }
+ snmp_free_pdu( raw_pdu);
+ return SNMP_ERROR_TOO_BIG;
+ }
+ }
+ }
+ else
+#endif
+ status = snmp_build( raw_pdu, databuff, (int *) &bufflen, version,
+ community.data(), (int) community.len());
+
+ LOG_BEGIN(DEBUG_LOG | 4);
+ LOG("SNMPMessage: return value for build message");
+ LOG(status);
+ LOG_END;
+
+ if ((status != 0)
+#ifdef _SNMPv3
+ && ((version != version3) || (status != SNMPv3_MP_OK))
+#endif
+ ) {
+ valid_flag = false;
+ // prevention of SNMP++ Enterprise Oid death
+ if ( enterprise.len() >0) {
+ raw_pdu->enterprise = 0;
+ raw_pdu->enterprise_length=0;
+ }
+ snmp_free_pdu( raw_pdu);
+#ifdef _SNMPv3
+ if (version == version3)
+ return status;
+ else
+#endif
+ // NOTE: This is an assumption - in most cases during normal
+ // operation the reason is a tooBig - another could be a
+ // damaged variable binding.
+ return SNMP_ERROR_TOO_BIG;
+ }
+ valid_flag = true;
+
+ // prevention of SNMP++ Enterprise Oid death
+ if ( enterprise.len() >0) {
+ raw_pdu->enterprise = 0;
+ raw_pdu->enterprise_length=0;
+ }
+
+ snmp_free_pdu( raw_pdu);
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+// load up a SnmpMessage
+int SnmpMessage::load( unsigned char *data,
+ unsigned long len)
+{
+ bufflen = MAX_SNMP_PACKET;
+ valid_flag = false;
+
+ if (len <= MAX_SNMP_PACKET)
+ {
+ memcpy( (unsigned char *) databuff, (unsigned char *) data,
+ (unsigned int) len);
+ bufflen = len;
+ valid_flag = true;
+ }
+ else
+ return SNMP_ERROR_WRONG_LENGTH;
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+// unload the data into SNMP++ objects
+int SnmpMessage::unload(Pdu &pdu, // Pdu object
+ OctetStr &community, // community object
+ snmp_version &version, // SNMP version #
+ OctetStr *engine_id, // optional v3
+ OctetStr *security_name, // optional v3
+ long int *security_model,
+ UdpAddress *from_addr,
+ Snmp *snmp_session)
+{
+ pdu.clear();
+
+ if (!valid_flag)
+ return SNMP_CLASS_INVALID;
+
+ snmp_pdu *raw_pdu;
+ raw_pdu = snmp_pdu_create(0); // do a "snmp_free_pdu( raw_pdu)" before return
+
+ int status;
+
+#ifdef _SNMPv3
+ OctetStr context_engine_id;
+ OctetStr context_name;
+ long int security_level = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+
+ if ((security_model) && (security_name) && (engine_id) && (snmp_session)) {
+ status = v3MP::I->snmp_parse(snmp_session, raw_pdu,
+ databuff, (int)bufflen, *engine_id,
+ *security_name, context_engine_id, context_name,
+ security_level, *security_model, version, *from_addr);
+ if (status != SNMPv3_MP_OK) {
+ pdu.set_request_id( raw_pdu->reqid);
+ pdu.set_type( raw_pdu->command);
+ snmp_free_pdu( raw_pdu);
+ return status;
+ }
+ pdu.set_context_engine_id(context_engine_id);
+ pdu.set_context_name(context_name);
+ pdu.set_security_level(security_level);
+ pdu.set_message_id(raw_pdu->msgid);
+ pdu.set_maxsize_scopedpdu(raw_pdu->maxsize_scopedpdu);
+ }
+ else {
+#endif
+ unsigned char community_name[MAX_LEN_COMMUNITY + 1];
+ int community_len = MAX_LEN_COMMUNITY + 1;
+
+ status = snmp_parse(raw_pdu, databuff, (int) bufflen,
+ community_name, community_len, version);
+ if (status != SNMP_CLASS_SUCCESS) {
+ snmp_free_pdu(raw_pdu);
+ return status;
+ }
+ community.set_data( community_name, community_len);
+
+#ifdef _SNMPv3
+ }
+#endif
+ // load up the SNMP++ variables
+ pdu.set_request_id(raw_pdu->reqid);
+ pdu.set_error_status((int) raw_pdu->errstat);
+ pdu.set_error_index((int) raw_pdu->errindex);
+ pdu.set_type( raw_pdu->command);
+
+ // deal with traps a little different
+ if ( raw_pdu->command == sNMP_PDU_V1TRAP) {
+ // timestamp
+ TimeTicks timestamp;
+ timestamp = raw_pdu->time;
+ pdu.set_notify_timestamp( timestamp);
+
+ // set the agent address
+ IpAddress agent_addr(inet_ntoa(raw_pdu->agent_addr.sin_addr));
+ if (agent_addr != "0.0.0.0")
+ {
+ pdu.set_v1_trap_address(agent_addr);
+
+ LOG_BEGIN(DEBUG_LOG | 4);
+ LOG("SNMPMessage: Trap address of received v1 trap");
+ LOG(agent_addr.get_printable());
+ LOG_END;
+ }
+
+ // set enterprise, notifyid
+ Oid enterprise;
+
+ if (raw_pdu->enterprise_length >0) {
+ for (int i=0; i< raw_pdu->enterprise_length; i++) {
+ enterprise += (int) (raw_pdu->enterprise[i]);
+ }
+ pdu.set_notify_enterprise(enterprise);
+ }
+ switch (raw_pdu->trap_type) {
+ case 0:
+ pdu.set_notify_id(coldStart);
+ break;
+
+ case 1:
+ pdu.set_notify_id(warmStart);
+ break;
+
+ case 2:
+ pdu.set_notify_id(linkDown);
+ break;
+
+ case 3:
+ pdu.set_notify_id(linkUp);
+ break;
+
+ case 4:
+ pdu.set_notify_id(authenticationFailure);
+ break;
+
+ case 5:
+ pdu.set_notify_id(egpNeighborLoss);
+ break;
+
+ case 6: { // enterprise specific
+ // base id + specific #
+ Oid eOid = enterprise;
+ eOid += 0ul;
+ eOid += raw_pdu->specific_type;
+ pdu.set_notify_id( eOid);
+ break;
+ }
+ default:
+ {
+ LOG_BEGIN(WARNING_LOG | 3);
+ LOG("SNMPMessage: Received trap with illegal trap type");
+ LOG(raw_pdu->trap_type);
+ LOG_END;
+ }
+ }
+ }
+
+ // vbs
+ Vb tempvb;
+ Oid tempoid;
+ struct variable_list *vp;
+ int vb_nr = 1;
+
+ for(vp = raw_pdu->variables; vp; vp = vp->next_variable, vb_nr++) {
+
+ // extract the oid portion
+ tempoid.set_data( (unsigned long *)vp->name,
+ ( unsigned int) vp->name_length);
+ tempvb.set_oid( tempoid);
+
+ // extract the value portion
+ switch(vp->type){
+
+ // octet string
+ case sNMP_SYNTAX_OCTETS:
+ {
+ OctetStr octets( (unsigned char *) vp->val.string,
+ (unsigned long) vp->val_len);
+ tempvb.set_value( octets);
+ }
+ break;
+ case sNMP_SYNTAX_OPAQUE:
+ {
+ OpaqueStr octets( (unsigned char *) vp->val.string,
+ (unsigned long) vp->val_len);
+ tempvb.set_value( octets);
+ }
+ break;
+
+ // object id
+ case sNMP_SYNTAX_OID:
+ {
+ Oid oid( (unsigned long*) vp->val.objid,
+ (int) vp->val_len);
+ tempvb.set_value( oid);
+ if ((vb_nr == 2) &&
+ ((raw_pdu->command == sNMP_PDU_TRAP) ||
+ (raw_pdu->command == sNMP_PDU_INFORM)) &&
+ (tempoid == SNMP_MSG_OID_TRAPID))
+ {
+ // set notify_id
+ pdu.set_notify_id(oid);
+ continue; // don't add vb to pdu
+ }
+ }
+ break;
+
+ // timeticks
+ case sNMP_SYNTAX_TIMETICKS:
+ {
+ TimeTicks timeticks( (unsigned long) *(vp->val.integer));
+ tempvb.set_value( timeticks);
+ if ((vb_nr == 1) &&
+ ((raw_pdu->command == sNMP_PDU_TRAP) ||
+ (raw_pdu->command == sNMP_PDU_INFORM)) &&
+ (tempoid == SNMP_MSG_OID_SYSUPTIME))
+ {
+ // set notify_timestamp
+ pdu.set_notify_timestamp( timeticks);
+ continue; // don't add vb to pdu
+ }
+ }
+ break;
+
+ // 32 bit counter
+ case sNMP_SYNTAX_CNTR32:
+ {
+ Counter32 counter32( (unsigned long) *(vp->val.integer));
+ tempvb.set_value( counter32);
+ }
+ break;
+
+ // 32 bit gauge
+ case sNMP_SYNTAX_GAUGE32:
+ {
+ Gauge32 gauge32( (unsigned long) *(vp->val.integer));
+ tempvb.set_value( gauge32);
+ }
+ break;
+
+ // ip address
+ case sNMP_SYNTAX_IPADDR:
+ {
+ char buffer[42];
+
+ if (vp->val_len == 16)
+ sprintf( buffer, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+ vp->val.string[ 0], vp->val.string[ 1], vp->val.string[ 2],
+ vp->val.string[ 3], vp->val.string[ 4], vp->val.string[ 5],
+ vp->val.string[ 6], vp->val.string[ 7], vp->val.string[ 8],
+ vp->val.string[ 9], vp->val.string[10], vp->val.string[11],
+ vp->val.string[12], vp->val.string[13], vp->val.string[14],
+ vp->val.string[15]);
+ else
+ sprintf( buffer,"%d.%d.%d.%d",
+ vp->val.string[0], vp->val.string[1],
+ vp->val.string[2], vp->val.string[3]);
+ IpAddress ipaddress( buffer);
+ tempvb.set_value( ipaddress);
+ }
+ break;
+
+ // 32 bit integer
+ case sNMP_SYNTAX_INT:
+ {
+ SnmpInt32 int32( (long) *(vp->val.integer));
+ tempvb.set_value( int32);
+ }
+ break;
+
+ // 32 bit unsigned integer
+/* Not distinguishable from Gauge32
+ case sNMP_SYNTAX_UINT32:
+ {
+ SnmpUInt32 uint32( (unsigned long) *(vp->val.integer));
+ tempvb.set_value( uint32);
+ }
+ break;
+*/
+ // v2 counter 64's
+ case sNMP_SYNTAX_CNTR64:
+ { // Frank Fock (was empty before)
+ Counter64 c64(((counter64*)vp->val.counter64)->high,
+ ((counter64*)vp->val.counter64)->low);
+ tempvb.set_value( c64);
+ break;
+ }
+ case sNMP_SYNTAX_NULL:
+ tempvb.set_null();
+ break;
+
+ // v2 vb exceptions
+ case sNMP_SYNTAX_NOSUCHOBJECT:
+ case sNMP_SYNTAX_NOSUCHINSTANCE:
+ case sNMP_SYNTAX_ENDOFMIBVIEW:
+ tempvb.set_exception_status(vp->type);
+ break;
+
+ default:
+ tempvb.set_null();
+
+ } // end switch
+
+ // append the vb to the pdu
+ pdu += tempvb;
+ }
+
+ snmp_free_pdu( raw_pdu);
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## target.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ T A R G E T . C P P
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION: Target class defines target SNMP agents.
+
+=====================================================================*/
+char target_cpp_version[]="#(@) SNMP++ $Id: target.cpp 1686 2009-11-24 13:47:44Z katz $";
+#include "snmp_pp/target.h"
+#include "snmp_pp/v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define PUBLIC "public"
+
+// class variables for default behavior control
+unsigned long SnmpTarget::default_timeout = 100;
+int SnmpTarget::default_retries = 1;
+
+//----------------------------------------------------------------------
+//--------[ Abstract SnmpTarget Member Functions ]----------------------
+//----------------------------------------------------------------------
+
+// get the address
+int SnmpTarget::get_address(GenAddress &address) const
+{
+ if (validity == false) return FALSE;
+
+ address = my_address;
+ return TRUE;
+}
+
+// set the address
+int SnmpTarget::set_address(const Address &address)
+{
+ my_address = address;
+ if ( my_address.valid())
+ validity = true;
+ else
+ validity = false;
+
+ return validity;
+}
+
+SnmpTarget* SnmpTarget::clone() const
+{
+ GenAddress addr = my_address;
+ SnmpTarget* res = new SnmpTarget;
+ res->set_timeout(timeout);
+ res->set_retry(retries);
+ res->set_address(addr);
+ res->set_version(version);
+ return res;
+}
+
+//=============[ int operator == SnmpTarget, SnmpTarget ]======================
+// equivlence operator overloaded
+int SnmpTarget::operator==( const SnmpTarget &rhs) const
+{
+ if (my_address != rhs.my_address) return 0;
+ if (version != rhs.version) return 0;
+ if (timeout != rhs.timeout) return 0;
+ if (retries != rhs.retries) return 0;
+ return 1; // they are equal
+}
+
+// reset the object
+void SnmpTarget::clear()
+{
+ validity = false;
+ timeout = default_timeout;
+ retries = default_retries;
+ version = version1;
+ ttype = type_base;
+ my_address.clear();
+}
+
+//----------------------------------------------------------------------
+//--------[ CTarget Member Functions ]----------------------------------
+//----------------------------------------------------------------------
+
+//---------[ CTarget::CTarget( void) ]----------------------------------
+// CTarget constructor no args
+CTarget::CTarget( void)
+ : read_community(PUBLIC), write_community(PUBLIC)
+{
+ ttype = type_ctarget; // overwrite value set in SnmpTarget()
+}
+
+//-----------[ CTarget:: CTarget ]-------------------------------------
+// CTarget constructor with args
+CTarget::CTarget(const Address &address,
+ const char *read_community_name,
+ const char *write_community_name)
+ : SnmpTarget(address),
+ read_community(read_community_name), write_community(write_community_name)
+{
+ ttype = type_ctarget; // overwrite value set in SnmpTarget()
+}
+
+//-----------[ CTarget:: CTarget ]-----------------------------------
+// CTarget constructor with args
+CTarget::CTarget(const Address &address,
+ const OctetStr& read_community_name,
+ const OctetStr& write_community_name)
+ : SnmpTarget(address),
+ read_community(read_community_name), write_community(write_community_name)
+{
+ ttype = type_ctarget; // overwrite value set in SnmpTarget()
+}
+
+
+//-----------[ CTarget:: CTarget( Address &address) ]--------------
+// CTarget constructor with args
+CTarget::CTarget(const Address &address)
+ : SnmpTarget(address), read_community(PUBLIC), write_community(PUBLIC)
+{
+ ttype = type_ctarget; // overwrite value set in SnmpTarget()
+}
+
+//-----------[ CTarget:: CTarget( const CTarget &target) ]-------
+// CTarget constructor with args
+CTarget::CTarget( const CTarget &target)
+{
+ read_community = target.read_community;
+ write_community = target.write_community;
+ my_address = target.my_address;
+ timeout = target.timeout;
+ retries = target.retries;
+ version = target.version;
+ validity = target.validity;
+ ttype = type_ctarget;
+}
+
+//----------[ CTarget::resolve_to_V1 ]---------------------------------
+// resolve entity
+// common interface for Community based targets
+int CTarget::resolve_to_C ( OctetStr &read_comm,
+ OctetStr &write_comm,
+ GenAddress &address,
+ unsigned long &t,
+ int &r,
+ unsigned char &v) const
+{
+ // if the target is invalid then return false
+ if ( !validity)
+ return FALSE;
+
+ read_comm = read_community;
+ write_comm = write_community;
+ address = my_address;
+
+ t = timeout;
+ r = retries;
+ v = version;
+
+ return TRUE;
+}
+
+// overloaded assignment
+CTarget& CTarget::operator=( const CTarget& target)
+{
+ if (this == &target) return *this; // check for self assignment
+
+ timeout = target.timeout;
+ retries = target.retries;
+ read_community = target.read_community;
+ write_community = target.write_community;
+ validity = target.validity;
+ my_address = target.my_address;
+ version = target.version;
+ return *this;
+}
+
+//=============[ int operator == CTarget, CTarget ]==========================
+// equivlence operator overloaded
+int CTarget::operator==( const CTarget &rhs) const
+{
+ if (SnmpTarget::operator==(rhs) == 0) return 0;
+ // need to compare all the members of a CTarget
+ if (read_community != rhs.read_community) return 0;
+ if (write_community != rhs.write_community) return 0;
+ return 1; // equal
+}
+
+// reset the object
+void CTarget::clear()
+{
+ SnmpTarget::clear();
+ read_community.clear();
+ write_community.clear();
+ ttype = type_ctarget; // overwrite value set in SnmpTarget::clear()
+}
+
+//----------------------------------------------------------------------
+//--------[ UTarget Member Functions ]----------------------------------
+//----------------------------------------------------------------------
+
+//---------[ UTarget::UTarget( void) ]----------------------------------
+// UTarget constructor no args
+UTarget::UTarget()
+ : security_name(INITIAL_USER),
+#ifdef _SNMPv3
+ security_model(SNMP_SECURITY_MODEL_USM), engine_id("")
+#else
+ security_model(SNMP_SECURITY_MODEL_V1)
+#endif
+{
+#ifdef _SNMPv3
+ version = version3;
+#endif
+ ttype = type_utarget;
+}
+
+//-----------[ UTarget:: UTarget ]-------------------------------------
+// UTarget constructor with args
+UTarget::UTarget( const Address &address,
+ const char *sec_name,
+ const int sec_model)
+ : SnmpTarget(address), security_name(sec_name), security_model(sec_model)
+#ifdef _SNMPv3
+ ,engine_id("")
+#endif
+{
+#ifdef _SNMPv3
+ version = version3;
+#endif
+ ttype = type_utarget;
+}
+
+//-----------[ UTarget:: UTarget ]-----------------------------------
+// UTarget constructor with args
+UTarget::UTarget( const Address &address,
+ const OctetStr &sec_name,
+ const int sec_model)
+ : SnmpTarget(address), security_name(sec_name), security_model(sec_model)
+#ifdef _SNMPv3
+ ,engine_id("")
+#endif
+{
+#ifdef _SNMPv3
+ version = version3;
+#endif
+ ttype = type_utarget;
+}
+
+//-----------[ UTarget:: UTarget( Address &address) ]--------------
+// UTarget constructor with args
+UTarget::UTarget( const Address &address)
+ : SnmpTarget(address), security_name(INITIAL_USER),
+#ifdef _SNMPv3
+ security_model(SNMP_SECURITY_MODEL_USM), engine_id("")
+#else
+ security_model(SNMP_SECURITY_MODEL_V1)
+#endif
+{
+#ifdef _SNMPv3
+ version = version3;
+#endif
+ ttype = type_utarget;
+}
+
+//-----------[ UTarget:: UTarget( const UTarget &target) ]-------
+// UTarget constructor with args
+UTarget::UTarget( const UTarget &target)
+{
+#ifdef _SNMPv3
+ engine_id = target.engine_id;
+#endif
+ security_name = target.security_name;
+ security_model = target.security_model;
+ my_address = target.my_address;
+ timeout = target.timeout;
+ retries = target.retries;
+ version = target.version;
+ validity = target.validity;
+ ttype = type_utarget;
+}
+
+
+// set the address
+int UTarget::set_address(const Address &address)
+{
+#ifdef _SNMPv3
+ engine_id = ""; // delete engine_id
+#endif
+ return SnmpTarget::set_address(address);
+}
+
+int UTarget::resolve_to_U( OctetStr& sec_name,
+ int &sec_model,
+ GenAddress &address,
+ unsigned long &t,
+ int &r,
+ unsigned char &v) const
+{
+ // if the target is invalid then return false
+ if ( !validity)
+ return FALSE;
+
+ sec_name = security_name;
+ sec_model = security_model;
+ address = my_address;
+
+ t = timeout;
+ r = retries;
+ v = version;
+
+ return TRUE;
+}
+
+// overloaded assignment
+UTarget& UTarget::operator=(const UTarget& target)
+{
+ if (this == &target) return *this; // check for self assignment
+
+ timeout = target.timeout;
+ retries = target.retries;
+
+#ifdef _SNMPv3
+ engine_id = target.engine_id;
+#endif
+ security_name = target.security_name;
+ security_model = target.security_model;
+ version = target.version;
+
+ validity = target.validity;
+ my_address = target.my_address;
+
+ return *this;
+}
+
+//=============[ int operator == UTarget, UTarget ]==========================
+// equivlence operator overloaded
+int UTarget::operator==(const UTarget &rhs) const
+{
+ if (SnmpTarget::operator==(rhs) == 0) return 0;
+ // need to compare all the members of a UTarget
+ // but don`t compare engine_id
+ if (security_name != rhs.security_name) return 0;
+ if (security_model != rhs.security_model) return 0;
+ return 1; // they are equal
+}
+
+// reset the object
+void UTarget::clear()
+{
+ SnmpTarget::clear();
+ security_name = INITIAL_USER;
+#ifdef _SNMPv3
+ security_model = SNMP_SECURITY_MODEL_USM;
+ engine_id.clear();
+ version = version3;
+#else
+ security_model = SNMP_SECURITY_MODEL_V1;
+#endif
+ ttype = type_utarget;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## timetick.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+ T I M E T I C K. C P P
+
+ TIMETICK CLASS IMPLEMENTATION
+
+ DESIGN + AUTHOR: Peter E Mellquist
+
+ DESCRIPTION:
+ Class implentation for SMI Timeticks class.
+=====================================================================*/
+char timetick_cpp_version[]="#(@) SNMP++ $Id: timetick.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+#include "snmp_pp/timetick.h" // include header file for timetick class
+#include <stdio.h> // for sprintf() usage.
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// Copy constructor
+TimeTicks::TimeTicks(const TimeTicks &t)
+{
+ smival.value.uNumber = t.smival.value.uNumber;
+ smival.syntax = sNMP_SYNTAX_TIMETICKS;
+}
+
+// general assignment from any Value
+SnmpSyntax& TimeTicks::operator=(const SnmpSyntax &in_val)
+{
+ if (this == &in_val) return *this; // handle assignement from itself
+
+ valid_flag = false; // will get set true if really valid
+ if (in_val.valid())
+ {
+ switch (in_val.get_syntax())
+ {
+ case sNMP_SYNTAX_UINT32:
+ // case sNMP_SYNTAX_GAUGE32: .. indistinquishable from UINT32
+ case sNMP_SYNTAX_CNTR32:
+ case sNMP_SYNTAX_TIMETICKS:
+ case sNMP_SYNTAX_INT32: // implied cast int -> uint
+ smival.value.uNumber =
+ ((TimeTicks &)in_val).smival.value.uNumber;
+ valid_flag = true;
+ break;
+ }
+ }
+ m_changed = true;
+ return *this;
+}
+
+// ASCII format return
+const char *TimeTicks::get_printable() const
+{
+ if (m_changed == false) return output_buffer;
+
+ unsigned long hseconds, seconds, minutes, hours, days;
+ unsigned long tt = smival.value.uNumber;
+ TimeTicks *nc_this = PP_CONST_CAST(TimeTicks*, this);
+
+ days = tt / 8640000;
+ tt %= 8640000;
+
+ hours = tt / 360000;
+ tt %= 360000;
+
+ minutes = tt / 6000;
+ tt %= 6000;
+
+ seconds = tt / 100;
+ tt %= 100;
+
+ hseconds = tt;
+
+ if (days == 0)
+ sprintf(nc_this->output_buffer, "%lu:%02lu:%02lu.%02lu",
+ hours, minutes, seconds, hseconds);
+ else if (days == 1)
+ sprintf(nc_this->output_buffer, "1 day %lu:%02lu:%02lu.%02lu",
+ hours, minutes, seconds, hseconds);
+ else
+ sprintf(nc_this->output_buffer, "%lu days, %lu:%02lu:%02lu.%02lu",
+ days, hours, minutes, seconds, hseconds);
+
+ nc_this->m_changed = false;
+ return output_buffer;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## usm_v3.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+char usm_v3_cpp_version[]="@(#) SNMP++ $Id: usm_v3.cpp 1788 2010-07-23 20:02:38Z katz $";
+
+#if defined(_AIX) || defined(__APPLE__)
+#include <unistd.h>
+#endif
+#ifdef __MINGW32__
+#include <io.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+
+#include "snmp_pp/v3.h"
+#include "snmp_pp/usm_v3.h"
+#include "snmp_pp/auth_priv.h"
+#include "snmp_pp/reentrant.h"
+#include "snmp_pp/mp_v3.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/vb.h"
+#include "snmp_pp/pdu.h"
+#include "snmp_pp/log.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// Use locking on access methods in an multithreading enviroment.
+#ifdef _THREADS
+#define BEGIN_REENTRANT_CODE_BLOCK SnmpSynchronize auto_lock(*this)
+#define BEGIN_REENTRANT_CODE_BLOCK_CONST \
+ SnmpSynchronize auto_lock(*(PP_CONST_CAST(SnmpSynchronized*, this)))
+#define BEGIN_AUTO_LOCK(obj) SnmpSynchronize auto_lock(*obj)
+#else
+#define BEGIN_REENTRANT_CODE_BLOCK
+#define BEGIN_REENTRANT_CODE_BLOCK_CONST
+#define BEGIN_AUTO_LOCK(obj)
+#endif
+
+#ifndef min
+#define min(a,b) ( (a) < (b) ? (a) : (b) )
+#endif
+
+#define MAX_LINE_LEN 2048 // Max line length in usm user files
+
+// structure for key update
+struct UsmKeyUpdate
+{
+ OctetStr engineID;
+ OctetStr securityName;
+ OctetStr newPassword;
+ OctetStr newKey;
+ int type;
+};
+
+/* ------------------------- UsmTimeTable --------------------------*/
+
+/**
+ * This class provides a table for the time values (engine boots and
+ * engine time) for snmp entities that are identified through their
+ * engine id.
+ *
+ * @author Jochen Katz
+ */
+class USMTimeTable : public SnmpSynchronized
+{
+public:
+
+ /**
+ * Initialize the usmTimeTable.
+ *
+ * The usmTimeTable stores for each known engineID the engineBoots
+ * and the difference to the local system time
+ *
+ * @param owner - Pointer to the USM object that created this table
+ * @param engine_boots - The new value for the snmpEngineBoots counter
+ * @param result - OUT: Result of the creation of the table
+ */
+ USMTimeTable(const USM *owner, const unsigned int engine_boots, int &result);
+
+ ~USMTimeTable();
+
+ /**
+ * Add a new entry to the usmTimeTable. The caller is responsible for
+ * not adding an engineID twice.
+ *
+ * @param engine_id - The engineID of the SNMP entity
+ * @param engine_boots - The engine boot counter
+ * @param engine_time - The engine time
+ *
+ * @return - SNMPv3_USM_ERROR (no memory) or SNMPv3_USM_OK
+ */
+ int add_entry(const OctetStr &engine_id,
+ const long int engine_boots, const long int engine_time);
+
+ /**
+ * Delete this engine id from the table.
+ *
+ * @param engine_id - The engineID of the SNMP entity
+ *
+ * @return - SNMPv3_USM_ERROR (no memory) or SNMPv3_USM_OK
+ */
+ int delete_entry(const OctetStr &engine_id);
+
+ /**
+ * Return engineBoots and engineTime for a given engineID
+ *
+ * @param engine_id - The engineID of the SNMP entity
+ * @param engine_boots - OUT: boot counter (0 if not found)
+ * @param engine_time - OUT: engine time (0 if not found)
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_OK (entry found, values are filled)
+ * SNMPv3_USM_UNKNOWN_ENGINEID ( not found)
+ */
+ int get_time(const OctetStr &engine_id,
+ long int &engine_boots, long int &engine_time);
+
+ /**
+ * Return the engineBoots and engineTime of this snmp entity.
+ *
+ * @param engine_boots - OUT: boot counter (0 if not found)
+ * @param engine_time - OUT: engine time (0 if not found)
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_OK (entry found, values are filled)
+ */
+ int get_local_time(long int &engine_boots, long int &engine_time);
+
+ /**
+ * Return the engineBoots value of this snmp entity.
+ *
+ * @return - engine_boots value if initialized, 0 else
+ */
+ unsigned long get_local_boots()
+ { return (table ? table[0].engine_boots : 0); };
+
+ /**
+ * Return the engineTime value of this snmp entity.
+ *
+ * @return - engine_time value if initialized, 0 else
+ */
+ unsigned long get_local_time();
+
+ /**
+ * Check if the given values for engineBoots and engineTime are
+ * in the time window. If the time values are ok, the entry in
+ * the usmTimeTable is updated with the given time values.
+ *
+ * @param engine_id - The engineID of the SNMP entity
+ * @param engine_boots - The boot counter
+ * @param engine_time - The engine time
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_NOT_IN_TIME_WINDOW,
+ * SNMPv3_USM_OK (time ok),
+ * SNMPv3_USM_UNKNOWN_ENGINEID
+ */
+ int check_time(const OctetStr &engine_id,
+ const long int engine_boots, const long int engine_time);
+
+ /**
+ * Check if the given engineID is known: If the USM is in
+ * the discovery mode, all engineIDs are accepted and entries
+ * in the timeTable are created.
+ *
+ * @param engine_id - engine id to check
+ *
+ * @return - SNMPv3_USM_ERROR (not found and no discovery)
+ * SNMPv3_USM_OK (found or discovery set)
+ */
+ int check_engine_id(const OctetStr &engine_id);
+
+private:
+ struct Entry_T
+ {
+ unsigned char engine_id[MAXLENGTH_ENGINEID];
+ int engine_id_len;
+ long int engine_boots;
+ long int time_diff;
+ long int latest_received_time;
+ };
+
+ struct Entry_T *table; ///< Array of entries
+ const USM *usm; ///< Pointer to the USM, this table belongs to
+ int max_entries; ///< the maximum number of entries
+ int entries; ///< the current amount of entries
+};
+
+
+/* ------------------------- UsmUserNameTable ----------------------*/
+
+/**
+ * This class holds USM users with PASSWORDS.
+ *
+ * Whenever the USM has to process a message of a user that is not
+ * found in the USMUserTable, this table is queried for the
+ * properties of the user. If the user is found, a localized entry
+ * for the USMUserTable is created and used for processing the message.
+ */
+class USMUserNameTable : public SnmpSynchronized
+{
+public:
+ USMUserNameTable(int &result);
+ ~USMUserNameTable();
+
+ /**
+ * Add a new user to the usmUserNameTable. If the userName is already
+ * known, the old entry is replaced.
+ *
+ * It is not recommended to add users with userName != securityName.
+ *
+ * @param user_name - Unique userName
+ * @param security_name - Unique securityName
+ * @param auth_proto - Possible values are:
+ * SNMP_AUTHPROTOCOL_NONE,
+ * SNMP_AUTHPROTOCOL_HMACMD5,
+ * SNMP_AUTHPROTOCOL_HMACSHA
+ * @param priv_proto - Possible values are:
+ * SNMP_PRIVPROTOCOL_NONE,
+ * SNMP_PRIVPROTOCOL_DES,
+ * SNMP_PRIVPROTOCOL_IDEA
+ * @param auth_pass - Secret password for authentication
+ * @param priv_pass - Secret password for privacy
+ *
+ * @return - SNMPv3_USM_OK or
+ * SNMP_v3_USM_ERROR (memory error, not initialized)
+ */
+ int add_entry(const OctetStr& user_name,
+ const OctetStr& security_name,
+ const long int auth_proto,
+ const long int priv_proto,
+ const OctetStr& auth_pass,
+ const OctetStr& priv_pass);
+
+ /**
+ * Delete all occurences of the user with the given securityName
+ * from the table.
+ *
+ * @param security_name - the securityName of the user
+ *
+ * @return - SNMPv3_USM_OK, SNMPv3_USM_ERROR (not initialized)
+ */
+ int delete_security_name(const OctetStr& security_name);
+
+ /**
+ * Get the entry with the given securityName from the usmUserNameTable
+ *
+ * @note Use lock() and unlock() for thread synchronizytion.
+ *
+ * @param security_name -
+ *
+ * @return - pointer to the struct or NULL (no need to delete anything)
+ */
+ const struct UsmUserNameTableEntry* get_entry(const OctetStr &security_name);
+
+ /**
+ * Get a clone of the entry with the given securityName from the usmUserNameTable
+ *
+ * @note call delete_cloned_entry() with the retruned pointer.
+ *
+ * @param security_name -
+ *
+ * @return - pointer to the struct or NULL
+ */
+ struct UsmUserNameTableEntry* get_cloned_entry(const OctetStr &security_name);
+
+ /**
+ * Deletes a entry created through get_cloned_entry().
+ *
+ * @param entry -
+ */
+ void delete_cloned_entry(struct UsmUserNameTableEntry* &entry);
+
+ /**
+ * Get the securityName from a userName
+ *
+ * @param user_name -
+ * @param user_name_len -
+ * @param security_name - Buffer for the securityName
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+ * SNMPv3_USM_OK
+ */
+ int get_security_name(const unsigned char *user_name,
+ const long int user_name_len,
+ OctetStr &security_name);
+
+ /**
+ * Get the userName from a securityName
+ *
+ * @param user_name - Buffer for the userName
+ * @param user_name_len - Has to be set to the max length of the
+ * buffer. Is set to the length of the found
+ * securityName or to 0 if not found.
+ * @param security_name -
+ * @param security_name_len -
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+ * SNMPv3_USM_OK
+ */
+ int get_user_name(unsigned char *user_name, long int *user_name_len,
+ const unsigned char *security_name,
+ const long int security_name_len);
+
+ /**
+ * Save all entries into a file.
+ */
+ int save_to_file(const char *name, AuthPriv *ap);
+
+ /**
+ * Load the table from a file.
+ */
+ int load_from_file(const char *name, AuthPriv *ap);
+
+ const UsmUserNameTableEntry *peek_first() const
+ { if (entries > 0) return table; return 0; };
+
+ const UsmUserNameTableEntry *peek_next(const UsmUserNameTableEntry *e) const;
+
+private:
+ struct UsmUserNameTableEntry *table;
+
+ int max_entries; ///< the maximum number of entries
+ int entries; ///< the current amount of entries
+};
+
+
+/* ---------------------------- UsmUserTable ------------------- */
+
+/**
+ * This class holds USM users with localized KEYS.
+ */
+class USMUserTable : public SnmpSynchronized
+{
+public:
+ USMUserTable(int &result);
+
+ ~USMUserTable();
+
+ /**
+ * Get the number of valid entries in the table.
+ *
+ * @return - number of entries
+ */
+ int size() const { return entries; };
+
+ /**
+ * Get the userName from a securityName
+ *
+ * @param user_name - Buffer for the userName
+ * @param user_name_len - Has to be set to the max length of the
+ * buffer. Is set to the length of the found
+ * securityName or to 0 if not found.
+ * @param sec_name -
+ * @param sec_name_len -
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+ * SNMPv3_USM_OK
+ */
+ int get_user_name(unsigned char *user_name, long int *user_name_len,
+ const unsigned char *sec_name, const long sec_name_len);
+
+ /**
+ * Get the sec_name from a userName
+ *
+ * @param user_name -
+ * @param user_name_len -
+ * @param sec_name - Object for the security name
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+ * SNMPv3_USM_OK
+ */
+ int get_security_name(const unsigned char *user_name,
+ const long user_name_len,
+ OctetStr &sec_name);
+
+ /**
+ * Delete all entries of this user from the usmUserTable
+ *
+ * @param user_name - The userName that should be deleted
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_OK (user deleted or not in table)
+ */
+ int delete_entries(const OctetStr& user_name);
+
+ /**
+ * Delete all entries with this engine id from the table.
+ *
+ * @param engine id - The engine id
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_OK (user deleted or not in table)
+ */
+ int delete_engine_id(const OctetStr& engine_id);
+
+ /**
+ * Delete the entry with the given userName and engineID
+ * from the usmUserTable
+ *
+ * @param engine_id - The engine id
+ * @param user_name - The userName that should be deleted
+ *
+ * @return - SNMPv3_USM_ERROR (not initialized),
+ * SNMPv3_USM_OK (user deleted or not in table)
+ */
+ int delete_entry(const OctetStr& engine_id, const OctetStr& user_name);
+
+ /**
+ * Protected (for agent++):
+ *
+ * Get the user at the specified position of the usmUserTable.
+ *
+ * @note Use lock() and unlock() for thread synchronization.
+ *
+ * @param number - get the entry at position number (1...)
+ *
+ * @return - a pointer to the structure or NULL if number is out
+ * of range (no need to delete anything)
+ */
+ const struct UsmUserTableEntry *get_entry(const int number);
+
+ /**
+ * Get a user of the usmUserTable.
+ *
+ * @note Use lock() and unlock() for thread synchronization.
+ *
+ * @param engine_id - Get a user for this engine id
+ * @param sec_name - Get the user with this security name
+ *
+ * @return - a pointer to the structure or NULL if the user is not
+ * found (no need to delete anything)
+ */
+ const struct UsmUserTableEntry *get_entry(const OctetStr &engine_id,
+ const OctetStr &sec_name);
+
+ /**
+ * Get a user of the usmUserTable.
+ *
+ * @note call delete_cloned_entry() with the retruned pointer.
+ *
+ * @param engine_id - Get a user for this engine id
+ * @param sec_name - Get the user with this security name
+ *
+ * @return - a pointer to the structure or NULL if the user is not
+ * found
+ */
+ struct UsmUserTableEntry *get_cloned_entry(const OctetStr &engine_id,
+ const OctetStr &sec_name);
+
+ /**
+ * Deletes a entry created through get_cloned_entry().
+ *
+ * @param entry -
+ */
+ void delete_cloned_entry(struct UsmUserTableEntry* &entry);
+
+ /**
+ * Get a user of the usmUserTable.
+ *
+ * There could be more than one entry with the given
+ * sec_name. Always the first entry that is found is returned.
+ *
+ * @note Use lock() and unlock() for thread synchronization.
+ *
+ * @param sec_name - security name to search for
+ *
+ * @return - a pointer to the structure or NULL if the user is not
+ * found (no need to delete anything)
+ */
+ const struct UsmUserTableEntry *get_entry(const OctetStr &sec_name);
+
+ /**
+ * Public:
+ *
+ * Add or replace a user in the usmUserTable. The usmUserTable stores
+ * users with their localized keys.
+ *
+ * @param engine_id - The engine_id, the key was localized with
+ * @param user_name - The name of the user (in the USM)
+ * @param sec_name - The security name of the user, this name
+ * is the same for all securityModels
+ * @param auth_proto - Possible values are:
+ * SNMP_AUTHPROTOCOL_NONE,
+ * SNMP_AUTHPROTOCOL_HMACMD5,
+ * SNMP_AUTHPROTOCOL_HMACSHA
+ * @param auth_key - The key used for authentications
+ * @param priv_proto - Possible values are:
+ * SNMP_PRIVPROTOCOL_NONE,
+ * SNMP_PRIVPROTOCOL_DES,
+ * SNMP_PRIVPROTOCOL_IDEA
+ * @param priv_key - The key used for privacy
+ *
+ * @return - SNMPv3_USM_OK
+ * SNMP_v3_USM_ERROR (not initialized, no memory)
+ */
+ int add_entry(const OctetStr &engine_id,
+ const OctetStr &user_name, const OctetStr &sec_name,
+ const long int auth_proto, const OctetStr &auth_key,
+ const long int priv_proto, const OctetStr &priv_key);
+
+ /**
+ * Replace a localized key of the user and engine_id in the
+ * usmUserTable.
+ *
+ * @param user_name - The name of the user in the USM
+ * @param engine_id - Change the localized key for the SNMP
+ * entity with this engine_id
+ * @param new_key - The new key
+ * @param key_type - AUTHKEY, OWNAUTHKEY, PRIVKEY or OWNPRIVKEY
+ *
+ * @return - SNMPv3_USM_ERROR (no such entry or not initialized),
+ * SNMPv3_USM_OK
+ */
+ int update_key(const OctetStr &user_name,
+ const OctetStr &engine_id,
+ const OctetStr &new_key,
+ const int key_type);
+
+ /**
+ * Save all entries into a file.
+ */
+ int save_to_file(const char *name, AuthPriv *ap);
+
+ /**
+ * Load the table from a file.
+ */
+ int load_from_file(const char *name, AuthPriv *ap);
+
+ const UsmUserTableEntry *peek_first() const
+ { if (entries > 0) return table; return 0; };
+
+ const UsmUserTableEntry *peek_next(const UsmUserTableEntry *e) const;
+
+private:
+ void delete_entry(const int nr);
+
+ struct UsmUserTableEntry *table;
+
+ int max_entries; ///< the maximum number of entries
+ int entries; ///< the current amount of entries
+};
+
+
+
+struct UsmSecurityParameters {
+ unsigned char msgAuthoritativeEngineID[MAXLENGTH_ENGINEID];
+ long int msgAuthoritativeEngineIDLength;
+ long int msgAuthoritativeEngineBoots;
+ long int msgAuthoritativeEngineTime;
+ unsigned char msgUserName[MAXLEN_USMUSERNAME];
+ long int msgUserNameLength;
+ unsigned char *msgAuthenticationParameters;
+ long int msgAuthenticationParametersLength;
+ unsigned char *msgPrivacyParameters;
+ unsigned int msgPrivacyParametersLength;
+};
+
+
+
+
+struct SecurityStateReference
+{
+ unsigned char msgUserName[MAXLEN_USMUSERNAME]; int msgUserNameLength;
+ unsigned char *securityName; int securityNameLength;
+ unsigned char *securityEngineID; int securityEngineIDLength;
+ int authProtocol;
+ unsigned char* authKey; int authKeyLength;
+ int privProtocol;
+ unsigned char* privKey; int privKeyLength;
+ int securityLevel;
+};
+
+
+
+
+void USM::inc_stats_unsupported_sec_levels()
+{
+ if (usmStatsUnsupportedSecLevels == MAXUINT32)
+ usmStatsUnsupportedSecLevels = 0;
+ else
+ usmStatsUnsupportedSecLevels++;
+}
+
+void USM::inc_stats_not_in_time_windows()
+{
+ if (usmStatsNotInTimeWindows == MAXUINT32)
+ usmStatsNotInTimeWindows = 0;
+ else
+ usmStatsNotInTimeWindows++;
+}
+
+void USM::inc_stats_unknown_user_names()
+{
+ if (usmStatsUnknownUserNames == MAXUINT32)
+ usmStatsUnknownUserNames = 0;
+ else
+ usmStatsUnknownUserNames++;
+}
+
+void USM::inc_stats_unknown_engine_ids()
+{
+ if (usmStatsUnknownEngineIDs == MAXUINT32)
+ usmStatsUnknownEngineIDs = 0;
+ else
+ usmStatsUnknownEngineIDs++;
+}
+
+void USM::inc_stats_wrong_digests()
+{
+ if (usmStatsWrongDigests == MAXUINT32)
+ usmStatsWrongDigests = 0;
+ else
+ usmStatsWrongDigests++;
+}
+
+void USM::inc_stats_decryption_errors()
+{
+ if (usmStatsDecryptionErrors == MAXUINT32)
+ usmStatsDecryptionErrors = 0;
+ else
+ usmStatsDecryptionErrors++;
+}
+
+
+void USM::delete_sec_state_reference(struct SecurityStateReference *ssr)
+{
+ if (ssr)
+ {
+ ssr->msgUserName[0] = 0;
+ if (ssr->securityName) delete [] ssr->securityName;
+ if (ssr->securityEngineID) delete [] ssr->securityEngineID;
+ if (ssr->authKey)
+ {
+ memset(ssr->authKey, 0, ssr->authKeyLength);
+ delete [] ssr->authKey;
+ }
+ if (ssr->privKey)
+ {
+ memset(ssr->privKey, 0, ssr->privKeyLength);
+ delete [] ssr->privKey;
+ }
+ }
+ delete ssr;
+}
+
+struct SecurityStateReference *USM::get_new_sec_state_reference()
+{
+ struct SecurityStateReference *res = new SecurityStateReference;
+
+ if (!res)
+ return NULL;
+
+ memset(res, 0, sizeof(struct SecurityStateReference));
+ return res;
+}
+
+
+USM::USM(unsigned int engine_boots, const OctetStr &engine_id,
+ const v3MP *v3_mp,
+ unsigned int *msgID, int &result)
+ : local_snmp_engine_id (engine_id),
+ v3mp (v3_mp),
+
+ discovery_mode (TRUE),
+
+ usmStatsUnsupportedSecLevels (0),
+ usmStatsNotInTimeWindows (0),
+ usmStatsUnknownUserNames (0),
+ usmStatsUnknownEngineIDs (0),
+ usmStatsWrongDigests (0),
+ usmStatsDecryptionErrors (0),
+
+ usm_add_user_cb (0)
+{
+ auth_priv = new AuthPriv(result);
+ if (result != SNMPv3_USM_OK)
+ return;
+ auth_priv->add_default_modules();
+
+ usm_user_name_table = new USMUserNameTable(result);
+ if (result != SNMPv3_USM_OK)
+ return;
+
+ usm_user_table = new USMUserTable(result);
+ if (result != SNMPv3_USM_OK)
+ return;
+
+#ifdef _TEST
+
+ printf("\nTesting 3DES starts\n\n");
+ OctetStr engineId = OctetStr::from_hex_string("00 00 00 00 00 00 "
+ "00 00 00 00 00 02");
+
+ OctetStr oldKey, newKey, delta;
+ oldKey.set_len(64);
+ newKey.set_len(64);
+ unsigned int key_len=64;
+
+ debughexcprintf(0,"engineID", engineId.data(), engineId.len());
+
+ auth_priv->password_to_key_priv(SNMP_AUTHPROTOCOL_HMACSHA,
+ SNMP_PRIVPROTOCOL_3DESEDE,
+ (unsigned char*)"maplesyrup", 10,
+ engineId.data(), engineId.len(),
+ oldKey.data(),
+ &key_len);
+ oldKey.set_len(key_len);
+ key_len=64;
+ auth_priv->password_to_key_priv(SNMP_AUTHPROTOCOL_HMACSHA,
+ SNMP_PRIVPROTOCOL_3DESEDE,
+ (unsigned char*)"newsyrup", 8,
+ engineId.data(), engineId.len(),
+ newKey.data(),
+ &key_len);
+ newKey.set_len(key_len);
+
+ OctetStr expectedKey = OctetStr::from_hex_string("78 e2 dc ce 79 d5 94 03 b5 8c 1b ba a5 bf f4 63 91 f1 cd 25 97 74 35 55 f9 fc f9 4a c3 e7 e9 22");
+
+ if (newKey != expectedKey)
+ {
+ printf("newKey != expectedKey\n");
+ printf("newKey: %s\n", newKey.get_printable_hex());
+ printf("expected: %s\n", expectedKey.get_printable_hex());
+ }
+
+ auth_priv->get_keychange_value(SNMP_AUTHPROTOCOL_HMACSHA,
+ oldKey, newKey, delta);
+
+ OctetStr expectedDelta = OctetStr::from_hex_string(
+ "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
+ "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
+ "ce 13 28 fb 9a 9c 19 ce c1 51 a3 5a 77 f9 20 39 "
+ "ca ff 00 c9 b3 9b 19 a0 5e 01 75 55 94 37 6a 57");
+
+ if (delta != expectedDelta)
+ {
+ printf("delta != expectedDelta\n");
+ printf("delta: %s\n", delta.get_printable_hex());
+ printf("expected: %s\n", expectedDelta.get_printable_hex());
+ }
+
+ printf("\nTesting 3DES finished\n\n");
+
+ printf(" Testing DES:\n");
+ PrivDES pd;
+ pp_uint64 testsalt=0xbabec0de;
+ pd.set_salt(&testsalt);
+
+ const char *desplaintext[10];
+ desplaintext[0] = "abcdefghijklmnopqrstuvwxyz123456";
+ desplaintext[1] = "abcdefghijklmnopqrstuvwxyz1234567";
+ desplaintext[2] = "abcdefghijklmnopqrstuvwxyz12345678";
+ desplaintext[3] = "abcdefghijklmnopqrstuvwxyz123456789";
+ desplaintext[4] = "abcdefghijklmnopqrstuvwxyz123456789A";
+ desplaintext[5] = "abcdefghijklmnopqrstuvwxyz123456789AB";
+ desplaintext[6] = "abcdefghijklmnopqrstuvwxyz123456789ABC";
+ desplaintext[7] = "abcdefghijklmnopqrstuvwxyz123456789ABCD";
+ desplaintext[8] = "abcdefghijklmnopqrstuvwxyz123456789ABCDE";
+ desplaintext[9] = "abcdefghijklmnopqrstuvwxyz123456789ABCDEF";
+
+ unsigned char desencrypted[80];
+ unsigned char desdecrypted[80];
+ unsigned char desprivparams[8];
+ unsigned char deskey[17] = "illegal_des_key!";
+
+ for (int i=0; i<9; i++)
+ {
+ unsigned int encrypt_len = 80;
+ unsigned int decrypt_len = 80;
+ unsigned int desprivparamslen = 8;
+
+ memset(desencrypted, 'x', 80);
+ memset(desdecrypted, 'y', 80);
+
+ debughexcprintf(1, "Plaintext", (unsigned char*)desplaintext[i],
+ strlen(desplaintext[i]));
+
+ int res = pd.encrypt(deskey, 16,
+ (unsigned char*)desplaintext[i],
+ strlen(desplaintext[i]),
+ desencrypted, &encrypt_len,
+ desprivparams, &desprivparamslen,
+ 0x2340abcd, 0);
+
+ printf("%d: Result of encryption is %d\n", i, res);
+ debughexcprintf(1, "Encrypted", desencrypted, encrypt_len);
+
+ res = pd.decrypt(deskey, 16,
+ desencrypted, encrypt_len,
+ desdecrypted, &decrypt_len,
+ desprivparams, desprivparamslen,
+ 0x2340abcd, 0);
+ printf("%d: Result of decryption is %d\n", i, res);
+ debughexcprintf(1, "Decrypted", desdecrypted, decrypt_len);
+
+ if (memcmp(desplaintext[i], desdecrypted, strlen(desplaintext[i])))
+ printf("\n********* FAILED **********\n");
+ else
+ printf("\nOK\n");
+
+ }
+
+
+
+#if 0
+ printf(" Testing SHA:\n");
+
+ // test password2key-algor:
+ unsigned char keysha[50];
+ auth_priv->password_to_key_auth(...(unsigned char*)"maplesyrup",10,
+ (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,keysha);
+ printf("Output of PasswordToKey-algorithm for SHA:\n");
+ for (int i=0; i< 20; i++) {
+ printf("%02X ", keysha[i]);
+ if ((i+1)%4==0) printf(" ");
+ if ((i+1)%16==0) printf("\n");
+ }
+ printf("\nOutput should be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
+ printf("66 95 fe bc 92 88 e3 62 82 23 5f c7 15 1f 12 84\n97 b3 8f 3f\n");
+ printf("\nTesting MD5:\n");
+ unsigned char keymd5[50];
+ apPasswordToKeyMD5((unsigned char*)"maplesyrup",10,
+ (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,keymd5);
+ printf("Output of PasswordToKey-algorithm for MD5:\n");
+ for (int i=0; i< 16; i++) {
+ printf("%02X ", keymd5[i]);
+ if ((i+1)%4==0) printf(" ");
+ if ((i+1)%16==0) printf("\n");
+ }
+ printf("Output ahould be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
+ printf("52 6f 5e ed 9f cc e2 6f 89 64 c2 93 07 87 d8 2b\n");
+
+ printf("\nTesting IDEA:\n");
+ unsigned char source[35] = "Hallo, das ist ein test!", encrypted[35], decrypted[35], params[8];
+ int len_encrypted = 35, len_decrypted = 35;
+ apIDEAEncryptData((unsigned char*)"1234567890abcdef",
+ source, 25, encrypted, &len_encrypted, params);
+
+ apIDEADecryptData((unsigned char*)"1234567890abcdef",
+ encrypted, len_encrypted,
+ decrypted, &len_decrypted, params);
+
+
+ printf("params:\n");
+ for (int i=0; i< 8; i++) {
+ printf("%02X ", params[i]);
+ if ((i+1)%4==0) printf(" ");
+ if ((i+1)%16==0) printf("\n");
+ }
+ printf("\nsource:\n");
+ for (int i=0; i< 25; i++) {
+ printf("%02X ", source[i]);
+ if ((i+1)%4==0) printf(" ");
+ if ((i+1)%16==0) printf("\n");
+ }
+ printf("\n");
+ printf("encrypted:\n");
+ for (int i=0; i< 25; i++) {
+ printf("%02X ", encrypted[i]);
+ if ((i+1)%4==0) printf(" ");
+ if ((i+1)%16==0) printf("\n");
+ }
+ printf("\n");
+ printf("decrypted:\n");
+ for (int i=0; i< 25; i++) {
+ printf("%02X ", decrypted[i]);
+ if ((i+1)%4==0) printf(" ");
+ if ((i+1)%16==0) printf("\n");
+ }
+ printf("\n");
+ for (int i=0; i<25; i++)
+ if (source[i]!=decrypted[i]) {
+ printf("\n*** source != decrypted ****\n\n");
+ break;
+ }
+
+ // test keyUpdate md5
+ printf("\n Test KeyUpdate Algorithm:\n");
+ printf("Test MD5:\n");
+ OctetStr oldKey = OctetStr(keymd5, SNMPv3_AP_OUTPUT_LENGTH_MD5);
+
+ unsigned char newkeymd5[50];
+ apPasswordToKeyMD5((unsigned char*)"newsyrup",8,
+ (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,newkeymd5);
+ printf("Output of PasswordToKey-algorithm for MD5:\n");
+ for (int i=0; i< 16; i++) {
+ printf("%02X ", newkeymd5[i]);
+ if ((i+1)%4==0) printf(" ");
+ if ((i+1)%16==0) printf("\n");
+ }
+ printf("Output ahould be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
+ printf("87 02 1d 7b d9 d1 01 ba 05 ea 6e 3b f9 d9 bd 4a\n");
+ OctetStr result;
+ apNewKey(oldKey, OctetStr(newkeymd5, SNMPv3_AP_OUTPUT_LENGTH_MD5),
+ result, SNMPv3_usmHMACMD5AuthProtocol);
+
+ // test keyUpdate sha (auth)
+ printf("\nTest SHA for authPassword:\n");
+ oldKey = OctetStr(keysha, SNMPv3_AP_OUTPUT_LENGTH_SHA);
+
+ unsigned char newkeysha[50];
+ apPasswordToKeySHA((unsigned char*)"newsyrup",8,
+ (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,newkeysha);
+ printf("Output of PasswordToKey-algorithm for sha:\n");
+ for (int i=0; i< SNMPv3_AP_OUTPUT_LENGTH_SHA; i++) {
+ printf("%02X ", newkeysha[i]);
+ if ((i+1)%4==0) printf(" ");
+ if ((i+1)%16==0) printf("\n");
+ }
+ printf("Output ahould be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
+ printf("78 e2 dc ce 79 d5 94 03 b5 8c 1b ba a5 bf f4 63 \n91 f1 cd 25\n");
+
+ apNewKey(oldKey, OctetStr(newkeysha, SNMPv3_AP_OUTPUT_LENGTH_SHA),
+ result, SNMPv3_usmHMACSHAAuthProtocol);
+ // test keyUpdate sha (privPassword DES)
+ printf("\nTest SHA for privPassword:\n");
+
+ oldKey = OctetStr(keysha, SNMPv3_AP_OUTPUT_LENGTH_MD5);
+ apNewKey(oldKey, OctetStr(newkeysha, SNMPv3_AP_OUTPUT_LENGTH_MD5),
+ result, SNMPv3_usmHMACSHAAuthProtocol);
+ printf("Result should be:\n");
+ printf("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n");
+ printf("7e f8 d8 a4 c9 cd b2 6b 47 59 1c d8 52 ff 88 b5\n");
+#endif
+ /* test AES key extension algorithm */
+ unsigned char key_sha[SNMPv3_USM_MAX_KEY_LEN];
+ unsigned int key_sha_len = SNMPv3_USM_MAX_KEY_LEN;
+
+ int res = auth_priv->password_to_key_priv(
+ SNMP_AUTHPROTOCOL_HMACSHA,
+ SNMP_PRIVPROTOCOL_AES256,
+ (unsigned char*)"maplesyrup", 10,
+ (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2", 12,
+ key_sha, &key_sha_len);
+
+ debugprintf(0, "aes key extension result %i, key_sha_len = %i.",
+ res, key_sha_len);
+ debughexcprintf(0, "key_sha", key_sha, key_sha_len);
+
+ unsigned char pt[56] = "This is a secret message, nobody is allowed to read it!";
+ unsigned char *plaintext = pt;
+ unsigned char ct[56];
+ unsigned char *cipher = ct;
+ unsigned int cipherlen = 56;
+ unsigned char privpar[8];
+ unsigned int privparlen = 8;
+
+ Priv *priv = auth_priv->get_priv(SNMP_PRIVPROTOCOL_AES256);
+ pp_uint64 salt = 0;
+ priv->set_salt(&salt);
+ auth_priv->encrypt_msg(SNMP_PRIVPROTOCOL_AES256,
+ key_sha, key_sha_len,
+ plaintext, 55, cipher, &cipherlen,
+ privpar, &privparlen,
+ 0xdeadc0deUL, 0xbeefdedeUL);
+
+ auth_priv->decrypt_msg(SNMP_PRIVPROTOCOL_AES256,
+ key_sha, key_sha_len,
+ cipher, 55, plaintext, &cipherlen,
+ privpar, privparlen,
+ 0xdeadc0deUL, 0xbeefdedeUL);
+
+#endif // _TEST
+
+ usm_time_table = new USMTimeTable(this, engine_boots, result);
+ if (result != SNMPv3_USM_OK)
+ return;
+
+ *msgID = (engine_boots & 0x7FFF) << 16;
+}
+
+USM::~USM()
+{
+ if (usm_time_table)
+ delete usm_time_table;
+ usm_time_table = NULL;
+
+ if (usm_user_table)
+ delete usm_user_table;
+ usm_user_table = NULL;
+
+ if (usm_user_name_table)
+ {
+ delete usm_user_name_table;
+ usm_user_name_table = NULL;
+ }
+
+ if (auth_priv)
+ {
+ delete auth_priv;
+ auth_priv = NULL;
+ }
+}
+
+// Delete this engine id form all USM tables (users and engine time).
+int USM::remove_engine_id(const OctetStr &engine_id)
+{
+ int retval1, retval2;
+
+ retval1 = usm_time_table->delete_entry(engine_id);
+
+ retval2 = usm_user_table->delete_entries(engine_id);
+
+ if ((retval1 == SNMPv3_USM_ERROR) ||
+ (retval2 == SNMPv3_USM_ERROR))
+ return SNMPv3_USM_ERROR;
+
+ return SNMPv3_USM_OK;
+}
+
+// Delete the time information for the given engine id
+int USM::remove_time_information(const OctetStr &engine_id)
+{
+ if (usm_time_table->delete_entry(engine_id) == SNMPv3_USM_ERROR)
+ return SNMPv3_USM_ERROR;
+
+ return SNMPv3_USM_OK;
+}
+
+int USM::update_key(const unsigned char* user_name,
+ const long int user_name_len,
+ const unsigned char* engine_id,
+ const long int engine_id_len,
+ const unsigned char* new_key,
+ const long int new_key_len,
+ const int type_of_key)
+{
+ OctetStr key(new_key, new_key_len);
+ int res;
+ res = usm_user_table->update_key(OctetStr(user_name, user_name_len),
+ OctetStr(engine_id, engine_id_len),
+ key, type_of_key);
+ key.clear();
+ return res;
+}
+
+int USM::add_localized_user(const OctetStr &engine_id,
+ const OctetStr &user_name,
+ const OctetStr &security_name,
+ const long auth_protocol,
+ const OctetStr &auth_key,
+ const long priv_protocol,
+ const OctetStr &priv_key)
+{
+ return usm_user_table->add_entry(engine_id, user_name, security_name,
+ auth_protocol, auth_key,
+ priv_protocol, priv_key);
+}
+
+
+int USM::add_usm_user(const OctetStr& user_name,
+ const OctetStr& security_name,
+ const long int auth_protocol,
+ const long int priv_protocol,
+ const OctetStr& auth_password,
+ const OctetStr& priv_password)
+{
+ /* delete localized entries if some exists */
+ delete_localized_user(user_name);
+
+ int result = usm_user_name_table->add_entry(user_name,security_name,
+ auth_protocol, priv_protocol,
+ auth_password, priv_password);
+ if (result != SNMPv3_USM_OK)
+ return result;
+
+ struct UsmUser *dummy;
+ dummy = get_user(local_snmp_engine_id, security_name);
+ if (dummy) free_user(dummy);
+
+ return SNMPv3_USM_OK;
+}
+
+int USM::add_usm_user(const OctetStr& user_name,
+ const OctetStr& security_name,
+ const long int auth_protocol,
+ const long int priv_protocol,
+ const OctetStr& auth_password,
+ const OctetStr& priv_password,
+ const OctetStr& engine_id)
+{
+ OctetStr auth_key;
+ OctetStr priv_key;
+
+ auth_key.set_len(SNMPv3_USM_MAX_KEY_LEN);
+ priv_key.set_len(SNMPv3_USM_MAX_KEY_LEN);
+
+ unsigned int auth_key_len = auth_key.len();
+ unsigned int priv_key_len = priv_key.len();
+
+ int res = build_localized_keys(engine_id, auth_protocol, priv_protocol,
+ auth_password.data(), auth_password.len(),
+ priv_password.data(), priv_password.len(),
+ auth_key.data(), &auth_key_len,
+ priv_key.data(), &priv_key_len);
+
+ if (res != SNMPv3_USM_OK)
+ return res;
+
+ auth_key.set_len(auth_key_len);
+ priv_key.set_len(priv_key_len);
+
+ res = usm_user_table->add_entry(engine_id, user_name, security_name,
+ auth_protocol, auth_key,
+ priv_protocol, priv_key);
+
+ auth_key.clear();
+ priv_key.clear();
+
+ return res;
+}
+
+int USM::add_usm_user(const OctetStr& security_name,
+ const long int auth_protocol,
+ const long int priv_protocol,
+ const OctetStr& auth_password,
+ const OctetStr& priv_password)
+{
+ // usmUserName: UserName for UserbasedSecurityModel
+ // usmSecurityName: UserName for all SecurityModels
+ return add_usm_user(security_name, security_name,
+ auth_protocol, priv_protocol,
+ auth_password, priv_password);
+}
+
+int USM::delete_localized_user(const OctetStr& usmUserName)
+{
+ return usm_user_table->delete_entries(usmUserName);
+}
+
+int USM::delete_localized_user(const OctetStr& engine_id,
+ const OctetStr& user_name)
+{
+ return usm_user_table->delete_entry(engine_id, user_name);
+}
+
+
+int USM::build_localized_keys(const OctetStr &engine_id,
+ const int auth_prot,
+ const int priv_prot,
+ const unsigned char *auth_password,
+ const unsigned int auth_password_len,
+ const unsigned char *priv_password,
+ const unsigned int priv_password_len,
+ unsigned char *auth_key,
+ unsigned int *auth_key_len,
+ unsigned char *priv_key,
+ unsigned int *priv_key_len)
+{
+ int res = auth_priv->password_to_key_auth(
+ auth_prot, auth_password,
+ auth_password_len,
+ engine_id.data(), engine_id.len(),
+ auth_key, auth_key_len);
+
+ if (res != SNMPv3_USM_OK)
+ {
+ if (res == SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL)
+ {
+ LOG_BEGIN(ERROR_LOG | 4);
+ LOG("Could not generate localized key: Unsupported auth protocol");
+ LOG(auth_prot);
+ LOG_END;
+ }
+ else
+ {
+ LOG_BEGIN(ERROR_LOG | 4);
+ LOG("Could not generate localized auth key, error code");
+ LOG(res);
+ LOG_END;
+ }
+ return res;
+ }
+
+ res = auth_priv->password_to_key_priv(auth_prot, priv_prot, priv_password,
+ priv_password_len,
+ engine_id.data(), engine_id.len(),
+ priv_key, priv_key_len);
+
+ if (res != SNMPv3_USM_OK)
+ {
+ if (res == SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL)
+ {
+ LOG_BEGIN(ERROR_LOG | 4);
+ LOG("Could not generate localized key: Unsupported priv protocol");
+ LOG(priv_prot);
+ LOG_END;
+ }
+ else
+ {
+ LOG_BEGIN(ERROR_LOG | 4);
+ LOG("Could not generate localized priv key, error code");
+ LOG(res);
+ LOG_END;
+ }
+ return res;
+ }
+
+ return res; // OK
+}
+
+struct UsmUser *USM::get_user(const OctetStr &engine_id,
+ const OctetStr &security_name)
+{
+ debugprintf(7,"USM::get_user: user (%s) engine_id (%s)",
+ security_name.get_printable(),engine_id.get_printable());
+
+ struct UsmUserNameTableEntry *name_table_entry = NULL;
+ struct UsmUserTableEntry *user_table_entry = NULL;
+
+ user_table_entry = usm_user_table->get_cloned_entry(engine_id,
+ security_name);
+ if (!user_table_entry)
+ {
+ name_table_entry = usm_user_name_table->get_cloned_entry(security_name);
+ if (!name_table_entry)
+ {
+ const struct UsmUserTableEntry *entry;
+
+ BEGIN_AUTO_LOCK(usm_user_table);
+
+ entry = usm_user_table->get_entry(security_name);
+
+ if ((entry) && (engine_id.len() == 0))
+ {
+ // there is a entry for this security_name in the usmUserTable
+ // so return an entry for this user to do engine_id discovery
+ struct UsmUser *res = new UsmUser;
+ if (!res)
+ return 0;
+
+ res->engineID = 0;
+ res->engineIDLength = 0;
+ res->usmUserName = v3strcpy(entry->usmUserName,
+ entry->usmUserNameLength);
+ res->usmUserNameLength = entry->usmUserNameLength;
+ res->securityName = v3strcpy(entry->usmUserSecurityName,
+ entry->usmUserSecurityNameLength);
+ res->securityNameLength = entry->usmUserSecurityNameLength;
+ res->authProtocol = SNMP_AUTHPROTOCOL_NONE;
+ res->authKey = 0; res->authKeyLength = 0;
+ res->privProtocol = SNMP_PRIVPROTOCOL_NONE;
+ res->privKey = 0; res->privKeyLength = 0;
+
+ if ((res->usmUserNameLength && !res->usmUserName) ||
+ (res->securityNameLength && !res->securityName))
+ {
+ free_user(res);
+ }
+ return res;
+ }
+ else
+ {
+ debugprintf(1, "USM::get_user: User unknown");
+ return NULL;
+ }
+ }
+ // here we have valid name_table_entry but not user_table_entry
+ if (engine_id.len() == 0)
+ {
+ // do not add a user
+ struct UsmUser *res = new UsmUser;
+ if (!res)
+ {
+ usm_user_name_table->delete_cloned_entry(name_table_entry);
+ return 0;
+ }
+ res->engineID = 0;
+ res->engineIDLength = 0;
+ res->usmUserName = v3strcpy(name_table_entry->usmUserName.data(),
+ name_table_entry->usmUserName.len());
+ res->usmUserNameLength = name_table_entry->usmUserName.len();
+ res->securityName = v3strcpy(
+ name_table_entry->usmUserSecurityName.data(),
+ name_table_entry->usmUserSecurityName.len());
+ res->securityNameLength = name_table_entry->usmUserSecurityName.len();
+ res->authProtocol = SNMP_AUTHPROTOCOL_NONE;
+ res->authKey = 0;
+ res->authKeyLength = 0;
+ res->privProtocol = SNMP_PRIVPROTOCOL_NONE;
+ res->privKey = 0;
+ res->privKeyLength = 0;
+
+ if ((res->usmUserNameLength && !res->usmUserName) ||
+ (res->securityNameLength && !res->securityName))
+ {
+ free_user(res);
+ }
+ usm_user_name_table->delete_cloned_entry(name_table_entry);
+ return res;
+ }
+ else
+ {
+ // We can add a new user:
+ unsigned char privKey[SNMPv3_USM_MAX_KEY_LEN];
+ unsigned char authKey[SNMPv3_USM_MAX_KEY_LEN];
+ unsigned int authKeyLength = SNMPv3_USM_MAX_KEY_LEN;
+ unsigned int privKeyLength = SNMPv3_USM_MAX_KEY_LEN;
+
+ int res = build_localized_keys(engine_id,
+ name_table_entry->usmUserAuthProtocol,
+ name_table_entry->usmUserPrivProtocol,
+ name_table_entry->authPassword,
+ name_table_entry->authPasswordLength,
+ name_table_entry->privPassword,
+ name_table_entry->privPasswordLength,
+ authKey, &authKeyLength,
+ privKey, &privKeyLength);
+
+ if (res != SNMPv3_USM_OK)
+ {
+ LOG_BEGIN(ERROR_LOG | 4);
+ LOG("Cannot add User: error code");
+ LOG(res);
+ LOG_END;
+
+ usm_user_name_table->delete_cloned_entry(name_table_entry);
+ return 0;
+ }
+
+ OctetStr akey(authKey, authKeyLength);
+ OctetStr pkey(privKey, privKeyLength);
+ add_localized_user(
+ engine_id,
+ name_table_entry->usmUserName,
+ name_table_entry->usmUserSecurityName,
+ name_table_entry->usmUserAuthProtocol, akey,
+ name_table_entry->usmUserPrivProtocol, pkey);
+
+ if (usm_add_user_cb)
+ {
+ // inform agent++ about new user
+ debugprintf(5, "Informing agent++ about newly created user");
+ usm_add_user_cb(engine_id,
+ name_table_entry->usmUserName,
+ name_table_entry->usmUserSecurityName,
+ name_table_entry->usmUserAuthProtocol, akey,
+ name_table_entry->usmUserPrivProtocol, pkey);
+ }
+ akey.clear();
+ pkey.clear();
+
+ user_table_entry = usm_user_table->get_cloned_entry(engine_id,
+ security_name);
+ if (!user_table_entry)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("Get of just added localized entry failed (sec name) (engine id)");
+ LOG(security_name.get_printable());
+ LOG(engine_id.get_printable());
+ LOG_END;
+ usm_user_name_table->delete_cloned_entry(name_table_entry);
+ return 0;
+ }
+ }
+ usm_user_name_table->delete_cloned_entry(name_table_entry);
+ }
+ struct UsmUser *res = new UsmUser;
+ if (!res)
+ {
+ usm_user_table->delete_cloned_entry(user_table_entry);
+ return 0;
+ }
+ res->engineID = user_table_entry->usmUserEngineID;
+ res->engineIDLength = user_table_entry->usmUserEngineIDLength;
+ res->usmUserName = user_table_entry->usmUserName;
+ res->usmUserNameLength = user_table_entry->usmUserNameLength;
+ res->securityName = user_table_entry->usmUserSecurityName;
+ res->securityNameLength = user_table_entry->usmUserSecurityNameLength;
+ res->authProtocol = user_table_entry->usmUserAuthProtocol;
+ res->authKey = user_table_entry->usmUserAuthKey;
+ res->authKeyLength = user_table_entry->usmUserAuthKeyLength;
+ res->privProtocol = user_table_entry->usmUserPrivProtocol;
+ res->privKey = user_table_entry->usmUserPrivKey;
+ res->privKeyLength = user_table_entry->usmUserPrivKeyLength;
+
+ user_table_entry->usmUserEngineID = 0;
+ user_table_entry->usmUserName = 0;
+ user_table_entry->usmUserSecurityName = 0;
+ user_table_entry->usmUserAuthKey = 0;
+ user_table_entry->usmUserPrivKey = 0;
+
+ usm_user_table->delete_cloned_entry(user_table_entry);
+
+ return res;
+}
+
+// Free the structure returned from get_user().
+void USM::free_user(struct UsmUser *&user)
+{
+ if (!user) return;
+
+ if (user->engineID) delete [] user->engineID;
+ if (user->usmUserName) delete [] user->usmUserName;
+ if (user->securityName) delete [] user->securityName;
+
+ if (user->authKey)
+ {
+ memset(user->authKey, 0, user->authKeyLength);
+ delete [] user->authKey;
+ }
+
+ if (user->privKey)
+ {
+ memset(user->privKey, 0, user->privKeyLength);
+ delete [] user->privKey;
+ }
+
+ delete user;
+
+ user = 0;
+}
+
+void USM::delete_usm_user(const OctetStr& security_name)
+{
+ usm_user_name_table->delete_security_name(security_name);
+
+ unsigned char username[MAXLEN_USMUSERNAME + 1];
+ long int length = MAXLEN_USMUSERNAME;
+
+ if ((get_user_name(username, &length,
+ security_name.data(), security_name.len()))
+ == SNMPv3_USM_OK)
+ delete_localized_user(OctetStr(username, length));
+}
+
+int USM::get_security_name(const unsigned char *user_name,
+ const long int user_name_len,
+ OctetStr &security_name)
+{
+ debugprintf(20,"USM::get_security_name: get user (%s)",
+ OctetStr(user_name,user_name_len).get_printable());
+
+ int result;
+
+ result = usm_user_name_table->get_security_name(user_name, user_name_len,
+ security_name);
+ if (result == SNMPv3_USM_OK)
+ return SNMPv3_USM_OK;
+
+ result = usm_user_table->get_security_name(user_name, user_name_len,
+ security_name);
+ if (result == SNMPv3_USM_OK)
+ return SNMPv3_USM_OK;
+
+ debugprintf(1, "USM::get_security_name: User unknown");
+ return SNMPv3_USM_ERROR;
+}
+
+int USM::get_user_name(unsigned char *user_name, long int *user_name_len,
+ const unsigned char *security_name,
+ const long int security_name_len)
+{
+ int result;
+ long int buf_len = *user_name_len;
+
+ result = usm_user_name_table->get_user_name(user_name, user_name_len,
+ security_name,
+ security_name_len);
+
+ if (result == SNMPv3_USM_OK)
+ return SNMPv3_USM_OK;
+
+ *user_name_len = buf_len;
+
+ result = usm_user_table->get_user_name(user_name, user_name_len,
+ security_name, security_name_len);
+
+ if (result == SNMPv3_USM_OK)
+ return SNMPv3_USM_OK;
+
+ debugprintf(1, "usmGetUsmUserName: User unknown");
+ return SNMPv3_USM_ERROR;
+}
+
+
+void USM::delete_sec_parameters( struct UsmSecurityParameters *usp)
+{
+ usp->msgAuthoritativeEngineID[0] = 0;
+ usp->msgAuthoritativeEngineIDLength = 0;
+ usp->msgAuthoritativeEngineBoots = 0;
+ usp->msgAuthoritativeEngineTime = 0;
+ usp->msgUserName[0] = 0;
+ usp->msgUserNameLength = 0;
+
+ if (usp->msgAuthenticationParameters) {
+ delete [] usp->msgAuthenticationParameters;
+ usp->msgAuthenticationParameters = NULL;
+ }
+ usp->msgAuthenticationParametersLength = 0;
+ if (usp->msgPrivacyParameters) {
+ delete [] usp->msgPrivacyParameters;
+ usp->msgPrivacyParameters = NULL;
+ }
+ usp->msgPrivacyParametersLength = 0;
+}
+
+
+const struct UsmUserTableEntry *USM::get_user(int number)
+{
+ return usm_user_table->get_entry(number);
+}
+
+const struct UsmUserNameTableEntry *USM::get_user(const OctetStr &security_name)
+{
+ return usm_user_name_table->get_entry(security_name);
+}
+
+int USM::get_user_count() const
+{
+ return usm_user_table->size();
+}
+
+DLLOPT void USM::add_user_added_callback(const usm_add_user_callback cb)
+{
+ usm_add_user_cb = cb;
+}
+
+int USM::get_time(const OctetStr &engine_id,
+ long int *engine_boots, long int *engine_time)
+{
+ return usm_time_table->get_time(engine_id, *engine_boots, *engine_time);
+}
+
+int USM::get_local_time(long int *engine_boots, long int *engine_time) const
+{
+ return usm_time_table->get_local_time(*engine_boots, *engine_time);
+}
+
+AuthPriv *USM::get_auth_priv()
+{
+ return auth_priv;
+}
+
+struct UsmKeyUpdate* USM::key_update_prepare(const OctetStr& securityName,
+ SnmpTarget& target,
+ const OctetStr& newPassword,
+ Pdu& pdu, int type,
+ int &status,
+ const OctetStr& oldpass,
+ const OctetStr& oldengid,
+ const OctetStr& newengid)
+{
+ // check address
+
+ GenAddress genaddress;
+ target.get_address(genaddress);
+ UdpAddress udp_address(genaddress);
+ if (!udp_address.valid()) {
+ debugprintf(0, "usmPrepareKeyUpdate: Address invalid.");
+ status = SNMPv3_USM_ADDRESS_ERROR;
+ return NULL;
+ }
+
+ OctetStr engineID = "";
+ // get engineID
+ if (v3mp->get_from_engine_id_table(engineID,
+ (char*)udp_address.get_printable())
+ != SNMPv3_MP_OK ) {
+ debugprintf(0, "usmPrepareKeyUpdate: Could not find engineID of given address.");
+ status = SNMPv3_USM_ADDRESS_ERROR;
+ return NULL;
+ }
+
+ // get user
+ struct UsmUser* user;
+ user = get_user(engineID, securityName);
+
+ if (user == NULL) {
+ debugprintf(0, "usmPrepareKeyUpdate: Could not find user in usmTables.");
+ status = SNMPv3_USM_UNKNOWN_SECURITY_NAME;
+ return NULL;
+ }
+
+ /* set old and new key */
+ unsigned char key[SNMPv3_USM_MAX_KEY_LEN];
+ unsigned int key_len = SNMPv3_USM_MAX_KEY_LEN;
+ OctetStr newKey;
+ OctetStr oldKey;
+
+ switch (type) {
+ case AUTHKEY:
+ case OWNAUTHKEY: {
+ status = auth_priv->password_to_key_auth(
+ user->authProtocol,
+ newPassword.data(), newPassword.len(),
+ engineID.data(), engineID.len(),
+ key, &key_len);
+ oldKey = OctetStr(user->authKey, user->authKeyLength);
+ break;
+ }
+ case PRIVKEY:
+ case OWNPRIVKEY: {
+ status = auth_priv->password_to_key_priv(
+ user->authProtocol,
+ user->privProtocol,
+ newPassword.data(), newPassword.len(),
+ engineID.data(), engineID.len(),
+ key, &key_len);
+ oldKey = OctetStr(user->privKey, user->privKeyLength);
+ break;
+ }
+ default: {
+ debugprintf(0, "usmPrepareKeyUpdate: wrong type specified.");
+ status = SNMPv3_USM_ERROR;
+ free_user(user);
+ return NULL;
+ }
+ }
+
+ if (status != SNMPv3_USM_OK)
+ {
+ debugprintf(0, "usmPrepareKeyUpdate: password_to_key failed (code %i).",
+ status);
+ free_user(user);
+ return NULL;
+ }
+
+ newKey = OctetStr(key, key_len);
+
+ /* get value to set and random value */
+ OctetStr newValue;
+ OctetStr random_value;
+
+ auth_priv->get_keychange_value(user->authProtocol,
+ oldKey, newKey, newValue);
+
+ char tmp_rand;
+ for (int i = 0; i<30; i++) {
+ tmp_rand = rand();
+ random_value += tmp_rand;
+ }
+
+ // Oid in usmUserTable
+ Oid userOid = Oid(oidUsmUserEntry);
+ Oid publicOid = Oid(oidUsmUserEntry);
+
+ publicOid += "11";
+
+ switch (type) {
+ case AUTHKEY: {
+ userOid += "6";
+ break;
+ }
+ case OWNAUTHKEY: {
+ userOid += "7";
+ break;
+ }
+ case PRIVKEY: {
+ userOid += "9";
+ break;
+ }
+ case OWNPRIVKEY: {
+ userOid += "10";
+ break;
+ }
+ default: {
+ debugprintf(0, "KeyChange error: wrong type:");
+ status = SNMPv3_USM_ERROR;
+ free_user(user);
+ return NULL;
+ }
+ }
+
+ userOid += engineID.len();
+ publicOid += engineID.len();
+
+ for (unsigned int j=0; j<engineID.len(); j++) {
+ userOid += (engineID)[j];
+ publicOid += (engineID)[j];
+ }
+
+ OctetStr os = securityName;
+ userOid += os.len();
+ publicOid += os.len();
+
+ for (unsigned int k=0; k<os.len(); k++) {
+ userOid += os[k];
+ publicOid += os[k];
+ }
+
+ Vb vb;
+ vb.set_oid(userOid);
+ vb.set_value(newValue);
+ pdu += vb;
+
+ vb.set_oid(publicOid);
+ vb.set_value(random_value);
+ pdu += vb;
+
+ struct UsmKeyUpdate *uku = new struct UsmKeyUpdate;
+ uku->engineID = engineID;
+ uku->securityName = securityName;
+ uku->newPassword = newPassword;
+ uku->newKey = newKey;
+ uku->type = type;
+
+ free_user(user);
+ status = SNMPv3_USM_OK;
+ return uku;
+}
+
+void USM::key_update_abort(struct UsmKeyUpdate *uku)
+{
+ delete uku;
+}
+
+int USM::key_update_commit(struct UsmKeyUpdate *uku, int update_type)
+{
+ if (!uku) return SNMPv3_USM_ERROR;
+
+ int result;
+ OctetStr userName;
+
+ switch (update_type)
+ {
+ case USM_KeyUpdate: {
+ result = update_key(uku->securityName.data(), uku->securityName.len(),
+ uku->engineID.data(), uku->engineID.len(),
+ uku->newKey.data(), uku->newKey.len(),
+ uku->type);
+ delete uku;
+ return result;
+ }
+ case USM_PasswordKeyUpdate: {
+ result = update_key(uku->securityName.data(), uku->securityName.len(),
+ uku->engineID.data(), uku->engineID.len(),
+ uku->newKey.data(), uku->newKey.len(),
+ uku->type);
+ struct UsmUserNameTableEntry *entry;
+ entry = usm_user_name_table->get_cloned_entry(uku->securityName);
+ if (!entry || (result != SNMPv3_USM_OK)) {
+ delete uku;
+ if (entry)
+ usm_user_name_table->delete_cloned_entry(entry);
+ return SNMPv3_USM_ERROR;
+ }
+
+ result = SNMPv3_USM_ERROR;
+
+ switch (uku->type) {
+ case OWNAUTHKEY:
+ case AUTHKEY: {
+ OctetStr privPass(entry->privPassword, entry->privPasswordLength);
+ result = add_usm_user(uku->securityName, entry->usmUserName,
+ entry->usmUserAuthProtocol,
+ entry->usmUserPrivProtocol,
+ uku->newPassword, privPass);
+ break;
+ }
+ case OWNPRIVKEY:
+ case PRIVKEY: {
+ OctetStr authPass(entry->privPassword, entry->privPasswordLength);
+ result = add_usm_user(uku->securityName, entry->usmUserName,
+ entry->usmUserAuthProtocol,
+ entry->usmUserPrivProtocol,
+ authPass, uku->newPassword);
+ break;
+ }
+ }
+ delete uku;
+ usm_user_name_table->delete_cloned_entry(entry);
+ return result;
+ }
+ case USM_PasswordAllKeyUpdate: {
+ struct UsmUserNameTableEntry *entry;
+ entry = usm_user_name_table->get_cloned_entry(uku->securityName);
+ if (!entry) {
+ delete uku;
+ return SNMPv3_USM_ERROR;
+ }
+
+ result = SNMPv3_USM_ERROR;
+
+ switch (uku->type) {
+ case OWNAUTHKEY:
+ case AUTHKEY: {
+ OctetStr privPass = OctetStr(entry->privPassword,
+ entry->privPasswordLength);
+ delete_usm_user(uku->securityName);
+ result = add_usm_user(uku->securityName, entry->usmUserName,
+ entry->usmUserAuthProtocol,
+ entry->usmUserPrivProtocol,
+ uku->newPassword, privPass);
+ break;
+ }
+ case OWNPRIVKEY:
+ case PRIVKEY: {
+ OctetStr authPass = OctetStr(entry->authPassword,
+ entry->authPasswordLength);
+ delete_usm_user(uku->securityName);
+ result = add_usm_user(uku->securityName, entry->usmUserName,
+ entry->usmUserAuthProtocol,
+ entry->usmUserPrivProtocol,
+ authPass, uku->newPassword);
+ break;
+ }
+ }
+ delete uku;
+ usm_user_name_table->delete_cloned_entry(entry);
+ return result;
+ }
+ }
+ delete uku;
+ return SNMPv3_USM_ERROR;
+}
+
+int USM::generate_msg(
+ unsigned char *globalData, // message header, admin data
+ int globalDataLength,
+ int maxMessageSize, // of the sending SNMP entity
+ const OctetStr &securityEngineID,// authoritative SNMP entity
+ const OctetStr &securityName, // on behalf of this principal
+ int securityLevel, // Level of Security requested
+ unsigned char *scopedPDU, // message (plaintext) payload
+ int scopedPDULength,
+ struct SecurityStateReference *securityStateReference,
+ unsigned char *wholeMsg, // OUT complete generated message
+ int *wholeMsgLength) // OUT length of generated message
+{
+ Buffer<unsigned char> buffer(MAX_SNMP_PACKET);
+ Buffer<unsigned char> buffer2(MAX_SNMP_PACKET);
+ unsigned char *bufPtr = buffer.get_ptr();
+ unsigned char *buf2Ptr = buffer2.get_ptr();
+
+ if (!bufPtr || !buf2Ptr)
+ return SNMPv3_USM_ERROR;
+
+ unsigned char *wholeMsgPtr;
+ int startAuthPar = 0;
+ struct UsmUser *user = NULL;
+ struct UsmSecurityParameters usmSecurityParams;
+
+ int bufLength = 0;
+ unsigned int buf2Length = 0;
+ int totalLength = 0; // Bytes encoded
+ int restLength = maxMessageSize; // max Bytes left in packet-buffer
+ int rc;
+ int responseMsg = 0;
+
+ if (securityStateReference) {
+ // this is a response message
+ responseMsg = 1;
+ user = new UsmUser;
+ if (!user)
+ return SNMPv3_USM_ERROR;
+ if (securityStateReference->securityEngineID) {
+ user->engineIDLength = securityStateReference->securityEngineIDLength;
+ user->engineID = securityStateReference->securityEngineID;
+ } else {
+ user->engineIDLength = securityEngineID.len();
+ user->engineID = v3strcpy(securityEngineID.data(),
+ securityEngineID.len());
+ }
+
+ user->usmUserName = new unsigned char[MAXLEN_USMUSERNAME + 1];
+ if (securityStateReference->securityName)
+ {
+ user->securityName = securityStateReference->securityName;
+ user->securityNameLength = securityStateReference->securityNameLength;
+ memcpy(user->usmUserName, securityStateReference->msgUserName,
+ securityStateReference->msgUserNameLength);
+ user->usmUserNameLength = securityStateReference->msgUserNameLength;
+ }
+ else
+ {
+ user->securityNameLength = securityName.len();
+ user->securityName = v3strcpy(securityName.data(), securityName.len());
+ if (securityStateReference->msgUserNameLength)
+ {
+ securityStateReference->msgUserName[0] = 0;
+ securityStateReference->msgUserNameLength = 0;
+ }
+ user->usmUserNameLength = MAXLEN_USMUSERNAME;
+ get_user_name(user->usmUserName, &user->usmUserNameLength,
+ securityName.data(), securityName.len());
+ if ((user->usmUserNameLength == 0) &&
+ (securityName.len() <= MAXLEN_USMUSERNAME)) {
+ memcpy(user->usmUserName, securityName.data(), securityName.len());
+ user->usmUserName[securityName.len()] = 0;
+ user->usmUserNameLength = securityName.len();
+ }
+ }
+ user->authProtocol = securityStateReference->authProtocol;
+ user->authKey = securityStateReference->authKey;
+ user->authKeyLength = securityStateReference->authKeyLength;
+ user->privProtocol = securityStateReference->privProtocol;
+ user->privKeyLength = securityStateReference->privKeyLength;
+ user->privKey = securityStateReference->privKey;
+
+ delete securityStateReference;
+ securityStateReference = NULL;
+ }
+ else
+ {
+ if (securityEngineID.len() == 0)
+ {
+ // discovery
+ user = new UsmUser;
+ if (!user)
+ return SNMPv3_USM_ERROR;
+ memset(user, 0, sizeof(UsmUser));
+ }
+ else
+ {
+ // search for user in usmUserTable
+ user = get_user(securityEngineID, securityName);
+
+ if (!user) {
+ debugprintf(0, "USM: User unknown!");
+ return SNMPv3_USM_UNKNOWN_SECURITY_NAME;
+ }
+ }
+ }
+
+ if (securityEngineID.len() > MAXLENGTH_ENGINEID)
+ {
+ debugprintf(0, "engine_id too long %i > %i",
+ securityEngineID.len(), MAXLENGTH_ENGINEID);
+ free_user(user);
+ return SNMPv3_USM_ERROR;
+ }
+
+ if (user->usmUserNameLength > MAXLEN_USMUSERNAME)
+ {
+ debugprintf(0, "user name too long %i > %i",
+ user->usmUserNameLength, MAXLEN_USMUSERNAME);
+ free_user(user);
+ return SNMPv3_USM_ERROR;
+ }
+
+ usmSecurityParams.msgAuthoritativeEngineIDLength = securityEngineID.len();
+ usmSecurityParams.msgUserNameLength = user->usmUserNameLength;
+ memcpy(usmSecurityParams.msgUserName,
+ user->usmUserName, user->usmUserNameLength);
+ memcpy(usmSecurityParams.msgAuthoritativeEngineID,
+ securityEngineID.data(), securityEngineID.len());
+
+ usmSecurityParams.msgPrivacyParametersLength = 0;
+ usmSecurityParams.msgPrivacyParameters = NULL;
+
+ usmSecurityParams.msgAuthenticationParametersLength = 0;
+ usmSecurityParams.msgAuthenticationParameters = NULL;
+
+ if (securityLevel >= SNMP_SECURITY_LEVEL_AUTH_NOPRIV)
+ {
+ // get engineBoots, engineTime
+ rc = usm_time_table->get_time(
+ securityEngineID,
+ usmSecurityParams.msgAuthoritativeEngineBoots,
+ usmSecurityParams.msgAuthoritativeEngineTime);
+ if (rc == SNMPv3_USM_UNKNOWN_ENGINEID) {
+ usm_time_table->add_entry(securityEngineID,
+ usmSecurityParams.msgAuthoritativeEngineBoots,
+ usmSecurityParams.msgAuthoritativeEngineTime);
+ }
+ if (rc == SNMPv3_USM_ERROR) {
+ debugprintf(0, "usm: usmGetTime error.");
+ free_user(user);
+ return SNMPv3_USM_ERROR;
+ }
+ }
+
+ if (securityLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
+ {
+ usmSecurityParams.msgPrivacyParametersLength
+ = auth_priv->get_priv_params_len(user->privProtocol);
+ usmSecurityParams.msgPrivacyParameters
+ = new unsigned char[usmSecurityParams.msgPrivacyParametersLength];
+
+ // encrypt Message
+ int enc_result = auth_priv->encrypt_msg(
+ user->privProtocol,
+ user->privKey, user->privKeyLength,
+ scopedPDU, scopedPDULength,
+ buf2Ptr, &buf2Length,
+ usmSecurityParams.msgPrivacyParameters,
+ &usmSecurityParams.msgPrivacyParametersLength,
+ usmSecurityParams.msgAuthoritativeEngineBoots,
+ usmSecurityParams.msgAuthoritativeEngineTime);
+ if (enc_result != SNMPv3_USM_OK)
+ {
+ int return_value;
+
+ if (user->privProtocol == SNMP_PRIVPROTOCOL_NONE)
+ {
+ debugprintf(0, "usm: Privacy requested, but no UserPrivProtocol");
+ return_value = SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
+ }
+ else
+ {
+ return_value = SNMPv3_USM_ENCRYPTION_ERROR;
+ }
+
+ debugprintf(0, "usm: Encryption error (result %i).", enc_result);
+
+ delete_sec_parameters(&usmSecurityParams);
+ free_user(user);
+ return return_value;
+ }
+
+ bufPtr = asn_build_string(bufPtr, &restLength, ASN_UNI_PRIM | ASN_OCTET_STR,
+ buf2Ptr, buf2Length);
+ if (!bufPtr) {
+ debugprintf(0, "usm: Encoding Error");
+ free_user(user);
+ return SNMPv3_USM_ERROR;
+ }
+ bufLength = SAFE_INT_CAST(bufPtr - buffer.get_ptr());
+ totalLength = bufLength;
+ bufPtr = buffer.get_ptr();
+ memcpy(buf2Ptr, bufPtr, bufLength);
+ buf2Length = bufLength;
+
+ } else { // (securityLevel != SNMP_SECURITY_LEVEL_AUTH_PRIV)
+ buf2Ptr = scopedPDU;
+ buf2Length = scopedPDULength;
+ totalLength = scopedPDULength;
+ }
+ if (!bufPtr) {
+ debugprintf(0, "usm: Encoding Error");
+ free_user(user);
+ return SNMPv3_USM_ERROR;
+ }
+
+ totalLength += SAFE_INT_CAST(bufPtr - buffer.get_ptr());
+ memcpy(bufPtr, buf2Ptr, buf2Length);
+ bufLength = totalLength;
+
+ debugprintf(21, "buf after privacy:");
+ debughexprintf(21, buffer.get_ptr(), bufLength);
+
+ wholeMsgPtr = wholeMsg;
+
+ if (securityLevel >= SNMP_SECURITY_LEVEL_AUTH_NOPRIV)
+ {
+ /* Build message with authentication */
+ usmSecurityParams.msgAuthenticationParametersLength
+ = auth_priv->get_auth_params_len(user->authProtocol);
+ usmSecurityParams.msgAuthenticationParameters
+ = new unsigned char[usmSecurityParams.msgAuthenticationParametersLength];
+ memset((char*)(usmSecurityParams.msgAuthenticationParameters), 0,
+ usmSecurityParams.msgAuthenticationParametersLength);
+
+ wholeMsgPtr = build_whole_msg(wholeMsgPtr, &maxMessageSize,
+ globalData, globalDataLength,
+ &startAuthPar, // for MD5, SHA,...
+ usmSecurityParams,
+ buffer.get_ptr(),
+ bufLength); // the msgData
+ if (wholeMsgPtr == NULL)
+ {
+ debugprintf(0, "usm: could not generate wholeMsg");
+ delete_sec_parameters(&usmSecurityParams);
+ free_user(user);
+ return SNMPv3_USM_ERROR;
+ }
+ *wholeMsgLength = SAFE_INT_CAST(wholeMsgPtr - wholeMsg);
+
+ rc = auth_priv->auth_out_msg(user->authProtocol,
+ user->authKey,
+ wholeMsg, *wholeMsgLength,
+ wholeMsg + startAuthPar);
+
+ if (rc!=SNMPv3_USM_OK)
+ {
+ debugprintf(0, "usm: Authentication error for outgoing message."
+ " error code (%i).", rc);
+ delete_sec_parameters(&usmSecurityParams);
+ free_user(user);
+ return rc;
+ }
+ }
+ else
+ {
+ //build Message without authentication
+
+ // Set engineBoots and enigneTime to zero!
+ usmSecurityParams.msgAuthoritativeEngineBoots = 0;
+ usmSecurityParams.msgAuthoritativeEngineTime = 0;
+
+ usmSecurityParams.msgAuthenticationParametersLength = 0;
+ usmSecurityParams.msgAuthenticationParameters = 0;
+
+ wholeMsgPtr = build_whole_msg(wholeMsgPtr, &maxMessageSize,
+ globalData, globalDataLength,
+ &startAuthPar, // dummy ( no auth)
+ usmSecurityParams,
+ buffer.get_ptr(),
+ bufLength); // the msgData
+ if (wholeMsgPtr == NULL) {
+ debugprintf(0, "usm: could not generate wholeMsg");
+ delete_sec_parameters(&usmSecurityParams);
+ free_user(user);
+ return SNMPv3_USM_ERROR;
+ }
+ *wholeMsgLength = SAFE_INT_CAST(wholeMsgPtr - wholeMsg);
+ }
+
+ debugprintf(21, "Complete Whole Msg:");
+ debughexprintf(21, wholeMsg, *wholeMsgLength);
+
+ delete_sec_parameters(&usmSecurityParams);
+ free_user(user);
+ return SNMPv3_USM_OK;
+}
+
+int USM::process_msg(
+ int maxMessageSize, // of the sending SNMP entity
+ unsigned char *securityParameters,// for the received message
+ int securityParametersLength,
+ int securityParametersPosition,
+ long int securityLevel, // Level of Security
+ unsigned char *wholeMsg, // as received on the wire
+ int wholeMsgLength, // length as received on the wire
+ unsigned char *msgData,
+ int msgDataLength,
+ OctetStr &security_engine_id, // authoritative SNMP entity
+ OctetStr &security_name, //identification of the principal
+ unsigned char *scopedPDU, // message (plaintext) payload
+ int *scopedPDULength,
+ long *maxSizeResponseScopedPDU, // maximum size of the Response PDU
+ struct SecurityStateReference *securityStateReference,
+ // reference to security state
+ // information, needed for response
+ const UdpAddress &fromAddress)
+{
+ unsigned char* sp = securityParameters;
+ int spLength = securityParametersLength;
+ unsigned char type;
+ long int engineBoots, engineTime;
+ unsigned char authParam[SNMPv3_AP_MAXLENGTH_AUTHPARAM];
+ unsigned char privParam[SNMPv3_AP_MAXLENGTH_PRIVPARAM];
+ int authParamLength = SNMPv3_AP_MAXLENGTH_AUTHPARAM;
+ int privParamLength = SNMPv3_AP_MAXLENGTH_PRIVPARAM;
+ Buffer<unsigned char> encryptedScopedPDU(MAX_SNMP_PACKET);
+ int encryptedScopedPDULength = msgDataLength;
+ struct UsmUser *user = NULL;
+ int rc;
+ int notInTime = 0;
+
+ // check securityParameters
+ sp = asn_parse_header( sp, &spLength, &type);
+ if (sp == NULL){
+ debugprintf(0, "bad header of securityParameters");
+ return SNMPv3_USM_PARSE_ERROR;
+ }
+ debugprintf(3, "Parsed securityParametersLength = 0x%x", spLength);
+
+ if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)){
+ debugprintf(0, "wrong type in header of securityParameters");
+ return SNMPv3_USM_PARSE_ERROR;
+ }
+
+ // extract security parameters
+ {
+ int len = MAXLENGTH_ENGINEID + 1;
+ unsigned char data[MAXLENGTH_ENGINEID + 1];
+ sp = asn_parse_string( sp, &spLength, &type, data, &len);
+
+ debugprintf(3, "Parsed securityEngineID, length = 0x%x", len);
+ if (sp==NULL) {
+ debugprintf(0, "bad parse of securityEngineID");
+ return SNMPv3_USM_PARSE_ERROR;
+ }
+ security_engine_id.set_data(data, len);
+ }
+
+ sp = asn_parse_int(sp, &spLength, &type, &engineBoots);
+ if ((sp == NULL) || (engineBoots < 0)) {
+ debugprintf(0, "bad parse of engineBoots");
+ return SNMPv3_USM_PARSE_ERROR;
+ }
+
+ sp = asn_parse_int(sp, &spLength, &type, &engineTime);
+ if ((sp == NULL) || (engineTime < 0)) {
+ debugprintf(0, "bad parse of engineTime");
+ return SNMPv3_USM_PARSE_ERROR;
+ }
+
+ debugprintf(3, "Parsed engineBoots(0x%lx), engineTime(0x%lx)",
+ engineTime, engineBoots);
+
+ unsigned char usmUserName[MAXLEN_USMUSERNAME + 1];
+ int usmUserNameLength = MAXLEN_USMUSERNAME;
+
+ sp = asn_parse_string( sp, &spLength, &type,
+ (unsigned char*)&usmUserName, &usmUserNameLength);
+
+ if (sp==NULL) {
+ debugprintf(0, "bad parse of usmUserName");
+ return SNMPv3_USM_PARSE_ERROR;
+ }
+
+ sp = asn_parse_string( sp, &spLength, &type,
+ (unsigned char*)&authParam, &authParamLength);
+
+ if (sp==NULL) {
+ debugprintf(0, "bad parse of msgAuthenticationParameters");
+ return SNMPv3_USM_PARSE_ERROR;
+ }
+ int authParametersPosition = securityParametersPosition +
+ SAFE_INT_CAST(sp - securityParameters) - authParamLength;
+
+ sp = asn_parse_string( sp, &spLength, &type,
+ (unsigned char*)&privParam, &privParamLength);
+
+ if (sp==NULL) {
+ debugprintf(0, "bad parse of msgPrivacyParameters");
+ return SNMPv3_USM_PARSE_ERROR;
+ }
+ if (spLength !=0) {
+ debugprintf(0, "Error Parsing msgPrivacyParameters");
+ return SNMPv3_USM_PARSE_ERROR;
+ }
+ debugprintf(5, "Parsed usmUserName length(0x%x)"
+ " msgAuthenticationParameters length(0x%x)"
+ " msgPrivacyParameters length(0x%x)",
+ usmUserNameLength, authParamLength, privParamLength);
+
+ // prepare securityStateReference
+ if (usmUserNameLength > MAXLEN_USMUSERNAME)
+ {
+ debugprintf(0, "user name too long: %i > %i.",
+ usmUserNameLength, MAXLEN_USMUSERNAME);
+ return SNMPv3_USM_PARSE_ERROR;
+ }
+
+ securityStateReference->msgUserNameLength = usmUserNameLength;
+ memcpy(securityStateReference->msgUserName, usmUserName,
+ securityStateReference->msgUserNameLength);
+
+ securityStateReference->securityEngineIDLength = security_engine_id.len();
+ securityStateReference->securityEngineID =
+ new unsigned char [securityStateReference->securityEngineIDLength];
+ memcpy(securityStateReference->securityEngineID, security_engine_id.data(),
+ securityStateReference->securityEngineIDLength);
+
+ securityStateReference->securityLevel = securityLevel;
+
+ securityStateReference->securityNameLength = 0;
+ securityStateReference->securityName = NULL;
+ securityStateReference->authProtocol = 1;
+ securityStateReference->privProtocol = 1;
+ securityStateReference->authKey = NULL;
+ securityStateReference->privKey = NULL;
+
+ // in case we return with error,
+ // perhaps v3MP can decode it (requestID!!!)
+ memcpy(scopedPDU, msgData, msgDataLength);
+ *scopedPDULength = msgDataLength;
+
+ if ((security_engine_id.len() == 0) ||
+ (usm_time_table->check_engine_id(security_engine_id) != SNMPv3_USM_OK ))
+ {
+ inc_stats_unknown_engine_ids();
+
+ // *+* REPORT *+*
+ securityStateReference->securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ security_name.set_data(usmUserName, usmUserNameLength);
+
+ debugprintf(2, "USM: EngineID unknown");
+ return SNMPv3_USM_UNKNOWN_ENGINEID;
+ }
+
+ // get securityName:
+ if ((usmUserNameLength) ||
+ (securityLevel != SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV))
+ {
+ rc = get_security_name(usmUserName, usmUserNameLength, security_name);
+ if (rc != SNMPv3_USM_OK) {
+ inc_stats_unknown_user_names();
+ security_name.set_data(usmUserName, usmUserNameLength);
+
+ debugprintf(2,"usmProcessMsg: unknown user (%s)",
+ security_name.get_printable());
+ return SNMPv3_USM_UNKNOWN_SECURITY_NAME;
+ }
+ }
+ else
+ {
+ debugprintf(2, "Accepting zero length user/security name.");
+ security_name = "";
+ }
+
+ securityStateReference->securityNameLength = security_name.len();
+ securityStateReference->securityName =
+ new unsigned char [securityStateReference->securityNameLength];
+ memcpy(securityStateReference->securityName, security_name.data(),
+ securityStateReference->securityNameLength);
+
+ // get user from LCD (usmUserTable)
+ if (usmUserNameLength)
+ {
+ user = get_user(security_engine_id, security_name);
+
+ if (!user) {
+ inc_stats_unknown_user_names();
+ debugprintf(0, "usmProcessMsg: unknown user");
+ return SNMPv3_USM_UNKNOWN_SECURITY_NAME;
+ }
+ }
+ else
+ {
+ user = new UsmUser;
+ if (!user)
+ {
+ debugprintf(0, "Memory error");
+ return SNMPv3_USM_ERROR;
+ }
+ memset(user, 0, sizeof(UsmUser));
+ }
+
+ if (((securityLevel > SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV) &&
+ (user->authProtocol == SNMP_AUTHPROTOCOL_NONE)) ||
+ ((securityLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV) &&
+ (user->privProtocol == SNMP_PRIVPROTOCOL_NONE))) {
+ inc_stats_unsupported_sec_levels();
+ debugprintf(0, "usmProcessMsg: unsupported Securitylevel");
+ free_user(user);
+ return SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
+ }
+
+ if (securityLevel > SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV)
+ {
+ rc = auth_priv->auth_inc_msg(user->authProtocol,
+ user->authKey,
+ wholeMsg, wholeMsgLength,
+ wholeMsg + authParametersPosition,
+ authParamLength);
+ if (rc != SNMPv3_USM_OK)
+ {
+ switch (rc)
+ {
+ case SNMPv3_USM_AUTHENTICATION_FAILURE:
+ debugprintf(0, "usmProcessMsg: Authentication failure.");
+ inc_stats_wrong_digests();
+ /* set securityLevel for Report */
+ break;
+ case SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL:
+ debugprintf(0, "usmProcessMsg: unknown AuthProtocol");
+ inc_stats_unsupported_sec_levels();
+ default:
+ debugprintf(0, "usmProcessMsg: error authenticating msg."
+ " Error code (%i).", rc);
+ // todo: is it ok to increment this counter?
+ inc_stats_unsupported_sec_levels();
+ break;
+ }
+ securityStateReference->securityLevel= SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+ free_user(user);
+ return rc;
+ }
+
+ rc = usm_time_table->check_time(security_engine_id,
+ engineBoots, engineTime);
+ if (rc == SNMPv3_USM_NOT_IN_TIME_WINDOW)
+ {
+ inc_stats_not_in_time_windows();
+ debugprintf(2, "***Message not in TimeWindow!");
+ notInTime = 1;
+ }
+ if (rc == SNMPv3_USM_UNKNOWN_ENGINEID)
+ {
+ debugprintf(0, "***EngineID not in timeTable!");
+ free_user(user);
+ return rc;
+ }
+ }
+
+ *scopedPDULength = MAX_SNMP_PACKET;
+
+ // decrypt ScopedPDU if message is in time window
+ if ((securityLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
+ && (!notInTime)) {
+ msgData = asn_parse_string( msgData, &msgDataLength, &type,
+ encryptedScopedPDU.get_ptr(),
+ &encryptedScopedPDULength);
+ if (msgData == NULL){
+ debugprintf(0, "usmProcessMsg: bad header of encryptedPDU");
+ free_user(user);
+ return SNMPv3_USM_PARSE_ERROR;
+ }
+
+ // decrypt Message
+ unsigned int tmp_length = *scopedPDULength;
+ int dec_result = auth_priv->decrypt_msg(
+ user->privProtocol,
+ user->privKey, user->privKeyLength,
+ encryptedScopedPDU.get_ptr(),
+ encryptedScopedPDULength,
+ scopedPDU, &tmp_length,
+ (unsigned char*)&privParam, privParamLength,
+ engineBoots, engineTime);
+ *scopedPDULength = tmp_length;
+ if (dec_result != SNMPv3_USM_OK)
+ {
+ int return_value;
+ if (dec_result == SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL)
+ {
+ debugprintf(0, "usmProcessMsg: unknown PrivacyProtocol");
+ inc_stats_unsupported_sec_levels();
+ return_value = SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
+ }
+ else // catch all
+ {
+ debugprintf(0, "usmProcessMsg: Decryption error (result %i).",
+ dec_result);
+ inc_stats_decryption_errors();
+ return_value = SNMPv3_USM_DECRYPTION_ERROR;
+ }
+ free_user(user);
+ return return_value;
+ }
+
+ debugprintf(21, "scopedPDU(1):");
+ debughexprintf(21, scopedPDU, *scopedPDULength);
+
+ // test for decryption error
+ // first byte 0x30
+ if (scopedPDU[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCE)) {
+ debugprintf(0, "Decryption error detected");
+ inc_stats_decryption_errors();
+ free_user(user);
+ return SNMPv3_USM_DECRYPTION_ERROR;
+ }
+ }
+ else {
+ // message was not encrypted
+ memcpy(scopedPDU, msgData, msgDataLength);
+ *scopedPDULength = msgDataLength;
+ }
+
+ *maxSizeResponseScopedPDU = maxMessageSize - (wholeMsgLength - *scopedPDULength);
+
+ security_name.set_data(user->securityName, user->securityNameLength);
+
+ securityStateReference->authProtocol = user->authProtocol;
+ securityStateReference->privProtocol = user->privProtocol;
+
+ securityStateReference->authKeyLength = user->authKeyLength;
+ securityStateReference->authKey = user->authKey;
+
+ securityStateReference->privKeyLength = user->privKeyLength;
+ securityStateReference->privKey = user->privKey;
+
+ user->authKey = 0;
+ user->privKey = 0;
+
+ free_user(user);
+
+ if (notInTime)
+ return SNMPv3_USM_NOT_IN_TIME_WINDOW;
+
+ return SNMPv3_USM_OK;
+}
+
+unsigned char *USM::build_sec_params(unsigned char *outBuf, int *maxLength,
+ struct UsmSecurityParameters sp,
+ int *position)
+{
+ Buffer<unsigned char> buf(MAX_SNMP_PACKET);
+ unsigned char *bufPtr = buf.get_ptr();
+ unsigned char *outBufPtr = outBuf;
+ int length = *maxLength;
+ int totalLength;
+
+ debugprintf(5, "Coding octstr sp.msgAuthoritativeEngineID, length = 0x%lx",
+ sp.msgAuthoritativeEngineIDLength);
+ bufPtr = asn_build_string(bufPtr, &length,
+ ASN_UNI_PRIM | ASN_OCTET_STR,
+ sp.msgAuthoritativeEngineID,
+ sp.msgAuthoritativeEngineIDLength);
+ if (bufPtr == NULL) {
+ debugprintf(0, "usmBuildSecurityParameters error coding engineid");
+ return NULL;
+ }
+
+ debugprintf(5, "Coding int sp.msgAuthoritativeEngineBoots = 0x%lx",
+ sp.msgAuthoritativeEngineBoots);
+ bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
+ &sp.msgAuthoritativeEngineBoots);
+
+ if (bufPtr == NULL) {
+ debugprintf(0, "usmBuildSecurityParameters error coding engineboots");
+ return NULL;
+ }
+
+ debugprintf(5, "Coding int sp.msgAuthoritativeEngineTime = 0x%lx",
+ sp.msgAuthoritativeEngineTime);
+ bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
+ &sp.msgAuthoritativeEngineTime);
+
+ if (bufPtr == NULL) {
+ debugprintf(0, "usmBuildSecurityParameters error coding enginetime");
+ return NULL;
+ }
+
+ debugprintf(5, "Coding octstr sp.msgUserName, length = 0x%lx",
+ sp.msgUserNameLength);
+ bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
+ sp.msgUserName, sp.msgUserNameLength);
+ if (bufPtr == NULL) {
+ debugprintf(0, "usmBuildSecurityParameters error coding msgusername");
+ return NULL;
+ }
+
+ *position = SAFE_INT_CAST(bufPtr - buf.get_ptr()) + 2;
+
+ debugprintf(5, "Coding octstr sp.msgAu..Para.. , length = 0x%lx",
+ sp.msgAuthenticationParametersLength);
+ bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
+ sp.msgAuthenticationParameters,
+ sp.msgAuthenticationParametersLength);
+
+ if (bufPtr == NULL) {
+ debugprintf(0, "usmBuildSecurityParameters error coding authparams");
+ return NULL;
+ }
+
+ debugprintf(5, "Coding octstr sp.msgPr..Para.. , length = 0x%lx",
+ sp.msgPrivacyParametersLength);
+ bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
+ sp.msgPrivacyParameters,
+ sp.msgPrivacyParametersLength);
+
+ if (bufPtr == NULL) {
+ debugprintf(0, "usmBuildSecurityParameters error coding privparams");
+ return NULL;
+ }
+
+ totalLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());
+
+ debugprintf(5, "Coding sequence (securityPar), length = 0x%x", totalLength);
+ outBufPtr = asn_build_sequence(outBufPtr, maxLength, ASN_SEQ_CON,
+ totalLength);
+
+ if (outBufPtr == NULL) {
+ debugprintf(0, "usm: usmBuildSecurityParameters error coding secparams");
+ return NULL;
+ }
+
+ if (*maxLength < totalLength) {
+ debugprintf(0, "usm: usmBuildSecurityParameters error (length mismatch)");
+ return NULL;
+ }
+ *position += SAFE_INT_CAST(outBufPtr - outBuf);
+ memcpy(outBufPtr, buf.get_ptr(), totalLength);
+ outBufPtr += totalLength;
+ *maxLength -= totalLength;
+
+ debugprintf(21, "bufSecurityData:");
+ debughexprintf(21, outBuf, SAFE_INT_CAST(outBufPtr - outBuf));
+
+ return outBufPtr;
+}
+
+unsigned char *USM::build_whole_msg(
+ unsigned char *outBuf, int *maxLength,
+ unsigned char *globalData, long int globalDataLength,
+ int *positionAuthPar,
+ struct UsmSecurityParameters securityParameters,
+ unsigned char *msgData, long int msgDataLength)
+{
+ Buffer<unsigned char> buf(MAX_SNMP_PACKET);
+ unsigned char *bufPtr = buf.get_ptr();
+ Buffer<unsigned char> secPar(MAX_SNMP_PACKET);
+ unsigned char *secParPtr = secPar.get_ptr();
+ unsigned char *outBufPtr = outBuf;
+ long int secParLength;
+ int length = *maxLength;
+ int totalLength;
+
+ int dummy = *maxLength;
+
+ secParPtr = build_sec_params(secParPtr, &dummy, securityParameters,
+ positionAuthPar);
+
+ if (!secParPtr)
+ return NULL;
+ secParLength = SAFE_INT_CAST(secParPtr - secPar.get_ptr());
+
+ long int dummyVersion = 3;
+ debugprintf(3, "Coding int snmpVersion = 0x%lx",dummyVersion);
+ bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
+ &dummyVersion);
+ if (bufPtr == NULL) {
+ debugprintf(0, "usmBuildWholeMsg error");
+ return NULL;
+ }
+
+ // globalData is encoded as sequence
+ length -= globalDataLength;
+ if (length < 0) {
+ debugprintf(0, "usmBuildWholeMsg error");
+ return NULL;
+ }
+ memcpy(bufPtr, globalData, globalDataLength);
+ bufPtr += globalDataLength;
+
+ *positionAuthPar += SAFE_INT_CAST(bufPtr - buf.get_ptr()) +2;
+ if (secParLength> 0x7f)
+ *positionAuthPar += 2;
+
+ debugprintf(3, "Coding octstr securityParameter, length = 0x%lx",
+ secParLength);
+ bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
+ secPar.get_ptr(), secParLength);
+
+ if (bufPtr == NULL) {
+ debugprintf(0, "usmBuildWholeMsg error2");
+ return NULL;
+ }
+
+ // msgData (ScopedPduData) is encoded
+ length -=msgDataLength;
+ if (length < 0) {
+ debugprintf(10, "usmBuildWholeMsg error: msgDataLength = %i",
+ msgDataLength);
+ debugprintf(10, "maxLength = %i, encoded = %i", *maxLength,
+ SAFE_INT_CAST(bufPtr - buf.get_ptr()));
+ return NULL;
+ }
+ memcpy(bufPtr, msgData, msgDataLength);
+ bufPtr += msgDataLength;
+
+ totalLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());
+
+ debugprintf(3, "Coding sequence (wholeMsg), length = 0x%x", totalLength);
+
+ outBufPtr = asn_build_sequence(outBufPtr, maxLength, ASN_SEQ_CON,
+ totalLength);
+
+ if (outBufPtr == NULL) {
+ debugprintf(0, "usm: usmBuildWholeMsg error");
+ return NULL;
+ }
+
+ if (*maxLength < totalLength) {
+ debugprintf(0, "usm: usmBuildWholeMsg error");
+ return NULL;
+ }
+ *positionAuthPar += SAFE_INT_CAST(outBufPtr - outBuf);
+ memcpy(outBufPtr, buf.get_ptr(), totalLength);
+ outBufPtr += totalLength;
+ *maxLength -= totalLength;
+
+ debugprintf(21,"bufWholeMsg:");
+ debughexprintf(21, outBuf, SAFE_INT_CAST(outBufPtr - outBuf));
+
+ return outBufPtr;
+}
+
+inline void USM::delete_user_ptr(struct UsmUser *user)
+{
+ if (!user) return;
+ if (user->engineID) {
+ delete [] user->engineID;
+ user->engineID = NULL;
+ }
+ if (user->usmUserName) {
+ delete [] user->usmUserName;
+ user->usmUserName = NULL;
+ }
+ if (user->securityName) {
+ delete [] user->securityName;
+ user->securityName = NULL;
+ }
+ if (user->authKey) {
+ memset(user->authKey, 0, user->authKeyLength);
+ delete [] user->authKey;
+ user->authKey = NULL;
+ }
+ if (user->privKey) {
+ memset(user->privKey, 0, user->privKeyLength);
+ delete [] user->privKey;
+ user->authKey = NULL;
+ }
+}
+
+// Save all localized users into a file.
+int USM::save_localized_users(const char *file)
+{
+ return usm_user_table->save_to_file(file, auth_priv);
+}
+
+// Load localized users from a file.
+int USM::load_localized_users(const char *file)
+{
+ return usm_user_table->load_from_file(file, auth_priv);
+}
+
+// Safe all users with their passwords into a file.
+int USM::save_users(const char *file)
+{
+ return usm_user_name_table->save_to_file(file, auth_priv);
+}
+
+// Load users with their passwords from a file.
+int USM::load_users(const char *file)
+{
+ return usm_user_name_table->load_from_file(file, auth_priv);
+}
+
+// Lock the UsmUserNameTable for access through peek_first/next_user()
+void USM::lock_user_name_table()
+{
+ usm_user_name_table->lock();
+}
+
+// Get a const pointer to the first entry of the UsmUserNameTable.
+const UsmUserNameTableEntry *USM::peek_first_user()
+{
+ return usm_user_name_table->peek_first();
+}
+
+// Get a const pointer to the next entry of the UsmUserNameTable.
+const UsmUserNameTableEntry *USM::peek_next_user(const UsmUserNameTableEntry *e)
+{
+ return usm_user_name_table->peek_next(e);
+}
+
+// Unlock the UsmUserNameTable after access through peek_first/next_user()
+void USM::unlock_user_name_table()
+{
+ usm_user_name_table->unlock();
+}
+
+// Lock the UsmUserTable for access through peek_first/next_luser()
+void USM::lock_user_table()
+{
+ usm_user_table->lock();
+}
+
+// Get a const pointer to the first entry of the UsmUserTable.
+const UsmUserTableEntry *USM::peek_first_luser()
+{
+ return usm_user_table->peek_first();
+}
+
+// Get a const pointer to the next entry of the UsmUserTable.
+const UsmUserTableEntry *USM::peek_next_luser(const UsmUserTableEntry *e)
+{
+ return usm_user_table->peek_next(e);
+}
+
+// Unlock the UsmUserTable after access through peek_first/next_luser()
+void USM::unlock_user_table()
+{
+ usm_user_table->unlock();
+}
+
+
+/* ----------------------- class USMTimeTable --------------------*/
+
+USMTimeTable::USMTimeTable(const USM *owner,
+ const unsigned int engine_boots, int &result)
+{
+ time_t now;
+
+ table = new struct Entry_T[5];
+
+ if (!table)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMTimeTable: error constructing table.");
+ LOG_END;
+
+ result = SNMPv3_USM_ERROR;
+ return;
+ }
+
+ usm = owner;
+
+ /* the first entry always contains the local engine id and time */
+ time(&now);
+
+ table[0].time_diff = - SAFE_LONG_CAST(now);
+ table[0].engine_boots = engine_boots;
+ table[0].engine_id_len = min(usm->get_local_engine_id().len(),
+ MAXLENGTH_ENGINEID);
+ memcpy(table[0].engine_id, usm->get_local_engine_id().data(),
+ table[0].engine_id_len);
+
+ entries = 1;
+ max_entries = 5;
+
+ result = SNMPv3_USM_OK;
+}
+
+USMTimeTable::~USMTimeTable()
+{
+ if (table)
+ {
+ delete [] table;
+ table = NULL;
+ }
+ entries = 0;
+ max_entries = 0;
+}
+
+int USMTimeTable::add_entry(const OctetStr &engine_id,
+ const long int engine_boots,
+ const long int engine_time)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ LOG_BEGIN(INFO_LOG | 11);
+ LOG("USMTimeTable: Adding entry (engine id) (boot) (time)");
+ LOG(engine_id.get_printable());
+ LOG(engine_boots);
+ LOG(engine_time);
+ LOG_END;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ if (entries == max_entries)
+ {
+ /* resize Table */
+ struct Entry_T *tmp = new struct Entry_T[4 * max_entries];
+
+ if (!tmp)
+ return SNMPv3_USM_ERROR;
+
+ memcpy(tmp, table, entries * sizeof(Entry_T));
+
+ struct Entry_T *victim = table;
+ table = tmp;
+ delete [] victim;
+
+ max_entries *= 4;
+ }
+
+ time_t now;
+ time(&now);
+
+ table[entries].engine_boots = engine_boots;
+ table[entries].latest_received_time = engine_time;
+ table[entries].time_diff = engine_time - SAFE_ULONG_CAST(now);
+ table[entries].engine_id_len = engine_id.len();
+ table[entries].engine_id_len = min(table[entries].engine_id_len,
+ MAXLENGTH_ENGINEID);
+ memcpy(table[entries].engine_id,
+ engine_id.data(), table[entries].engine_id_len);
+
+ entries++;
+
+ return SNMPv3_USM_OK;
+}
+
+// Delete this engine id from the table.
+int USMTimeTable::delete_entry(const OctetStr &engine_id)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ LOG_BEGIN(INFO_LOG | 12);
+ LOG("USMTimeTable: Deleting entry (engine id)");
+ LOG(engine_id.get_printable());
+ LOG_END;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i=1; i < entries; i++) /* start from 1 */
+ if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
+ engine_id.data(), engine_id.len()))
+ {
+ if (i != entries - 1)
+ table[i] = table[entries - 1];
+
+ entries--;
+
+ return SNMPv3_USM_OK;
+ }
+
+ return SNMPv3_USM_OK;
+}
+
+unsigned long USMTimeTable::get_local_time()
+{
+ if (!table)
+ return 0;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ time_t now;
+ time(&now);
+
+ return table[0].time_diff + SAFE_ULONG_CAST(now);
+}
+
+int USMTimeTable::get_local_time(long int &engine_boots,
+ long int &engine_time)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ time_t now;
+ time(&now);
+
+ engine_boots = table[0].engine_boots;
+ engine_time = table[0].time_diff + SAFE_ULONG_CAST(now);
+
+ LOG_BEGIN(DEBUG_LOG | 11);
+ LOG("USMTimeTable: returning local time (boots) (time)");
+ LOG(engine_boots);
+ LOG(engine_time);
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+}
+
+int USMTimeTable::get_time(const OctetStr &engine_id,
+ long int &engine_boots, long int &engine_time)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i=0; i < entries; i++)
+ if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
+ engine_id.data(), engine_id.len()))
+ {
+ /* Entry found */
+ time_t now;
+ time(&now);
+
+ engine_boots = table[i].engine_boots;
+ engine_time = table[i].time_diff + SAFE_ULONG_CAST(now);
+
+ LOG_BEGIN(INFO_LOG | 4);
+ LOG("USMTimeTable: Returning time (engine id) (boot) (time)");
+ LOG(engine_id.get_printable());
+ LOG(engine_boots);
+ LOG(engine_time);
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+ }
+
+ /* no entry */
+ engine_boots = 0;
+ engine_time = 0;
+
+ LOG_BEGIN(INFO_LOG | 4);
+ LOG("USMTimeTable: No entry found for (engine id)");
+ LOG(engine_id.get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_UNKNOWN_ENGINEID;
+}
+
+int USMTimeTable::check_time(const OctetStr &engine_id,
+ const long int engine_boots,
+ const long int engine_time)
+
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ time_t now;
+ time(&now);
+
+ /* table[0] contains the local engine_id and time */
+ if (unsignedCharCompare(table[0].engine_id, table[0].engine_id_len,
+ engine_id.data(), engine_id.len()))
+ {
+ /* Entry found, we are authoritative */
+ if ((table[0].engine_boots == 2147483647) ||
+ (table[0].engine_boots != engine_boots) ||
+ (labs(SAFE_ULONG_CAST(now) + table[0].time_diff - engine_time) > 150))
+ {
+ LOG_BEGIN(DEBUG_LOG | 9);
+ LOG("USMTimeTable: Check time failed, authoritative (id) (boot) (time)");
+ LOG(engine_id.get_printable());
+ LOG(engine_boots);
+ LOG(engine_time);
+ LOG_END;
+
+ return SNMPv3_USM_NOT_IN_TIME_WINDOW;
+ }
+ else
+ {
+ LOG_BEGIN(DEBUG_LOG | 9);
+ LOG("USMTimeTable: Check time ok, authoritative (id)");
+ LOG(engine_id.get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+ }
+ }
+
+ for (int i=1; i < entries; i++)
+ if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
+ engine_id.data(), engine_id.len()))
+ {
+ /* Entry found we are not authoritative */
+ if ((engine_boots < table[i].engine_boots) ||
+ ((engine_boots == table[i].engine_boots) &&
+ (table[i].time_diff + now > engine_time + 150)) ||
+ (table[i].engine_boots == 2147483647))
+ {
+ LOG_BEGIN(DEBUG_LOG | 9);
+ LOG("USMTimeTable: Check time failed, not authoritative (id)");
+ LOG(engine_id.get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_NOT_IN_TIME_WINDOW;
+ }
+ else
+ {
+ if ((engine_boots > table[i].engine_boots) ||
+ ((engine_boots == table[i].engine_boots) &&
+ (engine_time > table[i].latest_received_time)))
+ {
+ /* time ok, update values */
+ table[i].engine_boots = engine_boots;
+ table[i].latest_received_time = engine_time;
+ table[i].time_diff = engine_time - SAFE_ULONG_CAST(now);
+ }
+
+ LOG_BEGIN(DEBUG_LOG | 9);
+ LOG("USMTimeTable: Check time ok, not authoritative, updated (id)");
+ LOG(engine_id.get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+ }
+ }
+
+ LOG_BEGIN(DEBUG_LOG | 9);
+ LOG("USMTimeTable: Check time, engine id not found");
+ LOG(engine_id.get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_UNKNOWN_ENGINEID;
+}
+
+
+int USMTimeTable::check_engine_id(const OctetStr &engine_id)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ {
+ // Begin reentrant code block
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i=0; i < entries; i++)
+ if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
+ engine_id.data(), engine_id.len()))
+ return SNMPv3_USM_OK;
+ }
+
+ /* if in discovery mode: accept all EngineID's (rfc2264 page 26) */
+ if (usm->is_discovery_enabled())
+ return add_entry(engine_id, 0, 0);
+
+ LOG_BEGIN(DEBUG_LOG | 9);
+ LOG("USMTimeTable: Check id, not found (id)");
+ LOG(engine_id.get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+}
+
+
+
+/* ------------------------- USMUserNameTable ----------------------*/
+
+USMUserNameTable::USMUserNameTable(int &result)
+{
+ /* init Table */
+ table = new struct UsmUserNameTableEntry[10];
+ if (!table)
+ {
+ result = SNMPv3_USM_ERROR;
+ return;
+ }
+ max_entries = 10;
+ entries = 0;
+ result = SNMPv3_USM_OK;
+}
+
+USMUserNameTable::~USMUserNameTable()
+{
+ if (table)
+ {
+ for (int i=0; i < entries; i++)
+ {
+ if (table[i].authPassword)
+ {
+ memset(table[i].authPassword, 0, table[i].authPasswordLength);
+ delete [] table[i].authPassword;
+ }
+
+ if (table[i].privPassword)
+ {
+ memset(table[i].privPassword, 0, table[i].privPasswordLength);
+ delete [] table[i].privPassword;
+ }
+ }
+ delete [] table;
+ table = NULL;
+ }
+ entries = 0;
+ max_entries = 0;
+}
+
+int USMUserNameTable::add_entry(const OctetStr& user_name,
+ const OctetStr& security_name,
+ const long int auth_proto,
+ const long int priv_proto,
+ const OctetStr& auth_pass,
+ const OctetStr& priv_pass)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ int found=0;
+ int i;
+ for (i = 0; i < entries; i++)
+ if (table[i].usmUserName == user_name)
+ {
+ found=1;
+ break;
+ }
+
+ if (found)
+ {
+ /* replace user */
+ table[i].usmUserSecurityName = security_name;
+ table[i].usmUserAuthProtocol = auth_proto;
+ table[i].usmUserPrivProtocol = priv_proto;
+
+ if (table[i].authPassword)
+ {
+ memset(table[i].authPassword, 0, table[i].authPasswordLength);
+ delete [] table[i].authPassword;
+ }
+ table[i].authPassword = v3strcpy(auth_pass.data(), auth_pass.len());
+ table[i].authPasswordLength = auth_pass.len();
+
+ if (table[i].privPassword)
+ {
+ memset(table[i].privPassword, 0, table[i].privPasswordLength);
+ delete [] table[i].privPassword;
+ }
+ table[i].privPassword = v3strcpy(priv_pass.data(), priv_pass.len());
+ table[i].privPasswordLength = priv_pass.len();
+ }
+ else
+ {
+ if (entries == max_entries)
+ {
+ /* resize Table */
+ struct UsmUserNameTableEntry *tmp;
+ tmp = new struct UsmUserNameTableEntry[4 * max_entries];
+ if (!tmp)
+ return SNMPv3_USM_ERROR;
+ for (i=0; i < entries; i++)
+ tmp[i] = table[i];
+
+ struct UsmUserNameTableEntry *victim = table;
+ table = tmp;
+ delete [] victim;
+
+ max_entries *= 4;
+ }
+
+ table[entries].usmUserName = user_name;
+ table[entries].usmUserSecurityName = security_name;
+ table[entries].usmUserAuthProtocol = auth_proto;
+ table[entries].usmUserPrivProtocol = priv_proto;
+
+ table[entries].authPasswordLength = auth_pass.len();
+ table[entries].authPassword = v3strcpy(auth_pass.data(), auth_pass.len());
+ if (!table[entries].authPassword)
+ return SNMPv3_USM_ERROR;
+
+ table[entries].privPasswordLength = priv_pass.len();
+ table[entries].privPassword = v3strcpy(priv_pass.data(), priv_pass.len());
+ if (!table[entries].privPassword)
+ return SNMPv3_USM_ERROR;
+
+ entries++;
+ }
+
+ return SNMPv3_USM_OK;
+}
+
+int USMUserNameTable::delete_security_name(const OctetStr& security_name)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i = 0; i < entries; i++)
+ if (table[i].usmUserSecurityName == security_name)
+ {
+ memset(table[i].authPassword, 0, table[i].authPasswordLength);
+ delete [] table[i].authPassword;
+ memset(table[i].privPassword, 0, table[i].privPasswordLength);
+ delete [] table[i].privPassword;
+ entries--;
+ if (entries > i)
+ table[i] = table[entries];
+ break;
+ }
+ return SNMPv3_USM_OK;
+}
+
+const struct UsmUserNameTableEntry* USMUserNameTable::get_entry(
+ const OctetStr &security_name)
+{
+ if (!table)
+ return NULL;
+
+ for (int i = 0; i < entries; i++)
+ if (table[i].usmUserSecurityName == security_name)
+ return &table[i];
+ return NULL;
+}
+
+struct UsmUserNameTableEntry* USMUserNameTable::get_cloned_entry(const OctetStr &security_name)
+{
+ lock();
+ const struct UsmUserNameTableEntry *e = get_entry(security_name);
+ struct UsmUserNameTableEntry *res = 0;
+
+ if (e)
+ {
+ res = new struct UsmUserNameTableEntry;
+ }
+
+ if (res)
+ {
+ res->usmUserName = e->usmUserName;
+ res->usmUserSecurityName = e->usmUserSecurityName;
+ res->usmUserAuthProtocol = e->usmUserAuthProtocol;
+ res->usmUserPrivProtocol = e->usmUserPrivProtocol;
+ res->authPassword = v3strcpy(e->authPassword, e->authPasswordLength);
+ res->authPasswordLength = e->authPasswordLength;
+ res->privPassword = v3strcpy(e->privPassword, e->privPasswordLength);
+ res->privPasswordLength = e->privPasswordLength;
+
+ if ((res->authPasswordLength && !res->authPassword) ||
+ (res->privPasswordLength && !res->privPassword))
+ {
+ delete_cloned_entry(res);
+ }
+ }
+
+ unlock();
+ return res;
+}
+
+void USMUserNameTable::delete_cloned_entry(struct UsmUserNameTableEntry* &entry)
+{
+ if (!entry) return;
+
+ if (entry->authPassword)
+ {
+ memset(entry->authPassword, 0, entry->authPasswordLength);
+ delete [] entry->authPassword;
+ }
+
+ if (entry->privPassword)
+ {
+ memset(entry->privPassword, 0, entry->privPasswordLength);
+ delete [] entry->privPassword;
+ }
+
+ delete entry;
+
+ entry = 0;
+}
+
+
+int USMUserNameTable::get_security_name(const unsigned char *user_name,
+ const long int user_name_len,
+ OctetStr &security_name)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i = 0; i < entries; i++)
+ if (unsignedCharCompare(table[i].usmUserName.data(),
+ table[i].usmUserName.len(),
+ user_name, user_name_len))
+ {
+ security_name = table[i].usmUserSecurityName;
+
+ LOG_BEGIN(INFO_LOG | 9);
+ LOG("USMUserNameTable: Translated (user name) to (security name)");
+ LOG(table[i].usmUserName.get_printable());
+ LOG(security_name.get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+ }
+
+ int logclass = WARNING_LOG;
+ if (user_name_len == 0) logclass = INFO_LOG;
+ LOG_BEGIN(logclass | 5);
+ LOG("USMUserNameTable: No entry for (user name) in table");
+ LOG(OctetStr(user_name, user_name_len).get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+}
+
+int USMUserNameTable::get_user_name(unsigned char *user_name,
+ long int *user_name_len,
+ const unsigned char *security_name,
+ const long int security_name_len)
+{
+ unsigned long buf_len = *user_name_len;
+ *user_name_len = 0;
+
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i = 0; i < entries; i++)
+ if (unsignedCharCompare(table[i].usmUserSecurityName.data(),
+ table[i].usmUserSecurityName.len(),
+ security_name, security_name_len))
+ {
+ if (buf_len < table[i].usmUserName.len())
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserNameTable: Buffer for user name too small (is) (should)");
+ LOG(buf_len);
+ LOG(table[i].usmUserName.len());
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+ }
+ *user_name_len = table[i].usmUserName.len();
+ memcpy(user_name, table[i].usmUserName.data(),
+ table[i].usmUserName.len());
+
+ LOG_BEGIN(INFO_LOG | 9);
+ LOG("USMUserNameTable: Translated (security name) to (user name)");
+ LOG(table[i].usmUserSecurityName.get_printable());
+ LOG(table[i].usmUserName.get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+ }
+
+ int logclass = WARNING_LOG;
+ if (security_name_len == 0) logclass = INFO_LOG;
+ LOG_BEGIN(logclass | 5);
+ LOG("USMUserNameTable: No entry for (security name) in table");
+ LOG(OctetStr(security_name, security_name_len).get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+}
+
+// Save all entries into a file.
+int USMUserNameTable::save_to_file(const char *name, AuthPriv *ap)
+{
+ char encoded[MAX_LINE_LEN * 2];
+ FILE *file_out;
+ char tmp_file_name[MAXLENGTH_FILENAME];
+ bool failed = false;
+
+ if (!name || !ap)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserNameTable: save_to_file called with illegal param");
+ if (!name)
+ {
+ LOG("filename");
+ }
+ if (!ap)
+ {
+ LOG("AuthPriv pointer");
+ }
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+ }
+
+ LOG_BEGIN(INFO_LOG | 4);
+ LOG("USMUserNameTable: Saving users to file");
+ LOG(name);
+ LOG_END;
+
+ sprintf(tmp_file_name, "%s.tmp", name);
+ file_out = fopen(tmp_file_name, "w");
+ if (!file_out)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserNameTable: could not create tmpfile");
+ LOG(tmp_file_name);
+ LOG_END;
+
+ return SNMPv3_USM_FILECREATE_ERROR;
+ }
+
+ {
+ // Begin reentrant code block
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i=0; i < entries; ++i)
+ {
+ LOG_BEGIN(INFO_LOG | 8);
+ LOG("USMUserNameTable: Saving user to file");
+ LOG(table[i].usmUserName.get_printable());
+ LOG_END;
+
+ encodeString(table[i].usmUserName.data(), table[i].usmUserName.len(),
+ encoded);
+ encoded[2 * table[i].usmUserName.len()] = '\n';
+ if (fwrite(encoded, 2 * table[i].usmUserName.len() + 1, 1,
+ file_out) != 1)
+ { failed = true; break; }
+
+ encodeString(table[i].usmUserSecurityName.data(),
+ table[i].usmUserSecurityName.len(), encoded);
+ encoded[2 * table[i].usmUserSecurityName.len()] = '\n';
+ if (fwrite(encoded, 2 * table[i].usmUserSecurityName.len() + 1, 1,
+ file_out) != 1)
+ { failed = true; break; }
+
+ encodeString(table[i].authPassword, table[i].authPasswordLength,
+ encoded);
+ encoded[2 * table[i].authPasswordLength] = '\n';
+ if (fwrite(encoded, 2 * table[i].authPasswordLength + 1, 1,
+ file_out) != 1)
+ { failed = true; break; }
+
+ encodeString(table[i].privPassword, table[i].privPasswordLength,
+ encoded);
+ encoded[2 * table[i].privPasswordLength] = '\n';
+ if (fwrite(encoded, 2 * table[i].privPasswordLength + 1, 1,
+ file_out) != 1)
+ { failed = true; break; }
+
+ if (table[i].usmUserAuthProtocol == SNMP_AUTHPROTOCOL_NONE)
+ {
+ if (fwrite("none\n", 5, 1, file_out) != 1)
+ { failed = true; break; }
+ }
+ else
+ {
+ const Auth *a = ap->get_auth(table[i].usmUserAuthProtocol);
+ if (!a) { failed = true; break; }
+ sprintf(encoded, "%s\n", a->get_id_string());
+ if (fwrite(encoded, strlen(a->get_id_string()) + 1, 1, file_out) != 1)
+ { failed = true; break; }
+ }
+
+ if (table[i].usmUserPrivProtocol == SNMP_PRIVPROTOCOL_NONE)
+ {
+ if (fwrite("none\n", 5, 1, file_out) != 1)
+ { failed = true; break; }
+ }
+ else
+ {
+ const Priv *p = ap->get_priv(table[i].usmUserPrivProtocol);
+ if (!p) { failed = true; break; }
+ sprintf(encoded, "%s\n", p->get_id_string());
+ if (fwrite(encoded, strlen(p->get_id_string()) + 1, 1, file_out) != 1)
+ { failed = true; break; }
+ }
+ }
+ }
+
+ fclose(file_out);
+ if (failed)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserNameTable: Failed to write table entries.");
+ LOG_END;
+
+#ifdef WIN32
+ _unlink(tmp_file_name);
+#else
+ unlink(tmp_file_name);
+#endif
+ return SNMPv3_USM_FILEWRITE_ERROR;
+ }
+#ifdef WIN32
+ _unlink(name);
+#else
+ unlink(name);
+#endif
+ if (rename(tmp_file_name, name))
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserNameTable: Could not rename file (from) (to)");
+ LOG(tmp_file_name);
+ LOG(name);
+ LOG_END;
+
+ return SNMPv3_USM_FILERENAME_ERROR;
+ }
+
+ LOG_BEGIN(INFO_LOG | 4);
+ LOG("USMUserNameTable: Saving users to file finished");
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+}
+
+// Load the table from a file.
+int USMUserNameTable::load_from_file(const char *name, AuthPriv *ap)
+{
+ char decoded[MAX_LINE_LEN];
+ FILE *file_in;
+ unsigned char line[MAX_LINE_LEN * 2];
+
+ if (!name || !ap)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserNameTable: load_to_file called with illegal param");
+ if (!name)
+ {
+ LOG("filename");
+ }
+ if (!ap)
+ {
+ LOG("AuthPriv pointer");
+ }
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+ }
+
+ LOG_BEGIN(INFO_LOG | 4);
+ LOG("USMUserNameTable: Loading users from file");
+ LOG(name);
+ LOG_END;
+
+ file_in = fopen(name, "r");
+ if (!file_in)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserNameTable: could not open file");
+ LOG(name);
+ LOG_END;
+
+ return SNMPv3_USM_FILEOPEN_ERROR;
+ }
+
+ int len;
+ bool failed = false;
+ while (fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ {
+ // user_name
+ len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+ decodeString(line, len, decoded);
+ OctetStr user_name((unsigned char*)decoded, len / 2);
+
+ // security_name
+ if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ { failed = true; break; }
+ len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+ decodeString(line, len, decoded);
+ OctetStr user_security_name((unsigned char*)decoded, len / 2);
+
+ // auth password
+ if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ { failed = true; break; }
+ len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+ decodeString(line, len, decoded);
+ OctetStr auth_pass((unsigned char*)decoded, len / 2);
+
+ // priv password
+ if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ { failed = true; break; }
+ len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+ decodeString(line, len, decoded);
+ OctetStr priv_pass((unsigned char*)decoded, len / 2);
+
+ // auth protocol
+ if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ { failed = true; break; }
+ line[strlen((char*)line) - 1] = 0;
+ int auth_prot = SNMP_AUTHPROTOCOL_NONE;
+ if (strcmp((char*)line, "none") != 0)
+ {
+ auth_prot = ap->get_auth_id((char*)line);
+ if (auth_prot < 0)
+ { failed = true; break; }
+ }
+
+ if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ { failed = true; break; }
+ line[strlen((char*)line) - 1] = 0;
+ int priv_prot = SNMP_PRIVPROTOCOL_NONE;
+ if (strcmp((char*)line, "none") != 0)
+ {
+ priv_prot = ap->get_priv_id((char*)line);
+ if (priv_prot < 0)
+ { failed = true; break; }
+ }
+
+ LOG_BEGIN(INFO_LOG | 7);
+ LOG("USMUserNameTable: Adding user (user name) (sec name) (auth) (priv)");
+ LOG(user_name.get_printable());
+ LOG(user_security_name.get_printable());
+ LOG(auth_prot);
+ LOG(priv_prot);
+ LOG_END;
+
+ if (add_entry(user_name, user_security_name, auth_prot, priv_prot,
+ auth_pass, priv_pass) == SNMPv3_USM_ERROR)
+ {
+ failed = true;
+
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserNameTable: Error adding (user name)");
+ LOG(user_name.get_printable());
+ LOG_END;
+ }
+ }
+
+ fclose(file_in);
+ if (failed)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserNameTable: Failed to read table entries");
+ LOG_END;
+
+ return SNMPv3_USM_FILEREAD_ERROR;
+ }
+
+ LOG_BEGIN(INFO_LOG | 4);
+ LOG("USMUserNameTable: Loaded all users from file");
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+}
+
+const UsmUserNameTableEntry *USMUserNameTable::peek_next(
+ const UsmUserNameTableEntry *e) const
+{
+ if (e == 0) return 0;
+ if (e - table < 0) return 0;
+ if (e - table >= entries - 1) return 0;
+ return (e + 1);
+}
+
+/* ---------------------------- USMUserTable ------------------- */
+
+USMUserTable::USMUserTable(int &result)
+{
+ entries = 0;
+
+ table = new struct UsmUserTableEntry[10];
+ if (!table)
+ {
+ result = SNMPv3_USM_ERROR;
+ return;
+ }
+ max_entries = 10;
+}
+
+USMUserTable::~USMUserTable()
+{
+ if (table)
+ {
+ for (int i = 0; i < entries; i++)
+ {
+ if (table[i].usmUserEngineID)
+ delete [] table[i].usmUserEngineID;
+ if (table[i].usmUserName)
+ delete [] table[i].usmUserName;
+ if (table[i].usmUserSecurityName)
+ delete [] table[i].usmUserSecurityName;
+ if (table[i].usmUserAuthKey)
+ {
+ memset(table[i].usmUserAuthKey, 0, table[i].usmUserAuthKeyLength);
+ delete [] table[i].usmUserAuthKey;
+ }
+ if (table[i].usmUserPrivKey)
+ {
+ memset(table[i].usmUserPrivKey, 0, table[i].usmUserPrivKeyLength);
+ delete [] table[i].usmUserPrivKey;
+ }
+ }
+ delete [] table;
+ table = NULL;
+ max_entries = 0;
+ entries = 0;
+ }
+}
+
+int USMUserTable::get_user_name(unsigned char *user_name,
+ long int *user_name_len,
+ const unsigned char *sec_name,
+ const long sec_name_len)
+
+{
+ long buf_len = *user_name_len;
+ *user_name_len = 0;
+
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i=0; i < entries; i++)
+ if (unsignedCharCompare(table[i].usmUserSecurityName,
+ table[i].usmUserSecurityNameLength,
+ sec_name, sec_name_len))
+ {
+ if (buf_len < table[i].usmUserNameLength)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserTable: Buffer for user name too small (is) (should)");
+ LOG(buf_len);
+ LOG(table[i].usmUserNameLength);
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+ }
+ *user_name_len = table[i].usmUserNameLength;
+ memcpy(user_name, table[i].usmUserName, table[i].usmUserNameLength);
+
+ LOG_BEGIN(INFO_LOG | 9);
+ LOG("USMUserTable: Translated (security name) to (user name)");
+ LOG(OctetStr(sec_name, sec_name_len).get_printable());
+ LOG(OctetStr(table[i].usmUserName, table[i].usmUserNameLength).get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+ }
+
+ int logclass = WARNING_LOG;
+ if (sec_name_len == 0) logclass = INFO_LOG;
+ LOG_BEGIN(logclass | 5);
+ LOG("USMUserTable: No entry for (security name) in table");
+ LOG(OctetStr(sec_name, sec_name_len).get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+}
+
+int USMUserTable::get_security_name(const unsigned char *user_name,
+ const long user_name_len,
+ OctetStr &sec_name)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i=0; i < entries; i++)
+ if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
+ user_name, user_name_len))
+ {
+ sec_name.set_data(table[i].usmUserSecurityName,
+ table[i].usmUserSecurityNameLength);
+ LOG_BEGIN(INFO_LOG | 9);
+ LOG("USMUserTable: Translated (user name) to (security name)");
+ LOG(OctetStr(table[i].usmUserName, table[i].usmUserNameLength).get_printable());
+ LOG(sec_name.get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+ }
+
+ int logclass = WARNING_LOG;
+ if (user_name_len == 0) logclass = INFO_LOG;
+ LOG_BEGIN(logclass | 5);
+ LOG("USMUserTable: No entry for (user name) in table");
+ LOG(OctetStr(user_name, user_name_len).get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+}
+
+int USMUserTable::delete_entries(const OctetStr& user_name)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i = 0; i < entries; i++)
+ if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
+ user_name.data(), user_name.len()))
+ {
+ /* delete this entry and recheck this position */
+ delete_entry(i);
+ i--;
+ }
+ return SNMPv3_USM_OK;
+}
+
+// Delete all entries of this user from the usmUserTable
+int USMUserTable::delete_engine_id(const OctetStr& engine_id)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i = 0; i < entries; i++)
+ if (unsignedCharCompare(table[i].usmUserEngineID,
+ table[i].usmUserEngineIDLength,
+ engine_id.data(), engine_id.len()))
+ {
+ /* delete this entry and recheck this position*/
+ delete_entry(i);
+ i--;
+ }
+ return SNMPv3_USM_OK;
+}
+
+int USMUserTable::delete_entry(const OctetStr& engine_id,
+ const OctetStr& user_name)
+{
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i = 0; i < entries; i++)
+ if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
+ user_name.data(), user_name.len()))
+ if (unsignedCharCompare(table[i].usmUserEngineID,
+ table[i].usmUserEngineIDLength,
+ engine_id.data(), engine_id.len()))
+ {
+ /* delete this entry and recheck this position*/
+ delete_entry(i);
+ i--;
+ }
+ return SNMPv3_USM_OK;
+}
+
+const struct UsmUserTableEntry *USMUserTable::get_entry(const int number)
+{
+ if ((entries < number) || (number < 1))
+ return NULL;
+
+ return &table[number - 1];
+}
+
+const struct UsmUserTableEntry *USMUserTable::get_entry(const OctetStr &engine_id,
+ const OctetStr &sec_name)
+{
+ if (!table)
+ return NULL;
+
+ for (int i = 0; i < entries; i++)
+ if (unsignedCharCompare(table[i].usmUserSecurityName,
+ table[i].usmUserSecurityNameLength,
+ sec_name.data(), sec_name.len()))
+ if (unsignedCharCompare(table[i].usmUserEngineID,
+ table[i].usmUserEngineIDLength,
+ engine_id.data(), engine_id.len()))
+ return &table[i];
+ return NULL;
+}
+
+struct UsmUserTableEntry *USMUserTable::get_cloned_entry(
+ const OctetStr &engine_id,
+ const OctetStr &sec_name)
+{
+ lock();
+ const struct UsmUserTableEntry *e = get_entry(engine_id, sec_name);
+ struct UsmUserTableEntry *res = 0;
+
+ if (e)
+ {
+ res = new struct UsmUserTableEntry;
+ }
+
+ if (res)
+ {
+ res->usmUserEngineID = v3strcpy(e->usmUserEngineID,
+ e->usmUserEngineIDLength);
+ res->usmUserEngineIDLength = e->usmUserEngineIDLength;
+ res->usmUserName = v3strcpy(e->usmUserName,
+ e->usmUserNameLength);
+ res->usmUserNameLength = e->usmUserNameLength;
+ res->usmUserSecurityName = v3strcpy(e->usmUserSecurityName,
+ e->usmUserSecurityNameLength);
+ res->usmUserSecurityNameLength = e->usmUserSecurityNameLength;
+ res->usmUserAuthProtocol = e->usmUserAuthProtocol;
+ res->usmUserAuthKey = v3strcpy(e->usmUserAuthKey,
+ e->usmUserAuthKeyLength);
+ res->usmUserAuthKeyLength = e->usmUserAuthKeyLength;
+ res->usmUserPrivProtocol = e->usmUserPrivProtocol;
+ res->usmUserPrivKey = v3strcpy(e->usmUserPrivKey,
+ e->usmUserPrivKeyLength);
+ res->usmUserPrivKeyLength = e->usmUserPrivKeyLength;
+
+ if ((res->usmUserEngineIDLength && !res->usmUserEngineID) ||
+ (res->usmUserNameLength && !res->usmUserName) ||
+ (res->usmUserSecurityNameLength && !res->usmUserSecurityName) ||
+ (res->usmUserAuthKeyLength && !res->usmUserAuthKey) ||
+ (res->usmUserPrivKeyLength && !res->usmUserPrivKey))
+ {
+ delete_cloned_entry(res);
+ }
+ }
+
+ unlock();
+ return res;
+}
+
+void USMUserTable::delete_cloned_entry(struct UsmUserTableEntry* &entry)
+{
+ if (!entry) return;
+
+ if (entry->usmUserEngineID) delete [] entry->usmUserEngineID;
+ if (entry->usmUserName) delete [] entry->usmUserName;
+ if (entry->usmUserSecurityName) delete [] entry->usmUserSecurityName;
+
+ if (entry->usmUserAuthKey)
+ {
+ memset(entry->usmUserAuthKey, 0, entry->usmUserAuthKeyLength);
+ delete [] entry->usmUserAuthKey;
+ }
+
+ if (entry->usmUserPrivKey)
+ {
+ memset(entry->usmUserPrivKey, 0, entry->usmUserPrivKeyLength);
+ delete [] entry->usmUserPrivKey;
+ }
+
+ delete entry;
+
+ entry = 0;
+}
+
+
+const struct UsmUserTableEntry *USMUserTable::get_entry(const OctetStr &sec_name)
+{
+ if (!table)
+ return NULL;
+
+ for (int i = 0; i < entries; i++)
+ if (unsignedCharCompare(table[i].usmUserSecurityName,
+ table[i].usmUserSecurityNameLength,
+ sec_name.data(), sec_name.len()))
+ return &table[i];
+ return NULL;
+}
+
+int USMUserTable::add_entry(
+ const OctetStr &engine_id,
+ const OctetStr &user_name, const OctetStr &sec_name,
+ const long int auth_proto, const OctetStr &auth_key,
+ const long int priv_proto, const OctetStr &priv_key)
+{
+ LOG_BEGIN(INFO_LOG | 7);
+ LOG("USMUserTable: Adding user (user name) (engine id) (auth) (priv)");
+ LOG(user_name.get_printable());
+ LOG(engine_id.get_printable());
+ LOG(auth_proto);
+ LOG(priv_proto);
+ LOG_END;
+
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ if (entries == max_entries)
+ {
+ /* resize Table */
+ struct UsmUserTableEntry *tmp;
+ tmp = new struct UsmUserTableEntry[4 * max_entries];
+ if (!tmp) return SNMPv3_USM_ERROR;
+ for (int i = 0; i < entries; i++)
+ tmp[i] = table[i];
+ delete [] table;
+ table = tmp;
+ max_entries *= 4;
+ }
+
+ for (int i = 0; i < entries; i++)
+ if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
+ user_name.data(), user_name.len()))
+ if (unsignedCharCompare(table[i].usmUserEngineID,
+ table[i].usmUserEngineIDLength,
+ engine_id.data(), engine_id.len()))
+ {
+ /* delete this entry */
+ delete_entry(i);
+ break;
+ }
+
+ /* add user at the last position */
+ table[entries].usmUserEngineIDLength = engine_id.len();
+ table[entries].usmUserEngineID = v3strcpy(engine_id.data(),
+ engine_id.len());
+ table[entries].usmUserNameLength = user_name.len();
+ table[entries].usmUserName = v3strcpy(user_name.data(),
+ user_name.len());
+ table[entries].usmUserSecurityNameLength = sec_name.len();
+ table[entries].usmUserSecurityName = v3strcpy(sec_name.data(),
+ sec_name.len());
+ table[entries].usmUserAuthProtocol = auth_proto;
+ table[entries].usmUserAuthKeyLength = auth_key.len();
+ table[entries].usmUserAuthKey = v3strcpy(auth_key.data(),
+ auth_key.len());
+ table[entries].usmUserPrivProtocol = priv_proto;
+ table[entries].usmUserPrivKeyLength = priv_key.len();
+ table[entries].usmUserPrivKey = v3strcpy(priv_key.data(),
+ priv_key.len());
+ entries++;
+ return SNMPv3_USM_OK;
+}
+
+int USMUserTable::update_key(const OctetStr &user_name,
+ const OctetStr &engine_id,
+ const OctetStr &new_key,
+ const int key_type)
+{
+ LOG_BEGIN(INFO_LOG | 7);
+ LOG("USMUserTable: Update key for user (name) (engine id) (type)");
+ LOG(user_name.get_printable());
+ LOG(engine_id.get_printable());
+ LOG(key_type);
+ LOG_END;
+
+ if (!table)
+ return SNMPv3_USM_ERROR;
+
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i = 0; i < entries; i++)
+ if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
+ user_name.data(), user_name.len()))
+ if (unsignedCharCompare(table[i].usmUserEngineID,
+ table[i].usmUserEngineIDLength,
+ engine_id.data(), engine_id.len()))
+ {
+ LOG_BEGIN(DEBUG_LOG | 15);
+ LOG("USMUserTable: New key");
+ LOG(new_key.get_printable());
+ LOG_END;
+
+ /* update key: */
+ switch (key_type)
+ {
+ case AUTHKEY:
+ case OWNAUTHKEY:
+ {
+ if (table[i].usmUserAuthKey)
+ {
+ memset(table[i].usmUserAuthKey, 0,
+ table[i].usmUserAuthKeyLength);
+ delete [] table[i].usmUserAuthKey;
+ }
+ table[i].usmUserAuthKeyLength = new_key.len();
+ table[i].usmUserAuthKey = v3strcpy(new_key.data(), new_key.len());
+ return SNMPv3_USM_OK;
+ }
+ case PRIVKEY:
+ case OWNPRIVKEY:
+ {
+ if (table[i].usmUserPrivKey)
+ {
+ memset(table[i].usmUserPrivKey, 0,
+ table[i].usmUserPrivKeyLength);
+ delete [] table[i].usmUserPrivKey;
+ }
+ table[i].usmUserPrivKeyLength = new_key.len();
+ table[i].usmUserPrivKey = v3strcpy(new_key.data(), new_key.len());
+ return SNMPv3_USM_OK;
+ }
+ default:
+ {
+ LOG_BEGIN(WARNING_LOG | 3);
+ LOG("USMUserTable: setting new key failed (wrong type).");
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+ }
+ }
+ }
+
+ LOG_BEGIN(INFO_LOG | 7);
+ LOG("USMUserTable: setting new key failed (user) not found");
+ LOG(user_name.get_printable());
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+}
+
+void USMUserTable::delete_entry(const int nr)
+{
+ /* Table is locked through caller, so do NOT lock table!
+ * All checks have been made, so dont check again!
+ */
+
+ if (table[nr].usmUserEngineID) delete [] table[nr].usmUserEngineID;
+ if (table[nr].usmUserName) delete [] table[nr].usmUserName;
+ if (table[nr].usmUserSecurityName) delete [] table[nr].usmUserSecurityName;
+ if (table[nr].usmUserAuthKey)
+ {
+ memset(table[nr].usmUserAuthKey, 0, table[nr].usmUserAuthKeyLength);
+ delete [] table[nr].usmUserAuthKey;
+ }
+ if (table[nr].usmUserPrivKey)
+ {
+ memset(table[nr].usmUserPrivKey, 0, table[nr].usmUserPrivKeyLength);
+ delete [] table[nr].usmUserPrivKey;
+ }
+
+ /* We have now one entry less */
+ entries--;
+
+ if (entries > nr)
+ {
+ /* move the last entry to the deleted position */
+ table[nr] = table[entries];
+ }
+}
+
+// Save all entries into a file.
+int USMUserTable::save_to_file(const char *name, AuthPriv *ap)
+{
+ char encoded[MAX_LINE_LEN * 2];
+ FILE *file_out;
+ char tmp_file_name[MAXLENGTH_FILENAME];
+ bool failed = false;
+
+ if (!name || !ap)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserTable: save_to_file called with illegal param");
+ if (!name)
+ {
+ LOG("filename");
+ }
+ if (!ap)
+ {
+ LOG("AuthPriv pointer");
+ }
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+ }
+
+ LOG_BEGIN(INFO_LOG | 4);
+ LOG("USMUserTable: Saving users to file");
+ LOG(name);
+ LOG_END;
+
+ sprintf(tmp_file_name, "%s.tmp", name);
+ file_out = fopen(tmp_file_name, "w");
+ if (!file_out)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserTable: could not create tmpfile");
+ LOG(tmp_file_name);
+ LOG_END;
+
+ return SNMPv3_USM_FILECREATE_ERROR;
+ }
+
+ {
+ // Begin reentrant code block
+ BEGIN_REENTRANT_CODE_BLOCK;
+
+ for (int i=0; i < entries; ++i)
+ {
+ LOG_BEGIN(INFO_LOG | 8);
+ LOG("USMUserTable: Saving user to file");
+ LOG(OctetStr(table[i].usmUserName, table[i].usmUserNameLength)
+ .get_printable());
+ LOG_END;
+
+ encodeString(table[i].usmUserEngineID, table[i].usmUserEngineIDLength,
+ encoded);
+ encoded[2 * table[i].usmUserEngineIDLength] = '\n';
+ if (fwrite(encoded, 2 * table[i].usmUserEngineIDLength + 1, 1,
+ file_out) != 1)
+ { failed = true; break; }
+
+ encodeString(table[i].usmUserName, table[i].usmUserNameLength, encoded);
+ encoded[2 * table[i].usmUserNameLength] = '\n';
+ if (fwrite(encoded, 2 * table[i].usmUserNameLength + 1, 1,
+ file_out) != 1)
+ { failed = true; break; }
+
+ encodeString(table[i].usmUserSecurityName,
+ table[i].usmUserSecurityNameLength, encoded);
+ encoded[2 * table[i].usmUserSecurityNameLength] = '\n';
+ if (fwrite(encoded, 2 * table[i].usmUserSecurityNameLength + 1, 1,
+ file_out) != 1)
+ { failed = true; break; }
+
+ encodeString(table[i].usmUserAuthKey, table[i].usmUserAuthKeyLength,
+ encoded);
+ encoded[2 * table[i].usmUserAuthKeyLength] = '\n';
+ if (fwrite(encoded, 2 * table[i].usmUserAuthKeyLength + 1, 1,
+ file_out) != 1)
+ { failed = true; break; }
+
+ encodeString(table[i].usmUserPrivKey, table[i].usmUserPrivKeyLength,
+ encoded);
+ encoded[2 * table[i].usmUserPrivKeyLength] = '\n';
+ if (fwrite(encoded, 2 * table[i].usmUserPrivKeyLength + 1, 1,
+ file_out) != 1)
+ { failed = true; break; }
+
+ if (table[i].usmUserAuthProtocol == SNMP_AUTHPROTOCOL_NONE)
+ {
+ if (fwrite("none\n", 5, 1, file_out) != 1)
+ { failed = true; break; }
+ }
+ else
+ {
+ const Auth *a = ap->get_auth(table[i].usmUserAuthProtocol);
+ if (!a) { failed = true; break; }
+ sprintf(encoded, "%s\n", a->get_id_string());
+ if (fwrite(encoded, strlen(a->get_id_string()) + 1, 1, file_out) != 1)
+ { failed = true; break; }
+ }
+
+ if (table[i].usmUserPrivProtocol == SNMP_PRIVPROTOCOL_NONE)
+ {
+ if (fwrite("none\n", 5, 1, file_out) != 1)
+ { failed = true; break; }
+ }
+ else
+ {
+ const Priv *p = ap->get_priv(table[i].usmUserPrivProtocol);
+ if (!p) { failed = true; break; }
+ sprintf(encoded, "%s\n", p->get_id_string());
+ if (fwrite(encoded, strlen(p->get_id_string()) + 1, 1, file_out) != 1)
+ { failed = true; break; }
+ }
+ }
+ }
+
+ fclose(file_out);
+ if (failed)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserTable: Failed to write table entries.");
+ LOG_END;
+
+#ifdef WIN32
+ _unlink(tmp_file_name);
+#else
+ unlink(tmp_file_name);
+#endif
+ return SNMPv3_USM_FILEWRITE_ERROR;
+ }
+#ifdef WIN32
+ _unlink(name);
+#else
+ unlink(name);
+#endif
+ if (rename(tmp_file_name, name))
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserTable: Could not rename file (from) (to)");
+ LOG(tmp_file_name);
+ LOG(name);
+ LOG_END;
+
+ return SNMPv3_USM_FILERENAME_ERROR;
+ }
+
+ LOG_BEGIN(INFO_LOG | 4);
+ LOG("USMUserTable: Saving users to file finished");
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+}
+
+// Load the table from a file.
+int USMUserTable::load_from_file(const char *name, AuthPriv *ap)
+{
+ char decoded[MAX_LINE_LEN];
+ FILE *file_in;
+ unsigned char line[MAX_LINE_LEN * 2];
+
+ if (!name || !ap)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserTable: load_from_file called with illegal param");
+ if (!name)
+ {
+ LOG("filename");
+ }
+ if (!ap)
+ {
+ LOG("AuthPriv pointer");
+ }
+ LOG_END;
+
+ return SNMPv3_USM_ERROR;
+ }
+
+ LOG_BEGIN(INFO_LOG | 4);
+ LOG("USMUserTable: Loading users from file");
+ LOG(name);
+ LOG_END;
+
+ file_in = fopen(name, "r");
+ if (!file_in)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserTable: could not open file");
+ LOG(name);
+ LOG_END;
+
+ return SNMPv3_USM_FILEOPEN_ERROR;
+ }
+
+ bool failed = false;
+ int len;
+ while (fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ {
+ // engine_id
+ len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+ decodeString(line, len, decoded);
+ OctetStr engine_id((unsigned char*)decoded, len / 2);
+
+ // user_name
+ if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ { failed = true; break; }
+ len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+ decodeString(line, len, decoded);
+ OctetStr user_name((unsigned char*)decoded, len / 2);
+
+ // security_name
+ if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ { failed = true; break; }
+ len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+ decodeString(line, len, decoded);
+ OctetStr user_security_name((unsigned char*)decoded, len / 2);
+
+ // auth key
+ if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ { failed = true; break; }
+ len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+ decodeString(line, len, decoded);
+ OctetStr auth_key((unsigned char*)decoded, len / 2);
+
+ // priv key
+ if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ { failed = true; break; }
+ len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+ decodeString(line, len, decoded);
+ OctetStr priv_key((unsigned char*)decoded, len / 2);
+
+ // auth protocol
+ if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ { failed = true; break; }
+ line[strlen((char*)line) - 1] = 0;
+ int auth_prot = SNMP_AUTHPROTOCOL_NONE;
+ if (strcmp((char*)line, "none") != 0)
+ {
+ auth_prot = ap->get_auth_id((char*)line);
+ if (auth_prot < 0)
+ { failed = true; break; }
+ }
+
+ if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+ { failed = true; break; }
+ line[strlen((char*)line) - 1] = 0;
+ int priv_prot = SNMP_PRIVPROTOCOL_NONE;
+ if (strcmp((char*)line, "none") != 0)
+ {
+ priv_prot = ap->get_priv_id((char*)line);
+ if (priv_prot < 0)
+ { failed = true; break; }
+ }
+
+ LOG_BEGIN(INFO_LOG | 7);
+ LOG("USMUserTable: Adding localized (user name) (eng id) (auth) (priv)");
+ LOG(user_name.get_printable());
+ LOG(engine_id.get_printable());
+ LOG(auth_prot);
+ LOG(priv_prot);
+ LOG_END;
+
+ if (add_entry(engine_id, user_name, user_security_name,
+ auth_prot, auth_key, priv_prot, priv_key)
+ == SNMPv3_USM_ERROR)
+ {
+ failed = true;
+
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserTable: Error adding (user name)");
+ LOG(user_name.get_printable());
+ LOG_END;
+ }
+ }
+
+ fclose(file_in);
+ if (failed)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("USMUserTable: Failed to read table entries");
+ LOG_END;
+
+ return SNMPv3_USM_FILEREAD_ERROR;
+ }
+
+ LOG_BEGIN(INFO_LOG | 4);
+ LOG("USMUserTable: Loaded all users from file");
+ LOG_END;
+
+ return SNMPv3_USM_OK;
+}
+
+const UsmUserTableEntry *USMUserTable::peek_next(
+ const UsmUserTableEntry *e) const
+{
+ if (e == 0) return 0;
+ if (e - table < 0) return 0;
+ if (e - table >= entries - 1) return 0;
+ return (e + 1);
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
+
+#endif // _SNMPv3
--- /dev/null
+/*_############################################################################
+ _##
+ _## uxsnmp.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+ U X S N M P . C P P
+
+ UXSNMP CLASS DECLARATION
+
+ Description: Snmp class
+
+ Author: Peter E Mellquist
+=====================================================================*/
+char snmp_cpp_version[]="#(@) SNMP++ $Id: uxsnmp.cpp 1798 2010-08-14 20:10:48Z katz $";
+
+/* CK Ng added support for WIN32 in the whole file */
+
+//-----[ includes ]----------------------------------------------------
+#ifdef WIN32
+#include <sys/types.h> // system types
+#include <sys/timeb.h> // _timeb and _ftime
+#else
+#include <unistd.h> // unix
+#include <sys/socket.h> // bsd socket stuff
+#include <netinet/in.h> // network types
+#include <arpa/inet.h> // arpa types
+#include <sys/types.h> // system types
+#if !(defined CPU && CPU == PPC603)
+#include <sys/time.h> // time stuff
+#endif
+#endif
+#ifdef _AIX
+#define ss_family __ss_family
+#endif
+
+#include <stdlib.h> // need for malloc
+#include <errno.h> // ux errs
+
+#define _INCLUDE_SNMP_ERR_STRINGS
+
+//----[ snmp++ includes ]----------------------------------------------
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/uxsnmp.h" // class def for this module
+#include "snmp_pp/oid_def.h" // class def for well known trap oids
+#include "snmp_pp/v3.h"
+#include "snmp_pp/msgqueue.h" // message queue
+#include "snmp_pp/notifyqueue.h" // notification queue
+#include "snmp_pp/snmpmsg.h" // asn serialization class
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/usm_v3.h"
+#include "snmp_pp/vb.h"
+#include "snmp_pp/log.h"
+#include "snmp_pp/IPv6Utility.h"
+
+#if defined (CPU) && CPU == PPC603
+#include <sockLib.h>
+#include <taskLib.h>
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//-----[ special includes ]-------------------------------------------
+extern "C"
+{
+ //------------[ if using Wind-U, then bring in the ms-windows header ]
+#ifndef WIN32
+ typedef short WORD;
+ typedef long DWORD;
+#endif
+}
+
+//-----[ macros ]------------------------------------------------------
+#define DEFAULT_TIMEOUT 1000 // one second default timeout
+#define DEFAULT_RETRIES 1 // no retry default
+#define SNMP_PORT 161 // port # for SNMP
+#define SNMP_TRAP_PORT 162 // port # for SNMP traps
+
+#ifdef WIN32
+#ifdef __BCPLUSPLUS__
+#define _timeb timeb
+#define _ftime ftime
+#endif
+#define close closesocket
+#endif
+
+//--------[ globals ]---------------------------------------------------
+
+//--------------[ well known trap ids ]-----------------------------------
+const coldStartOid coldStart;
+const warmStartOid warmStart;
+const linkDownOid linkDown;
+const linkUpOid linkUp;
+const authenticationFailureOid authenticationFailure;
+const egpNeighborLossOid egpNeighborLoss;
+const snmpTrapEnterpriseOid snmpTrapEnterprise;
+
+
+#ifdef _SNMPv3
+
+void deleteV3Callback(struct Snmp::V3CallBackData *&cbData)
+{
+ if (cbData->pdu) {
+ delete cbData->pdu;
+ cbData->pdu = 0;
+ }
+ if (cbData->target) {
+ delete cbData->target;
+ cbData->target = 0;
+ }
+ delete cbData;
+ cbData = 0;
+}
+
+void v3CallBack(int reason, Snmp *snmp, Pdu &pdu, SnmpTarget &target, void *v3cd)
+{
+ struct Snmp::V3CallBackData *cbData = (struct Snmp::V3CallBackData*)v3cd;
+
+ Vb tmpvb;
+ pdu.get_vb(tmpvb,0);
+
+ debugprintf(5, "v3CallBack: received oid: %s with value: %s",
+ tmpvb.get_printable_oid(), tmpvb.get_printable_value());
+ debugprintf(5, "v3CallBack: error_msg (%s), pdu_type (%i)",
+ snmp->error_msg(tmpvb.get_oid()), pdu.get_type());
+
+ if ((pdu.get_type() == REPORT_MSG) &&
+ (((tmpvb.get_oid() == oidUsmStatsUnknownEngineIDs) &&
+ (cbData->reports_received == 0)) ||
+ ((tmpvb.get_oid() == oidUsmStatsNotInTimeWindows) &&
+ (cbData->reports_received <= 1)))) {
+ // hide those reports from user
+ int rc;
+ if ((cbData->pdu) && (cbData->target)) {
+ rc = snmp->snmp_engine(*(cbData->pdu), cbData->non_reps,
+ cbData->max_reps, *(cbData->target),
+ (snmp_callback)(cbData->oldCallback),
+ (void *)cbData->cbd, INVALID_SOCKET,
+ cbData->reports_received + 1);
+ debugprintf(3,"v3CallBack: snmp_engine called, rc (%i)", rc);
+ }
+ else
+ rc = SNMP_CLASS_ERROR;
+
+ if (rc != SNMP_CLASS_SUCCESS) {
+ // call callback if snmp_engine failed or pdu or target was 0
+ debugprintf(3,"v3CallBack: calling user callback");
+ snmp_callback tmp_callBack;
+ tmp_callBack = (snmp_callback)(cbData->oldCallback);
+ tmp_callBack(rc, snmp, pdu, target, (void *)cbData->cbd);
+ }
+ }
+ else {
+ debugprintf(3,"v3CallBack: calling user callback");
+ snmp_callback tmp_callBack;
+ tmp_callBack = (snmp_callback)(cbData->oldCallback);
+ tmp_callBack(reason, snmp, pdu, target, (void *)cbData->cbd);
+ }
+ // save to delete it here, because either snmp_engine created a new
+ // callback entry or the user specified callback has been called
+ deleteV3Callback(cbData);
+ return;
+}
+#endif
+
+//--------[ make the pdu request id ]-----------------------------------
+// return a unique rid, clock can be too slow , so use current_rid
+long Snmp::MyMakeReqId()
+{
+ long rid;
+ eventListHolder->snmpEventList()->lock();
+ do {
+ rid = ++current_rid;
+
+#ifdef INVALID_REQID
+ debugprintf(-10, "\nWARNING: Using constand RequestID!\n");
+ rid = 0xc0de;
+#endif
+
+ if ( current_rid > PDU_MAX_RID)
+ {
+ current_rid = rid = PDU_MIN_RID;
+ // let other tasks proceed
+ eventListHolder->snmpEventList()->unlock();
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100;
+ select(0, 0, 0, 0, &tv);
+ eventListHolder->snmpEventList()->lock();
+ }
+ } while (eventListHolder->snmpEventList()->GetEntry(rid));
+ eventListHolder->snmpEventList()->unlock();
+
+ return rid;
+}
+
+//---------[ Send SNMP Request ]---------------------------------------
+// Send out a snmp request
+DLLOPT int send_snmp_request(SnmpSocket sock, unsigned char *send_buf,
+ size_t send_len, Address & address)
+{
+ // UX only supports UDP type addresses (addr and port) right now
+ if (address.get_type() != Address::type_udp)
+ return -1;// unsupported address type
+
+ debugprintf(1, "++ SNMP++: sending to %s:",
+ ((UdpAddress &)address).UdpAddress::get_printable());
+ debughexprintf(5, send_buf, SAFE_UINT_CAST(send_len));
+
+ int send_result;
+
+ if (((UdpAddress &)address).get_ip_version() == Address::version_ipv4)
+ {
+ // prepare the destination address
+ struct sockaddr_in agent_addr; // send socket struct
+ memset(&agent_addr, 0, sizeof(agent_addr));
+ agent_addr.sin_family = AF_INET;
+ agent_addr.sin_addr.s_addr
+ = inet_addr(((IpAddress &)address).IpAddress::get_printable());
+ agent_addr.sin_port = htons(((UdpAddress &)address).get_port());
+
+ send_result = sendto(sock, (char*) send_buf, SAFE_INT_CAST(send_len), 0,
+ (struct sockaddr*) &agent_addr, sizeof(agent_addr));
+ }
+ else
+ {
+#ifdef SNMP_PP_IPv6
+ struct sockaddr_in6 agent_addr;
+ memset(&agent_addr, 0, sizeof(agent_addr));
+ unsigned int scope = 0;
+
+ OctetStr addrstr = ((IpAddress &)address).IpAddress::get_printable();
+
+ if (((IpAddress &)address).has_ipv6_scope())
+ {
+ scope = ((IpAddress &)address).get_scope();
+
+ int i = addrstr.len() - 1;
+ while ((i>0) && (addrstr[i] != '%'))
+ {
+ addrstr.set_len(addrstr.len() - 1);
+ i--;
+ }
+ if (addrstr[i] == '%')
+ addrstr.set_len(addrstr.len() - 1);
+ }
+
+ if (inet_pton(AF_INET6, addrstr.get_printable(),
+ &agent_addr.sin6_addr) < 0)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("Snmp transport: inet_pton returns (errno) (str)");
+ LOG(errno);
+ LOG(strerror(errno));
+ LOG_END;
+ return -1;
+ }
+ agent_addr.sin6_family = AF_INET6;
+ agent_addr.sin6_port = htons(((UdpAddress &)address).get_port());
+ agent_addr.sin6_scope_id = scope;
+ send_result = sendto( sock, (char*) send_buf, send_len, 0,
+ (struct sockaddr*) &agent_addr, sizeof(agent_addr));
+#else
+ debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
+ return -1;
+#endif
+ }
+
+ if (send_result < 0)
+ {
+ debugprintf(0, "Error sending packet: %s", strerror(errno));
+ return -1; // send error!
+ }
+
+ return 0;
+}
+
+//---------[ receive a snmp response ]---------------------------------
+// Receive a response from the specified socket.
+// This function does not set the request id in the pdu if
+// any error occur in receiving or parsing. This is important
+// because the caller initializes this to zero and checks it to
+// see whether it has been changed to a valid value. The
+// return value is the normal PDU status or SNMP_CLASS_SUCCESS.
+// when we are successful in receiving a pdu. Otherwise it
+// is an error status.
+
+int receive_snmp_response(SnmpSocket sock, Snmp &snmp_session,
+ Pdu &pdu, UdpAddress &fromaddress,
+ OctetStr &engine_id, bool process_msg = true)
+{
+ unsigned char receive_buffer[MAX_SNMP_PACKET + 1];
+ long receive_buffer_len; // len of received data
+#ifdef SNMP_PP_IPv6
+ struct sockaddr_storage from_addr;
+#else
+ struct sockaddr_in from_addr;
+#endif
+#if !(defined (CPU) && CPU == PPC603) && (defined __GNUC__ || defined __FreeBSD__ || defined _AIX) && ! defined __MINGW32__
+ socklen_t fromlen;
+#else
+ int fromlen;
+#endif
+ fromlen = sizeof(from_addr);
+
+ memset(&from_addr, 0, sizeof(from_addr));
+
+ // do the read
+ do {
+ receive_buffer_len = (long) recvfrom(sock, (char *) receive_buffer,
+ MAX_SNMP_PACKET + 1, 0,
+ (struct sockaddr*) &from_addr,
+ &fromlen);
+ debugprintf(2, "++ SNMP++: something received...");
+ } while ((receive_buffer_len < 0) && (EINTR == errno));
+
+ if (receive_buffer_len < 0 ) // error or no data pending
+ return SNMP_CLASS_TL_FAILED;
+ debugprintf(6, "Length received %i from socket %i; fromlen %i",
+ receive_buffer_len, sock, fromlen);
+
+ if (receive_buffer_len == MAX_SNMP_PACKET + 1)
+ {
+ // Message is too long...
+ debugprintf(1, "Received message is ignored (packet too long)");
+ return SNMP_CLASS_ERROR;
+ }
+
+ if (((sockaddr_in&)from_addr).sin_family == AF_INET)
+ {
+ // IPv4
+ fromaddress = inet_ntoa(((sockaddr_in&)from_addr).sin_addr);
+ fromaddress.set_port(ntohs(((sockaddr_in&)from_addr).sin_port));
+ }
+#ifdef SNMP_PP_IPv6
+ else if (from_addr.ss_family == AF_INET6)
+ {
+ // IPv6
+ char tmp_buffer[INET6_ADDRSTRLEN+1];
+
+ inet_ntop(AF_INET6, &(((sockaddr_in6&)from_addr).sin6_addr),
+ tmp_buffer, INET6_ADDRSTRLEN);
+
+ fromaddress = tmp_buffer;
+ fromaddress.set_port(ntohs(((sockaddr_in6&)from_addr).sin6_port));
+ if (((sockaddr_in6&)from_addr).sin6_scope_id != 0)
+ fromaddress.set_scope(((sockaddr_in6&)from_addr).sin6_scope_id);
+ }
+#endif // SNMP_PP_IPv6
+ else
+ {
+ debugprintf(0, "Unknown socket address family (%i).",
+ ((sockaddr_in&)from_addr).sin_family);
+ return SNMP_CLASS_ERROR;
+ }
+
+ debugprintf(1, "++ SNMP++: data received from %s.",
+ fromaddress.get_printable());
+ debughexprintf(5, receive_buffer, receive_buffer_len);
+
+ if (process_msg == false)
+ return SNMP_CLASS_SUCCESS; // return success
+
+ SnmpMessage snmpmsg;
+ if ( snmpmsg.load( receive_buffer, receive_buffer_len) != SNMP_CLASS_SUCCESS)
+ return SNMP_CLASS_ERROR;
+
+ OctetStr community_name;
+ snmp_version version;
+ OctetStr security_name;
+
+#ifdef _SNMPv3
+ long int security_model;
+ if (snmpmsg.is_v3_message() == TRUE)
+ {
+ int returncode = snmpmsg.unloadv3(pdu, version, engine_id,
+ security_name, security_model,
+ fromaddress, snmp_session);
+ if (returncode != SNMP_CLASS_SUCCESS)
+ return returncode;
+ }
+ else
+ {
+#endif
+ int returncode = snmpmsg.unload( pdu, community_name, version);
+ if (returncode != SNMP_CLASS_SUCCESS)
+ return SNMP_CLASS_ERROR;
+#ifdef _SNMPv3
+ }
+ if (version == version3)
+ {
+ debugprintf(4,"receive_snmp_response: engine_id (%s), security_name (%s), "
+ "security_model (%i), security_level (%i)",
+ engine_id.get_printable(), security_name.get_printable(),
+ security_model, pdu.get_security_level());
+ debugprintf(5," addtoengineidtable: (%s)",
+ (unsigned char*)fromaddress.get_printable());
+ }
+#endif
+
+ //-----[ check for error status stuff..]
+ // an error status is a valid pdu,
+ // the caller needs to know about it
+ if ( pdu.get_error_status() != 0)
+ return pdu.get_error_status();
+
+ debugprintf(5,"receive_snmp_response requestID = %li, "
+ "returning SUCCESS.", pdu.get_request_id());
+
+ return SNMP_CLASS_SUCCESS; // Success! return
+}
+
+
+//---------[ receive a snmp trap ]---------------------------------
+// Receive a trap from the specified socket
+// note: caller has to delete target!
+int receive_snmp_notification(SnmpSocket sock, Snmp &snmp_session,
+ Pdu &pdu, SnmpTarget **target)
+{
+ unsigned char receive_buffer[MAX_SNMP_PACKET + 1];
+ long receive_buffer_len; // len of received data
+
+#ifdef SNMP_PP_IPv6
+ struct sockaddr_storage from_addr;
+#else
+ struct sockaddr_in from_addr;
+#endif // SNMP_PP_IPv6
+
+#if !(defined (CPU) && CPU == PPC603) && (defined __GNUC__ || defined __FreeBSD__ || defined _AIX) && ! defined __MINGW32__
+ socklen_t fromlen;
+#else
+ int fromlen;
+#endif
+ fromlen = sizeof(from_addr);
+
+ memset(&from_addr, 0, sizeof(from_addr));
+
+ // do the read
+ do {
+ receive_buffer_len = (long) recvfrom(sock, (char *) receive_buffer,
+ MAX_SNMP_PACKET + 1, 0,
+ (struct sockaddr*)&from_addr,
+ &fromlen);
+ } while (receive_buffer_len < 0 && EINTR == errno);
+
+ if (receive_buffer_len < 0 ) // error or no data pending
+ return SNMP_CLASS_TL_FAILED;
+
+ if (receive_buffer_len == MAX_SNMP_PACKET + 1)
+ {
+ // Message is too long...
+ debugprintf(1, "Received message is ignored (packet too long)");
+ return SNMP_CLASS_ERROR;
+ }
+
+ // copy fromaddress and remote port
+ UdpAddress fromaddress;
+
+ if (((sockaddr_in&)from_addr).sin_family == AF_INET)
+ {
+ // IPv4
+ fromaddress = inet_ntoa(((sockaddr_in&)from_addr).sin_addr);
+ fromaddress.set_port(ntohs(((sockaddr_in&)from_addr).sin_port));
+ }
+#ifdef SNMP_PP_IPv6
+ else if (from_addr.ss_family == AF_INET6)
+ {
+ // IPv6
+ char tmp_buffer[INET6_ADDRSTRLEN+1];
+
+ inet_ntop(AF_INET6, &(((sockaddr_in6&)from_addr).sin6_addr),
+ tmp_buffer, INET6_ADDRSTRLEN);
+
+ fromaddress = tmp_buffer;
+ fromaddress.set_port(ntohs(((sockaddr_in6&)from_addr).sin6_port));
+ if (((sockaddr_in6&)from_addr).sin6_scope_id != 0)
+ fromaddress.set_scope(((sockaddr_in6&)from_addr).sin6_scope_id);
+ }
+#endif // SNMP_PP_IPv6
+ else
+ {
+ debugprintf(0, "Unknown socket address family (%i).",
+ ((sockaddr_in&)from_addr).sin_family);
+ return SNMP_CLASS_TL_FAILED;
+ }
+
+ debugprintf(1, "++ SNMP++: data received from %s.",
+ fromaddress.get_printable());
+ debughexprintf(5, receive_buffer, receive_buffer_len);
+
+ SnmpMessage snmpmsg;
+ if ( snmpmsg.load( receive_buffer, receive_buffer_len) != SNMP_CLASS_SUCCESS)
+ return SNMP_CLASS_ERROR;
+
+ OctetStr community_name;
+ snmp_version version;
+ OctetStr engine_id;
+ OctetStr security_name;
+
+#ifdef _SNMPv3
+ long int security_model;
+ if (snmpmsg.is_v3_message() == TRUE)
+ {
+ int returncode = snmpmsg.unloadv3(pdu, version, engine_id,
+ security_name, security_model,
+ fromaddress, snmp_session);
+ if (returncode != SNMP_CLASS_SUCCESS)
+ return returncode;
+ }
+ else
+ {
+#endif
+ int returncode = snmpmsg.unload( pdu, community_name, version);
+ if (returncode != SNMP_CLASS_SUCCESS)
+ return SNMP_CLASS_ERROR;
+#ifdef _SNMPv3
+ }
+
+ if (version == version3) {
+ *target = new UTarget();
+ (*target)->set_address(fromaddress);
+ (*target)->set_version(version);
+ ((UTarget*)*target)->set_engine_id(engine_id);
+ ((UTarget*)*target)->set_security_name(security_name);
+ ((UTarget*)*target)->set_security_model(security_model);
+
+ v3MP::I->add_to_engine_id_table(engine_id,
+ (char*)(fromaddress.IpAddress::get_printable()),
+ fromaddress.get_port());
+
+ debugprintf(4,"receive_snmp_notification: engine_id (%s), security_name "
+ "(%s), security_model (%i), security_level (%i)",
+ engine_id.get_printable(), security_name.get_printable(),
+ security_model, pdu.get_security_level());
+ }
+ else
+ {
+#endif
+ *target = new CTarget();
+ (*target)->set_version(version);
+ (*target)->set_address(fromaddress);
+ ((CTarget*)*target)->set_readcommunity( community_name);
+ ((CTarget*)*target)->set_writecommunity( community_name);
+#ifdef _SNMPv3
+ }
+#endif
+ return SNMP_CLASS_SUCCESS; // Success! return
+}
+
+
+//--------[ map action ]------------------------------------------------
+// map the snmp++ action to a SMI pdu type
+void Snmp::map_action( unsigned short action, unsigned short & pdu_action)
+{
+ switch( action)
+ {
+ case sNMP_PDU_GET:
+ case sNMP_PDU_GET_ASYNC:
+ pdu_action = sNMP_PDU_GET;
+ break;
+
+ case sNMP_PDU_SET:
+ case sNMP_PDU_SET_ASYNC:
+ pdu_action = sNMP_PDU_SET;
+ break;
+
+ case sNMP_PDU_GETNEXT:
+ case sNMP_PDU_GETNEXT_ASYNC:
+ pdu_action = sNMP_PDU_GETNEXT;
+ break;
+
+ case sNMP_PDU_GETBULK:
+ case sNMP_PDU_GETBULK_ASYNC:
+ pdu_action = sNMP_PDU_GETBULK;
+ break;
+
+ case sNMP_PDU_RESPONSE:
+ pdu_action = sNMP_PDU_RESPONSE;
+ break;
+
+ case sNMP_PDU_INFORM:
+ case sNMP_PDU_INFORM_ASYNC:
+ pdu_action = sNMP_PDU_INFORM;
+ break;
+
+ case sNMP_PDU_REPORT:
+ pdu_action = sNMP_PDU_REPORT;
+ break;
+
+ default:
+ pdu_action = sNMP_PDU_GET; // TM ?? error ??
+ break;
+
+ }; // end switch
+}
+
+//------[ Snmp Class Constructor ]--------------------------------------
+
+Snmp::Snmp(int &status, const unsigned short port, const bool bind_ipv6)
+ : SnmpSynchronized(),
+ m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
+{
+ IpAddress *addresses[2];
+
+ if (bind_ipv6)
+ {
+ listen_address = "::";
+
+ addresses[0] = NULL;
+ addresses[1] = &listen_address;
+
+ init(status, addresses, 0, port);
+ }
+ else
+ {
+ listen_address = "0.0.0.0";
+
+ addresses[0] = &listen_address;
+ addresses[1] = NULL;
+
+ init(status, addresses, port, 0);
+ }
+
+}
+
+Snmp::Snmp( int &status, const UdpAddress& addr)
+ : SnmpSynchronized(),
+ m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
+{
+ IpAddress *addresses[2];
+
+ listen_address = addr;
+
+ if (listen_address.get_ip_version() == Address::version_ipv4)
+ {
+ addresses[0] = &listen_address;
+ addresses[1] = NULL;
+ init(status, addresses, addr.get_port(), 0);
+ }
+ else
+ {
+ addresses[0] = NULL;
+ addresses[1] = &listen_address;
+ init(status, addresses, 0, addr.get_port());
+ }
+}
+
+Snmp::Snmp( int &status, const UdpAddress& addr_v4,
+ const UdpAddress& addr_v6)
+ : SnmpSynchronized(),
+ m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
+{
+ IpAddress *addresses[2];
+
+ listen_address = addr_v4;
+ IpAddress address_v6((IpAddress)addr_v6);
+ addresses[0] = &listen_address;
+ addresses[1] = &address_v6;
+
+ init(status, addresses, addr_v4.get_port(), addr_v6.get_port());
+}
+
+void Snmp::socket_startup()
+{
+#ifdef WIN32
+ WSADATA WSAData;
+ (void)WSAStartup(0x0101, &WSAData);
+#endif
+}
+
+void Snmp::socket_cleanup()
+{
+#ifdef WIN32
+ int iRetValue = WSACleanup();
+ debugprintf(4, "WSACleanup: ReturnValue (%i)", iRetValue);
+#endif
+}
+
+void Snmp::init(int& status, IpAddress *addresses[2],
+ const unsigned short port_v4,
+ const unsigned short port_v6)
+{
+#ifdef _THREADS
+#ifdef WIN32
+ m_hThread = INVALID_HANDLE_VALUE;
+ m_hThreadEndEvent = ::CreateEvent(NULL, true, false, NULL);
+#endif
+#endif
+
+ eventListHolder = new EventListHolder(this);
+ // initialize the request_id
+ eventListHolder->snmpEventList()->lock();
+// srand(time(0)); // better than nothing
+ current_rid = (rand() % (PDU_MAX_RID - PDU_MIN_RID +1)) + PDU_MIN_RID;
+ debugprintf(4, "Initialized request_id to %i.", current_rid);
+ eventListHolder->snmpEventList()->unlock();
+
+ // intialize all the trap receiving member variables
+ notifycallback = 0;
+ notifycallback_data = 0;
+#ifdef HPUX
+ int errno = 0;
+#endif
+
+ status = SNMP_CLASS_ERROR;
+ iv_snmp_session = INVALID_SOCKET;
+#ifdef SNMP_PP_IPv6
+ iv_snmp_session_ipv6 = INVALID_SOCKET;
+#endif
+
+ /* Open IPv4 socket */
+ if (addresses[0])
+ {
+ // open a socket to be used for the session
+ if (( iv_snmp_session = socket( AF_INET, SOCK_DGRAM,0)) == INVALID_SOCKET)
+ {
+#ifdef WIN32
+ int werr = WSAGetLastError();
+ debugprintf(1, "Call to socket throws error %d", werr);
+ if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (WSAEHOSTDOWN == werr)
+ status = SNMP_CLASS_TL_FAILED;
+ else
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+#else
+ if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (EHOSTDOWN == errno)
+ status = SNMP_CLASS_TL_FAILED;
+ else
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+#endif
+ }
+ else
+ {
+ // set up the manager socket attributes
+ unsigned long inaddr = inet_addr(addresses[0]->get_printable());
+ struct sockaddr_in mgr_addr;
+ memset(&mgr_addr, 0, sizeof(mgr_addr));
+ mgr_addr.sin_family = AF_INET;
+ mgr_addr.sin_addr.s_addr = inaddr;
+ mgr_addr.sin_port = htons( port_v4);
+#ifdef CYGPKG_NET_OPENBSD_STACK
+ mgr_addr.sin_len = sizeof(mgr_addr);
+#endif
+
+ // bind the socket
+ if (bind(iv_snmp_session, (struct sockaddr*)&mgr_addr,
+ sizeof(mgr_addr)) < 0)
+ {
+#ifdef WIN32
+ int werr = WSAGetLastError();
+ debugprintf(1, "Call to bind throws error %d", werr);
+ if (WSAEADDRINUSE == werr)
+ status = SNMP_CLASS_TL_IN_USE;
+ else if (WSAENOBUFS == werr)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (werr == WSAEAFNOSUPPORT)
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+ else if (werr == WSAENETUNREACH)
+ status = SNMP_CLASS_TL_FAILED;
+ else if (werr == EACCES)
+ status = SNMP_CLASS_TL_ACCESS_DENIED;
+ else
+ status = SNMP_CLASS_INTERNAL_ERROR;
+#else
+ if (EADDRINUSE == errno)
+ status = SNMP_CLASS_TL_IN_USE;
+ else if (ENOBUFS == errno)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (errno == EAFNOSUPPORT)
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+ else if (errno == ENETUNREACH)
+ status = SNMP_CLASS_TL_FAILED;
+ else if (errno == EACCES)
+ status = SNMP_CLASS_TL_ACCESS_DENIED;
+ else
+ {
+ debugprintf(0, "Uncatched errno value %d, returning internal error.",
+ errno);
+ status = SNMP_CLASS_INTERNAL_ERROR;
+ }
+#endif
+ close(iv_snmp_session); // close the dynamic socket
+ iv_snmp_session = INVALID_SOCKET;
+ }
+ else
+ {
+ status = SNMP_CLASS_SUCCESS;
+#ifdef SNMP_BROADCAST
+ int enable_broadcast = 1;
+ setsockopt(iv_snmp_session, SOL_SOCKET, SO_BROADCAST,
+ (char*)&enable_broadcast, sizeof(enable_broadcast));
+#endif
+ }
+ }
+ if (status != SNMP_CLASS_SUCCESS)
+ return;
+ }
+
+ /* Open IPv6 socket */
+ if (addresses[1])
+ {
+#ifdef SNMP_PP_IPv6
+ // open a socket to be used for the session
+ if (( iv_snmp_session_ipv6 = socket( AF_INET6, SOCK_DGRAM,0))
+ == INVALID_SOCKET)
+ {
+#ifdef WIN32
+ int werr = WSAGetLastError();
+ if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (WSAEHOSTDOWN == werr)
+ status = SNMP_CLASS_TL_FAILED;
+ else
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+#else
+ if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (EHOSTDOWN == errno)
+ status = SNMP_CLASS_TL_FAILED;
+ else
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+#endif
+ }
+ else
+ {
+ // set up the manager socket attributes
+ struct sockaddr_in6 mgr_addr;
+ memset(&mgr_addr, 0, sizeof(mgr_addr));
+ unsigned int scope = 0;
+
+ OctetStr addrstr = addresses[1]->get_printable();
+
+ if (addresses[1]->has_ipv6_scope())
+ {
+ scope = addresses[1]->get_scope();
+
+ int i = addrstr.len() - 1;
+ while ((i>0) && (addrstr[i] != '%'))
+ {
+ addrstr.set_len(addrstr.len() - 1);
+ i--;
+ }
+ if (addrstr[i] == '%')
+ addrstr.set_len(addrstr.len() - 1);
+ }
+ if (inet_pton(AF_INET6, addrstr.get_printable(),
+ &mgr_addr.sin6_addr) < 0)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("Snmp transport: inet_pton returns (errno) (str)");
+ LOG(errno);
+ LOG(strerror(errno));
+ LOG_END;
+ status = SNMP_CLASS_INVALID_ADDRESS;
+ return;
+ }
+
+ mgr_addr.sin6_family = AF_INET6;
+ mgr_addr.sin6_port = htons( port_v6);
+ mgr_addr.sin6_scope_id = scope;
+ // bind the socket
+ if (bind(iv_snmp_session_ipv6, (struct sockaddr*) &mgr_addr,
+ sizeof(mgr_addr)) < 0)
+ {
+#ifdef WIN32
+ int werr = WSAGetLastError();
+ if (WSAEADDRINUSE == werr)
+ status = SNMP_CLASS_TL_IN_USE;
+ else if (WSAENOBUFS == werr)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (werr == WSAEAFNOSUPPORT)
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+ else if (werr == WSAENETUNREACH)
+ status = SNMP_CLASS_TL_FAILED;
+ else if (werr == EACCES)
+ status = SNMP_CLASS_TL_ACCESS_DENIED;
+ else
+ status = SNMP_CLASS_INTERNAL_ERROR;
+#else
+ if (EADDRINUSE == errno)
+ status = SNMP_CLASS_TL_IN_USE;
+ else if (ENOBUFS == errno)
+ status = SNMP_CLASS_RESOURCE_UNAVAIL;
+ else if (errno == EAFNOSUPPORT)
+ status = SNMP_CLASS_TL_UNSUPPORTED;
+ else if (errno == ENETUNREACH)
+ status = SNMP_CLASS_TL_FAILED;
+ else if (errno == EACCES)
+ status = SNMP_CLASS_TL_ACCESS_DENIED;
+ else
+ status = SNMP_CLASS_INTERNAL_ERROR;
+#endif
+ close(iv_snmp_session_ipv6); // close the dynamic socket
+ iv_snmp_session_ipv6 = INVALID_SOCKET;
+ }
+ else
+ {
+ status = SNMP_CLASS_SUCCESS;
+#ifdef SNMP_BROADCAST
+ int enable_broadcast = 1;
+ setsockopt(iv_snmp_session_ipv6, SOL_SOCKET, SO_BROADCAST,
+ (char*)&enable_broadcast, sizeof(enable_broadcast));
+#endif
+ }
+ }
+#else
+ debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
+#endif // SNMP_PP_IPv6
+ }
+ return;
+}
+
+
+//---------[ Snmp Class Destructor ]----------------------------------
+Snmp::~Snmp()
+{
+ stop_poll_thread();
+
+#ifdef _THREADS
+#ifdef WIN32
+ ::CloseHandle(m_hThreadEndEvent);
+#endif
+#endif
+
+ // if we failed during construction then don't try
+ // to free stuff up that was not allocated
+ if (iv_snmp_session != INVALID_SOCKET)
+ {
+ // go through the snmpEventList and delete any outstanding
+ // events on this socket
+ eventListHolder->snmpEventList()->DeleteSocketEntry(iv_snmp_session);
+
+ close(iv_snmp_session); // close the dynamic socket
+ }
+ // if we failed during construction then don't try
+ // to free stuff up that was not allocated
+
+#ifdef SNMP_PP_IPv6
+ if (iv_snmp_session_ipv6 != INVALID_SOCKET)
+ {
+ // go through the snmpEventList and delete any outstanding
+ // events on this socket
+ eventListHolder->snmpEventList()->DeleteSocketEntry(iv_snmp_session_ipv6);
+
+ close(iv_snmp_session_ipv6); // close the dynamic socket
+ }
+#endif
+
+ // shut down trap reception if used
+ notify_unregister();
+
+ delete eventListHolder;
+}
+
+// Get the version of the snmp++ library at runtime
+// This function MUST stay in the cpp file!
+const char *Snmp::get_version()
+{
+ return SNMP_PP_VERSION_STRING;
+}
+
+//-------------------[ returns error string ]--------------------------
+const char *Snmp::error_msg(const int c)
+{
+#ifdef _SNMPv3
+ if (c>=SNMPv3_USM_MIN_ERROR)
+ return ((c>SNMPv3_USM_MAX_ERROR)?pv3Errs[SNMPv3_USM_ERRORCOUNT]:pv3Errs[c-SNMPv3_USM_MIN_ERROR]);
+ if (c<=SNMPv3_MP_MAX_ERROR)
+ return ((c<SNMPv3_MP_MIN_ERROR)?nv3Errs[SNMPv3_MP_ERRORCOUNT]:nv3Errs[SNMPv3_MP_MAX_ERROR - c]);
+#endif
+ return ((c<0)?
+ ((c<MAX_NEG_ERROR)?nErrs[-(MAX_NEG_ERROR)+1]:nErrs[-c]):
+ ((c>MAX_POS_ERROR)?pErrs[MAX_POS_ERROR+1]:pErrs[c]));
+}
+
+#ifdef _SNMPv3
+const char* Snmp::error_msg(const Oid& v3Oid)
+{
+ // UsmStats
+ if (v3Oid == oidUsmStatsUnsupportedSecLevels)
+ return error_msg(SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL);
+
+ if (v3Oid == oidUsmStatsNotInTimeWindows)
+ return error_msg(SNMPv3_USM_NOT_IN_TIME_WINDOW);
+
+ if (v3Oid == oidUsmStatsUnknownUserNames )
+ return error_msg(SNMPv3_USM_UNKNOWN_SECURITY_NAME);
+
+ if (v3Oid == oidUsmStatsUnknownEngineIDs)
+ return error_msg(SNMPv3_USM_UNKNOWN_ENGINEID);
+
+ if (v3Oid == oidUsmStatsWrongDigests)
+ return error_msg(SNMPv3_USM_AUTHENTICATION_FAILURE);
+
+ if (v3Oid == oidUsmStatsDecryptionErrors)
+ return error_msg(SNMPv3_USM_DECRYPTION_ERROR);
+
+ // MPDstats
+ if (v3Oid == oidSnmpUnknownSecurityModels)
+ return error_msg(SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL);
+
+ if (v3Oid == oidSnmpInvalidMsgs)
+ return error_msg(SNMPv3_MP_INVALID_MESSAGE);
+
+ if (v3Oid == oidSnmpUnknownPDUHandlers)
+ return error_msg(SNMPv3_MP_UNKNOWN_PDU_HANDLERS);
+
+ if (v3Oid == oidSnmpUnavailableContexts)
+ return error_msg(SNMPv3_MP_UNAVAILABLE_CONTEXT);
+
+ if (v3Oid == oidSnmpUnknownContexts)
+ return error_msg(SNMPv3_MP_UNKNOWN_CONTEXT);
+
+ return error_msg(MAX_POS_ERROR + 1);
+}
+#endif
+
+//------------------------[ get ]---------------------------------------
+int Snmp::get(Pdu &pdu, const SnmpTarget &target)
+{
+ pdu.set_type( sNMP_PDU_GET);
+ return snmp_engine( pdu, 0, 0, target, NULL, 0);
+}
+
+//------------------------[ get async ]----------------------------------
+int Snmp::get(Pdu &pdu, const SnmpTarget &target,
+ const snmp_callback callback,
+ const void * callback_data)
+{
+ pdu.set_type( sNMP_PDU_GET_ASYNC);
+ return snmp_engine( pdu, 0, 0, target, callback, callback_data);
+}
+
+//------------------------[ get next ]-----------------------------------
+int Snmp::get_next(Pdu &pdu, const SnmpTarget &target)
+{
+ pdu.set_type( sNMP_PDU_GETNEXT);
+ return snmp_engine( pdu, 0, 0, target, NULL, 0);
+}
+
+//------------------------[ get next async ]-----------------------------
+int Snmp::get_next(Pdu &pdu, const SnmpTarget &target,
+ const snmp_callback callback,
+ const void * callback_data)
+{
+ pdu.set_type( sNMP_PDU_GETNEXT_ASYNC);
+ return snmp_engine( pdu, 0, 0, target, callback, callback_data);
+}
+
+//-------------------------[ set ]---------------------------------------
+int Snmp::set(Pdu &pdu, const SnmpTarget &target)
+{
+ pdu.set_type( sNMP_PDU_SET);
+ return snmp_engine( pdu, 0, 0, target, NULL, 0);
+}
+
+//------------------------[ set async ]----------------------------------
+int Snmp::set(Pdu &pdu, const SnmpTarget &target,
+ const snmp_callback callback,
+ const void * callback_data)
+{
+ pdu.set_type( sNMP_PDU_SET_ASYNC);
+ return snmp_engine( pdu, 0, 0, target, callback, callback_data);
+}
+
+//-----------------------[ get bulk ]------------------------------------
+int Snmp::get_bulk(Pdu &pdu, // pdu to use
+ const SnmpTarget &target,// destination target
+ const int non_repeaters, // number of non repeaters
+ const int max_reps) // maximum number of repetitions
+{
+ pdu.set_type( sNMP_PDU_GETBULK);
+ return snmp_engine( pdu, non_repeaters, max_reps, target, NULL, 0);
+}
+
+//-----------------------[ get bulk async ]------------------------------
+int Snmp::get_bulk(Pdu &pdu, // pdu to use
+ const SnmpTarget &target, // destination target
+ const int non_repeaters, // number of non repeaters
+ const int max_reps, // maximum number of repetitions
+ const snmp_callback callback,// callback to use
+ const void * callback_data) // callback data
+{
+ pdu.set_type( sNMP_PDU_GETBULK_ASYNC);
+ return snmp_engine( pdu, non_repeaters, max_reps, target,
+ callback, callback_data);
+}
+
+//------------------------[ inform_response ]----------------------------
+int Snmp::response(Pdu &pdu, // pdu to use
+ const SnmpTarget &target, // response target
+ const SnmpSocket fd)
+{
+ pdu.set_type( sNMP_PDU_RESPONSE);
+ return snmp_engine(pdu, 0, 0, target, NULL, 0, fd);
+}
+
+int Snmp::send_raw_data(unsigned char *send_buf,
+ size_t send_len, UdpAddress &address, SnmpSocket fd)
+{
+ // REENTRANT() removed because of #ifdef
+ SnmpSynchronize _synchronize(*this);
+
+ if (fd != INVALID_SOCKET)
+ return send_snmp_request(fd, send_buf, send_len, address);
+ else
+ {
+#ifdef SNMP_PP_IPv6
+ if (address.get_ip_version() == Address::version_ipv4)
+ {
+ if (iv_snmp_session != INVALID_SOCKET)
+ return send_snmp_request(iv_snmp_session, send_buf,
+ send_len, address);
+ else
+ address.map_to_ipv6();
+ }
+ return send_snmp_request(iv_snmp_session_ipv6, send_buf,
+ send_len, address);
+#else
+ return send_snmp_request(iv_snmp_session, send_buf,
+ send_len, address);
+#endif
+
+ }
+}
+
+//-----------------------[ cancel ]--------------------------------------
+int Snmp::cancel(const unsigned long request_id)
+{
+ eventListHolder->snmpEventList()->lock();
+ int status = eventListHolder->snmpEventList()->DeleteEntry(request_id);
+ eventListHolder->snmpEventList()->unlock();
+
+ return status;
+}
+
+
+//----------------------[ sending report, V3 only]-----------------------
+int Snmp::report(Pdu &pdu, // pdu to send
+ const SnmpTarget &target)// destination target
+{
+ pdu.set_type( sNMP_PDU_REPORT);
+ return snmp_engine( pdu, 0, 0, target, NULL, 0);
+}
+
+//----------------------[ blocking inform, V2 only]------------------------
+int Snmp::inform(Pdu &pdu, // pdu to send
+ const SnmpTarget &target)// destination target
+{
+ if (target.get_version() == version1)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("Snmp: Invalid Operation: Inform not defined for SNMPv1");
+ LOG_END;
+
+ return SNMP_CLASS_INVALID_OPERATION;
+ }
+
+ pdu.set_type( sNMP_PDU_INFORM);
+ check_notify_timestamp(pdu);
+ return snmp_engine( pdu, 0, 0, target, NULL, 0);
+}
+
+//----------------------[ asynch inform, V2 only]------------------------
+int Snmp::inform(Pdu &pdu, // pdu to send
+ const SnmpTarget &target, // destination target
+ const snmp_callback callback, // callback function
+ const void * callback_data) // callback data
+{
+ if (target.get_version() == version1)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("Snmp: Invalid Operation: Inform not defined for SNMPv1");
+ LOG_END;
+
+ return SNMP_CLASS_INVALID_OPERATION;
+ }
+
+ pdu.set_type(sNMP_PDU_INFORM_ASYNC);
+ check_notify_timestamp(pdu);
+ return snmp_engine( pdu, 0, 0, target, callback, callback_data);
+}
+
+
+//---------------------[ send a trap ]-----------------------------------
+int Snmp::trap(Pdu &pdu, // pdu to send
+ const SnmpTarget &target) // destination target
+{
+ OctetStr my_get_community;
+ OctetStr my_set_community;
+ GenAddress address;
+ unsigned long my_timeout;
+ int my_retry;
+ unsigned char version;
+ int status;
+
+ debugprintf(1, "++ SNMP++, Send a Trap");
+ //---------[ make sure pdu is valid ]---------------------------------
+ if (!pdu.valid())
+ {
+ debugprintf(0, "-- SNMP++, PDU Object Invalid");
+ return SNMP_CLASS_INVALID_PDU;
+ }
+
+ //---------[ make sure target is valid ]------------------------------
+ if (!target.valid())
+ {
+ debugprintf(0, "-- SNMP++, Target Object Invalid");
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+
+ CTarget* ctarget = NULL;
+ UTarget* utarget = NULL;
+ OctetStr security_name;
+ int security_model;
+
+ switch (target.get_type()) {
+ case SnmpTarget::type_ctarget:
+ ctarget = (CTarget*)(&target);
+ break;
+ case SnmpTarget::type_utarget:
+ utarget = (UTarget*)(&target);
+ break;
+ case SnmpTarget::type_base:
+ debugprintf(0, "-- SNMP++, do not use SnmpTarget, use a CTarget or UTarget");
+ return SNMP_CLASS_INVALID_TARGET;
+ default:
+ // target is not known
+ debugprintf(0, "-- SNMP++, type of target is unknown!");
+ return SNMP_CLASS_UNSUPPORTED;
+ }
+
+ if (ctarget) {
+ debugprintf(3, "snmp::trap called with CTarget");
+ if (!ctarget->resolve_to_C( my_get_community, my_set_community, address,
+ my_timeout, my_retry, version))
+ {
+ debugprintf(0, "-- SNMP++, Resolve Fail (CTarget)");
+ return SNMP_CLASS_UNSUPPORTED;
+ }
+#ifdef _SNMPv3
+ if (version == version3)
+ {
+ debugprintf(0, "-- SNMP++, use UTarget for SNMPv3");
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+#endif
+ }
+ else { // target is not a CTarget:
+ if (utarget) {
+ debugprintf(3, "trap called with UTarget");
+ if (!utarget->resolve_to_U( security_name, security_model, address,
+ my_timeout, my_retry, version))
+ {
+ debugprintf(0, "-- SNMP++, Resolve Fail (UTarget)");
+ return SNMP_CLASS_UNSUPPORTED;
+ }
+#ifdef _SNMPv3
+ if (version != version3) {
+#endif
+ my_get_community = security_name;
+ if ((security_model != SNMP_SECURITY_MODEL_V1) &&
+ (security_model != SNMP_SECURITY_MODEL_V2)) {
+ debugprintf(0, "-- SNMP++, Target contains invalid security_model/version combination");
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+#ifdef _SNMPv3
+ } // end if (version != version3)
+#endif
+ }
+ else { // target is neither CTarget nor UTarget:
+ debugprintf(0, "-- SNMP++, Resolve Fail");
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+ }
+
+ //--------[ determine request id to use ]------------------------------
+ pdu.set_request_id( MyMakeReqId());
+
+ //--------[ check timestamp, if null use system time ]-----------------
+ check_notify_timestamp(pdu);
+
+ //------[ validate address to use ]-------------------------------------
+ if (!address.valid()) {
+ debugprintf(0, "-- SNMP++, Bad address");
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+
+ if ((address.get_type() != Address::type_ip) &&
+ (address.get_type() != Address::type_udp) )
+ {
+ debugprintf(0, "-- SNMP++, Bad address type");
+ return SNMP_CLASS_TL_UNSUPPORTED;
+ }
+
+ UdpAddress udp_address(address);
+ if (!udp_address.valid()) {
+ debugprintf(0, "-- SNMP++, copy address failed");
+ return SNMP_CLASS_RESOURCE_UNAVAIL;
+ }
+
+ //----------[ choose the target address port ]-----------------------
+ if ((address.get_type() == Address::type_ip) || !udp_address.get_port())
+ udp_address.set_port(SNMP_TRAP_PORT);
+
+ //----------[ based on the target type, choose v1 or v1 trap type ]-----
+ if ( version == version1)
+ pdu.set_type( sNMP_PDU_V1TRAP);
+ else // v2 and v3 use v2TRAP
+ pdu.set_type( sNMP_PDU_TRAP);
+
+ SnmpMessage snmpmsg;
+
+#ifdef _SNMPv3
+ if ( version == version3) {
+
+ OctetStr engine_id = v3MP::I->get_local_engine_id();
+ if (!utarget) {
+ debugprintf(0, "-- SNMP++, dont know how to handle SNMPv3 without UTarget!");
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+
+ // set context_engine_id of pdu, if it is not set
+ if (pdu.get_context_engine_id().len() == 0)
+ {
+ debugprintf(8, "Setting contextEngineID of Pdu to (%s)",
+ engine_id.get_printable());
+ pdu.set_context_engine_id(engine_id);
+ }
+
+ debugprintf(4,"Snmp::trap:");
+ debugprintf(4," engineID (%s), securityName (%s)\n securityModel (%i) security_level (%i)",
+ engine_id.get_printable(), security_name.get_printable(),
+ security_model, pdu.get_security_level());
+ debugprintf(4," Addr/Port (%s)",udp_address.get_printable());
+
+ status = snmpmsg.loadv3( pdu, engine_id, security_name,
+ security_model, (snmp_version)version);
+ }
+ else
+#endif
+ status = snmpmsg.load( pdu, my_get_community, (snmp_version) version);
+
+ if ( status != SNMP_CLASS_SUCCESS) {
+ debugprintf(0, "snmp message load error!");
+ return status;
+ }
+
+ lock();
+ //------[ send the trap ]
+#ifdef SNMP_PP_IPv6
+ if (udp_address.get_ip_version() == Address::version_ipv4)
+ {
+ if (iv_snmp_session != INVALID_SOCKET)
+ status = send_snmp_request(iv_snmp_session,
+ snmpmsg.data(), (size_t)snmpmsg.len(),
+ udp_address);
+ else
+ {
+ udp_address.map_to_ipv6();
+ status = send_snmp_request(iv_snmp_session_ipv6,
+ snmpmsg.data(), (size_t)snmpmsg.len(),
+ udp_address);
+ }
+ }
+ else
+ status = send_snmp_request(iv_snmp_session_ipv6,
+ snmpmsg.data(), (size_t)snmpmsg.len(),
+ udp_address);
+#else
+ status = send_snmp_request(iv_snmp_session, snmpmsg.data(),
+ (size_t)snmpmsg.len(), udp_address);
+#endif
+
+ unlock();
+ if (status != 0)
+ return SNMP_CLASS_TL_FAILED;
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+//----------------[ set notify_timestamp if it is null ]-------------
+#if defined (CPU) && CPU == PPC603
+
+ struct SCommTimer
+ {
+ unsigned long NumMS;
+ unsigned long FractMS;
+ };
+
+ extern "C"
+ {
+ void GetTime (struct SCommTimer * Time);
+ }
+#endif
+
+void Snmp::check_notify_timestamp(Pdu &pdu)
+{
+ // As we don't know, when the application was started,
+ // use a continuously increasing notify_timestamp
+ TimeTicks timestamp;
+ pdu.get_notify_timestamp( timestamp);
+ if (timestamp <= 0)
+ {
+#ifdef WIN32
+ struct _timeb timebuffer;
+ _ftime( &timebuffer );
+ timebuffer.time -= 1103760000; // knock off 35 years worth of seconds
+ timestamp = SAFE_ULONG_CAST((timebuffer.time * 100) +
+ (timebuffer.millitm / 10));
+#elif defined (CPU) && CPU == PPC603
+ SCommTimer theTime;
+
+ GetTime(&theTime); // This function must be defined by the application
+
+ timestamp = theTime.NumMS/10;
+#else
+ struct timeval tp;
+ gettimeofday(&tp, NULL);
+ tp.tv_sec -= 1103760000; // knock off 35 years worth of seconds
+ timestamp = (tp.tv_sec * 100) + (tp.tv_usec / 10000);
+#endif
+
+ pdu.set_notify_timestamp( timestamp);
+ }
+}
+
+//-----------------------[ read the notification filters ]----------------
+int Snmp::get_notify_filter(OidCollection &trapids,
+ TargetCollection &targets)
+{
+ CNotifyEvent *e = eventListHolder->notifyEventList()->GetEntry(this);
+
+ if (!e) return SNMP_CLASS_INVALID;
+
+ e->get_filter(trapids, targets);
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+// Set the port for listening to traps and informs.
+void Snmp::notify_set_listen_port(const int port)
+{
+ eventListHolder->notifyEventList()->set_listen_port(port);
+}
+
+// Get the port that is used for listening to traps and informs.
+int Snmp::notify_get_listen_port()
+{
+ return eventListHolder->notifyEventList()->get_listen_port();
+}
+
+//-----------------------[ register to get traps]-------------------------
+int Snmp::notify_register(const OidCollection &trapids,
+ const TargetCollection &targets,
+ const snmp_callback callback,
+ const void *callback_data)
+{
+ // remove any previous filters for this session
+ notify_unregister();
+
+ // assign callback and callback data info
+ notifycallback = callback;
+ notifycallback_data = (void *)callback_data;
+
+ // add to the notify queue
+ return eventListHolder->notifyEventList()->AddEntry(this, trapids, targets);
+}
+
+//-----------------------[ un-register to get traps]----------------------
+int Snmp::notify_unregister()
+{
+ // remove from the notify queue
+ eventListHolder->notifyEventList()->DeleteEntry(this);
+
+ // null out callback information
+ notifycallback = 0;
+ notifycallback_data = 0;
+
+ return SNMP_CLASS_SUCCESS;
+}
+
+//---------[ get / set engine ]-----------------------------------------
+// The main snmp engine used for all requests
+// async requests return out early and don't wait in here for
+// the response
+int Snmp::snmp_engine( Pdu &pdu, // pdu to use
+ long int non_reps, // # of non repititions
+ long int max_reps, // # of max repititions
+ const SnmpTarget &target, // from this target
+ const snmp_callback cb,// callback for async calls
+ const void *cbd, // callback data
+ SnmpSocket fd,
+ int reports_received)
+
+{
+ long req_id = 0; // pdu request id
+ int status; // send status
+
+#ifdef _SNMPv3
+ // save original PDU for later reference
+ Pdu backupPdu = pdu;
+
+ for (int maxloops=0; maxloops<3; maxloops++)
+ {
+#endif
+
+ unsigned short pdu_action; // type of pdu to build
+ unsigned short action; // type of pdu to build
+ unsigned long my_timeout; // target specific timeout
+ int my_retry; // target specific retry
+
+ OctetStr my_get_community;
+ OctetStr my_set_community;
+ GenAddress address;
+ unsigned char version;
+
+ //---------[ make sure pdu is valid ]--------------------------
+ if ( !pdu.valid())
+ return SNMP_CLASS_INVALID_PDU;
+
+ //---------[ depending on user action, map the correct pdu action]
+ action = pdu.get_type();
+ map_action(action, pdu_action);
+
+ //---------[ check for correct mode ]---------------------------
+ // if the class was constructed as a blocked model, callback=0
+ // and async calls are attempted, an error is returned
+ if (( cb == 0) &&
+ ((action == sNMP_PDU_GET_ASYNC) ||
+ (action == sNMP_PDU_SET_ASYNC) ||
+ (action == sNMP_PDU_GETNEXT_ASYNC) ||
+ (action == sNMP_PDU_GETBULK_ASYNC) ||
+ (action == sNMP_PDU_INFORM_ASYNC)))
+ return SNMP_CLASS_INVALID_CALLBACK;
+
+ //---------[ more mode checking ]--------------------------------
+ // if the class was constructed as an async model, callback = something
+ // and blocked calls are attempted, an error is returned
+ if (( cb != 0) &&
+ ((action == sNMP_PDU_GET) ||
+ (action == sNMP_PDU_SET) ||
+ (action == sNMP_PDU_GETNEXT) ||
+ (action == sNMP_PDU_GETBULK) ||
+ (action == sNMP_PDU_INFORM)))
+ return SNMP_CLASS_INVALID_CALLBACK;
+
+ //---------[ make sure target is valid ]-------------------------
+ // make sure that the target is valid
+ if ( ! target.valid())
+ return SNMP_CLASS_INVALID_TARGET;
+
+ OctetStr community_string;
+ OctetStr security_name;
+ int security_model;
+ const CTarget* ctarget = NULL;
+ const UTarget* utarget = NULL;
+
+ switch (target.get_type())
+ {
+ case SnmpTarget::type_ctarget:
+ ctarget = (CTarget*)(&target);
+ break;
+ case SnmpTarget::type_utarget:
+ utarget = (UTarget*)(&target);
+ break;
+ case SnmpTarget::type_base:
+ debugprintf(0, "-- SNMP++, do not use SnmpTarget,"
+ "use a CTarget or UTarget");
+ return SNMP_CLASS_INVALID_TARGET;
+ default:
+ /* target is not known */
+ debugprintf(0, "-- SNMP++, type of target is unknown!");
+ return SNMP_CLASS_UNSUPPORTED;
+ }
+
+ if (ctarget) /* Is is a CTarget? */
+ {
+ debugprintf(3, "snmp_engine called with CTarget");
+ if (!ctarget->resolve_to_C( my_get_community, my_set_community,
+ address, my_timeout, my_retry, version))
+ {
+ debugprintf(0, "-- SNMP++, Resolve Fail (CTarget)");
+ return SNMP_CLASS_UNSUPPORTED;
+ }
+#ifdef _SNMPv3
+ if ((version == version3) ||
+ (action == sNMP_PDU_REPORT))
+ {
+ debugprintf(0, "-- SNMP++, use UTarget for SNMPv3");
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+#endif
+ //----------[ use the appropriate community string ]-----------------
+ if (( action == sNMP_PDU_GET) ||
+ ( action == sNMP_PDU_GET_ASYNC) ||
+ ( action == sNMP_PDU_GETNEXT) ||
+ ( action == sNMP_PDU_GETNEXT_ASYNC) ||
+ ( action == sNMP_PDU_GETBULK) ||
+ ( action == sNMP_PDU_GETBULK_ASYNC) ||
+ ( action == sNMP_PDU_INFORM) ||
+ ( action == sNMP_PDU_INFORM_ASYNC) ||
+ ( action == sNMP_PDU_RESPONSE))
+ community_string = my_get_community;
+ else /* got to be a set */
+ community_string = my_set_community;
+ }
+ else if (utarget) /* Is is a UTarget? */
+ {
+ debugprintf(3, "snmp_engine called with UTarget");
+ if (!utarget->resolve_to_U( security_name, security_model,
+ address, my_timeout,
+ my_retry, version))
+ {
+ debugprintf(0, "-- SNMP++, Resolve Fail (UTarget)");
+ return SNMP_CLASS_UNSUPPORTED;
+ }
+#ifdef _SNMPv3
+ if (version != version3)
+ {
+#endif
+ community_string = security_name;
+ if (((version == version1) && (security_model != SNMP_SECURITY_MODEL_V1)) ||
+ ((version == version2c) && (security_model != SNMP_SECURITY_MODEL_V2)))
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("Snmp: Target does not match SNMP version: (security model) (version)");
+ LOG(security_model);
+ LOG(version);
+ LOG_END;
+
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+#ifdef _SNMPv3
+ } // end if (version != version3)
+#endif
+ }
+ else
+ { // target is neither CTarget nor UTarget (should not happen)
+ debugprintf(0, "-- SNMP++, Resolve Fail");
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+
+ if (!address.valid())
+ {
+ debugprintf(0, "-- SNMP++, Target contains invalid address");
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+
+ //----------[ validate the target address ]--------------------------
+ if ((address.get_type() != Address::type_ip) &&
+ (address.get_type() != Address::type_udp) )
+ {
+ debugprintf(0, "-- SNMP++, Bad address type");
+ return SNMP_CLASS_TL_UNSUPPORTED;
+ }
+
+ UdpAddress udp_address(address);
+ if (!udp_address.valid())
+ {
+ debugprintf(0, "-- SNMP++, Bad address");
+ return SNMP_CLASS_RESOURCE_UNAVAIL;
+ }
+
+ //----------[ choose the target address port ]-----------------------
+ if ((address.get_type() == Address::type_ip) || !udp_address.get_port())
+ {
+ if (pdu_action == sNMP_PDU_INFORM)
+ udp_address.set_port(SNMP_TRAP_PORT);
+ else
+ udp_address.set_port(SNMP_PORT);
+ }
+ // otherwise port was already set
+
+ // check socket to use
+ SnmpSocket iv_session_used = fd;
+
+ if (fd == INVALID_SOCKET)
+ {
+#ifdef SNMP_PP_IPv6
+ if (udp_address.get_ip_version() == Address::version_ipv4)
+ {
+ if (iv_snmp_session != INVALID_SOCKET)
+ iv_session_used = iv_snmp_session;
+ else
+ {
+ udp_address.map_to_ipv6();
+ iv_session_used = iv_snmp_session_ipv6;
+ }
+ }
+ else
+ iv_session_used = iv_snmp_session_ipv6;
+#else
+ iv_session_used = iv_snmp_session;
+#endif
+ }
+
+ if ((pdu_action != sNMP_PDU_RESPONSE) &&
+ (pdu_action != sNMP_PDU_REPORT))
+ {
+ // set error index to none
+ pdu.set_error_index(0);
+
+ // determine request id to use
+ req_id = MyMakeReqId();
+ pdu.set_request_id(req_id);
+ }
+
+ //---------[ map GetBulk over v1 to GetNext ]-------------------------
+ if (( pdu_action == sNMP_PDU_GETBULK)&&( (snmp_version)version== version1))
+ pdu_action = sNMP_PDU_GETNEXT;
+ if ( pdu_action == sNMP_PDU_GETBULK) {
+ pdu.set_error_status((int) non_reps);
+ pdu.set_error_index((int) max_reps);
+ }
+
+ pdu.set_type( pdu_action);
+ SnmpMessage snmpmsg;
+
+#ifdef _SNMPv3
+ struct V3CallBackData *v3CallBackData = 0;
+
+ if (version == version3)
+ {
+ if (!utarget)
+ {
+ debugprintf(0, "-- SNMP++, need UTarget to send SNMPv3 message!");
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+ OctetStr engine_id;
+ utarget->get_engine_id(engine_id);
+ if (engine_id.len() == 0)
+ {
+ if (v3MP::I->get_from_engine_id_table(engine_id,
+ (char*)udp_address.get_printable())
+ == SNMPv3_MP_OK )
+ {
+ // Override const here
+ ((UTarget*)utarget)->set_engine_id(engine_id);
+ }
+ else
+ {
+ // check if engine id discovery is enabled
+ if ((!v3MP::I->get_usm()->is_discovery_enabled()) &&
+ ((pdu_action == sNMP_PDU_GET) ||
+ (pdu_action == sNMP_PDU_SET) ||
+ (pdu_action == sNMP_PDU_GETNEXT) ||
+ (pdu_action == sNMP_PDU_GETBULK) ||
+ (pdu_action == sNMP_PDU_INFORM)))
+ {
+ // no engine id, discovery disabled and not authoritytive
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("Not authoritative and discovery disabled. Target without engine id is invalid");
+ LOG_END;
+ return SNMP_CLASS_INVALID_TARGET;
+ }
+ }
+ }
+ // set context_engine_id of pdu, if it is not set
+ if (pdu.get_context_engine_id().len() == 0)
+ {
+ debugprintf(8, "Setting contextEngineID of Pdu to (%s)",
+ engine_id.get_printable());
+ pdu.set_context_engine_id(engine_id);
+ backupPdu.set_context_engine_id(engine_id);
+ }
+
+ debugprintf(4,"Snmp::snmp_engine: engineID (%s), securityName (%s)"
+ "securityModel (%i) security_level (%i)",
+ engine_id.get_printable(), security_name.get_printable(),
+ security_model, pdu.get_security_level());
+ debugprintf(4," Addr/Port (%s)",udp_address.get_printable());
+
+ status = snmpmsg.loadv3( pdu, engine_id, security_name,
+ security_model, (snmp_version)version);
+ }
+ else
+#endif
+ status = snmpmsg.load( pdu, community_string,(snmp_version) version);
+
+ if ( status != SNMP_CLASS_SUCCESS)
+ {
+ debugprintf(0, "snmp message load error!");
+ return status;
+ }
+
+ // first add the message to the queue
+ if ((pdu_action != sNMP_PDU_RESPONSE) &&
+ (pdu_action != sNMP_PDU_REPORT))
+ {
+#ifdef _SNMPv3
+ if ((version == version3) && ((action == sNMP_PDU_GET_ASYNC) ||
+ (action == sNMP_PDU_SET_ASYNC) ||
+ (action == sNMP_PDU_GETNEXT_ASYNC) ||
+ (action == sNMP_PDU_GETBULK_ASYNC) ||
+ (action == sNMP_PDU_INFORM_ASYNC))) {
+ // add callback for v3
+ v3CallBackData = new struct V3CallBackData;
+
+ v3CallBackData->pdu = new Pdu(pdu);
+ v3CallBackData->pdu->set_type(backupPdu.get_type());
+ v3CallBackData->non_reps = non_reps;
+ v3CallBackData->max_reps = max_reps;
+
+ v3CallBackData->target = new UTarget(*utarget);
+ v3CallBackData->oldCallback = cb;
+ v3CallBackData->cbd = cbd;
+ v3CallBackData->reports_received = reports_received;
+
+ // Add the message to the message queue
+ eventListHolder->snmpEventList()->AddEntry(req_id, this, iv_session_used,
+ target, pdu, snmpmsg.data(), (size_t) snmpmsg.len(),
+ udp_address, v3CallBack, (void *)v3CallBackData);
+ }
+ else
+#endif
+ {
+ eventListHolder->snmpEventList()->AddEntry(req_id, this, iv_session_used,
+ target, pdu, snmpmsg.data(), (size_t) snmpmsg.len(),
+ udp_address, cb, (void *)cbd);
+ }
+ }
+
+ //------[ send the request ]
+ lock();
+ status = send_snmp_request(iv_session_used,
+ snmpmsg.data(), (size_t) snmpmsg.len(),
+ udp_address);
+ unlock();
+
+ if (status != 0)
+ {
+ if ((pdu_action != sNMP_PDU_RESPONSE) &&
+ (pdu_action != sNMP_PDU_REPORT))
+ {
+ // remove the id from message queue
+ eventListHolder->snmpEventList()->lock();
+ eventListHolder->snmpEventList()->DeleteEntry(req_id);
+ eventListHolder->snmpEventList()->unlock();
+
+#ifdef _SNMPv3
+ // dont forget to delete this
+ if (v3CallBackData) deleteV3Callback(v3CallBackData);
+#endif
+ }
+ return SNMP_CLASS_TL_FAILED;
+ }
+
+ if ((pdu_action == sNMP_PDU_RESPONSE) ||
+ (pdu_action == sNMP_PDU_REPORT))
+ return SNMP_CLASS_SUCCESS; // don't wait for an answer
+
+ //----[ if an async mode request then return success ]-----
+ if (( action == sNMP_PDU_GET_ASYNC) ||
+ ( action == sNMP_PDU_SET_ASYNC) ||
+ ( action == sNMP_PDU_GETNEXT_ASYNC) ||
+ ( action == sNMP_PDU_GETBULK_ASYNC) ||
+ ( action == sNMP_PDU_INFORM_ASYNC))
+ return SNMP_CLASS_SUCCESS;
+
+ // Now wait for the response (or timeout) for our message.
+ // This handles any necessary retries.
+ status = eventListHolder->SNMPBlockForResponse(req_id, pdu);
+
+ if (pdu.get_type() != REPORT_MSG) {
+#ifdef _SNMPv3
+ if (status == SNMPv3_MP_OK)
+ return SNMP_CLASS_SUCCESS;
+ else
+#endif
+ return status;
+ }
+#ifdef _SNMPv3
+ else
+ if (status == SNMPv3_USM_DECRYPTION_ERROR)
+ return status;
+
+ // We received a REPORT-MSG, check if we should try another time
+ Vb first_vb;
+ Oid first_oid;
+ pdu.get_vb(first_vb,0);
+ first_vb.get_oid(first_oid);
+
+ debugprintf(1,"received oid: %s with value: %s",
+ first_vb.get_printable_oid(), first_vb.get_printable_value());
+ debugprintf(1, "%s", error_msg(first_oid));
+
+ switch (maxloops)
+ {
+ case 0:
+ {
+ // This was our first try, so we may receive a unknown engine id
+ // report or a not in time window report
+ if (first_oid == oidUsmStatsUnknownEngineIDs)
+ {
+ pdu = backupPdu; // restore pdu and try again
+ break;
+ }
+ else if (first_oid == oidUsmStatsNotInTimeWindows)
+ {
+ ++maxloops; // increase it, as the next request must succeed
+ pdu = backupPdu; // restore pdu and try again
+ break;
+ }
+ return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
+ }
+ case 1:
+ {
+ // This was the second try, engine id discovery should be ok
+ // so test only for not in time report
+ if (first_oid == oidUsmStatsNotInTimeWindows)
+ {
+ pdu = backupPdu; // restore pdu and try again
+ break;
+ }
+ return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
+ }
+ case 2:
+ {
+ // We tried three times: one for engine id discovery, one for
+ // time sync and we still get a report --> somethings wrong!
+ return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
+ }
+ }
+ }
+#endif
+ return status;
+}
+
+#ifdef _SNMPv3
+int Snmp::engine_id_discovery(OctetStr &engine_id,
+ const int timeout_sec,
+ const UdpAddress &addr)
+{
+ unsigned char *message;
+ int message_length;
+ SnmpSocket sock;
+ SnmpMessage snmpmsg;
+
+ unsigned char snmpv3_message[60] = {
+ 0x30, 0x3a,
+ 0x02, 0x01, 0x03, // Version: 3
+ 0x30, 0x0f, // global header length 15
+ 0x02, 0x03, 0x01, 0x00, 0x00, // message id
+ 0x02, 0x02, 0x10, 0x00, // message max size
+ 0x04, 0x01, 0x04, // flags (reportable set)
+ 0x02, 0x01, 0x03, // security model USM
+ 0x04, 0x10, // security params
+ 0x30, 0x0e,
+ 0x04, 0x00, // no engine id
+ 0x02, 0x01, 0x00, // boots 0
+ 0x02, 0x01, 0x00, // time 0
+ 0x04, 0x00, // no user name
+ 0x04, 0x00, // no auth par
+ 0x04, 0x00, // no priv par
+ 0x30, 0x12,
+ 0x04, 0x00, // no context engine id
+ 0x04, 0x00, // no context name
+ 0xa0, 0x0c, // GET PDU
+ 0x02, 0x02, 0x34, 0x26, // request id
+ 0x02, 0x01, 0x00, // error status no error
+ 0x02, 0x01, 0x00, // error index 0
+ 0x30, 0x00 // no data
+ };
+
+ message = (unsigned char *)snmpv3_message;
+ message_length = 60;
+
+ engine_id.clear();
+
+ UdpAddress uaddr(addr);
+
+#ifdef SNMP_PP_IPv6
+ if (uaddr.get_ip_version() == Address::version_ipv4)
+ {
+ if (iv_snmp_session != INVALID_SOCKET)
+ sock = iv_snmp_session;
+ else
+ {
+ uaddr.map_to_ipv6();
+ sock = iv_snmp_session_ipv6;
+ }
+ }
+ else
+ sock = iv_snmp_session_ipv6;
+#else
+ sock = iv_snmp_session;
+#endif
+
+ lock();
+ if (send_snmp_request(sock, message, message_length, uaddr) < 0)
+ {
+ debugprintf(0, "Error sending message.");
+ unlock();
+ return SNMP_CLASS_TL_FAILED;
+ }
+
+ // now wait for the responses
+ Pdu dummy_pdu;
+ int nfound = 0;
+ msec end_time;
+ struct timeval fd_timeout;
+
+ end_time += timeout_sec * 1000;
+
+#ifdef HAVE_POLL_SYSCALL
+ struct pollfd readfds;
+ int timeout;
+#else
+ fd_set readfds;
+#endif
+
+ do
+ {
+ bool something_to_receive = false;
+ end_time.GetDeltaFromNow(fd_timeout);
+
+#ifdef HAVE_POLL_SYSCALL
+ memset(&readfds, 0, sizeof(struct pollfd));
+ readfds.fd = sock;
+ readfds.events = POLLIN;
+ timeout = fd_timeout.tv_sec * 1000 + fd_timeout.tv_usec / 1000;
+ nfound = poll(&readfds, 1, timeout);
+ if ((nfound > 0) && (readfds.revents & POLLIN))
+ something_to_receive = true;
+#else
+ FD_ZERO(&readfds);
+ FD_SET(sock, &readfds);
+
+ nfound = select((int)(sock + 1), &readfds, NULL, NULL, &fd_timeout);
+ if ((nfound > 0) && (FD_ISSET(sock, &readfds)))
+ something_to_receive = true;
+#endif
+
+ if (something_to_receive)
+ {
+ // receive message
+ UdpAddress from;
+ int res = receive_snmp_response(sock, *this, dummy_pdu,
+ from, engine_id, true /* process_msg */);
+ if ((res == SNMP_CLASS_SUCCESS) ||
+ (res == SNMPv3_MP_UNKNOWN_PDU_HANDLERS))
+ {
+ //dummy_pdu.get_context_engine_id(engine_id);
+ debugprintf(3, "Response received from (%s) id %s.",
+ from.get_printable(), engine_id.get_printable());
+ unlock();
+ return SNMP_CLASS_SUCCESS;
+ }
+ else
+ {
+ debugprintf(0, "Error receiving discovery response.");
+ }
+ }
+ } while ((nfound > 0) ||
+ (fd_timeout.tv_sec > 0) || (fd_timeout.tv_usec > 0));
+ unlock();
+
+ return SNMP_CLASS_TIMEOUT;
+}
+#endif
+
+// Send a SNMP Broadcast message.
+int Snmp::broadcast_discovery(UdpAddressCollection &addresses,
+ const int timeout_sec,
+ const UdpAddress &addr,
+ const snmp_version version,
+ const OctetStr *community)
+{
+ unsigned char *message;
+ int message_length;
+ SnmpSocket sock;
+ SnmpMessage snmpmsg;
+
+#ifdef _SNMPv3
+ unsigned char snmpv3_broadcast_message[60] = {
+ 0x30, 0x3a,
+ 0x02, 0x01, 0x03, // Version: 3
+ 0x30, 0x0f, // global header length 15
+ 0x02, 0x03, 0x01, 0x00, 0x00, // message id
+ 0x02, 0x02, 0x10, 0x00, // message max size
+ 0x04, 0x01, 0x04, // flags (reportable set)
+ 0x02, 0x01, 0x03, // security model USM
+ 0x04, 0x10, // security params
+ 0x30, 0x0e,
+ 0x04, 0x00, // no engine id
+ 0x02, 0x01, 0x00, // boots 0
+ 0x02, 0x01, 0x00, // time 0
+ 0x04, 0x00, // no user name
+ 0x04, 0x00, // no auth par
+ 0x04, 0x00, // no priv par
+ 0x30, 0x12,
+ 0x04, 0x00, // no context engine id
+ 0x04, 0x00, // no context name
+ 0xa0, 0x0c, // GET PDU
+ 0x02, 0x02, 0x34, 0x26, // request id
+ 0x02, 0x01, 0x00, // error status no error
+ 0x02, 0x01, 0x00, // error index 0
+ 0x30, 0x00 // no data
+ };
+
+ if (version == version3)
+ {
+ message = (unsigned char *)snmpv3_broadcast_message;
+ message_length = 60;
+ }
+ else
+#endif
+ {
+ Pdu pdu;
+ Vb vb;
+ OctetStr get_community;
+
+ vb.set_oid("1.3.6.1.2.1.1.1.0");
+ pdu +=vb;
+ pdu.set_error_index(0); // set error index to none
+ pdu.set_request_id(MyMakeReqId()); // determine request id to use
+ pdu.set_type(sNMP_PDU_GET); // set pdu type
+
+ if (community)
+ get_community = *community;
+ else
+ get_community = "public";
+
+ int status = snmpmsg.load(pdu, get_community, version);
+ if (status != SNMP_CLASS_SUCCESS)
+ {
+ debugprintf(0, "Error encoding broadcast pdu (%i).", status);
+ return status;
+ }
+ message = snmpmsg.data();
+ message_length = snmpmsg.len();
+ }
+
+ UdpAddress uaddr(addr);
+
+#ifdef SNMP_PP_IPv6
+ if (uaddr.get_ip_version() == Address::version_ipv4)
+ {
+ if (iv_snmp_session != INVALID_SOCKET)
+ sock = iv_snmp_session;
+ else
+ {
+ uaddr.map_to_ipv6();
+ sock = iv_snmp_session_ipv6;
+ }
+ }
+ else
+ sock = iv_snmp_session_ipv6;
+#else
+ sock = iv_snmp_session;
+#endif
+
+ lock();
+ if (send_snmp_request(sock, message, message_length, uaddr) < 0)
+ {
+ debugprintf(0, "Error sending broadast.");
+ unlock();
+ return SNMP_CLASS_TL_FAILED;
+ }
+
+ // now wait for the responses
+ Pdu dummy_pdu;
+ OctetStr engine_id;
+ int nfound = 0;
+ msec end_time;
+ struct timeval fd_timeout;
+
+ end_time += timeout_sec * 1000;
+
+#ifdef HAVE_POLL_SYSCALL
+ struct pollfd readfds;
+ int timeout;
+#else
+ fd_set readfds;
+#endif
+
+ do
+ {
+ bool something_to_receive = false;
+ end_time.GetDeltaFromNow(fd_timeout);
+
+#ifdef HAVE_POLL_SYSCALL
+ memset(&readfds, 0, sizeof(struct pollfd));
+ readfds.fd = sock;
+ readfds.events = POLLIN;
+ timeout = fd_timeout.tv_sec * 1000 + fd_timeout.tv_usec / 1000;
+ nfound = poll(&readfds, 1, timeout);
+ if ((nfound > 0) && (readfds.revents & POLLIN))
+ something_to_receive = true;
+#else
+ FD_ZERO(&readfds);
+ FD_SET(sock, &readfds);
+
+ nfound = select((int)(sock + 1), &readfds, NULL, NULL, &fd_timeout);
+ if ((nfound > 0) && (FD_ISSET(sock, &readfds)))
+ something_to_receive = true;
+#endif
+
+ if (something_to_receive)
+ {
+ // receive message
+ UdpAddress from;
+ if (receive_snmp_response(sock, *this, dummy_pdu,
+ from, engine_id, false /* process_msg */)
+ == SNMP_CLASS_SUCCESS)
+ {
+ addresses += from;
+ }
+ else
+ {
+ debugprintf(0, "Error receiving broadcast response.");
+ }
+ }
+ } while ((nfound > 0) ||
+ (fd_timeout.tv_sec > 0) || (fd_timeout.tv_usec > 0));
+ unlock();
+
+#ifdef __DEBUG
+ for (int i=0; i < addresses.size(); ++i)
+ {
+ debugprintf(3, "Broadcast response received from (%s).",
+ addresses[i].get_printable());
+ }
+#endif
+ return 0;
+}
+
+// Starts the working thread for the recovery of the pending events
+bool Snmp::start_poll_thread(const int timeout)
+{
+#ifdef _THREADS
+ // store the timeout value for later
+ m_iPollTimeOut = timeout;
+
+ // if we are already running return ok
+ if (m_bThreadRunning == true) return true;
+
+ // since we are here, things must be fine so far...
+ m_bThreadRunning = true;
+
+ // start the ProcessThread function....
+#ifdef WIN32
+ DWORD id;
+ m_hThread = CreateThread(NULL, 0,
+ (LPTHREAD_START_ROUTINE)&Snmp::process_thread,
+ this, 0, &id);
+ if (m_hThread == NULL)
+ {
+ debugprintf(0, "Could not create ProcessThread");
+ m_bThreadRunning = false;
+ }
+#elif defined (CPU) && CPU == PPC603
+ m_hThread = taskSpawn("Snmp::process_thread", 0, 0, 10000, (int (*)(...))Snmp::process_thread, (int)this, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ if (m_hThread == ERROR)
+ {
+ // Could not create thread.
+ debugprintf(0, "Could not create ProcessThread");
+ m_bThreadRunning = false;
+ }
+#else
+ int rc = pthread_create(&m_hThread, NULL, Snmp::process_thread,
+ (void*) this);
+ if (rc)
+ {
+ // Could not create thread.
+ debugprintf(0, "Could not create ProcessThread");
+ m_bThreadRunning = false;
+ }
+#endif
+#endif
+ return m_bThreadRunning;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// stop_poll_thread
+// Stops the recovery of the pending events
+//
+///////////////////////////////////////////////////////////////////////////////
+void Snmp::stop_poll_thread()
+{
+ if (m_bThreadRunning == false) return;
+
+#ifdef _THREADS
+ // stop the thread
+ m_bThreadRunning = false;
+
+ // Wait for the working thread to stop....
+#ifdef WIN32
+ ::WaitForSingleObject(m_hThreadEndEvent, INFINITE);
+ CloseHandle(m_hThread);
+#elif defined (CPU) && CPU == PPC603
+ while (taskIdVerify(m_hThread) == OK)
+ taskDelay(10);
+#else
+ //int *status; // not used
+ pthread_join(m_hThread, NULL /*(void**) &status */);
+#endif
+#endif
+}
+
+#ifdef WIN32
+int Snmp::process_thread(Snmp *pSnmp)
+{
+#else
+void* Snmp::process_thread(void *arg)
+{
+ Snmp* pSnmp = (Snmp*) arg;
+#endif // !WIN32
+
+ // Loop as long as we haven't stopped
+ while (pSnmp->is_running())
+ {
+ pSnmp->eventListHolder
+ ->SNMPProcessEvents(pSnmp->m_iPollTimeOut);
+ }
+
+#ifdef _THREADS
+#ifdef WIN32
+ ::SetEvent(pSnmp->m_hThreadEndEvent);
+#else
+#if defined (CPU) && CPU == PPC603
+ exit(0);
+#else
+ pthread_exit(0);
+#endif
+#endif
+#endif
+ return 0;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## v3.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+
+char v3_cpp_version[]="#(@) SNMP++ $Id: v3.cpp 274 2006-11-03 19:21:16Z katz $";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _MSC_VER
+#ifndef __BCPLUSPLUS__
+#include <unistd.h>
+#endif
+#endif
+
+#include "snmp_pp/log.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/octet.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define MAX_LINE_LEN 100
+
+const char *logfilename = NULL;
+int debug_level = 19;
+
+// Set the amount of log messages you want to get.
+void debug_set_level(const int db_level)
+{
+ debug_level = db_level;
+}
+
+#ifdef _DEBUG
+
+void debughexcprintf(int db_level, const char *comment,
+ const unsigned char *data, const unsigned int len)
+{
+ if (db_level > debug_level) return;
+
+ char *buf = new char[MAX_LOG_SIZE];
+
+ if (NULL == buf) return; // not good!
+
+ if (comment && (strlen(comment) < MAX_LOG_SIZE - 25))
+ {
+ sprintf(buf, "%s (length %i): \n", comment, len);
+ LOG_BEGIN(DEBUG_LOG | 3);
+ LOG(buf);
+ LOG_END;
+ }
+
+ char *tmp = new char[4];
+
+ if (NULL == tmp) { delete [] buf ; return; }
+
+ buf[0] = '\0';
+ for (unsigned int i=0; i<len; i++)
+ {
+ sprintf(tmp, "%02X ", data[i]);
+ strcat(buf, tmp);
+
+ if ((i+1)%4==0)
+ {
+ sprintf(tmp, " ");
+ strcat(buf, tmp);
+ }
+
+ if ((i+1)%16==0)
+ {
+ LOG_BEGIN(DEBUG_LOG | 3);
+ LOG(buf);
+ LOG_END;
+
+ // reset the buf
+ buf[0] = '\0';
+ }
+ }
+
+ if (buf[0] != '\0')
+ {
+ // print the last part of the message
+ LOG_BEGIN(DEBUG_LOG | 3);
+ LOG(buf);
+ LOG_END;
+ }
+
+ // and cleanup...
+ delete [] tmp;
+ delete [] buf;
+}
+
+void debugprintf(int db_level, const char *format, ...)
+{
+ if (db_level > debug_level) return;
+
+ va_list args;
+
+ va_start(args, format);
+
+/////////////////////////////////////////////////////////////////
+// NOTE: This would be the best way to go (by using _vscprintf),
+// but it is part of the VC7.0, and it can't be used in VC6.0
+/////////////////////////////////////////////////////////////////
+ // _vscprintf doesn't count terminating '\0' so we add one more
+// int len = _vscprintf( format, args ) + 1;
+
+ char *buf = new char[MAX_LOG_SIZE];
+
+ if (NULL == buf) return; // not good!
+
+ vsprintf(buf, format, args);
+
+ va_end(args);
+
+ LOG_BEGIN(DEBUG_LOG | 1);
+ LOG(buf);
+ LOG_END;
+
+ // and cleanup...
+ delete [] buf;
+}
+
+#else
+#if (defined (__STRICT_ANSI__) || !defined (__GNUC__)) && !defined (_MSC_VER)
+void debugprintf(int, const char*, ...)
+{
+}
+#endif
+
+#endif
+
+#ifdef _SNMPv3
+
+unsigned char *v3strcpy(const unsigned char *src, const int srclen)
+{
+ unsigned char *res = new unsigned char[srclen+1];
+ if (!res) return NULL;
+ memcpy(res, src, srclen);
+ res[srclen] = '\0';
+ return res;
+}
+
+
+int unsignedCharCompare(const unsigned char *str1, const long int ptr1len,
+ const unsigned char *str2, const long int ptr2len)
+{
+ if (ptr1len != ptr2len) return 0;
+
+ const unsigned char *ptr1 = str1;
+ const unsigned char *ptr2 = str2;
+
+ for (int i=0; i < ptr1len; ++i)
+ if (*ptr1++ != *ptr2++) return 0;
+
+ return 1;
+}
+
+// Encode the given string into the output buffer.
+void encodeString(const unsigned char* in, const int in_length, char* out)
+{
+ char* out_ptr = out;
+ const unsigned char* in_ptr = in;
+
+ for (int i=0; i<in_length; i++)
+ {
+ *out_ptr++ = 64 + ((*in_ptr >> 4) & 0xF);
+ *out_ptr++ = 64 + (*in_ptr++ & 0xF);
+ }
+}
+
+// Decode the given encoded string into the output buffer.
+void decodeString(const unsigned char* in, const int in_length, char* out)
+{
+ char* out_ptr = out;
+ const unsigned char* in_ptr = in;
+
+ if ((in_length % 2) || (in_length < 0))
+ {
+ LOG_BEGIN(WARNING_LOG | 3);
+ LOG("decodeString: Illegal input length (len)");
+ LOG(in_length);
+ LOG_END;
+
+ *out = 0;
+ return;
+ }
+
+ for (int i= in_length / 2; i > 0; i--)
+ {
+ *out_ptr = (*in_ptr++ & 0xF) << 4;
+ *out_ptr++ |= (*in_ptr++ & 0xF);
+ }
+ *out_ptr = 0; // make sure it is null terminated
+}
+
+// Read the bootCounter of the given engineID stored in the given file.
+int getBootCounter(const char *fileName,
+ const OctetStr &engineId, unsigned int &boot)
+{
+ char line[MAX_LINE_LEN];
+ char encoded[MAXLENGTH_ENGINEID * 2 + 2];
+ int len = engineId.len();
+
+ FILE *file;
+
+ boot = 0;
+ file = fopen(fileName, "r");
+
+ if (!file)
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("getBootCounter: Could not open (file)");
+ LOG(fileName);
+ LOG_END;
+
+ return SNMPv3_FILEOPEN_ERROR;
+ }
+
+ if (len > MAXLENGTH_ENGINEID)
+ {
+ LOG_BEGIN(ERROR_LOG | 3);
+ LOG("getBootCounter: engine id too long, ignoring last bytes (len) (max)");
+ LOG(len);
+ LOG(MAXLENGTH_ENGINEID);
+ LOG_END;
+
+ len = MAXLENGTH_ENGINEID;
+ }
+
+ encodeString(engineId.data(), len, encoded);
+ encoded[2*len]=' ';
+ encoded[2*len + 1] = 0;
+
+ while (fgets(line, MAX_LINE_LEN, file))
+ {
+ line[MAX_LINE_LEN - 1] = 0;
+ /* ignore comments */
+ if (line[0]=='#')
+ continue;
+
+ if (!strncmp(encoded, line, len*2 + 1))
+ {
+ /* line starts with engineId */
+ char* ptr = line;
+ /* skip until first space */
+ while (*ptr != 0 && *ptr != ' ')
+ ptr++;
+
+ if (*ptr == 0)
+ {
+ fclose(file);
+
+ LOG_BEGIN(ERROR_LOG | 3);
+ LOG("getBootCounter: Illegal line: (file) (line)");
+ LOG(fileName);
+ LOG(line);
+ LOG_END;
+
+ return SNMPv3_FILE_ERROR;
+ }
+ boot = atoi(ptr);
+ fclose(file);
+
+ LOG_BEGIN(DEBUG_LOG | 3);
+ LOG("getBootCounter: found entry (file) (engine id) (boot counter)");
+ LOG(fileName);
+ LOG(engineId.get_printable());
+ LOG(boot);
+ LOG_END;
+
+ return SNMPv3_OK;
+ }
+ }
+ fclose(file);
+
+ LOG_BEGIN(WARNING_LOG | 3);
+ LOG("getBootCounter: No entry found (file) (engine id)");
+ LOG(fileName);
+ LOG(engineId.get_printable());
+ LOG_END;
+
+ return SNMPv3_NO_ENTRY_ERROR;
+}
+
+// Store the bootCounter of the given engineID in the given file.
+int saveBootCounter(const char *fileName,
+ const OctetStr &engineId, const unsigned int boot)
+{
+ char line[MAX_LINE_LEN];
+ char tmpFileName[MAXLENGTH_FILENAME];
+ char encoded[MAXLENGTH_ENGINEID * 2 + 2];
+ int found = FALSE;
+ int len = engineId.len();
+ FILE *file_in, *file_out;
+
+ tmpFileName[0] = 0;
+ sprintf(tmpFileName, "%s.tmp",fileName);
+ if (len > MAXLENGTH_ENGINEID)
+ {
+ LOG_BEGIN(ERROR_LOG | 3);
+ LOG("saveBootCounter: engine id too long, ignoring last bytes (len) (max)");
+ LOG(len);
+ LOG(MAXLENGTH_ENGINEID);
+ LOG_END;
+
+ len = MAXLENGTH_ENGINEID;
+ }
+
+ file_in = fopen(fileName, "r");
+ if (!file_in)
+ {
+ file_in = fopen(fileName, "w");
+ if (!file_in)
+ {
+ LOG_BEGIN(ERROR_LOG | 3);
+ LOG("saveBootCounter: could not create new file (file)");
+ LOG(fileName);
+ LOG_END;
+
+ return SNMPv3_FILECREATE_ERROR;
+ }
+
+ LOG_BEGIN(INFO_LOG | 3);
+ LOG("saveBootCounter: created new file (file)");
+ LOG(fileName);
+ LOG_END;
+
+ fputs("# \n",file_in);
+ fputs("# This file was created by an SNMP++v3 application,\n", file_in);
+ fputs("# it is used to store the snmpEngineBoots counters.\n", file_in);
+ fputs("# \n",file_in);
+ fputs("# Lines starting with '#' are comments.\n", file_in);
+ fputs("# The snmpEngineBoots counters are stored as\n", file_in);
+ fputs("# <encoded snmpEngineId> <bootCounter>\n", file_in);
+ fputs("# \n", file_in);
+ fclose(file_in);
+ file_in = fopen(fileName, "r");
+ }
+
+ file_out = fopen(tmpFileName, "w");
+
+ if ((file_in) && (file_out))
+ {
+ encodeString(engineId.data(), len, encoded);
+ encoded[len*2] = ' ';
+ encoded[len*2 + 1] = 0;
+
+ while (fgets(line, MAX_LINE_LEN, file_in))
+ {
+ line[MAX_LINE_LEN - 1] = 0;
+ if (!strncmp(encoded, line, len*2 + 1))
+ {
+ if (found)
+ {
+ LOG_BEGIN(WARNING_LOG | 3);
+ LOG("saveBootCounter: Removing doubled entry (file) (line)");
+ LOG(fileName);
+ LOG(line);
+ LOG_END;
+
+ continue;
+ }
+ sprintf(line,"%s%i\n", encoded, boot);
+ fputs(line, file_out);
+ found = TRUE;
+ continue;
+ }
+ fputs(line, file_out);
+ }
+ if (!found)
+ {
+ sprintf(line, "%s%i\n", encoded, boot);
+ fputs(line, file_out);
+ }
+ fclose(file_in);
+ fclose(file_out);
+#ifdef WIN32
+ _unlink(fileName);
+#endif
+ if (rename(tmpFileName, fileName))
+ {
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("saveBootCounter: Failed to rename temporary file (tmp file) (file)");
+ LOG(tmpFileName);
+ LOG(fileName);
+ LOG_END;
+
+ return SNMPv3_FILERENAME_ERROR;
+ }
+
+ LOG_BEGIN(INFO_LOG | 5);
+ LOG("saveBootCounter: Saved counter (file) (engine id) (boot)");
+ LOG(fileName);
+ LOG(engineId.get_printable());
+ LOG(boot);
+ LOG_END;
+
+ return SNMPv3_OK;
+ }
+
+ LOG_BEGIN(ERROR_LOG | 1);
+ LOG("saveBootCounter: Failed to open both files (file) (tmp file)");
+ LOG(fileName);
+ LOG(tmpFileName);
+ LOG_END;
+
+ return SNMPv3_FILEOPEN_ERROR;
+}
+
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+/*_############################################################################
+ _##
+ _## vb.cpp
+ _##
+ _## SNMP++v3.2.25
+ _## -----------------------------------------------
+ _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+ _##
+ _## This software is based on SNMP++2.6 from Hewlett Packard:
+ _##
+ _## Copyright (c) 1996
+ _## Hewlett-Packard Company
+ _##
+ _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ _## Permission to use, copy, modify, distribute and/or sell this software
+ _## and/or its documentation is hereby granted without fee. User agrees
+ _## to display the above copyright notice and this license notice in all
+ _## copies of the software and any documentation of the software. User
+ _## agrees to assume all liability for the use of the software;
+ _## Hewlett-Packard and Jochen Katz make no representations about the
+ _## suitability of this software for any purpose. It is provided
+ _## "AS-IS" without warranty of any kind, either express or implied. User
+ _## hereby grants a royalty-free license to any and all derivatives based
+ _## upon this software code base.
+ _##
+ _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
+ _##
+ _##########################################################################*/
+/*===================================================================
+
+ Copyright (c) 1999
+ Hewlett-Packard Company
+
+ ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+ Permission to use, copy, modify, distribute and/or sell this software
+ and/or its documentation is hereby granted without fee. User agrees
+ to display the above copyright notice and this license notice in all
+ copies of the software and any documentation of the software. User
+ agrees to assume all liability for the use of the software; Hewlett-Packard
+ makes no representations about the suitability of this software for any
+ purpose. It is provided "AS-IS" without warranty of any kind,either express
+ or implied. User hereby grants a royalty-free license to any and all
+ derivatives based upon this software code base.
+
+
+ V B . C P P
+
+ VARIABLE BINDING CLASS IMPLEMENTATION
+
+ DESCRIPTION:
+ This module contains the class implementation of the VB class.
+ The Vb class is an encapsulation of the snmp variable binding.
+
+ DESIGN + AUTHOR: Peter E Mellquist
+=====================================================================*/
+char vb_cpp_version[]="#(@) SNMP++ $Id: vb.cpp 341 2008-08-29 21:37:48Z katz $";
+
+#include "snmp_pp/vb.h" // include vb class defs
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define IP_ADDR_SIZE 4
+#define IPX_ADDR_SIZE 10
+#define MAC_ADDR_SIZE 6
+
+//--------------[ Vb::valid() ]-----------------------------------------
+// returns validity of a Vb object
+// must have a valid oid and value
+bool Vb::valid() const
+{
+ if (iv_vb_oid.valid() &&
+#ifdef WHEN_WE_HAVE_SNMPNULL_CLASS
+ iv_vb_value && iv_vb_value->valid()
+#else
+ ((iv_vb_value == NULL) || (iv_vb_value && iv_vb_value->valid()))
+#endif
+ )
+ return true;
+ return false;
+}
+
+//---------------[ Vb& Vb::operator=(const Vb &vb) ]--------------------
+// overloaded assignment allows assigning one Vb to another
+// this involves deep memory thus target vb needs to be freed
+// before assigning source
+Vb& Vb::operator=(const Vb &vb)
+{
+ if (this == &vb) return *this; // check for self assignment
+
+ free_vb(); // free up target to begin with
+
+ //-----[ reassign the Oid portion 1st ]
+ vb.get_oid(iv_vb_oid);
+
+ //-----[ next set the vb value portion ]
+ if (vb.iv_vb_value)
+ iv_vb_value = vb.iv_vb_value->clone();
+
+ exception_status = vb.exception_status;
+
+ return *this; // return self reference
+}
+
+//----------------[ void Vb::free_vb() ]--------------------------------
+// protected method to free memory
+// this method is used to free memory when assigning new vbs
+// or destructing
+// in the case of oids and octets, we need to do a deep free
+void Vb::free_vb()
+{
+ if (iv_vb_value)
+ {
+ delete iv_vb_value;
+ iv_vb_value = NULL;
+ }
+ exception_status = SNMP_CLASS_SUCCESS;
+}
+
+//---------------------[ Vb::get_value(int &i) ]----------------------
+// get value int
+// returns 0 on success and value
+int Vb::get_value(int &i) const
+{
+ if (iv_vb_value &&
+ iv_vb_value->valid() &&
+ (iv_vb_value->get_syntax() == sNMP_SYNTAX_INT32 ))
+ {
+ long lval;
+ lval = *((SnmpInt32 *)iv_vb_value);// SnmpInt32 includes cast to long,
+ i = (int) lval; // but not to int.
+ return SNMP_CLASS_SUCCESS;
+ }
+ return SNMP_CLASS_INVALID;
+}
+
+// get the unsigned int
+// returns 0 on success and a value
+int Vb::get_value(unsigned int &i) const
+{
+ if (iv_vb_value &&
+ iv_vb_value->valid() &&
+ ((iv_vb_value->get_syntax() == sNMP_SYNTAX_UINT32 ) ||
+ (iv_vb_value->get_syntax() == sNMP_SYNTAX_CNTR32 ) ||
+ (iv_vb_value->get_syntax() == sNMP_SYNTAX_GAUGE32 ) ||
+ (iv_vb_value->get_syntax() == sNMP_SYNTAX_TIMETICKS )))
+ {
+ unsigned long lval;
+ lval = *((SnmpUInt32 *)iv_vb_value);
+ i = (unsigned int)lval;
+ return SNMP_CLASS_SUCCESS;
+ }
+ return SNMP_CLASS_INVALID;
+}
+
+
+//--------------[ Vb::get_value(long int &i) ]-------------------------
+// get the signed long int
+// returns 0 on success and a value
+int Vb::get_value(long &i) const
+{
+ if (iv_vb_value &&
+ iv_vb_value->valid() &&
+ (iv_vb_value->get_syntax() == sNMP_SYNTAX_INT32 ))
+ {
+ i = *((SnmpInt32 *)iv_vb_value); // SnmpInt32 includes cast to long
+ return SNMP_CLASS_SUCCESS;
+ }
+ return SNMP_CLASS_INVALID;
+}
+
+
+//-----------------[ Vb::get_value(unsigned long int &i) ]--------------
+// get the unsigned long int
+// returns 0 on success and a value
+int Vb::get_value(unsigned long &i) const
+{
+ if (iv_vb_value &&
+ iv_vb_value->valid() &&
+ ((iv_vb_value->get_syntax() == sNMP_SYNTAX_UINT32 ) ||
+ (iv_vb_value->get_syntax() == sNMP_SYNTAX_CNTR32 ) ||
+ (iv_vb_value->get_syntax() == sNMP_SYNTAX_GAUGE32 ) ||
+ (iv_vb_value->get_syntax() == sNMP_SYNTAX_TIMETICKS )))
+ {
+ i = *((SnmpUInt32 *)iv_vb_value); // SnmpUint32 has includes to ulong
+ return SNMP_CLASS_SUCCESS;
+ }
+ return SNMP_CLASS_INVALID;
+}
+
+
+//--------------[ Vb::get_value(unsigned char WINFAR * ptr, unsigned long &len)
+// get a unsigned char string value
+// destructive, copies into given ptr
+// also returned is the length
+//
+// Note!! The user must provide a target string
+// which is big enough to hold the string
+int Vb::get_value(unsigned char *ptr, unsigned long &len) const
+{
+ if (iv_vb_value &&
+ iv_vb_value->valid() &&
+ (iv_vb_value->get_syntax() == sNMP_SYNTAX_OCTETS))
+ {
+ OctetStr *p_os = (OctetStr *)iv_vb_value;
+ len = p_os->len();
+ memcpy(ptr, p_os->data(), len);
+ ptr[len] = 0;
+ return SNMP_CLASS_SUCCESS;
+ }
+
+ if (ptr) ptr[0] = 0;
+ len = 0;
+ return SNMP_CLASS_INVALID;
+}
+
+//---------------[ Vb::get_value ]-------------------------------------
+// get an unsigned char array
+// caller specifies max len of target space
+int Vb::get_value(unsigned char *ptr, unsigned long &len,
+ const unsigned long maxlen,
+ const bool add_null_byte) const
+{
+ if (iv_vb_value &&
+ iv_vb_value->valid() &&
+ (iv_vb_value->get_syntax() == sNMP_SYNTAX_OCTETS) &&
+ (maxlen > 0))
+ {
+ OctetStr *p_os = (OctetStr *)iv_vb_value;
+ len = p_os->len();
+ if (len > maxlen) len = maxlen;
+ memcpy(ptr, p_os->data(), len);
+ if (add_null_byte)
+ {
+ if (len == maxlen)
+ ptr[len-1] = 0;
+ else
+ ptr[len] = 0;
+ }
+ return SNMP_CLASS_SUCCESS;
+ }
+
+ if (ptr) ptr[0] = 0;
+ len = 0;
+ return SNMP_CLASS_INVALID;
+}
+
+
+//---------------[ Vb::get_value(Value &val) ]--------
+int Vb::get_value(SnmpSyntax &val) const
+{
+ if (iv_vb_value)
+ {
+ val = *iv_vb_value;
+ if (val.valid())
+ return SNMP_CLASS_SUCCESS;
+ return SNMP_CLASS_INVALID;
+ }
+ // TM: should set val to be invalid
+ return SNMP_CLASS_INVALID;
+}
+
+//--------------[ Vb::get_value(char WINFAR *ptr) ]-------------------
+// get a char * from an octet string
+// the user must provide space or
+// memory will be stepped on
+int Vb::get_value(char *ptr) const
+{
+ if (iv_vb_value &&
+ iv_vb_value->valid() &&
+ (iv_vb_value->get_syntax() == sNMP_SYNTAX_OCTETS))
+ {
+ OctetStr *p_os = (OctetStr *)iv_vb_value;
+ unsigned long len = p_os->len();
+ memcpy(ptr, p_os->data(), len);
+ ptr[len] = 0;
+ return SNMP_CLASS_SUCCESS;
+ }
+
+ if (ptr) ptr[0] = 0;
+ return SNMP_CLASS_INVALID;
+}
+
+
+
+//-----[ misc]--------------------------------------------------------
+
+// return the current syntax
+// This method violates Object Orientation but may be useful if
+// the caller has a vb object and does not know what it is.
+// This would be useful in the implementation of a browser.
+SmiUINT32 Vb::get_syntax() const
+{
+ if (exception_status != SNMP_CLASS_SUCCESS)
+ return exception_status;
+ else
+ return (iv_vb_value ? iv_vb_value->get_syntax() : sNMP_SYNTAX_NULL);
+}
+
+void Vb::set_syntax(const SmiUINT32 syntax)
+{
+ free_vb(); // setting to SNMP_SYNTAX_NULL
+
+ exception_status = SNMP_CLASS_SUCCESS;
+
+ switch (syntax) {
+ case sNMP_SYNTAX_INT32:
+ iv_vb_value = new SnmpInt32();
+ break;
+ case sNMP_SYNTAX_TIMETICKS:
+ iv_vb_value = new TimeTicks();
+ break;
+ case sNMP_SYNTAX_CNTR32:
+ iv_vb_value = new Counter32();
+ break;
+ case sNMP_SYNTAX_GAUGE32:
+ iv_vb_value = new Gauge32();
+ break;
+/* Not distinguishable from Gauge32
+ case sNMP_SYNTAX_UINT32:
+ iv_vb_value = new SnmpUInt32();
+ break;
+*/
+ case sNMP_SYNTAX_CNTR64:
+ iv_vb_value = new Counter64();
+ break;
+ case sNMP_SYNTAX_BITS:
+ case sNMP_SYNTAX_OCTETS:
+ iv_vb_value = new OctetStr();
+ break;
+ case sNMP_SYNTAX_OPAQUE:
+ iv_vb_value = new OpaqueStr();
+ break;
+ case sNMP_SYNTAX_IPADDR:
+ iv_vb_value = new IpAddress();
+ break;
+ case sNMP_SYNTAX_OID:
+ iv_vb_value = new Oid();
+ break;
+ case sNMP_SYNTAX_NULL:
+ break;
+ case sNMP_SYNTAX_NOSUCHINSTANCE:
+ exception_status = sNMP_SYNTAX_NOSUCHINSTANCE;
+ break;
+ case sNMP_SYNTAX_NOSUCHOBJECT:
+ exception_status = sNMP_SYNTAX_NOSUCHOBJECT;
+ break;
+ case sNMP_SYNTAX_ENDOFMIBVIEW:
+ exception_status = sNMP_SYNTAX_ENDOFMIBVIEW;
+ break;
+ case sNMP_SYNTAX_SEQUENCE:
+ break;
+ }
+}
+
+static char blank_string[] = "";
+
+// return the printabel value
+const char WINFAR *Vb::get_printable_value() const
+{
+ if (iv_vb_value)
+ return iv_vb_value->get_printable();
+ return blank_string;
+}
+
+int Vb::get_asn1_length() const
+{
+ // Header for vbs is always 4 Bytes! FIXME
+ if (iv_vb_value)
+ return iv_vb_oid.get_asn1_length() + iv_vb_value->get_asn1_length() + 4;
+
+ return iv_vb_oid.get_asn1_length() + 2 + 4;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
--- /dev/null
+DEFS =
+INCS = -Iinclude -I3rdparty/snmp++/include
+CXXFLAGS += -W -Wall -Wextra $(INCS) $(DEFS)
+LIBS = -lpthread \
+ -lssl \
+ -lcurl \
+ -lboost_system \
+ -lboost_program_options \
+ 3rdparty/snmp++/libsnmp++.a
+PROG = gssmd # GTS SNMP Switch Management Daemon
+VERSION = 1.0.4
+
+SOURCES = src/main.cpp \
+ src/pidfile.cpp \
+ src/settings.cpp \
+ src/settingsfileparser.cpp \
+ src/logger.cpp \
+ src/syncer.cpp \
+ src/subscriber.cpp \
+ src/switch.cpp \
+ src/acl.cpp \
+ src/snmptable.cpp \
+ src/dataparser.cpp
+
+.PHONY: all clean snmplib version tests
+
+all: $(PROG)
+
+tests:
+ $(MAKE) $(MAKECMDGOALS) -C tests
+
+snmplib:
+ $(MAKE) $(MAKECMDGOALS) -C 3rdparty
+
+include/version.h: version
+
+version:
+ @sed 's/@VERSION@/$(VERSION)/g' include/version.h.in > include/version.h
+ @sed -i 's/@GIT_SHA@/'`git rev-parse --short HEAD`'/g' include/version.h
+
+$(PROG): version $(subst .cpp,.o,$(SOURCES)) snmplib
+ $(CXX) $(subst .cpp,.o,$(SOURCES)) $(LIBS) -o $@
+
+clean: snmplib
+ rm -f src/*.o src/*.d $(PROG) include/version.h
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+-include $(subst .cpp,.d,$(SOURCES))
+endif
+endif
+
+%.d: %.cpp
+ @$(CXX) -MM $(CXXFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\).o[ :]*,src\/\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
--- /dev/null
+[general]
+
+# 'daemon' flag defines whether to daemonize or no
+# Default - no
+daemon
+
+
+# 'debug' flag make output a bit more verbose
+# Default - no
+#debug
+
+# Log file path
+# Default: /var/log/gssmd.log
+log_file = /home/faust/Projects/GTS/snmp-daemon/gssmd.log
+
+# PID file path
+# Default: /var/run/gssmd.pid
+pid_file = /home/faust/Projects/GTS/snmp-daemon/gssmd.pid
+
+[sync]
+
+# Switch sync interval, sec
+# Default: 60 sec
+switch_interval = 1
+
+# Info sync interval, sec
+# Default: 180 sec
+info_interval = 10
+
+# Upload profile ID
+# Default: 1
+up_profile_id = 1
+
+# Download profile ID
+# Default: 1
+down_profile_id = 2
+
+# Data access URL
+# No default value
+data_url = http://db.loc/?mm=api&mode=sh_switches
--- /dev/null
+#ifndef __GTS_ACL_H__
+#define __GTS_ACL_H__
+
+#include <string>
+
+class Pdu;
+
+namespace GTS {
+
+class ACL {
+ public:
+ ACL(unsigned id,
+ unsigned profileId,
+ const std::string & mac,
+ unsigned port,
+ unsigned shape,
+ unsigned burst,
+ bool isUpload);
+ ACL(const ACL & rvalue);
+ ~ACL();
+
+ ACL & operator=(const ACL & rvalue);
+
+ unsigned getId() const { return _id; }
+ unsigned getProfileId() const { return _profileId; }
+ const std::string & getMAC() const { return _mac; }
+ std::string getPort() const { return _port; }
+ unsigned getShape() const { return _shape; }
+ unsigned getBurst() const { return _burst; }
+
+ bool isUpload() const { return _isUpload; }
+
+ void appendPdu(Pdu & pdu) const;
+
+ private:
+ unsigned _id;
+ unsigned _profileId;
+ std::string _mac;
+ std::string _port;
+ unsigned _shape;
+ unsigned _burst;
+
+ bool _isUpload;
+
+ std::string getSuffix() const;
+};
+
+}
+
+#endif
--- /dev/null
+#ifndef __GTS_DATA_TYPES_H__
+#define __GTS_DATA_TYPES_H__
+
+#include <string>
+#include <list>
+
+namespace GTS {
+
+struct LineType {
+ std::string switchIP;
+ std::string readCommunity;
+ std::string writeCommunity;
+ unsigned uplinkPort;
+ unsigned userPort;
+ std::string mac;
+ unsigned upShape;
+ unsigned downShape;
+ unsigned upBurst;
+ unsigned downBurst;
+};
+
+typedef std::list<LineType> Lines;
+
+bool parseData(std::string & data, Lines & lines);
+
+}
+
+#endif
--- /dev/null
+#ifndef __GTS_LOGGER_H__
+#define __GTS_LOGGER_H__
+
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#define LOG_IT logger << __FILE__ << "(" << __LINE__ << ") : "
+
+namespace GTS {
+
+class Logger {
+public:
+ Logger()
+ : fout(),
+ consoleLog(true)
+ {}
+ Logger(const std::string & fileName)
+ : fout(fileName.c_str(), std::ios::app),
+ logFile(fileName),
+ consoleLog(!fout.is_open())
+ {}
+ ~Logger()
+ {};
+
+ bool setLogFile(const std::string & fileName);
+
+ std::ostream & operator<<(const std::string & str);
+private:
+ std::ofstream fout;
+ std::string logFile;
+ bool consoleLog;
+
+ void _logDate();
+};
+
+}
+
+extern GTS::Logger logger;
+
+#endif
--- /dev/null
+#ifndef __GTS_OIDS_H__
+#define __GTS_OIDS_H__
+
+#define swACLEtherRuleProfileID ".1.3.6.1.4.1.171.12.9.2.1.1.1"
+#define swACLEtherRuleAccessID ".1.3.6.1.4.1.171.12.9.3.1.1.2"
+#define swACLEtherRuleRowStatus ".1.3.6.1.4.1.171.12.9.3.1.1.15"
+#define swACLEtherRuleSrcMacAddress ".1.3.6.1.4.1.171.12.9.3.1.1.4"
+#define swACLEtherRuleDstMacAddress ".1.3.6.1.4.1.171.12.9.3.1.1.5"
+#define swACLEtherRulePermit ".1.3.6.1.4.1.171.12.9.3.1.1.13"
+#define swACLEtherRulePort ".1.3.6.1.4.1.171.12.9.3.1.1.14"
+#define swACLEtherRuleRxRate ".1.3.6.1.4.1.171.12.9.3.1.1.17"
+#define swACLMeterBurstSize ".1.3.6.1.4.1.171.12.9.6.1.1.6"
+
+#endif
--- /dev/null
+#ifndef __GTS_PIDFILE_H__
+#define __GTS_PIDFILE_H__
+
+#include <string>
+
+#include <boost/noncopyable.hpp>
+
+namespace GTS {
+
+class PIDFile : private boost::noncopyable {
+ public:
+ PIDFile();
+ PIDFile(const std::string & file);
+ ~PIDFile();
+ private:
+ const std::string fileName;
+ void _create();
+};
+
+}
+
+#endif
--- /dev/null
+#ifndef __GTS_SETTINGS_H__
+#define __GTS_SETTINGS_H__
+
+#include <string>
+
+#include <boost/noncopyable.hpp>
+#include <boost/program_options.hpp>
+
+namespace po = boost::program_options;
+
+namespace GTS {
+
+class SettingsParser;
+class Settings {
+ public:
+ // Construction / destruction
+ Settings();
+ Settings(const Settings & rvalue);
+ ~Settings();
+
+ const Settings & operator=(const Settings & rvalue);
+
+ // Accessors
+ bool isHelp() const throw() { return _isHelp; }
+ bool isVersion() const throw() { return _isVersion; }
+ bool isDebug() const throw() { return _isDebug; }
+ bool isDaemon() const throw() { return _isDaemon; }
+
+ const std::string & configFile() const throw() { return _configFile; }
+ const std::string & logFile() const throw() { return _logFile; }
+ const std::string & PIDFile() const throw() { return _PIDFile; }
+
+ time_t switchSyncInterval() const throw() { return _switchSyncInterval; }
+ time_t infoSyncInterval() const throw() { return _infoSyncInterval; }
+
+ unsigned upProfileId() const throw() { return _upProfileId; }
+ unsigned downProfileId() const throw() { return _downProfileId; }
+
+ const std::string & dataURL() const throw() { return _dataURL; }
+
+ // Setters
+ void setIsHelp(bool value) throw() { _isHelp = value; }
+ void setIsVersion(bool value) throw() { _isVersion = value; }
+ void setIsDebug(bool value) throw() { _isDebug = value; }
+ void setIsDaemon(bool value) throw() { _isDaemon = value; }
+
+ void setConfigFile(const std::string & value) throw() { _configFile = value; }
+ void setLogFile(const std::string & value) throw() { _logFile = value; }
+ void setPIDFile(const std::string & value) throw() { _PIDFile = value; }
+
+ void setSwitchSyncInterval(time_t value) throw() { _switchSyncInterval = value; }
+ void setInfoSyncInterval(time_t value) throw() { _infoSyncInterval = value; }
+
+ void setUpProfileId(unsigned value) throw() { _upProfileId = value; }
+ void setDownProfileId(unsigned value) throw() { _downProfileId = value; }
+
+ void setDataURL(const std::string & value) throw() { _dataURL = value; }
+
+ private:
+ bool _isHelp;
+ bool _isVersion;
+ bool _isDebug;
+ bool _isDaemon;
+
+ std::string _configFile;
+ std::string _logFile;
+ std::string _PIDFile;
+
+ time_t _switchSyncInterval;
+ time_t _infoSyncInterval;
+
+ unsigned _upProfileId;
+ unsigned _downProfileId;
+
+ std::string _dataURL;
+
+ friend class SettingsParser;
+};
+
+class SettingsParser : private boost::noncopyable {
+ public:
+ SettingsParser();
+ ~SettingsParser();
+
+ void init(int argc, char * argv[]);
+ void reloadConfig();
+ void printHelp() const;
+
+ const Settings & settings() const { return _settings; };
+ private:
+ po::options_description _desc;
+ Settings _settings;
+
+ void parseFile(const std::string & fileName);
+};
+
+}
+
+#include "settings.inl.h"
+
+#endif
--- /dev/null
+#ifndef __GTS_SETTINGS_INL_H__
+#define __GTS_SETTINGS_INL_H__
+
+#include <iostream>
+#include <sstream>
+
+namespace GTS {
+
+inline
+Settings::Settings()
+ : _isHelp(true),
+ _isVersion(false),
+ _isDebug(false),
+ _isDaemon(false),
+ _configFile("/etc/gssmd/gssmd.conf"),
+ _logFile("/var/log/gssmd.log"),
+ _PIDFile("/var/run/gssmd.pid"),
+ _switchSyncInterval(180),
+ _infoSyncInterval(60),
+ _upProfileId(1),
+ _downProfileId(2)
+{
+}
+
+inline
+Settings::Settings(const Settings & rvalue)
+ : _isHelp(rvalue._isHelp),
+ _isVersion(rvalue._isVersion),
+ _isDebug(rvalue._isDebug),
+ _isDaemon(rvalue._isDaemon),
+ _configFile(rvalue._configFile),
+ _logFile(rvalue._logFile),
+ _PIDFile(rvalue._PIDFile),
+ _switchSyncInterval(rvalue._switchSyncInterval),
+ _infoSyncInterval(rvalue._infoSyncInterval),
+ _upProfileId(rvalue._upProfileId),
+ _downProfileId(rvalue._downProfileId),
+ _dataURL(rvalue._dataURL)
+{
+}
+
+inline
+Settings::~Settings()
+{
+}
+
+inline
+const Settings & Settings::operator=(const Settings & rvalue)
+{
+ _isHelp = rvalue._isHelp;
+ _isVersion = rvalue._isVersion;
+ _isDebug = rvalue._isDebug;
+ _isDaemon = rvalue._isDaemon;
+ _configFile = rvalue._configFile;
+ _logFile = rvalue._logFile;
+ _PIDFile = rvalue._PIDFile;
+ _switchSyncInterval = rvalue._switchSyncInterval;
+ _infoSyncInterval = rvalue._infoSyncInterval;
+ _upProfileId = rvalue._upProfileId;
+ _downProfileId = rvalue._downProfileId;
+ _dataURL = rvalue._dataURL;
+ return *this;
+}
+
+inline
+SettingsParser::~SettingsParser()
+{
+}
+
+inline
+void SettingsParser::printHelp() const
+{
+ std::cout << _desc << std::endl;
+}
+
+}
+
+#endif
--- /dev/null
+#ifndef __GTS_SNMPTABLE_H__
+#define __GTS_SNMPTABLE_H__
+
+#include <list>
+
+#include "snmp_pp/snmp_pp.h"
+
+namespace GTS {
+
+typedef std::list<Vb> SNMPList;
+
+class SNMPTable {
+ public:
+ SNMPTable(Snmp & snmp,
+ const CTarget & target,
+ const Oid & oid);
+ ~SNMPTable();
+
+ bool valid() const { return _valid; }
+ bool empty() const { return _list.empty(); }
+
+ template <typename T>
+ bool valueExists(const T & value) const;
+ bool getByOid(const Oid & oid, Vb & vb) const;
+ const SNMPList & getList() const { return _list; }
+
+ private:
+ SNMPList _list;
+ bool _valid;
+};
+
+}
+
+#include "snmptable.inl.h"
+
+#endif
--- /dev/null
+#ifndef __GTS_SNMPTABLE_INL_H__
+#define __GTS_SNMPTABLE_INL_H__
+
+namespace GTS {
+
+template <typename T>
+inline
+bool SNMPTable::valueExists(const T & value) const
+{
+ SNMPList::const_iterator it;
+ for (it = _list.begin(); it != _list.end(); ++it) {
+ T v;
+ if (it->get_value(v) != SNMP_CLASS_SUCCESS) {
+ continue;
+ }
+ if (v == value)
+ return true;
+ }
+ return false;
+}
+
+}
+
+#endif
--- /dev/null
+#ifndef __GTS_SUBSCRIBER_H__
+#define __GTS_SUBSCRIBER_H__
+
+#include <string>
+
+namespace GTS {
+
+class Subscriber {
+ public:
+ Subscriber(const std::string & mac,
+ unsigned port,
+ unsigned upShape,
+ unsigned downShape,
+ unsigned upBurst,
+ unsigned downBurst);
+ ~Subscriber();
+
+ std::string getHexMAC() const;
+ const std::string & getMAC() const { return _mac; }
+ unsigned getPort() const { return _port; }
+ unsigned getUpShape() const { return _upShape; }
+ unsigned getUpBurst() const { return _upBurst; }
+ unsigned getDownShape() const { return _downShape; }
+ unsigned getDownBurst() const { return _downBurst; }
+
+ private:
+ std::string _mac;
+ unsigned _port;
+ unsigned _upShape;
+ unsigned _downShape;
+ unsigned _upBurst;
+ unsigned _downBurst;
+};
+
+}
+
+#endif
--- /dev/null
+#ifndef __GTS_SWITCH_H__
+#define __GTS_SWITCH_H__
+
+#include <string>
+#include <vector>
+
+class Snmp;
+class CTarget;
+
+namespace GTS {
+
+class Settings;
+class Subscriber;
+class ACL;
+class SNMPTable;
+
+class Switch {
+ public:
+ Switch(const Settings & settings,
+ Snmp & snmp,
+ const std::string & ip,
+ const std::string & readCommunity,
+ const std::string & writeCommunity,
+ unsigned uplinkPort);
+ Switch(const Switch & rvalue);
+ ~Switch();
+
+ Switch & operator=(const Switch & rvalue);
+
+ const std::string & getIP() const { return _ip; }
+ const std::string & getReadCommunity() const { return _readCommunity; }
+ const std::string & getWriteCommunity() const { return _writeCommunity; }
+ unsigned getUplinkPort() const { return _uplinkPort; }
+
+ void addSubscriber(const Subscriber & subscriber);
+
+ void sync();
+
+ private:
+ const Settings & _settings;
+ Snmp & _snmp;
+
+ std::string _ip;
+ std::string _readCommunity;
+ std::string _writeCommunity;
+ unsigned _uplinkPort;
+
+ unsigned _nextUpACL;
+ unsigned _nextDownACL;
+
+ std::vector<ACL> _acls;
+
+ bool checkProfiles(const CTarget & target);
+ bool dropACLs(const CTarget & target);
+ bool dropACLsByTable(const CTarget & target, unsigned profileId, const SNMPTable & table);
+ bool createACLs(const CTarget & target);
+};
+
+}
+
+#endif
--- /dev/null
+#ifndef __GTS_SYNCER_H__
+#define __GTS_SYNCER_H__
+
+#include <ctime>
+#include <list>
+#include <map>
+
+#include <boost/function.hpp>
+
+class Snmp;
+
+namespace GTS {
+
+class SettingsParser;
+class Switch;
+
+class Timer {
+ public:
+ Timer(boost::function<void ()> callback, time_t interval);
+ ~Timer();
+
+ void fire();
+
+ time_t getInterval() const { return _interval; }
+ time_t getLastFire() const { return _lastFire; }
+ int getTimeout() const;
+ private:
+ time_t _interval;
+ time_t _lastFire;
+ boost::function<void ()> _callback;
+};
+
+typedef std::list<Timer>::iterator TimerIterator;
+typedef std::pair<Switch, TimerIterator> TimedSwitch;
+
+class Syncer {
+ public:
+ Syncer(SettingsParser & sp,
+ Snmp & snmp);
+ ~Syncer();
+
+ void run(const bool & running, bool & reload);
+
+ private:
+ SettingsParser & _settingsParser;
+ Snmp & _snmp;
+ std::list<Timer> _timers;
+ std::list<TimedSwitch> _switches;
+
+ bool wait();
+ void syncInfo();
+ Timer & getNextTimer();
+ bool getSwitchesState(std::map<std::string, Switch> & switches);
+ bool getDBData(std::string & data) const;
+};
+
+}
+
+#endif
--- /dev/null
+#ifndef __GTS_VERSION_H__
+#define __GTS_VERSION_H__
+
+#include <string>
+
+namespace GTS {
+ static const std::string version("@VERSION@");
+ static const std::string revision("git sha @GIT_SHA@");
+}
+
+#endif
--- /dev/null
+#include <boost/lexical_cast.hpp>
+#include <boost/format.hpp>
+
+#include "snmp_pp/snmp_pp.h"
+
+#include "acl.h"
+#include "oids.h"
+#include "logger.h"
+
+using GTS::ACL;
+
+ACL::ACL(unsigned id,
+ unsigned profileId,
+ const std::string & mac,
+ unsigned port,
+ unsigned shape,
+ unsigned burst,
+ bool isUpload)
+ : _id(id),
+ _profileId(profileId),
+ _mac(mac),
+ _shape(shape),
+ _burst(burst),
+ _isUpload(isUpload)
+{
+ port = 1 << (32 - port);
+ _port = (boost::format("%|08x|") % port).str();
+}
+
+ACL::ACL(const ACL & rvalue)
+ : _id(rvalue._id),
+ _profileId(rvalue._profileId),
+ _mac(rvalue._mac),
+ _port(rvalue._port),
+ _shape(rvalue._shape),
+ _burst(rvalue._burst),
+ _isUpload(rvalue._isUpload)
+{
+}
+
+ACL::~ACL()
+{
+}
+
+ACL & ACL::operator=(const ACL & rvalue)
+{
+ _id = rvalue._id;
+ _profileId = rvalue._profileId;
+ _mac = rvalue._mac;
+ _port = rvalue._port;
+ _shape = rvalue._shape;
+ _burst = rvalue._burst;
+ _isUpload = rvalue._isUpload;
+
+ return *this;
+}
+
+void ACL::appendPdu(Pdu & pdu) const
+{
+ std::string oidValue;
+ // MAC
+ if (_isUpload) {
+ oidValue = swACLEtherRuleSrcMacAddress;
+ oidValue += getSuffix();
+ } else {
+ oidValue = swACLEtherRuleDstMacAddress;
+ oidValue += getSuffix();
+ }
+ Vb vb(Oid(oidValue.c_str()));
+ vb.set_value(OctetStr::from_hex_string(_mac.c_str()));
+ pdu += vb;
+
+ // Permit rule
+ oidValue = swACLEtherRulePermit;
+ oidValue += getSuffix();
+ vb.set_oid(Oid(oidValue.c_str()));
+ vb.set_value(int(2));
+ pdu += vb;
+
+ // Port
+ oidValue = swACLEtherRulePort;
+ oidValue += getSuffix();
+ vb.set_oid(Oid(oidValue.c_str()));
+ vb.set_value(OctetStr::from_hex_string(_port.c_str()));
+ pdu += vb;
+
+ // Shape
+ oidValue = swACLEtherRuleRxRate;
+ oidValue += getSuffix();
+ vb.set_oid(Oid(oidValue.c_str()));
+ vb.set_value(int(_shape));
+ pdu += vb;
+
+ // Create ACL
+ oidValue = swACLEtherRuleRowStatus;
+ oidValue += getSuffix();
+ vb.set_oid(Oid(oidValue.c_str()));
+ vb.set_value(int(4));
+ pdu += vb;
+
+ // Burst
+ /*oidValue = swACLMeterBurstSize;
+ oidValue += getSuffix();
+ vb.set_oid(Oid(oidValue.c_str()));
+ vb.set_value(int(_burst));
+ pdu += vb;*/
+}
+
+inline
+std::string ACL::getSuffix() const
+{
+ return std::string(".") +
+ boost::lexical_cast<std::string>(_profileId) +
+ "." +
+ boost::lexical_cast<std::string>(_id);
+}
--- /dev/null
+#include <string>
+#include <list>
+
+#include <boost/spirit/include/qi.hpp>
+#include <boost/fusion/include/std_pair.hpp>
+#include <boost/fusion/include/adapt_struct.hpp>
+
+#include "datatypes.h"
+#include "logger.h"
+
+namespace qi = boost::spirit::qi;
+
+using GTS::LineType;
+using GTS::Lines;
+
+BOOST_FUSION_ADAPT_STRUCT(
+ GTS::LineType,
+ (std::string, switchIP)
+ (std::string, readCommunity)
+ (std::string, writeCommunity)
+ (unsigned, uplinkPort)
+ (unsigned, userPort)
+ (std::string, mac)
+ (unsigned, upShape)
+ (unsigned, downShape)
+ (unsigned, upBurst)
+ (unsigned, downBurst)
+)
+
+template <typename Iterator>
+struct LinesGrammar
+ : qi::grammar<Iterator, Lines()>
+{
+ LinesGrammar()
+ : LinesGrammar::base_type(query)
+ {
+ query = +line;
+ line = ip >> qi::lit(",") >>
+ community >> qi::lit(",") >>
+ community >> qi::lit(",") >>
+ port >> qi::lit(",") >>
+ port >> qi::lit(",") >>
+ mac >> qi::lit(",") >>
+ shape >> qi::lit(",") >>
+ shape >> qi::lit(",") >>
+ shape >> qi::lit(",") >>
+ shape >> eol;
+ ip = +qi::digit >> qi::char_('.') >>
+ +qi::digit >> qi::char_('.') >>
+ +qi::digit >> qi::char_('.') >>
+ +qi::digit;
+ community = +qi::char_("a-zA-Z0-9_");
+ port = qi::int_;
+ mac = qi::xdigit >> qi::xdigit >>
+ qi::xdigit >> qi::xdigit >>
+ qi::xdigit >> qi::xdigit >>
+ qi::xdigit >> qi::xdigit >>
+ qi::xdigit >> qi::xdigit >>
+ qi::xdigit >> qi::xdigit;
+ shape = qi::int_;
+ eol = qi::lit("\r\n") | '\r' | '\n';
+ }
+
+ qi::rule<Iterator, Lines()> query;
+ qi::rule<Iterator, LineType()> line;
+ qi::rule<Iterator, std::string()> ip, community, mac;
+ qi::rule<Iterator, unsigned()> port, shape;
+ qi::rule<Iterator> eol;
+};
+
+bool GTS::parseData(std::string & data, Lines & lines)
+{
+ std::string::iterator begin(data.begin());
+ std::string::iterator end(data.end());
+
+ LinesGrammar<std::string::iterator> parser; // Our parser
+
+ if (!qi::parse(begin, end, parser, lines)) {
+ logger << "parseData() - Failed to parse data" << std::endl;
+ return false;
+ }
+
+ return true;
+}
--- /dev/null
+#include <ctime>
+
+#include "logger.h"
+
+using GTS::Logger;
+
+bool Logger::setLogFile(const std::string & fileName)
+{
+ fout.open(fileName.c_str(), std::ios::app);
+ logFile = fileName;
+ return !(consoleLog = !fout.is_open());
+}
+
+std::ostream & Logger::operator<<(const std::string & str)
+{
+ _logDate();
+ if (consoleLog) {
+ return std::cout << str;
+ } else {
+ fout.close();
+ fout.open(logFile.c_str(), std::ios::app);
+ if (fout) {
+ fout << str;
+ }
+ return fout;
+ }
+}
+
+inline
+void Logger::_logDate()
+{
+ time_t t = time(NULL);
+ struct tm *ts = localtime(&t);
+ if (consoleLog) {
+ std::cout << "["
+ << (ts->tm_year + 1900) << "-"
+ << (ts->tm_mon < 9 ? "0" : "") << (ts->tm_mon + 1) << "-"
+ << (ts->tm_mday < 10 ? "0" : "") << ts->tm_mday << " "
+ << (ts->tm_hour < 10 ? "0" : "") << ts->tm_hour << ":"
+ << (ts->tm_min < 10 ? "0" : "") << ts->tm_min << ":"
+ << (ts->tm_sec < 10 ? "0" : "") << ts->tm_sec
+ << "] ";
+ } else {
+ fout.close();
+ fout.open(logFile.c_str(), std::ios::app);
+ if (fout) {
+ fout << "["
+ << (ts->tm_year + 1900) << "-"
+ << (ts->tm_mon < 9 ? "0" : "") << (ts->tm_mon + 1) << "-"
+ << (ts->tm_mday < 10 ? "0" : "") << ts->tm_mday << " "
+ << (ts->tm_hour < 10 ? "0" : "") << ts->tm_hour << ":"
+ << (ts->tm_min < 10 ? "0" : "") << ts->tm_min << ":"
+ << (ts->tm_sec < 10 ? "0" : "") << ts->tm_sec
+ << "] ";
+ }
+ }
+}
--- /dev/null
+#include <unistd.h> // daemon
+
+#include <cerrno> // errno
+#include <cstring> // strerror
+#include <csignal>
+#include <iostream>
+#include <exception>
+
+#include "snmp_pp/snmp_pp.h"
+
+#include "syncer.h"
+#include "version.h"
+#include "settings.h"
+#include "pidfile.h"
+#include "logger.h"
+
+GTS::Logger logger;
+static bool running = true;
+static bool reload = false;
+
+void setSignalHandlers();
+
+int main(int argc, char * argv[])
+{
+ GTS::SettingsParser sParser;
+
+ // Set filter for logging
+ DefaultLog::log()->set_filter(ERROR_LOG, 7);
+ DefaultLog::log()->set_filter(WARNING_LOG, 7);
+ DefaultLog::log()->set_filter(EVENT_LOG, 0);
+ DefaultLog::log()->set_filter(INFO_LOG, 0);
+ DefaultLog::log()->set_filter(DEBUG_LOG, 0);
+
+ try {
+ sParser.init(argc, argv);
+ }
+ catch (const std::exception & ex) {
+ logger << ex.what() << std::endl;
+ return -1;
+ }
+
+ if (sParser.settings().isHelp()) {
+ sParser.printHelp();
+ return 0;
+ }
+
+ if (sParser.settings().isVersion()) {
+ std::cout << "GTS SNMP Switch Management Daemon " << GTS::version << " (revision: " << GTS::revision << ")" << std::endl;
+ return 0;
+ }
+
+ if (sParser.settings().isDebug()) {
+ std::cout << "Settings dump:\n"
+ << "\t- help: " << (sParser.settings().isHelp() ? "yes" : "no") << "\n"
+ << "\t- version: " << (sParser.settings().isVersion() ? "yes" : "no") << "\n"
+ << "\t- debug: " << (sParser.settings().isDebug() ? "yes" : "no") << "\n"
+ << "\t- daemon: " << (sParser.settings().isDaemon() ? "yes" : "no") << "\n"
+ << "\t- config file: " << sParser.settings().configFile() << "\n"
+ << "\t- log file: " << sParser.settings().logFile() << "\n"
+ << "\t- PID file: " << sParser.settings().PIDFile() << "\n"
+ << "\t- switch sync interval: " << sParser.settings().switchSyncInterval() << "\n"
+ << "\t- info sync interval: " << sParser.settings().infoSyncInterval() << "\n"
+ << "\t- switch's upload profile id: " << sParser.settings().upProfileId() << "\n"
+ << "\t- switch's download profile id: " << sParser.settings().downProfileId() << "\n"
+ << "\t- data URL: " << sParser.settings().dataURL() << std::endl;
+ }
+
+ if (sParser.settings().isDaemon()) {
+ if (daemon(0, sParser.settings().isDebug())) {
+ logger << "Failed to daemonize: " << strerror(errno) << std::endl;
+ return -1;
+ }
+ }
+ logger.setLogFile(sParser.settings().logFile());
+
+ try {
+ int status = 0;
+ Snmp snmp(status);
+
+ if (status) {
+ logger << "Failed to initialize SNMP" << std::endl;
+ return -1;
+ }
+
+ GTS::PIDFile pf(sParser.settings().PIDFile());
+ GTS::Syncer syncer(sParser, snmp);
+
+ logger << "Starting gssmd main thread..." << std::endl;
+
+ setSignalHandlers();
+
+ // Start main thread
+ syncer.run(running, reload);
+
+ logger << "Main thread stopped." << std::endl;
+ }
+ catch (std::exception & ex) {
+ logger << "Exception: " << ex.what() << std::endl;
+ return -1;
+ }
+
+ return 0;
+}
+
+void catchTERM(int)
+{
+ running = false;
+
+ struct sigaction newsa, oldsa;
+ sigset_t sigmask;
+
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGTERM);
+ newsa.sa_handler = SIG_IGN;
+ newsa.sa_mask = sigmask;
+ newsa.sa_flags = 0;
+ sigaction(SIGTERM, &newsa, &oldsa);
+
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGINT);
+ newsa.sa_handler = SIG_IGN;
+ newsa.sa_mask = sigmask;
+ newsa.sa_flags = 0;
+ sigaction(SIGINT, &newsa, &oldsa);
+}
+
+void catchHUP(int)
+{
+ reload = true;
+}
+
+void setSignalHandlers()
+{
+ struct sigaction newsa, oldsa;
+ sigset_t sigmask;
+
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGTERM);
+ newsa.sa_handler = catchTERM;
+ newsa.sa_mask = sigmask;
+ newsa.sa_flags = 0;
+ sigaction(SIGTERM, &newsa, &oldsa);
+
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGINT);
+ newsa.sa_handler = catchTERM;
+ newsa.sa_mask = sigmask;
+ newsa.sa_flags = 0;
+ sigaction(SIGINT, &newsa, &oldsa);
+
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGPIPE);
+ newsa.sa_handler = SIG_IGN;
+ newsa.sa_mask = sigmask;
+ newsa.sa_flags = 0;
+ sigaction(SIGPIPE, &newsa, &oldsa);
+
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGHUP);
+ newsa.sa_handler = catchHUP;
+ newsa.sa_mask = sigmask;
+ newsa.sa_flags = 0;
+ sigaction(SIGHUP, &newsa, &oldsa);
+}
--- /dev/null
+#include <sys/types.h> // pid_t
+#include <unistd.h> // getpid
+
+#include <cerrno>
+#include <cstring>
+#include <fstream>
+
+#include "pidfile.h"
+#include "logger.h"
+
+using GTS::PIDFile;
+
+PIDFile::PIDFile()
+ : fileName("/var/run/gssmd.pid")
+{
+ _create();
+}
+
+PIDFile::PIDFile(const std::string & file)
+ : fileName(file)
+{
+ _create();
+}
+
+PIDFile::~PIDFile()
+{
+ if (unlink(fileName.c_str())) {
+ logger << "Failed to unlink pid-file: " << strerror(errno) << std::endl;
+ return;
+ }
+}
+
+void PIDFile::_create()
+{
+ std::ofstream file(fileName.c_str());
+
+ if (!file.is_open()) {
+ logger << "Failed to create pid-file: " << strerror(errno) << std::endl;
+ return;
+ }
+
+ pid_t pid = getpid();
+ file << pid;
+ logger << "PID: " << pid << std::endl;
+}
--- /dev/null
+#include "logger.h"
+#include "settings.h"
+
+using GTS::Settings;
+using GTS::SettingsParser;
+
+SettingsParser::SettingsParser()
+ : _desc("Allowed options")
+{
+ // Declare the supported options.
+ _desc.add_options()
+ ("help", "produce help message")
+ ("config,c", po::value<std::string>()->default_value("/etc/gssmd/gssmd.conf"), "config file location")
+ ("daemon,d", "daemonize after start")
+ ("debug", "gssmd debugging")
+ ("log-file", po::value<std::string>(), "log file location")
+ ("pid-file", po::value<std::string>(), "PID file location")
+ ("switch-sync-interval,s", po::value<time_t>(), "switch synchronization interval")
+ ("info-sync-interval,i", po::value<time_t>(), "info synchronization interval")
+ ("up-profile-id", po::value<unsigned>(), "switch's upload profile id")
+ ("down-profile-id", po::value<unsigned>(), "switch's download profile id")
+ ("data-url", po::value<std::string>(), "data access URL")
+ ("version,v", "show gssmd version and exit")
+ ;
+}
+
+void SettingsParser::init(int argc, char * argv[])
+{
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, _desc), vm);
+ po::notify(vm);
+
+ _settings._isHelp = vm.count("help");
+ _settings._isVersion = vm.count("version");
+
+ if (vm.count("config")) {
+ _settings._configFile = vm["config"].as<std::string>();
+ }
+
+ if (!_settings._isHelp &&
+ !_settings._isVersion) {
+ try {
+ parseFile(_settings._configFile);
+ }
+ catch (std::exception & ex) {
+ logger << "Error parsing config file '" << _settings._configFile << "': " << ex.what() << std::endl;
+ }
+ }
+
+ if (vm.count("debug")) {
+ _settings._isDebug = true;
+ }
+ if (vm.count("daemon")) {
+ _settings._isDaemon = true;
+ }
+
+ if (vm.count("log-file")) {
+ _settings._logFile = vm["log-file"].as<std::string>();
+ }
+
+ if (vm.count("pid-file")) {
+ _settings._PIDFile = vm["pid-file"].as<std::string>();
+ }
+
+ if (vm.count("switch-sync-interval")) {
+ _settings._switchSyncInterval = vm["switch-sync-interval"].as<time_t>();
+ }
+
+ if (vm.count("info-sync-interval")) {
+ _settings._infoSyncInterval = vm["info-sync-interval"].as<time_t>();
+ }
+
+ if (vm.count("up-profile-id")) {
+ _settings._upProfileId = vm["up-profile-id"].as<unsigned>();
+ }
+
+ if (vm.count("down-profile-id")) {
+ _settings._downProfileId = vm["down-profile-id"].as<unsigned>();
+ }
+
+ if (vm.count("data-url")) {
+ _settings._dataURL = vm["data-url"].as<std::string>();
+ }
+}
+
+void SettingsParser::reloadConfig()
+{
+ parseFile(_settings._configFile);
+}
--- /dev/null
+#include <fstream>
+#include <numeric>
+#include <map>
+#include <string>
+
+#include <boost/spirit/include/qi.hpp>
+#include <boost/fusion/include/std_pair.hpp>
+
+#include "settings.h"
+
+namespace qi = boost::spirit::qi;
+
+namespace {
+
+typedef std::map<std::string, std::string> PairsType;
+typedef std::map<std::string, PairsType> SectionsType;
+
+template <typename Iterator>
+struct IniGrammar
+ : qi::grammar<Iterator, SectionsType()>
+{
+ IniGrammar()
+ : IniGrammar::base_type(query)
+ {
+ query = +(section | (comment >> eol) | (space >> eol));
+ section = sectionHeader >> -sectionContent;
+ sectionHeader = '[' >> space >> key >> space >> ']' >> eol;
+ sectionContent = +((line | comment | space) >> eol);
+ comment = (qi::char_(';') | '#') >> *qi::print;
+ line = space >> key >> space >> -('=' >> space >> value >> space);
+ key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
+ value = +qi::print;
+ space = *qi::char_("\t ");
+ eol = qi::lit("\r\n") | '\r' | '\n';
+ }
+
+ qi::rule<Iterator, SectionsType()> query;
+ qi::rule<Iterator, std::pair<std::string, PairsType>()> section;
+ qi::rule<Iterator, PairsType()> sectionContent;
+ qi::rule<Iterator, std::pair<std::string, std::string>()> line;
+ qi::rule<Iterator, std::string()> key, value, sectionHeader;
+ qi::rule<Iterator> comment, space, eol;
+};
+
+inline
+bool sectionExists(const SectionsType & data, const std::string & sectionName) throw()
+{
+ return data.find(sectionName) != data.end();
+}
+
+inline
+bool fieldExists(const SectionsType & data, const std::string & sectionName, const std::string & fieldName) throw()
+{
+ const SectionsType::const_iterator sectionIterator(data.find(sectionName));
+ if (sectionIterator == data.end())
+ return false;
+ return sectionIterator->second.find(fieldName) != sectionIterator->second.end();
+}
+
+inline
+bool fieldValue(const SectionsType & data, const std::string & sectionName, const std::string & fieldName, std::string & value) throw()
+{
+ const SectionsType::const_iterator sectionIterator(data.find(sectionName));
+ if (sectionIterator == data.end())
+ return false;
+ const PairsType::const_iterator pairIterator(sectionIterator->second.find(fieldName));
+ if (pairIterator == sectionIterator->second.end())
+ return false;
+ value = pairIterator->second;
+ return true;
+}
+
+}
+
+using GTS::SettingsParser;
+
+void SettingsParser::parseFile(const std::string & fileName)
+{
+ std::ifstream in(fileName.c_str());
+ if (!in) {
+ throw std::runtime_error("Can't open file");
+ }
+
+ std::string text;
+ while(!in.eof()) {
+ std::string s;
+ std::getline(in, s);
+ text += s + "\n";
+ }
+
+ std::string::iterator begin = text.begin();
+ std::string::iterator end = text.end();
+
+ SectionsType data;
+ IniGrammar<std::string::iterator> parser; // Our parser
+
+ if (!qi::parse(begin, end, parser, data)) {
+ throw std::runtime_error("Parse error");
+ }
+
+ std::string res;
+ _settings._isDaemon = fieldExists(data, "general", "daemon");
+ _settings._isDebug = fieldExists(data, "general", "debug");
+ if (fieldValue(data, "general", "log_file", res)){
+ _settings._logFile = res;
+ }
+ if (fieldValue(data, "general", "pid_file", res)){
+ _settings._PIDFile = res;
+ }
+ if (fieldValue(data, "sync", "switch_interval", res)){
+ _settings._switchSyncInterval = boost::lexical_cast<time_t>(res);
+ }
+ if (fieldValue(data, "sync", "info_interval", res)){
+ _settings._infoSyncInterval = boost::lexical_cast<time_t>(res);
+ }
+ if (fieldValue(data, "sync", "up_profile_id", res)){
+ _settings._upProfileId = boost::lexical_cast<unsigned>(res);
+ }
+ if (fieldValue(data, "sync", "down_profile_id", res)){
+ _settings._downProfileId = boost::lexical_cast<unsigned>(res);
+ }
+ if (fieldValue(data, "sync", "data_url", res)){
+ _settings._dataURL = res;
+ }
+}
--- /dev/null
+#include "snmptable.h"
+#include "logger.h"
+
+using GTS::SNMPTable;
+
+SNMPTable::SNMPTable(Snmp & snmp,
+ const CTarget & target,
+ const Oid & oid)
+ : _valid(false)
+{
+ Vb vb(oid);
+ Pdu pdu(&vb, 1);
+ while (true) {
+ if (snmp.get_next(pdu, target) != SNMP_CLASS_SUCCESS) {
+ logger << "SNMPTable::SNMPTable() - failed to invoke Snmp::get_next (oid: '" << oid.get_printable() << "')" << std::endl;
+ return;
+ }
+ if (pdu.get_vb(0).get_oid().nCompare(oid.len(), oid) != 0) {
+ break;
+ }
+ _list.push_back(pdu.get_vb(0));
+ }
+
+ _valid = true;
+}
+
+SNMPTable::~SNMPTable()
+{
+}
+
+bool SNMPTable::getByOid(const Oid & oid, Vb & vb) const
+{
+ SNMPList::const_iterator it;
+ for (it = _list.begin(); it != _list.end(); ++it) {
+ if (it->valid() && it->get_oid() == oid) {
+ vb = *it;
+ return true;
+ }
+ }
+ return false;
+}
--- /dev/null
+#include "subscriber.h"
+
+using GTS::Subscriber;
+
+Subscriber::Subscriber(const std::string & mac,
+ unsigned port,
+ unsigned upShape,
+ unsigned downShape,
+ unsigned upBurst,
+ unsigned downBurst)
+ : _mac(mac),
+ _port(port),
+ _upShape(upShape),
+ _downShape(downShape),
+ _upBurst(upBurst),
+ _downBurst(downBurst)
+{
+}
+
+Subscriber::~Subscriber()
+{
+}
+
+std::string Subscriber::getHexMAC() const
+{
+ return _mac;
+}
--- /dev/null
+#include <boost/lexical_cast.hpp>
+
+#include "snmp_pp/snmp_pp.h"
+
+#include "switch.h"
+#include "settings.h"
+#include "subscriber.h"
+#include "acl.h"
+#include "logger.h"
+#include "snmptable.h"
+#include "oids.h"
+
+using GTS::Switch;
+using GTS::SNMPTable;
+
+Switch::Switch(const Settings & settings,
+ Snmp & snmp,
+ const std::string & ip,
+ const std::string & readCommunity,
+ const std::string & writeCommunity,
+ unsigned uplinkPort)
+ : _settings(settings),
+ _snmp(snmp),
+ _ip(ip),
+ _readCommunity(readCommunity),
+ _writeCommunity(writeCommunity),
+ _uplinkPort(uplinkPort),
+ _nextUpACL(1),
+ _nextDownACL(1)
+{
+}
+
+Switch::Switch(const Switch & rvalue)
+ : _settings(rvalue._settings),
+ _snmp(rvalue._snmp),
+ _ip(rvalue._ip),
+ _readCommunity(rvalue._readCommunity),
+ _writeCommunity(rvalue._writeCommunity),
+ _uplinkPort(rvalue._uplinkPort),
+ _nextUpACL(rvalue._nextUpACL),
+ _nextDownACL(rvalue._nextDownACL),
+ _acls(rvalue._acls)
+{
+}
+
+Switch::~Switch()
+{
+}
+
+Switch & Switch::operator=(const Switch & rvalue)
+{
+ _ip = rvalue._ip;
+ _readCommunity = rvalue._readCommunity;
+ _writeCommunity = rvalue._writeCommunity;
+ _uplinkPort = rvalue._uplinkPort;
+ _nextUpACL = rvalue._nextUpACL;
+ _nextDownACL = rvalue._nextDownACL;
+ _acls = rvalue._acls;
+
+ return *this;
+}
+
+void Switch::addSubscriber(const Subscriber & subscriber)
+{
+ _acls.push_back(ACL(_nextUpACL++,
+ _settings.upProfileId(),
+ subscriber.getMAC(),
+ subscriber.getPort(),
+ subscriber.getUpShape(),
+ subscriber.getUpBurst(),
+ true));
+ _acls.push_back(ACL(_nextDownACL++,
+ _settings.downProfileId(),
+ subscriber.getMAC(),
+ _uplinkPort,
+ subscriber.getDownShape(),
+ subscriber.getDownBurst(),
+ false));
+}
+
+void Switch::sync()
+{
+ IpAddress addr(_ip.c_str());
+ if (!addr.valid()) {
+ logger << "Switch::sync() - ivalid switch ip: '" << _ip << "'" << std::endl;
+ return;
+ }
+
+ CTarget target(addr, _readCommunity.c_str(), _writeCommunity.c_str());
+ if (!target.valid()) {
+ logger << "Switch::sync() - failed to create target for the switch '" << _ip << "'" << std::endl;
+ return;
+ }
+
+ target.set_version(version2c);
+
+ if (!checkProfiles(target)) {
+ logger << "Switch::sync() - no upload and download profiles defined for the switch '" << _ip << "'" << std::endl;
+ return;
+ }
+
+ if (!dropACLs(target)) {
+ logger << "Switch::sync() - failed to drop ACLs for the switch '" << _ip << "'" << std::endl;
+ return;
+ }
+
+ if (!createACLs(target)) {
+ logger << "Switch::sync() - failed to create ACLs for the switch '" << _ip << "'" << std::endl;
+ }
+
+ if (_settings.isDebug()) {
+ logger << "Switch::sync() - switch '" << _ip << "' synchronized successfully, ACLs: " << _acls.size() << std::endl;
+ }
+}
+
+bool Switch::checkProfiles(const CTarget & target)
+{
+ SNMPTable table(_snmp, target, Oid(swACLEtherRuleProfileID));
+ if (!table.valid()) {
+ logger << "Switch::checkProfiles() - profiles SNMPTable is invalid for the switch '" << _ip << "'" << std::endl;
+ return false;
+ }
+ if (table.empty()) {
+ // Ok, just an empty table
+ return false;
+ }
+ if (table.valueExists(
+ static_cast<int>(_settings.upProfileId())
+ ) &&
+ table.valueExists(
+ static_cast<int>(_settings.downProfileId())
+ )) {
+ return true;
+ }
+ return false;
+}
+
+bool Switch::dropACLs(const CTarget & target)
+{
+ std::string upOidValue(swACLEtherRuleAccessID);
+ upOidValue += ".";
+ upOidValue += boost::lexical_cast<std::string>(_settings.upProfileId());
+ std::string downOidValue(swACLEtherRuleAccessID);
+ downOidValue += ".";
+ downOidValue += boost::lexical_cast<std::string>(_settings.downProfileId());
+ SNMPTable aclsUpTable(_snmp, target, Oid(upOidValue.c_str()));
+ SNMPTable aclsDownTable(_snmp, target, Oid(downOidValue.c_str()));
+ if (!aclsUpTable.valid()) {
+ logger << "Switch::dropACLs() - upload profile acls SNMPTable is invalid for the switch '" << _ip << "'" << std::endl;
+ return false;
+ }
+ if (!aclsDownTable.valid()) {
+ logger << "Switch::dropACLs() - download profile acls SNMPTable is invalid for the switch '" << _ip << "'" << std::endl;
+ return false;
+ }
+ if (!aclsUpTable.empty()) {
+ if (!dropACLsByTable(target, _settings.upProfileId(), aclsUpTable)) {
+ logger << "Switch::dropACLs() - failed to drop acls from upload table for the switch '" << _ip << "'" << std::endl;
+ return false;
+ }
+ }
+ if (!aclsDownTable.empty()) {
+ if (!dropACLsByTable(target, _settings.downProfileId(), aclsDownTable)) {
+ logger << "Switch::dropACLs() - failed to drop acls from download table for the switch '" << _ip << "'" << std::endl;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Switch::dropACLsByTable(const CTarget & target, unsigned profileId, const SNMPTable & table)
+{
+ std::string dropACLOidPrefix(swACLEtherRuleRowStatus);
+ dropACLOidPrefix += ".";
+ dropACLOidPrefix += boost::lexical_cast<std::string>(profileId);
+ SNMPList aclsList(table.getList());
+ Pdu pdu;
+ SNMPList::const_iterator it;
+ for (it = aclsList.begin(); it != aclsList.end(); ++it) {
+ int id;
+ if (it->get_value(id) != SNMP_CLASS_SUCCESS) {
+ return false;
+ }
+ std::string dropACLOid(dropACLOidPrefix);
+ dropACLOid += ".";
+ dropACLOid += boost::lexical_cast<std::string>(id);
+ Vb vb(Oid(dropACLOid.c_str()));
+ vb.set_value(int(6));
+ pdu += vb;
+ }
+ if (_snmp.set(pdu, target) != SNMP_CLASS_SUCCESS) {
+ logger << "Switch::dropACLsByTable() - failed to invoke Snmp::set for the switch '" << _ip << "'" << std::endl;
+ return false;
+ }
+ return true;
+}
+
+bool Switch::createACLs(const CTarget & target)
+{
+ std::vector<ACL>::const_iterator it;
+ for (it = _acls.begin(); it != _acls.end(); ++it) {
+ Pdu pdu;
+ it->appendPdu(pdu);
+ if (_snmp.set(pdu, target) != SNMP_CLASS_SUCCESS) {
+ logger << "Switch::createACLs() - failed to invoke Snmp::set for the switch '" << _ip << "'" << std::endl;
+ return false;
+ }
+ }
+ return true;
+}
--- /dev/null
+#include <sys/select.h>
+
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+#include <cassert>
+#include <algorithm>
+#include <exception>
+
+#include <boost/bind.hpp>
+
+#include "snmp_pp/snmp_pp.h"
+
+#include "syncer.h"
+#include "settings.h"
+#include "switch.h"
+#include "subscriber.h"
+#include "datatypes.h"
+#include "logger.h"
+
+using GTS::Syncer;
+using GTS::Timer;
+using GTS::Switch;
+using GTS::Subscriber;
+using GTS::Lines;
+
+Timer::Timer(boost::function<void ()> callback, time_t interval)
+ : _interval(interval),
+ _lastFire(0),
+ _callback(callback)
+{
+}
+
+Timer::~Timer()
+{
+}
+
+int Timer::getTimeout() const
+{
+ double delta = difftime(time(NULL), _lastFire);
+ return _interval - delta;
+}
+
+void Timer::fire()
+{
+ _callback();
+ time(&_lastFire);
+}
+
+Syncer::Syncer(SettingsParser & sp,
+ Snmp & snmp)
+ : _settingsParser(sp),
+ _snmp(snmp)
+{
+ // 1 db syncer
+ _timers.push_back(Timer(boost::bind(&Syncer::syncInfo, this),
+ _settingsParser.settings().infoSyncInterval()));
+}
+
+Syncer::~Syncer()
+{
+}
+
+void Syncer::run(const bool & running, bool & reload)
+{
+ logger << "Syncer::run()" << std::endl;
+ while (running) {
+ if (wait()) {
+ logger << "Syncer::run() - wait stopped by signal" << std::endl;
+ if (!running)
+ break;
+ if (reload) {
+ logger << "Syncer::run() - reload" << std::endl;
+ try {
+ _settingsParser.reloadConfig();
+ }
+ catch (std::exception & ex) {
+ logger << "Syncer::run() - exception: " << ex.what() << std::endl;
+ }
+ reload = false;
+ }
+ }
+ }
+}
+
+bool Syncer::wait()
+{
+ Timer & timer(getNextTimer());
+
+ if (timer.getTimeout() > 0) {
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+
+ struct timeval tv;
+ tv.tv_sec = timer.getTimeout();
+ tv.tv_usec = 0;
+
+ int retval = select(1, &rfds, NULL, NULL, &tv);
+
+ if (retval == -1) {
+ return true;
+ }
+ }
+
+ timer.fire();
+
+ return false;
+}
+
+Timer & Syncer::getNextTimer()
+{
+ assert(_timers.size() && "Timer list must not be empty!");
+ int timeout = _timers.begin()->getTimeout();
+ std::list<Timer>::iterator it(_timers.begin());
+ std::list<Timer>::iterator pos(_timers.begin());
+ ++it;
+ while (it != _timers.end()) {
+ if (it->getTimeout() < timeout) {
+ pos = it;
+ timeout = pos->getTimeout();
+ }
+ ++it;
+ }
+ return *pos;
+}
+
+void Syncer::syncInfo()
+{
+ std::map<std::string, Switch> switches;
+ if (!getSwitchesState(switches)) {
+ logger << "Syncer::syncInfo() - failed to get new switch states" << std::endl;
+ return;
+ }
+ std::list<TimedSwitch>::iterator it(_switches.begin());
+ while (it != _switches.end()) {
+ _timers.erase(it->second);
+ _switches.erase(it++);
+ }
+ std::map<std::string, Switch>::const_iterator sit;
+ for (sit = switches.begin(); sit != switches.end(); ++sit) {
+ // Insert switch with no timer
+ _switches.push_back(std::make_pair(sit->second, _timers.end()));
+ // Insert timer for this switch
+ TimerIterator tit = _timers.insert(
+ _timers.end(),
+ Timer(boost::bind(&Switch::sync, &_switches.back().first),
+ _settingsParser.settings().switchSyncInterval()));
+ // Set timer iterator for this switch
+ _switches.back().second = tit;
+ }
+ logger << "Syncer::syncInfo() - data synchronization successfull, switches: " << _switches.size() << std::endl;
+}
+
+size_t curlWriteFunction(void * ptr, size_t size, size_t nmemb, void * userdata)
+{
+ char * data = static_cast<char *>(ptr);
+ std::string * dest = static_cast<std::string *>(userdata);
+ dest->append(data, size * nmemb);
+ return size * nmemb;
+}
+
+bool Syncer::getDBData(std::string & data) const
+{
+ CURL * handle = curl_easy_init();
+ if (handle) {
+ char errorBuffer[CURL_ERROR_SIZE];
+ curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); // Accept self-signed certs
+ curl_easy_setopt(handle, CURLOPT_LOW_SPEED_LIMIT, 1); // Less than 1 bps
+ curl_easy_setopt(handle, CURLOPT_LOW_SPEED_TIME, 60); // During 60 secs
+ curl_easy_setopt(handle, CURLOPT_URL, _settingsParser.settings().dataURL().c_str()); // Our URL
+ curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curlWriteFunction); // Our write callback
+ curl_easy_setopt(handle, CURLOPT_WRITEDATA, &data); // Our callback data
+ curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errorBuffer); // Buffer for an error messages
+ CURLcode res = curl_easy_perform(handle);
+ if (res) {
+ logger << "Syncer::getDBData() - DB communication error: '" << errorBuffer << "'" << std::endl;
+ curl_easy_cleanup(handle);
+ return false;
+ }
+ curl_easy_cleanup(handle);
+ return true;
+ }
+ logger << "Syncer::getDBData() - failed to init CURL library" << std::endl;
+ return false;
+}
+
+bool Syncer::getSwitchesState(std::map<std::string, Switch> & switches)
+{
+ if (_settingsParser.settings().dataURL().empty()) {
+ logger << "Switch::getSwitchesState() - data URL is empty" << std::endl;
+ return false;
+ }
+ std::string data;
+ if (!getDBData(data)) {
+ logger << "Syncer::getSwitchesState() - failed to fetch data from the URL: '" << _settingsParser.settings().dataURL() << "'" << std::endl;
+ return false;
+ }
+ Lines lines;
+ if (!parseData(data, lines)) {
+ logger << "Syncer::getSwitchesState() - failed to parse data:\n" << data << std::endl;
+ return false;
+ }
+ Lines::const_iterator it;
+ for (it = lines.begin(); it != lines.end(); ++it) {
+ std::pair<std::map<std::string, Switch>::iterator, bool> res(
+ switches.insert(
+ std::make_pair(
+ it->switchIP,
+ Switch(
+ _settingsParser.settings(),
+ _snmp,
+ it->switchIP,
+ it->readCommunity,
+ it->writeCommunity,
+ it->uplinkPort
+ )
+ )
+ )
+ );
+ res.first->second.addSubscriber(
+ Subscriber(
+ it->mac,
+ it->userPort,
+ it->upShape,
+ it->downShape,
+ it->upBurst,
+ it->downBurst
+ )
+ );
+ }
+ return true;
+}
--- /dev/null
+DEFS =
+INCS = -I../include -I../3rdparty/snmp++/include
+CXXFLAGS += -W -Wall -Wextra $(INCS) $(DEFS)
+LIBS = -lpthread \
+ -lssl \
+ -lboost_system \
+ -lboost_program_options \
+ ../3rdparty/snmp++/libsnmp++.a
+
+SOURCES1 = test_switch.cpp \
+ ../src/settings.cpp \
+ ../src/settingsfileparser.cpp \
+ ../src/logger.cpp \
+ ../src/subscriber.cpp \
+ ../src/switch.cpp \
+ ../src/acl.cpp \
+ ../src/snmptable.cpp
+
+SOURCES2 = test_data_parser.cpp \
+ ../src/logger.cpp \
+ ../src/dataparser.cpp
+
+.PHONY: all clean snmplib tests
+
+all: tests
+
+tests: test_switch test_data_parser
+
+snmplib:
+ $(MAKE) all -C ../3rdparty
+
+test_switch: $(subst .cpp,.o,$(SOURCES1)) snmplib
+ $(CXX) $(subst .cpp,.o,$(SOURCES1)) $(LIBS) -o $@
+
+test_data_parser: $(subst .cpp,.o,$(SOURCES2))
+ $(CXX) $(subst .cpp,.o,$(SOURCES2)) $(LIBS) -o $@
+
+clean: snmplib
+ rm -f *.o *.d test_switch test_data_parser
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+-include $(subst .cpp,.d,$(SOURCES))
+endif
+endif
+
+%.d: %.cpp
+ @$(CXX) -MM $(CXXFLAGS) $< > $@.$$$$; \
+ sed 's,\($*\).o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+ rm -f $@.$$$$
--- /dev/null
+#include <iostream>
+
+#include "datatypes.h"
+#include "logger.h"
+
+GTS::Logger logger;
+
+int main()
+{
+ GTS::Lines lines;
+ std::string data(
+"172.16.47.10,gts_community_r,gts_community_w,10,1,001CC0B16177,64,128,64,128\n"
+"172.16.47.11,gts_community_r,gts_community_w,10,1,001CC0B16178,65,129,66,138\n"
+"172.16.47.10,gts_community_r,gts_community_w,16,1,001CC0B16179,66,130,68,148\n"
+"172.16.47.10,gts_community_r,gts_community_w,16,8,001CC0B16180,67,131,70,158\n"
+ );
+
+ std::cout << data << std::endl;
+
+ if (!parseData(data, lines)) {
+ logger << "Failed to parse data" << std::endl;
+ } else {
+ GTS::Lines::const_iterator it;
+ for (it = lines.begin(); it != lines.end(); ++it) {
+ logger << "line: "
+ << it->switchIP << ","
+ << it->readCommunity << ","
+ << it->writeCommunity << ","
+ << it->uplinkPort << ","
+ << it->userPort << ","
+ << it->mac << ","
+ << it->upShape << ","
+ << it->downShape << ","
+ << it->upBurst << ","
+ << it->downBurst << std::endl;
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+#include <iostream>
+#include <exception>
+
+#include "snmp_pp/snmp_pp.h"
+
+#include "settings.h"
+#include "switch.h"
+#include "subscriber.h"
+#include "logger.h"
+
+GTS::Logger logger;
+
+int main()
+{
+ GTS::Settings settings;
+
+ settings.setIsDebug(true);
+ settings.setUpProfileId(1);
+ settings.setDownProfileId(2);
+
+ int status = 0;
+ Snmp snmp(status);
+
+ if (status) {
+ logger << "Failed to initialize SNMP" << std::endl;
+ return -1;
+ }
+
+ GTS::Switch sw(settings,
+ snmp,
+ "172.16.47.10",
+ "gts_community_r",
+ "gts_community_w",
+ 10);
+
+ sw.addSubscriber(
+ GTS::Subscriber(
+ "485b3936a273",
+ 1,
+ 8192,
+ 8192,
+ 256,
+ 512
+ )
+ );
+
+ sw.sync();
+ return 0;
+}