From ae26516a8828d54ab7c0e0bca92031a54a15ed62 Mon Sep 17 00:00:00 2001 From: Maxim Mamontov Date: Wed, 23 Nov 2011 19:08:57 +0200 Subject: [PATCH 1/1] Initial adding --- 3rdparty/Makefile | 8 + 3rdparty/snmp++/Makefile | 57 + 3rdparty/snmp++/include/snmp_pp/IPv6Utility.h | 77 + 3rdparty/snmp++/include/snmp_pp/address.h | 1165 +++++ 3rdparty/snmp++/include/snmp_pp/asn1.h | 444 ++ 3rdparty/snmp++/include/snmp_pp/auth_priv.h | 860 ++++ 3rdparty/snmp++/include/snmp_pp/collect.h | 396 ++ .../snmp++/include/snmp_pp/config_snmp_pp.h | 284 ++ 3rdparty/snmp++/include/snmp_pp/counter.h | 146 + 3rdparty/snmp++/include/snmp_pp/ctr64.h | 325 ++ 3rdparty/snmp++/include/snmp_pp/eventlist.h | 201 + .../snmp++/include/snmp_pp/eventlistholder.h | 118 + 3rdparty/snmp++/include/snmp_pp/gauge.h | 150 + 3rdparty/snmp++/include/snmp_pp/idea.h | 169 + 3rdparty/snmp++/include/snmp_pp/integer.h | 286 ++ 3rdparty/snmp++/include/snmp_pp/log.h | 560 +++ 3rdparty/snmp++/include/snmp_pp/md5.h | 128 + 3rdparty/snmp++/include/snmp_pp/mp_v3.h | 650 +++ 3rdparty/snmp++/include/snmp_pp/msec.h | 189 + 3rdparty/snmp++/include/snmp_pp/msgqueue.h | 224 + 3rdparty/snmp++/include/snmp_pp/notifyqueue.h | 202 + 3rdparty/snmp++/include/snmp_pp/octet.h | 462 ++ 3rdparty/snmp++/include/snmp_pp/oid.h | 457 ++ 3rdparty/snmp++/include/snmp_pp/oid_def.h | 118 + 3rdparty/snmp++/include/snmp_pp/pdu.h | 527 ++ 3rdparty/snmp++/include/snmp_pp/reentrant.h | 87 + 3rdparty/snmp++/include/snmp_pp/sha.h | 70 + 3rdparty/snmp++/include/snmp_pp/smi.h | 212 + 3rdparty/snmp++/include/snmp_pp/smival.h | 178 + 3rdparty/snmp++/include/snmp_pp/snmp_pp.h | 78 + 3rdparty/snmp++/include/snmp_pp/snmperrs.h | 274 + 3rdparty/snmp++/include/snmp_pp/snmpmsg.h | 170 + 3rdparty/snmp++/include/snmp_pp/target.h | 668 +++ 3rdparty/snmp++/include/snmp_pp/timetick.h | 168 + 3rdparty/snmp++/include/snmp_pp/usm_v3.h | 1114 ++++ 3rdparty/snmp++/include/snmp_pp/uxsnmp.h | 665 +++ 3rdparty/snmp++/include/snmp_pp/v3.h | 283 ++ 3rdparty/snmp++/include/snmp_pp/vb.h | 431 ++ 3rdparty/snmp++/src/IPv6Utility.cpp | 432 ++ 3rdparty/snmp++/src/address.cpp | 2756 ++++++++++ 3rdparty/snmp++/src/asn1.cpp | 1997 ++++++++ 3rdparty/snmp++/src/auth_priv.cpp | 2200 ++++++++ 3rdparty/snmp++/src/counter.cpp | 97 + 3rdparty/snmp++/src/ctr64.cpp | 308 ++ 3rdparty/snmp++/src/eventlist.cpp | 269 + 3rdparty/snmp++/src/eventlistholder.cpp | 367 ++ 3rdparty/snmp++/src/gauge.cpp | 72 + 3rdparty/snmp++/src/idea.cpp | 274 + 3rdparty/snmp++/src/integer.cpp | 257 + 3rdparty/snmp++/src/log.cpp | 410 ++ 3rdparty/snmp++/src/md5c.cpp | 364 ++ 3rdparty/snmp++/src/mp_v3.cpp | 1523 ++++++ 3rdparty/snmp++/src/msec.cpp | 280 ++ 3rdparty/snmp++/src/msgqueue.cpp | 789 +++ 3rdparty/snmp++/src/notifyqueue.cpp | 755 +++ 3rdparty/snmp++/src/octet.cpp | 851 ++++ 3rdparty/snmp++/src/oid.cpp | 748 +++ 3rdparty/snmp++/src/pdu.cpp | 585 +++ 3rdparty/snmp++/src/reentrant.cpp | 93 + 3rdparty/snmp++/src/sha.cpp | 287 ++ 3rdparty/snmp++/src/snmpmsg.cpp | 832 +++ 3rdparty/snmp++/src/target.cpp | 408 ++ 3rdparty/snmp++/src/timetick.cpp | 134 + 3rdparty/snmp++/src/usm_v3.cpp | 4476 +++++++++++++++++ 3rdparty/snmp++/src/uxsnmp.cpp | 2362 +++++++++ 3rdparty/snmp++/src/v3.cpp | 442 ++ 3rdparty/snmp++/src/vb.cpp | 378 ++ Makefile | 56 + gssmd.conf | 40 + include/.switch.h.swp | Bin 0 -> 12288 bytes include/.syncer.h.swp | Bin 0 -> 12288 bytes include/acl.h | 50 + include/datatypes.h | 28 + include/logger.h | 41 + include/oids.h | 14 + include/pidfile.h | 22 + include/settings.h | 101 + include/settings.inl.h | 78 + include/snmptable.h | 36 + include/snmptable.inl.h | 24 + include/subscriber.h | 37 + include/switch.h | 61 + include/syncer.h | 59 + include/version.h.in | 11 + src/.main.cpp.swp | Bin 0 -> 16384 bytes src/.switch.cpp.swp | Bin 0 -> 16384 bytes src/.syncer.cpp.swp | Bin 0 -> 16384 bytes src/acl.cpp | 116 + src/dataparser.cpp | 84 + src/logger.cpp | 57 + src/main.cpp | 164 + src/pidfile.cpp | 45 + src/settings.cpp | 89 + src/settingsfileparser.cpp | 125 + src/snmptable.cpp | 41 + src/subscriber.cpp | 27 + src/switch.cpp | 210 + src/syncer.cpp | 234 + tests/Makefile | 50 + tests/test_data_parser.cpp | 40 + tests/test_switch.cpp | 49 + 101 files changed, 39336 insertions(+) create mode 100644 3rdparty/Makefile create mode 100644 3rdparty/snmp++/Makefile create mode 100644 3rdparty/snmp++/include/snmp_pp/IPv6Utility.h create mode 100644 3rdparty/snmp++/include/snmp_pp/address.h create mode 100644 3rdparty/snmp++/include/snmp_pp/asn1.h create mode 100644 3rdparty/snmp++/include/snmp_pp/auth_priv.h create mode 100644 3rdparty/snmp++/include/snmp_pp/collect.h create mode 100644 3rdparty/snmp++/include/snmp_pp/config_snmp_pp.h create mode 100644 3rdparty/snmp++/include/snmp_pp/counter.h create mode 100644 3rdparty/snmp++/include/snmp_pp/ctr64.h create mode 100644 3rdparty/snmp++/include/snmp_pp/eventlist.h create mode 100644 3rdparty/snmp++/include/snmp_pp/eventlistholder.h create mode 100644 3rdparty/snmp++/include/snmp_pp/gauge.h create mode 100644 3rdparty/snmp++/include/snmp_pp/idea.h create mode 100644 3rdparty/snmp++/include/snmp_pp/integer.h create mode 100644 3rdparty/snmp++/include/snmp_pp/log.h create mode 100644 3rdparty/snmp++/include/snmp_pp/md5.h create mode 100644 3rdparty/snmp++/include/snmp_pp/mp_v3.h create mode 100644 3rdparty/snmp++/include/snmp_pp/msec.h create mode 100644 3rdparty/snmp++/include/snmp_pp/msgqueue.h create mode 100644 3rdparty/snmp++/include/snmp_pp/notifyqueue.h create mode 100644 3rdparty/snmp++/include/snmp_pp/octet.h create mode 100644 3rdparty/snmp++/include/snmp_pp/oid.h create mode 100644 3rdparty/snmp++/include/snmp_pp/oid_def.h create mode 100644 3rdparty/snmp++/include/snmp_pp/pdu.h create mode 100644 3rdparty/snmp++/include/snmp_pp/reentrant.h create mode 100644 3rdparty/snmp++/include/snmp_pp/sha.h create mode 100644 3rdparty/snmp++/include/snmp_pp/smi.h create mode 100644 3rdparty/snmp++/include/snmp_pp/smival.h create mode 100644 3rdparty/snmp++/include/snmp_pp/snmp_pp.h create mode 100644 3rdparty/snmp++/include/snmp_pp/snmperrs.h create mode 100644 3rdparty/snmp++/include/snmp_pp/snmpmsg.h create mode 100644 3rdparty/snmp++/include/snmp_pp/target.h create mode 100644 3rdparty/snmp++/include/snmp_pp/timetick.h create mode 100644 3rdparty/snmp++/include/snmp_pp/usm_v3.h create mode 100644 3rdparty/snmp++/include/snmp_pp/uxsnmp.h create mode 100644 3rdparty/snmp++/include/snmp_pp/v3.h create mode 100644 3rdparty/snmp++/include/snmp_pp/vb.h create mode 100644 3rdparty/snmp++/src/IPv6Utility.cpp create mode 100644 3rdparty/snmp++/src/address.cpp create mode 100644 3rdparty/snmp++/src/asn1.cpp create mode 100644 3rdparty/snmp++/src/auth_priv.cpp create mode 100644 3rdparty/snmp++/src/counter.cpp create mode 100644 3rdparty/snmp++/src/ctr64.cpp create mode 100644 3rdparty/snmp++/src/eventlist.cpp create mode 100644 3rdparty/snmp++/src/eventlistholder.cpp create mode 100644 3rdparty/snmp++/src/gauge.cpp create mode 100644 3rdparty/snmp++/src/idea.cpp create mode 100644 3rdparty/snmp++/src/integer.cpp create mode 100644 3rdparty/snmp++/src/log.cpp create mode 100644 3rdparty/snmp++/src/md5c.cpp create mode 100644 3rdparty/snmp++/src/mp_v3.cpp create mode 100644 3rdparty/snmp++/src/msec.cpp create mode 100644 3rdparty/snmp++/src/msgqueue.cpp create mode 100644 3rdparty/snmp++/src/notifyqueue.cpp create mode 100644 3rdparty/snmp++/src/octet.cpp create mode 100644 3rdparty/snmp++/src/oid.cpp create mode 100644 3rdparty/snmp++/src/pdu.cpp create mode 100644 3rdparty/snmp++/src/reentrant.cpp create mode 100644 3rdparty/snmp++/src/sha.cpp create mode 100644 3rdparty/snmp++/src/snmpmsg.cpp create mode 100644 3rdparty/snmp++/src/target.cpp create mode 100644 3rdparty/snmp++/src/timetick.cpp create mode 100644 3rdparty/snmp++/src/usm_v3.cpp create mode 100644 3rdparty/snmp++/src/uxsnmp.cpp create mode 100644 3rdparty/snmp++/src/v3.cpp create mode 100644 3rdparty/snmp++/src/vb.cpp create mode 100644 Makefile create mode 100644 gssmd.conf create mode 100644 include/.switch.h.swp create mode 100644 include/.syncer.h.swp create mode 100644 include/acl.h create mode 100644 include/datatypes.h create mode 100644 include/logger.h create mode 100644 include/oids.h create mode 100644 include/pidfile.h create mode 100644 include/settings.h create mode 100644 include/settings.inl.h create mode 100644 include/snmptable.h create mode 100644 include/snmptable.inl.h create mode 100644 include/subscriber.h create mode 100644 include/switch.h create mode 100644 include/syncer.h create mode 100644 include/version.h.in create mode 100644 src/.main.cpp.swp create mode 100644 src/.switch.cpp.swp create mode 100644 src/.syncer.cpp.swp create mode 100644 src/acl.cpp create mode 100644 src/dataparser.cpp create mode 100644 src/logger.cpp create mode 100644 src/main.cpp create mode 100644 src/pidfile.cpp create mode 100644 src/settings.cpp create mode 100644 src/settingsfileparser.cpp create mode 100644 src/snmptable.cpp create mode 100644 src/subscriber.cpp create mode 100644 src/switch.cpp create mode 100644 src/syncer.cpp create mode 100644 tests/Makefile create mode 100644 tests/test_data_parser.cpp create mode 100644 tests/test_switch.cpp diff --git a/3rdparty/Makefile b/3rdparty/Makefile new file mode 100644 index 0000000..6474668 --- /dev/null +++ b/3rdparty/Makefile @@ -0,0 +1,8 @@ +SHELL = /bin/sh + +.PHONY: all clean + +all: + $(MAKE) $(MAKECMDGOALS) -C snmp++ + +clean: all diff --git a/3rdparty/snmp++/Makefile b/3rdparty/snmp++/Makefile new file mode 100644 index 0000000..2a67cd9 --- /dev/null +++ b/3rdparty/snmp++/Makefile @@ -0,0 +1,57 @@ +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 $@.$$$$ diff --git a/3rdparty/snmp++/include/snmp_pp/IPv6Utility.h b/3rdparty/snmp++/include/snmp_pp/IPv6Utility.h new file mode 100644 index 0000000..20df968 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/IPv6Utility.h @@ -0,0 +1,77 @@ +/*_############################################################################ + _## + _## 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 + diff --git a/3rdparty/snmp++/include/snmp_pp/address.h b/3rdparty/snmp++/include/snmp_pp/address.h new file mode 100644 index 0000000..7e6866f --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/address.h @@ -0,0 +1,1165 @@ +/*_############################################################################ + _## + _## 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 + +#if defined (CPU) && CPU == PPC603 +#undef HASH1 +#undef HASH2 +#else +#include +#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 +#include +#endif + +#ifdef __unix +#if !defined(_AIX) && !defined(__QNX_NEUTRINO) +#include +#endif +#include +#include +#include +#include +#if defined _AIX +#include // 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 AddressCollection; +typedef SnmpCollection UdpAddressCollection; + +#ifdef SNMP_PP_NAMESPACE +} // end of namespace Snmp_pp +#endif + +#endif //_ADDRESS diff --git a/3rdparty/snmp++/include/snmp_pp/asn1.h b/3rdparty/snmp++/include/snmp_pp/asn1.h new file mode 100644 index 0000000..84ab242 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/asn1.h @@ -0,0 +1,444 @@ +/*_############################################################################ + _## + _## 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. + *
+ *  HeaderData ::= SEQUENCE {
+ *    msgID      INTEGER (0..2147483647),
+ *    msgMaxSize INTEGER (484..2147483647),
+ *    msgFlags   OCTET STRING (SIZE(1)),
+ *    msgSecurityModel INTEGER (0..2147483647)
+ *  }
+ *                                                                 
+ * @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. + *
+ *      HeaderData ::= SEQUENCE {
+ *          msgID      INTEGER (0..2147483647),
+ *          msgMaxSize INTEGER (484..2147483647),
+ *          msgFlags   OCTET STRING (SIZE(1)),
+ *          msgSecurityModel INTEGER (0..2147483647)
+ *      }
+ *                                                                 
+ * + * @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. + *
+ *      ScopedPDU ::= SEQUENCE {
+ *          contextEngineID  OCTET STRING,
+ *          contextName      OCTET STRING,
+ *          data             ANY -- e.g., PDUs as defined in RFC 1905
+ *      }
+ *                                                                 
+ * + * @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. + *
+ *    ScopedPDU ::= SEQUENCE {
+ *           contextEngineID OCTET STRING
+ *           contextName     OCTET STRING
+ *           data            ANY  -- PDU
+ *       }
+ *                                                                 
+ * 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 diff --git a/3rdparty/snmp++/include/snmp_pp/auth_priv.h b/3rdparty/snmp++/include/snmp_pp/auth_priv.h new file mode 100644 index 0000000..5b78870 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/auth_priv.h @@ -0,0 +1,860 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/collect.h b/3rdparty/snmp++/include/snmp_pp/collect.h new file mode 100644 index 0000000..faa8b92 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/collect.h @@ -0,0 +1,396 @@ +/*_############################################################################ + _## + _## 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 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 &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 &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; znext; + 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; znext; + 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; znext; + 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; znext; + 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; zget_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; zget_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 newCollection; + + for (int z=0; z= 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_ + diff --git a/3rdparty/snmp++/include/snmp_pp/config_snmp_pp.h b/3rdparty/snmp++/include/snmp_pp/config_snmp_pp.h new file mode 100644 index 0000000..e21567b --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/config_snmp_pp.h @@ -0,0 +1,284 @@ +/*_############################################################################ + _## + _## 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 +#include +#else +#include +#include +#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 +#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_ diff --git a/3rdparty/snmp++/include/snmp_pp/counter.h b/3rdparty/snmp++/include/snmp_pp/counter.h new file mode 100644 index 0000000..d3719bd --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/counter.h @@ -0,0 +1,146 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/ctr64.h b/3rdparty/snmp++/include/snmp_pp/ctr64.h new file mode 100644 index 0000000..338fe31 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/ctr64.h @@ -0,0 +1,325 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/eventlist.h b/3rdparty/snmp++/include/snmp_pp/eventlist.h new file mode 100644 index 0000000..fecaae5 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/eventlist.h @@ -0,0 +1,201 @@ +/*_############################################################################ + _## + _## 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 +#include // 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 +#else +#if !(defined CPU && CPU == PPC603) +#include // time stuff and fd_set +#endif +#include +#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 diff --git a/3rdparty/snmp++/include/snmp_pp/eventlistholder.h b/3rdparty/snmp++/include/snmp_pp/eventlistholder.h new file mode 100644 index 0000000..f007573 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/eventlistholder.h @@ -0,0 +1,118 @@ +/*_############################################################################ + _## + _## 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_ diff --git a/3rdparty/snmp++/include/snmp_pp/gauge.h b/3rdparty/snmp++/include/snmp_pp/gauge.h new file mode 100644 index 0000000..313c5a0 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/gauge.h @@ -0,0 +1,150 @@ +/*_############################################################################ + _## + _## 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_ diff --git a/3rdparty/snmp++/include/snmp_pp/idea.h b/3rdparty/snmp++/include/snmp_pp/idea.h new file mode 100644 index 0000000..f0c9df6 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/idea.h @@ -0,0 +1,169 @@ +/*_############################################################################ + _## + _## 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 + +Copyright (c) 1995 Tatu Ylonen , 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 + +Copyright (c) 1995 Tatu Ylonen , 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 */ + diff --git a/3rdparty/snmp++/include/snmp_pp/integer.h b/3rdparty/snmp++/include/snmp_pp/integer.h new file mode 100644 index 0000000..e6e6de5 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/integer.h @@ -0,0 +1,286 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/log.h b/3rdparty/snmp++/include/snmp_pp/log.h new file mode 100644 index 0000000..121df01 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/log.h @@ -0,0 +1,560 @@ +/*_############################################################################ + _## + _## 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 +#include + +#ifndef WIN32 +#include +#endif +#include +#include + + +#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_ diff --git a/3rdparty/snmp++/include/snmp_pp/md5.h b/3rdparty/snmp++/include/snmp_pp/md5.h new file mode 100644 index 0000000..67db51f --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/md5.h @@ -0,0 +1,128 @@ +/*_############################################################################ + _## + _## 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) diff --git a/3rdparty/snmp++/include/snmp_pp/mp_v3.h b/3rdparty/snmp++/include/snmp_pp/mp_v3.h new file mode 100644 index 0000000..b133db5 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/mp_v3.h @@ -0,0 +1,650 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/msec.h b/3rdparty/snmp++/include/snmp_pp/msec.h new file mode 100644 index 0000000..0b642f0 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/msec.h @@ -0,0 +1,189 @@ +/*_############################################################################ + _## + _## 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 /* 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 +#else +#include +#include +#endif + +#include + +#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_ diff --git a/3rdparty/snmp++/include/snmp_pp/msgqueue.h b/3rdparty/snmp++/include/snmp_pp/msgqueue.h new file mode 100644 index 0000000..7ff7d93 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/msgqueue.h @@ -0,0 +1,224 @@ +/*_############################################################################ + _## + _## 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 // 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 // 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 diff --git a/3rdparty/snmp++/include/snmp_pp/notifyqueue.h b/3rdparty/snmp++/include/snmp_pp/notifyqueue.h new file mode 100644 index 0000000..125e8c9 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/notifyqueue.h @@ -0,0 +1,202 @@ +/*_############################################################################ + _## + _## 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 // 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 // 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 diff --git a/3rdparty/snmp++/include/snmp_pp/octet.h b/3rdparty/snmp++/include/snmp_pp/octet.h new file mode 100644 index 0000000..06a1c14 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/octet.h @@ -0,0 +1,462 @@ +/*_############################################################################ + _## + _## 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: + *
+   * 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()
+   *                                                                     
+ * If the output format was set to OctetStr::OutputHex the + * produced string will look like this: + *
+   * 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
+   *                                                                     
+ * @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 diff --git a/3rdparty/snmp++/include/snmp_pp/oid.h b/3rdparty/snmp++/include/snmp_pp/oid.h new file mode 100644 index 0000000..2767eb7 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/oid.h @@ -0,0 +1,457 @@ +/*_############################################################################ + _## + _## 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 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_ diff --git a/3rdparty/snmp++/include/snmp_pp/oid_def.h b/3rdparty/snmp++/include/snmp_pp/oid_def.h new file mode 100644 index 0000000..49ed3fb --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/oid_def.h @@ -0,0 +1,118 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/pdu.h b/3rdparty/snmp++/include/snmp_pp/pdu.h new file mode 100644 index 0000000..fd7ec6f --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/pdu.h @@ -0,0 +1,527 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/reentrant.h b/3rdparty/snmp++/include/snmp_pp/reentrant.h new file mode 100644 index 0000000..6f35454 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/reentrant.h @@ -0,0 +1,87 @@ +/*_############################################################################ + _## + _## 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 +#elif defined (CPU) && CPU == PPC603 +#include +#else +#include +#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 + diff --git a/3rdparty/snmp++/include/snmp_pp/sha.h b/3rdparty/snmp++/include/snmp_pp/sha.h new file mode 100644 index 0000000..2e8d289 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/sha.h @@ -0,0 +1,70 @@ +/*_############################################################################ + _## + _## 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) + diff --git a/3rdparty/snmp++/include/snmp_pp/smi.h b/3rdparty/snmp++/include/snmp_pp/smi.h new file mode 100644 index 0000000..8f076e9 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/smi.h @@ -0,0 +1,212 @@ +/*_############################################################################ + _## + _## 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 + + diff --git a/3rdparty/snmp++/include/snmp_pp/smival.h b/3rdparty/snmp++/include/snmp_pp/smival.h new file mode 100644 index 0000000..c0807cc --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/smival.h @@ -0,0 +1,178 @@ +/*_############################################################################ + _## + _## 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_ */ + 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 diff --git a/3rdparty/snmp++/include/snmp_pp/snmp_pp.h b/3rdparty/snmp++/include/snmp_pp/snmp_pp.h new file mode 100644 index 0000000..e0f8340 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/snmp_pp.h @@ -0,0 +1,78 @@ +/*_############################################################################ + _## + _## 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_ diff --git a/3rdparty/snmp++/include/snmp_pp/snmperrs.h b/3rdparty/snmp++/include/snmp_pp/snmperrs.h new file mode 100644 index 0000000..bfe4064 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/snmperrs.h @@ -0,0 +1,274 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/snmpmsg.h b/3rdparty/snmp++/include/snmp_pp/snmpmsg.h new file mode 100644 index 0000000..897f253 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/snmpmsg.h @@ -0,0 +1,170 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/target.h b/3rdparty/snmp++/include/snmp_pp/target.h new file mode 100644 index 0000000..6c72c20 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/target.h @@ -0,0 +1,668 @@ +/*_############################################################################ + _## + _## 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 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 diff --git a/3rdparty/snmp++/include/snmp_pp/timetick.h b/3rdparty/snmp++/include/snmp_pp/timetick.h new file mode 100644 index 0000000..b7770b4 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/timetick.h @@ -0,0 +1,168 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/usm_v3.h b/3rdparty/snmp++/include/snmp_pp/usm_v3.h new file mode 100644 index 0000000..cec9367 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/usm_v3.h @@ -0,0 +1,1114 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/uxsnmp.h b/3rdparty/snmp++/include/snmp_pp/uxsnmp.h new file mode 100644 index 0000000..467f1cb --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/uxsnmp.h @@ -0,0 +1,665 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/include/snmp_pp/v3.h b/3rdparty/snmp++/include/snmp_pp/v3.h new file mode 100644 index 0000000..f63440a --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/v3.h @@ -0,0 +1,283 @@ +/*_############################################################################ + _## + _## 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 +#include + +#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 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 diff --git a/3rdparty/snmp++/include/snmp_pp/vb.h b/3rdparty/snmp++/include/snmp_pp/vb.h new file mode 100644 index 0000000..1623356 --- /dev/null +++ b/3rdparty/snmp++/include/snmp_pp/vb.h @@ -0,0 +1,431 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/src/IPv6Utility.cpp b/3rdparty/snmp++/src/IPv6Utility.cpp new file mode 100644 index 0000000..a6faab1 --- /dev/null +++ b/3rdparty/snmp++/src/IPv6Utility.cpp @@ -0,0 +1,432 @@ +/*_############################################################################ + _## + _## 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 //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) diff --git a/3rdparty/snmp++/src/address.cpp b/3rdparty/snmp++/src/address.cpp new file mode 100644 index 0000000..cc3a2de --- /dev/null +++ b/3rdparty/snmp++/src/address.cpp @@ -0,0 +1,2756 @@ +/*_############################################################################ + _## + _## 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 +#include +#include + +#if defined(__APPLE__) +#include +#include +#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 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= 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 3) || (digit_count < 1)) + return FALSE; + for (int i=0; i 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; ih_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= '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= '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 ::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 ::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 ::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 ::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 ::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 ::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 ::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 diff --git a/3rdparty/snmp++/src/asn1.cpp b/3rdparty/snmp++/src/asn1.cpp new file mode 100644 index 0000000..eec57c5 --- /dev/null +++ b/3rdparty/snmp++/src/asn1.cpp @@ -0,0 +1,1997 @@ +/*_############################################################################ + _## + _## 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 /**/ +#include /**/ +#endif + +#include /**/ + +#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> (8 * ((u_integer_len-1)-x)& 0xFF)); + } + else + { + for (x=0;x> (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 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 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 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 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 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 diff --git a/3rdparty/snmp++/src/auth_priv.cpp b/3rdparty/snmp++/src/auth_priv.cpp new file mode 100644 index 0000000..575de01 --- /dev/null +++ b/3rdparty/snmp++/src/auth_priv.cpp @@ -0,0 +1,2200 @@ +/*_############################################################################ + _## + _## 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 +#include +#include + +// Only use DES, AES, SHA1 and MD5 from libtomcrypt if openssl is not used +#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL) +#include +#endif + +// Use DES, AES, SHA and MD5 from openssl +#ifdef _USE_OPENSSL +#include +#include +#include +#include +#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 +#else +#include +#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 ; iset_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 ; iset_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; iget_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> (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; jpassword_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 diff --git a/3rdparty/snmp++/src/counter.cpp b/3rdparty/snmp++/src/counter.cpp new file mode 100644 index 0000000..42b2351 --- /dev/null +++ b/3rdparty/snmp++/src/counter.cpp @@ -0,0 +1,97 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/src/ctr64.cpp b/3rdparty/snmp++/src/ctr64.cpp new file mode 100644 index 0000000..27e0733 --- /dev/null +++ b/3rdparty/snmp++/src/ctr64.cpp @@ -0,0 +1,308 @@ +/*_############################################################################ + _## + _## 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 // 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 diff --git a/3rdparty/snmp++/src/eventlist.cpp b/3rdparty/snmp++/src/eventlist.cpp new file mode 100644 index 0000000..60ce60b --- /dev/null +++ b/3rdparty/snmp++/src/eventlist.cpp @@ -0,0 +1,269 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/src/eventlistholder.cpp b/3rdparty/snmp++/src/eventlistholder.cpp new file mode 100644 index 0000000..052b1ad --- /dev/null +++ b/3rdparty/snmp++/src/eventlistholder.cpp @@ -0,0 +1,367 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/src/gauge.cpp b/3rdparty/snmp++/src/gauge.cpp new file mode 100644 index 0000000..17f9c8f --- /dev/null +++ b/3rdparty/snmp++/src/gauge.cpp @@ -0,0 +1,72 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/src/idea.cpp b/3rdparty/snmp++/src/idea.cpp new file mode 100644 index 0000000..6229e2c --- /dev/null +++ b/3rdparty/snmp++/src/idea.cpp @@ -0,0 +1,274 @@ +/*_############################################################################ + _## + _## 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 + +Copyright (c) 1995 Tatu Ylonen , 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 + +#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 diff --git a/3rdparty/snmp++/src/integer.cpp b/3rdparty/snmp++/src/integer.cpp new file mode 100644 index 0000000..096657c --- /dev/null +++ b/3rdparty/snmp++/src/integer.cpp @@ -0,0 +1,257 @@ +/*_############################################################################ + _## + _## 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 // 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 diff --git a/3rdparty/snmp++/src/log.cpp b/3rdparty/snmp++/src/log.cpp new file mode 100644 index 0000000..df16708 --- /dev/null +++ b/3rdparty/snmp++/src/log.cpp @@ -0,0 +1,410 @@ +/*_############################################################################ + _## + _## 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 +#else +#include +#endif +#include +#include +#include +#include +#include + +#include + +#ifdef WIN32 +#ifdef __BCPLUSPLUS__ +#define _getpid getpid +#endif +#endif + +#if defined (CPU) && CPU == PPC603 +#include +#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=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; +} diff --git a/3rdparty/snmp++/src/md5c.cpp b/3rdparty/snmp++/src/md5c.cpp new file mode 100644 index 0000000..80140e4 --- /dev/null +++ b/3rdparty/snmp++/src/md5c.cpp @@ -0,0 +1,364 @@ +/*_############################################################################ + _## + _## 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 + +#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) diff --git a/3rdparty/snmp++/src/mp_v3.cpp b/3rdparty/snmp++/src/mp_v3.cpp new file mode 100644 index 0000000..0ca4d98 --- /dev/null +++ b/3rdparty/snmp++/src/mp_v3.cpp @@ -0,0 +1,1523 @@ +/*_############################################################################ + _## + _## 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 + +#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 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; idelete_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; idelete_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 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 msgSecurityParameters(MAX_SNMP_PACKET); + Buffer msgData(MAX_SNMP_PACKET); + int msgSecurityParametersLength = inBufLength, msgDataLength = inBufLength; + Buffer 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 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 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 diff --git a/3rdparty/snmp++/src/msec.cpp b/3rdparty/snmp++/src/msec.cpp new file mode 100644 index 0000000..ec7ea22 --- /dev/null +++ b/3rdparty/snmp++/src/msec.cpp @@ -0,0 +1,280 @@ +/*_############################################################################ + _## + _## 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 // for sprintf +#include // for strcat + +#ifdef WIN32 +#include // for _timeb +#include // 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 diff --git a/3rdparty/snmp++/src/msgqueue.cpp b/3rdparty/snmp++/src/msgqueue.cpp new file mode 100644 index 0000000..ea05766 --- /dev/null +++ b/3rdparty/snmp++/src/msgqueue.cpp @@ -0,0 +1,789 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/src/notifyqueue.cpp b/3rdparty/snmp++/src/notifyqueue.cpp new file mode 100644 index 0000000..87dd499 --- /dev/null +++ b/3rdparty/snmp++/src/notifyqueue.cpp @@ -0,0 +1,755 @@ +/*_############################################################################ + _## + _## 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 + +#if defined (CPU) && CPU == PPC603 +#include +#endif + +#if defined(__APPLE__) +#include +#include +#include +#include +#include +#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 +#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 diff --git a/3rdparty/snmp++/src/octet.cpp b/3rdparty/snmp++/src/octet.cpp new file mode 100644 index 0000000..c5fb693 --- /dev/null +++ b/3rdparty/snmp++/src/octet.cpp @@ -0,0 +1,851 @@ +/*_############################################################################ + _## + _## 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 // for isprint() used by get_printable() +#include // for sprintf() used by get_printable_hex() +#include // 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 diff --git a/3rdparty/snmp++/src/oid.cpp b/3rdparty/snmp++/src/oid.cpp new file mode 100644 index 0000000..119b889 --- /dev/null +++ b/3rdparty/snmp++/src/oid.cpp @@ -0,0 +1,748 @@ +/*_############################################################################ + _## + _## 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 // standard io +#if !(defined (CPU) && CPU == PPC603) +#include // memcpy's +#endif +#include // strlen, etc.. +#include // standard library +#include // isdigit +#include // 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 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 diff --git a/3rdparty/snmp++/src/pdu.cpp b/3rdparty/snmp++/src/pdu.cpp new file mode 100644 index 0000000..e142018 --- /dev/null +++ b/3rdparty/snmp++/src/pdu.cpp @@ -0,0 +1,585 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/src/reentrant.cpp b/3rdparty/snmp++/src/reentrant.cpp new file mode 100644 index 0000000..1a9f917 --- /dev/null +++ b/3rdparty/snmp++/src/reentrant.cpp @@ -0,0 +1,93 @@ +/*_############################################################################ + _## + _## 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 + diff --git a/3rdparty/snmp++/src/sha.cpp b/3rdparty/snmp++/src/sha.cpp new file mode 100644 index 0000000..0019351 --- /dev/null +++ b/3rdparty/snmp++/src/sha.cpp @@ -0,0 +1,287 @@ +/*_############################################################################ + _## + _## 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 +#else +#include +#endif +#include + +#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) diff --git a/3rdparty/snmp++/src/snmpmsg.cpp b/3rdparty/snmp++/src/snmpmsg.cpp new file mode 100644 index 0000000..a1036fc --- /dev/null +++ b/3rdparty/snmp++/src/snmpmsg.cpp @@ -0,0 +1,832 @@ +/*_############################################################################ + _## + _## 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 +#endif +#if defined(__APPLE__) +#include +#include +#include +#endif +#include + +#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; zget_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;zget_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 diff --git a/3rdparty/snmp++/src/target.cpp b/3rdparty/snmp++/src/target.cpp new file mode 100644 index 0000000..765935a --- /dev/null +++ b/3rdparty/snmp++/src/target.cpp @@ -0,0 +1,408 @@ +/*_############################################################################ + _## + _## 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 diff --git a/3rdparty/snmp++/src/timetick.cpp b/3rdparty/snmp++/src/timetick.cpp new file mode 100644 index 0000000..13a93d7 --- /dev/null +++ b/3rdparty/snmp++/src/timetick.cpp @@ -0,0 +1,134 @@ +/*_############################################################################ + _## + _## 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 // 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 diff --git a/3rdparty/snmp++/src/usm_v3.cpp b/3rdparty/snmp++/src/usm_v3.cpp new file mode 100644 index 0000000..ffe7c99 --- /dev/null +++ b/3rdparty/snmp++/src/usm_v3.cpp @@ -0,0 +1,4476 @@ +/*_############################################################################ + _## + _## 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 +#endif +#ifdef __MINGW32__ +#include +#endif +#include +#include +#include +#include + +#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; jengineID = 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 buffer(MAX_SNMP_PACKET); + Buffer 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 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 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 buf(MAX_SNMP_PACKET); + unsigned char *bufPtr = buf.get_ptr(); + Buffer 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 diff --git a/3rdparty/snmp++/src/uxsnmp.cpp b/3rdparty/snmp++/src/uxsnmp.cpp new file mode 100644 index 0000000..e033b50 --- /dev/null +++ b/3rdparty/snmp++/src/uxsnmp.cpp @@ -0,0 +1,2362 @@ +/*_############################################################################ + _## + _## 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 // system types +#include // _timeb and _ftime +#else +#include // unix +#include // bsd socket stuff +#include // network types +#include // arpa types +#include // system types +#if !(defined CPU && CPU == PPC603) +#include // time stuff +#endif +#endif +#ifdef _AIX +#define ss_family __ss_family +#endif + +#include // need for malloc +#include // 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 +#include +#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 ((cMAX_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 diff --git a/3rdparty/snmp++/src/v3.cpp b/3rdparty/snmp++/src/v3.cpp new file mode 100644 index 0000000..070631c --- /dev/null +++ b/3rdparty/snmp++/src/v3.cpp @@ -0,0 +1,442 @@ +/*_############################################################################ + _## + _## 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 +#include +#include +#include +#ifndef _MSC_VER +#ifndef __BCPLUSPLUS__ +#include +#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 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> 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("# \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 diff --git a/3rdparty/snmp++/src/vb.cpp b/3rdparty/snmp++/src/vb.cpp new file mode 100644 index 0000000..9722d80 --- /dev/null +++ b/3rdparty/snmp++/src/vb.cpp @@ -0,0 +1,378 @@ +/*_############################################################################ + _## + _## 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 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ab3acd3 --- /dev/null +++ b/Makefile @@ -0,0 +1,56 @@ +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 $@.$$$$ diff --git a/gssmd.conf b/gssmd.conf new file mode 100644 index 0000000..4daf70b --- /dev/null +++ b/gssmd.conf @@ -0,0 +1,40 @@ +[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 diff --git a/include/.switch.h.swp b/include/.switch.h.swp new file mode 100644 index 0000000000000000000000000000000000000000..c1dcb405accb6d75424159052e58398e140dbdd1 GIT binary patch literal 12288 zcmeI2&1=*^7>B171wZQN)x*?6ZMC{pL7`uMRA>vf7PnQr7_-UjHa44tnMrG@S`@wM ze;_D$(X-z4=EaNt10Fnj5fm?8{Utk_{pi*eZ^bwCA=%9PzLR-o5_V|{gIA}f`I+OV z7`DBPeO|jU{q$@ndwrU*q8%%poNu!&*yXa2ZGzBzFD;mxmEkSnXq77|Rd#b;;P|mC za%$Pr&cgA9_H`(N43L3;G0??Mojfs^WcD2D<_GrA|4R|dAp>N943GgbKnBPF86X2> zV3QiqQ3qSYwRf89A2s`qroH({J2F59$N(8217v^NZ{{H{Ehp|uKBX|p5ftTPZcmf`SJ75(og6m)gjDitx40MBEyYWr|cmp1Q z%isvu0)BKc_8q(fZ^3ckQ2f;S56@1&t*az?eJOU3v2~2_s za2WK0pBUeJa1-Rf05}TzK_5uQ&jD>@fDDiUGC&5%02%o24fKe>^@@z$#osXFW-ElD z&mAdjEzXZ$QhiPsD9y*`Y*`YT_i~*c^fx8AGK`Y&3oCPW!51534e&TnUMUbRk7QW% zd@A4ZXlTWNP_XbEqxhH?ZW8RM4i z_-Yv69nF?qx)q4q`eL{oAgrdLv3WkR(K0!Xd@op>4W+K-rhO|dy`aRcW$9@#9+t~- z;OUhOf-paByBII3yMTO9j$qbO*w<8029!p~ms?o1LX61PZilux6v{p{z@Z&!&j-T9x} z*ZBFlMTYAbV;{DDx%S_82ify;jP=Ao8{59ewIcd`S?nfDDiUGO!N~ zh?ud{hZ(CMLGt+j|LE`kzrSJZEqDW7f+ye+_zi4=2jD))!5t8SHfVqV)Bpz`zh>+; zcm-a7Kfnf90;j+U@c&W9{sJ$+Gw>8_fi}1bE`T%O5cuaS#@>T>;CJvCJOm1KzykOZ zd;$K&p5B2!K?W{@09*j)!8u^}JqPF_17v^9R0lMw>VYv?)}&%%^#brdb|ksWv+!I%~>AD^hoiFmf2!7kRTZLyZr| zv@n(Sqh}`*-BNh<7F}5Vy8P9+$C*<9YNldtU#)GYy{z2fa$Xb4*v9cr+`@^{rfFx2 zM@xsJl_v{VM;0v}8k>rqjOe8O9GQh0_fo4g24eILQD~QWs4FeQk$It3VI-Jj<~C9c z(ivxxyY#0y8dA(w8$Zh=6LEP*n;rLFae3?h)O>z6y^=6Lyi-Zay3cFQQaa2!>&?z9Pl z-XM*P%F?EDG&75{h(wZfMRafC-JVWpc!;#k_o|RPdsK=gS4Fbz1iUSdZd+wG{cM1$ z*b{NWrNd7MPKS%M3Vn-t5b?{p9wbQUw-FJ zmt1{xl5;D0-oi_|<8FK@v`UY*Qp(Rb{=T#Us6drU9)?&g?A*S7>B`OUY8WE4m)h#w G(eVkAO}SwJ literal 0 HcmV?d00001 diff --git a/include/acl.h b/include/acl.h new file mode 100644 index 0000000..468671f --- /dev/null +++ b/include/acl.h @@ -0,0 +1,50 @@ +#ifndef __GTS_ACL_H__ +#define __GTS_ACL_H__ + +#include + +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 diff --git a/include/datatypes.h b/include/datatypes.h new file mode 100644 index 0000000..28983df --- /dev/null +++ b/include/datatypes.h @@ -0,0 +1,28 @@ +#ifndef __GTS_DATA_TYPES_H__ +#define __GTS_DATA_TYPES_H__ + +#include +#include + +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 Lines; + +bool parseData(std::string & data, Lines & lines); + +} + +#endif diff --git a/include/logger.h b/include/logger.h new file mode 100644 index 0000000..35d3e46 --- /dev/null +++ b/include/logger.h @@ -0,0 +1,41 @@ +#ifndef __GTS_LOGGER_H__ +#define __GTS_LOGGER_H__ + +#include +#include +#include + +#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 diff --git a/include/oids.h b/include/oids.h new file mode 100644 index 0000000..510fb4d --- /dev/null +++ b/include/oids.h @@ -0,0 +1,14 @@ +#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 diff --git a/include/pidfile.h b/include/pidfile.h new file mode 100644 index 0000000..d2422bd --- /dev/null +++ b/include/pidfile.h @@ -0,0 +1,22 @@ +#ifndef __GTS_PIDFILE_H__ +#define __GTS_PIDFILE_H__ + +#include + +#include + +namespace GTS { + +class PIDFile : private boost::noncopyable { + public: + PIDFile(); + PIDFile(const std::string & file); + ~PIDFile(); + private: + const std::string fileName; + void _create(); +}; + +} + +#endif diff --git a/include/settings.h b/include/settings.h new file mode 100644 index 0000000..e061b96 --- /dev/null +++ b/include/settings.h @@ -0,0 +1,101 @@ +#ifndef __GTS_SETTINGS_H__ +#define __GTS_SETTINGS_H__ + +#include + +#include +#include + +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 diff --git a/include/settings.inl.h b/include/settings.inl.h new file mode 100644 index 0000000..e67aab7 --- /dev/null +++ b/include/settings.inl.h @@ -0,0 +1,78 @@ +#ifndef __GTS_SETTINGS_INL_H__ +#define __GTS_SETTINGS_INL_H__ + +#include +#include + +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 diff --git a/include/snmptable.h b/include/snmptable.h new file mode 100644 index 0000000..81efb56 --- /dev/null +++ b/include/snmptable.h @@ -0,0 +1,36 @@ +#ifndef __GTS_SNMPTABLE_H__ +#define __GTS_SNMPTABLE_H__ + +#include + +#include "snmp_pp/snmp_pp.h" + +namespace GTS { + +typedef std::list 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 + 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 diff --git a/include/snmptable.inl.h b/include/snmptable.inl.h new file mode 100644 index 0000000..63ff217 --- /dev/null +++ b/include/snmptable.inl.h @@ -0,0 +1,24 @@ +#ifndef __GTS_SNMPTABLE_INL_H__ +#define __GTS_SNMPTABLE_INL_H__ + +namespace GTS { + +template +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 diff --git a/include/subscriber.h b/include/subscriber.h new file mode 100644 index 0000000..44d6db3 --- /dev/null +++ b/include/subscriber.h @@ -0,0 +1,37 @@ +#ifndef __GTS_SUBSCRIBER_H__ +#define __GTS_SUBSCRIBER_H__ + +#include + +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 diff --git a/include/switch.h b/include/switch.h new file mode 100644 index 0000000..fc43284 --- /dev/null +++ b/include/switch.h @@ -0,0 +1,61 @@ +#ifndef __GTS_SWITCH_H__ +#define __GTS_SWITCH_H__ + +#include +#include + +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 _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 diff --git a/include/syncer.h b/include/syncer.h new file mode 100644 index 0000000..5d5aaa7 --- /dev/null +++ b/include/syncer.h @@ -0,0 +1,59 @@ +#ifndef __GTS_SYNCER_H__ +#define __GTS_SYNCER_H__ + +#include +#include +#include + +#include + +class Snmp; + +namespace GTS { + +class SettingsParser; +class Switch; + +class Timer { + public: + Timer(boost::function 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 _callback; +}; + +typedef std::list::iterator TimerIterator; +typedef std::pair TimedSwitch; + +class Syncer { + public: + Syncer(SettingsParser & sp, + Snmp & snmp); + ~Syncer(); + + void run(const bool & running, bool & reload); + + private: + SettingsParser & _settingsParser; + Snmp & _snmp; + std::list _timers; + std::list _switches; + + bool wait(); + void syncInfo(); + Timer & getNextTimer(); + bool getSwitchesState(std::map & switches); + bool getDBData(std::string & data) const; +}; + +} + +#endif diff --git a/include/version.h.in b/include/version.h.in new file mode 100644 index 0000000..e4db5ca --- /dev/null +++ b/include/version.h.in @@ -0,0 +1,11 @@ +#ifndef __GTS_VERSION_H__ +#define __GTS_VERSION_H__ + +#include + +namespace GTS { + static const std::string version("@VERSION@"); + static const std::string revision("git sha @GIT_SHA@"); +} + +#endif diff --git a/src/.main.cpp.swp b/src/.main.cpp.swp new file mode 100644 index 0000000000000000000000000000000000000000..57a74d5f8795588550e2cb2890a8f3181122fe43 GIT binary patch literal 16384 zcmeI2OKclO7{{kA&=e??RsvMic5p>;Q0k;DeJE**Kyed`B#q)WRcUG1de`>0_U>wT zoir3EDhJ?z#7jjyj!1}#6GdEl03^tX#{mh1-~yCN9C#c!v_(Ar-^^^hPMz4U6a-={ z{k--(zWL@qGdtgUe7I{gGsw55HZi=GG4}O|Lxan^7P2#27|R=#Af)sLucA>dTYiH= z$bL*1>>T#pBUUa9ItxKiHai19*I71fCzbQO#x`^bt$1eOz4^%(yO6-&5*3F(Y4n z)fcURRzNGD70?Q31+)TM0j+>mKr5gX&1P8!Q&;izgJHYSPF*XSbzyJ?{ZD1LA_gcnA!KEdz z1^U6IHpbopec=3J*aa)W)HRH~58eZ(z!+EtE?&*pFW^V;4mbne1kZtSPyu6L4QK;@ zUd7lSU<$knUI7n){a`!j0jt49{J?Snd;rdZm%$-$KS+aKum#)=Hi0!@6=(yC!8wfI zr{ELtHh31`ryZ6BJzxc(F}?{jcyYV}yI|x(+jWxJOy8dL$Y2Lw=U5Ygfva0G1Eal% zQ8|&83XHLQ$tVPT2k)AZUN(ZGNQOQ7G$XTUIA+Q6k&jl!GJQibpBgvKzzUP=RJ{%= zKyIjJk!+Q{a57#7S;8gcA$csUZ8He{N=~H7eo4kFP_Wc7B|Z;cBa~CI<0u8XgvX%P?Wl z^*qZ=iMC?qMQySWOgcHsPoeKg)&CCkpyV2+(wYi&cJgd!_#vl1>L}B)+roquX6=Gw zl=|g(2FYkFC^zPqut5rofBwXcrBbtd*taL!-JKO~DsPj)u;B-m-@yZ??8W>PMTaxJ zyX=z1y?j(Ig$WU&T{xCfxykmpk5w7T<2nO4qa(WvG+^@3<+fvowo$Slws>}EaCoN7 zRF7VEo`%r~D*=rh6KQzM!hO+)D6=|cFx4=4RHM48LVq%afP@wJtl(wRGTE1j6n6Pm} zxHI6UJK@ku;hyj2Y0BB=9POYm{`yAcGNx=TanMPy$a?j9SvwW4=~gOUYi-z0-W96~ zGdZ;UaicVQ52!4y!;C7~LMNJSLQ30mBUsd&gq_{@>18ix#+LUBo}KFHsw-My{)(Mv7FQ@;rH;wq!lDMN;_^sEYJq?&ZLz%w{f{vufX=W%JGQk~gR8{V33cWwBM}+)5}$BdhigZdS@(ceH9}zeA~8+2uE=YS0iZ z_u7WAfr)*DXT?2+4;qevP{+b%AO}4dtidOq$VQenB{%xYg2n%#K)=&6Zd2`ed}os$Bo1|d_l4bdK+H2gxYgX4W% zZI-dkw%5WxmrJzMc6VdxC)?NWq!1H#9NaRKz3Kb*_Kgkf?(5)Ps_xtsGDEv|w^BYm znjYHIN`-y*jtpgnluuim@+mzsvU^0f5mlg|&kE^Ih+gu%>x)nhVU&zt#0-lTh8+KB zW2eZO;une*DP|^FA#Sc{`1~%R@qq^sM~mPZLe>c$De|#%{IKhmR5V(R%4_nbLw3aX zh}eZw7$=IhF;ci7JYQ=&xl+ZnctR$niiud7XPdNj)F#3!5ir)Ksufq8r~+u%j2Wf4 zbjgbGJ`V%$>1B+oe#-D96)sc$h(4U7HkQkrj4QOdiEvF)N7W5r&Ce@hRSH z#j&w2Qbmy~w-83p|BLW!{3W30|CD+-`~lDNAA;AxlfVW2U>8V(ji3vx0=I#cU;+3G z&-34aDew_E4W0sdkO3RO63_;I!t?#d;52v!RKO4z1RKFJ@GG9_KL=;Q3*dP$0Y<@Q za4TToE7gZDs2}>J70?Q31+)TM0j+>mKr5gX_V&V(j}X;kKJnZ84laLSh#v`JD%YF{)-1RAANgkHY{PN?8#W8S?*IS* literal 0 HcmV?d00001 diff --git a/src/.switch.cpp.swp b/src/.switch.cpp.swp new file mode 100644 index 0000000000000000000000000000000000000000..6332d06144d95f981dfa5f03b585d41a083b25a3 GIT binary patch literal 16384 zcmeI3ZH(MT8ONt-TG}Qpp%I^o!sJS?UhcY=7nH)@3%XnaoX92DZ0=ME#L8=XZ=Kt- zjmN&1hO{LVK18C5co9NE@BvW?fsjyI5FkOn5JEu+`T>a+S|lnVf{;K+ynLzn&x<{_ z&wF>dqzELh^vkYi9*-aYXXf$D<4gO%{PYZcxPF-6vxktEpZLhko&!6`HuTRrR>VdY7+bPOSZIx~6*scFbt?!qZ>6%R6sQ!~o&tB1 z!-ozY;OE{yu%GU|cW!&lRA*HRR0>oIR0>oIR0>oIR0>oIR0{lGDi8%b$P@5id?$_pR!9UVWc0)T_hlt5Tp+pi-bxpi-bxpi-bxpi-bxpi-bxpi-bx;D1m7(Zz5zZD&VwF!6ik8Hz6m}FI^Yp73f==A21mdi@R!|$ya;{(o(3)OZm<_z+eOGP!7sqi!Oy_= zz<0rO;8}11JPFQ%39tuTyNi%3;LG4C@Cooy-~$i53mgKw!OM3N@-6TrI0g2B*Y6dQ>D_{WJ3wDED;Q8AL`5G7nL*N1M4sZ(~;Fa45 zvB4Q|63l=D;Dw!pd>=duE`!g3VK4|D0JnpSNY*?BE`X1Nli&on3;Y%RyaG({A#fD% zzTXE*K2&{1M(C- zp+`Grk2#}hY0qC+a6&pZMhBYWZ$KIitLs>c_#2Uq+jE#vqYu$Q9nj{d!cZJ5GY)}T@o)9SH0gAv+-MkT7W zm=i^=x4`NyJLa_G1u4ySc-S$~Z8nX3YK4v&Il_VM_K|FY-vUM#?*cKd3f{@Sg#hx3j)vXqbLZgQA zmC%ixbrm;uo30E+YI?dsW6NQPJ6kW@&vY<}Qp{n>YYoJ*#C;KDmVHFMB*@62okS5@ z@(~f2ho_P{QN-dlvqHD+gmp}@V;FizpD(pcFh2BrT-}{3~$$4ob|(~zfs$cjawP;|n8ZFOR6?ce(p`reML}Bb~U9!30It7~x zHkB){1XnG&ud;5;TW?vnIM}*sb3EE{&CZeB0K^b&rUS^3PdQzH2c7mUeb}kBz&oR^ z%T#y~y+y}qh`A6ub#W+%Y_`ub2AQ7B*anbLmXgl6Q2CB+9xfIp?~V?yc|aUP@Cm+FmgxQ z2&$}8qmK$n7)?)3BTVcucY&`uGTy3jl-fvz#99(hSgai}Q1hOz3$taXczH02k;PP_3l8X zgkM(fDsshgJ)bwlqbXmYgJhvRS&!$MWWpV8S-5;F2u8RY_|DgkVQ0dkk)E^aT4t|h znJlVzgJ6R2{r_p~{jOkd$oK!r`~7R!$G--C3O)-y1s1_!FbLiPc7cCmU;j_=4{#M+ z0iOZqKpp%G`}kME)8K<(CwL9}cL$sT)8Iky4EE-iz(v6K>u&>J!XEqrSOp=N1+U+U z90h2DN5N?@3Em4Pz;Ce^e+hgATma+Xt>6yuN9?=54!#K5-~(U+@ICq8u;+dbd>Z)R z!(bll1J7XJeF8s#3;40u6{}@!CN`afJ zfXp7KWffn%%H@VmD(GK4aF^#|cuh(2A+rhR$r!zbMgqoPbSMwHjRvCWHa2zqk~|wD z@+^G+X#{qhHk+;H+|<At`MH^G4oWCW zq!N7FY`75?UvgW}b{1UEsEtyT;VQBa&G4e3Ava1cBA#o@_}@x?IEMA_1kzJHkJG{y zQmoN%{`$NRo@J2(Yo-=($^LX*(r1GXEAOI`?n&|xN7qDVOr(i!Y9DR4fAo+;FVLZJ zy4;q1!8>lbEwc@Lv2VCuWE{zEx8~b0FnG32-5q|WTi{F=>ssEvc*Hdt*=O8XW?eF2 zxOU%j2kHabxy(saUn1knY=~^kYNj!Lul(l9`;P1AV!UFH-4dG|?#~v6xEE2^E{{zFAzm2BX?e+5=1UuXPU#rte&=RPVoj4KRe~4p^G1*uls;*Jq$*qL36<8GPCBHl zk+e(7yF*^Bkd8g=uQVewiW!_MWMkDOSTaxKBD6R)hiSUzO?@1u(l%WhV(}=}d9@_% zvcWvw%E;i_Z!oh9Q<~q1=oH!s{Ux0$6fWIB4BlTl!XsFTm82yNzqKFX+y{<@UMkj+L3@1ShnSdJ4taBuvz zNxoYPiA&v?+jC#_m6~~PjPr@|1=qDkxjQU-1H?tf18H6)s#IP%iH7-R)V0bQiGzMk zWSieoFzq`(lL(#hmp51*STjb2pgJkuC*c*B4EWmf>+~)+KS~=b^-N!{zh8Y~{TA0> znRk-wMzCH?^C+E$IDWuC3{M-^68q^fEMq3n)ya;X_v5U5b2*K5Ws(`9G8FNgf9xDz m#iNuNM6`u}YIJZgJ>Z2Kw4aw#oW%pL2z2XPUw32brvC#!8BvV@ literal 0 HcmV?d00001 diff --git a/src/.syncer.cpp.swp b/src/.syncer.cpp.swp new file mode 100644 index 0000000000000000000000000000000000000000..d65f4ff31e86d1b486807c89d246992e1f46ed41 GIT binary patch literal 16384 zcmeI3Ym6IL700Kc4J}XtMZ6@CZno-nym7qQL~4+;SxBBvO@!5a9z&NfD(WDnJzY z+etQs4}fN*Uu@s!x#ylabI+Mgebd3pUbeNg#lZC@!+7fBckOL$Sz|nUn_)DqE{~}E z3RlbObe!-CjZl4D3^=+!^gra-5g%RPywe!vp*_l1JlhFNb`V^7l)Oc*fm{QxP6Ia@ zTQ-kvqP{l|t!Hn!>Ayfm{Q*267GL8pt(}YarLa|D*<@V2yD%BwwSX zKcPOa>G^z(`h8G+ey*op{megd4dfcgHIQo{*Fdg;Tm!iVat-7f$Tg5_AlE>yf&W4c zSPjG23Aw&W2>`tR*YW>_b%ybK@N@7uI0e20J`I+E4eDSI*bPQN0lXEw@Bls0~ z0(=d86`TO~03Un+OoJ(KEqL)p!}vA$F8B^O3%(7$0v-VmgHzyM@G-C#jDn4z2;K?a z4%ULdzQHj53@(DF!D(Xv=PER>pV$fH8h z=oyLCA{vXA91N1G7Bf^LC$u6zWRV-O?Qv7r<4zcv@ld0qtRjlg4r8$<^=P@ANg3jH ziA+J4w`xK#9yQA4j&;PT1(q9{+>JI)aL4w&MlqgGh*l_Uiw8<3lru1_wZ%MN&M%sg z3^W?VPBh^xxSm*&FdHIug^Yw|9sCI$?#PJM9p-d`Xl4Bnlz7aLO@`ymgTnSX%R|XMXnyT%O!Y(>f0bR61s93bxZ2NY$af~!>h#IPd z4s<2sP8)xwXO6*(hRp^qvV8|;X7sDWIVwwE{XM95fX4~DaMW-%&a&+Uk?VV9 zCLD{iTv}>bkZpjMNl#>3co^aVKu?!=3^t7M^qrP&Jy_gf(>z9bj7%lDe@ zLa#@l(V}ogJv-84UuJP~z(EdE41&_xC&uU*vE}BBxhn7jXH9f6T!lfqc9k<7u)6R>BD-#wu%+#>O__wez zVVuVd{R}uRza%!BUV8d_@22WK#tF&A6OM+dczCMgZp4EYcLsIVt}Z#Yh})^>0M_%c zEQ&LbI#S`pGR7Kp#ziCeK^hhVbFUMa^pD)EGDph`_H2UmybX4kXH-;9eRhFO?kdU)(7^jC}MVIkHJ6YO%_XKeR; zwOpQYJqPYMRZ{KNxgEN7C(IU$BV?vXNRTO!yNQRv&8}y+yA6j8$@{6)8cLNlES#iP z0-W+Q#XO$5r(8_kQ>F~2r&QP}m8E7QgR2F>sQS#-jtd2jQZQ0#1;IqB<9O_WCz8>| zt@eT+;@sXz7uxc0k?C!B!}h3S@s(05)0B$U;`_>}4>eEC$5;5Me6&*q#sBBK#cwZI1ea}zaKQgt>7AP0de;W;5;}3z6I_BN5L%kJL2sx zg9G3qV(CwTGI$2D^CRH1;1=-m4TkYM@EkY`9tIDA8BhikQ*Q--K|FjBJO&zIAJ_vn zgSUZu5%+e$0yqe^fOCjxzs_kakv z;C;XZ>%iZjzjJ`%-v_}_Kyk1I?f~xxq~qNnzyAL;AdgOcC+_4#rJgeC(Z#fr*1vIN zLDb~oVwg#NMaln$w)5(`?CMTc>htX-Ge5WT4==6O+j3wd=(RvaMOlnm`z>l@X zSsWp|ER!e0|GcKK=^$QdyuyT3eeuxD@I)>D#$eHwpN@TUP1FKnJNsJ(qg~yCcbl*3* zx;rkBctZ>!q{bfigaRqM8*Fn*hgoBD;e^;OT4&p>hgP^UXqkORlg;MP`L0H1!kXQ7 zEUz1wEekuSV;WLaG6MY?e5X*&Du$wFS6txaPDC!k#UlBD2!c6b=!e=S#gCocW>ckB z2bvzuL;DN=p<`<*B3;=&VgQsQv`PdHoDd$S)4%ql30$flM5;wm3^ludzBV;CH#@iU z!1VOgTu}-tWkYftp{kOTyqBfc!8#7-)`G(gl8CM=&T(k2GCwuBV}1t`X=K`R?AdM@ zhg9MoGQ?=B9&q}=zFqT`*?mPJz#)3FO{JQ-bepLiXe6$ zCA$VUfV)fRi`Im$tDk3P_E4?5e`;#7HecC0Rb;nqk^@b4=`{m>A_-|9T$5=hMiUF(DncBgrxytnIkP;@MqAG z+_J*7J>5aJE3K_otsI{Ep!AqzAT|>MY zrQZ;-kqHyo;85DTFbJDef_@mjr=P5uFoP%*>!Z1mU!WT+W7nq0MT{`ClLDd zB^8-!7SFG}^#IpJd8qh}ju4GXTA}Z`N2T}TUFWNhMn zlg8>zqetdyM6DV0oG?_VEn BK>Ppz literal 0 HcmV?d00001 diff --git a/src/acl.cpp b/src/acl.cpp new file mode 100644 index 0000000..08f0405 --- /dev/null +++ b/src/acl.cpp @@ -0,0 +1,116 @@ +#include +#include + +#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(_profileId) + + "." + + boost::lexical_cast(_id); +} diff --git a/src/dataparser.cpp b/src/dataparser.cpp new file mode 100644 index 0000000..f83dbe5 --- /dev/null +++ b/src/dataparser.cpp @@ -0,0 +1,84 @@ +#include +#include + +#include +#include +#include + +#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 +struct LinesGrammar + : qi::grammar +{ + 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 query; + qi::rule line; + qi::rule ip, community, mac; + qi::rule port, shape; + qi::rule eol; +}; + +bool GTS::parseData(std::string & data, Lines & lines) +{ + std::string::iterator begin(data.begin()); + std::string::iterator end(data.end()); + + LinesGrammar parser; // Our parser + + if (!qi::parse(begin, end, parser, lines)) { + logger << "parseData() - Failed to parse data" << std::endl; + return false; + } + + return true; +} diff --git a/src/logger.cpp b/src/logger.cpp new file mode 100644 index 0000000..13e1f0f --- /dev/null +++ b/src/logger.cpp @@ -0,0 +1,57 @@ +#include + +#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 + << "] "; + } + } +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..71133c2 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,164 @@ +#include // daemon + +#include // errno +#include // strerror +#include +#include +#include + +#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); +} diff --git a/src/pidfile.cpp b/src/pidfile.cpp new file mode 100644 index 0000000..1b0ecbd --- /dev/null +++ b/src/pidfile.cpp @@ -0,0 +1,45 @@ +#include // pid_t +#include // getpid + +#include +#include +#include + +#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; +} diff --git a/src/settings.cpp b/src/settings.cpp new file mode 100644 index 0000000..5d04ad2 --- /dev/null +++ b/src/settings.cpp @@ -0,0 +1,89 @@ +#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()->default_value("/etc/gssmd/gssmd.conf"), "config file location") + ("daemon,d", "daemonize after start") + ("debug", "gssmd debugging") + ("log-file", po::value(), "log file location") + ("pid-file", po::value(), "PID file location") + ("switch-sync-interval,s", po::value(), "switch synchronization interval") + ("info-sync-interval,i", po::value(), "info synchronization interval") + ("up-profile-id", po::value(), "switch's upload profile id") + ("down-profile-id", po::value(), "switch's download profile id") + ("data-url", po::value(), "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(); + } + + 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(); + } + + if (vm.count("pid-file")) { + _settings._PIDFile = vm["pid-file"].as(); + } + + if (vm.count("switch-sync-interval")) { + _settings._switchSyncInterval = vm["switch-sync-interval"].as(); + } + + if (vm.count("info-sync-interval")) { + _settings._infoSyncInterval = vm["info-sync-interval"].as(); + } + + if (vm.count("up-profile-id")) { + _settings._upProfileId = vm["up-profile-id"].as(); + } + + if (vm.count("down-profile-id")) { + _settings._downProfileId = vm["down-profile-id"].as(); + } + + if (vm.count("data-url")) { + _settings._dataURL = vm["data-url"].as(); + } +} + +void SettingsParser::reloadConfig() +{ + parseFile(_settings._configFile); +} diff --git a/src/settingsfileparser.cpp b/src/settingsfileparser.cpp new file mode 100644 index 0000000..64f0d0b --- /dev/null +++ b/src/settingsfileparser.cpp @@ -0,0 +1,125 @@ +#include +#include +#include +#include + +#include +#include + +#include "settings.h" + +namespace qi = boost::spirit::qi; + +namespace { + +typedef std::map PairsType; +typedef std::map SectionsType; + +template +struct IniGrammar + : qi::grammar +{ + 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 query; + qi::rule()> section; + qi::rule sectionContent; + qi::rule()> line; + qi::rule key, value, sectionHeader; + qi::rule 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 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(res); + } + if (fieldValue(data, "sync", "info_interval", res)){ + _settings._infoSyncInterval = boost::lexical_cast(res); + } + if (fieldValue(data, "sync", "up_profile_id", res)){ + _settings._upProfileId = boost::lexical_cast(res); + } + if (fieldValue(data, "sync", "down_profile_id", res)){ + _settings._downProfileId = boost::lexical_cast(res); + } + if (fieldValue(data, "sync", "data_url", res)){ + _settings._dataURL = res; + } +} diff --git a/src/snmptable.cpp b/src/snmptable.cpp new file mode 100644 index 0000000..b0aaba3 --- /dev/null +++ b/src/snmptable.cpp @@ -0,0 +1,41 @@ +#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; +} diff --git a/src/subscriber.cpp b/src/subscriber.cpp new file mode 100644 index 0000000..046d29b --- /dev/null +++ b/src/subscriber.cpp @@ -0,0 +1,27 @@ +#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; +} diff --git a/src/switch.cpp b/src/switch.cpp new file mode 100644 index 0000000..43c83da --- /dev/null +++ b/src/switch.cpp @@ -0,0 +1,210 @@ +#include + +#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(_settings.upProfileId()) + ) && + table.valueExists( + static_cast(_settings.downProfileId()) + )) { + return true; + } + return false; +} + +bool Switch::dropACLs(const CTarget & target) +{ + std::string upOidValue(swACLEtherRuleAccessID); + upOidValue += "."; + upOidValue += boost::lexical_cast(_settings.upProfileId()); + std::string downOidValue(swACLEtherRuleAccessID); + downOidValue += "."; + downOidValue += boost::lexical_cast(_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(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(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::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; +} diff --git a/src/syncer.cpp b/src/syncer.cpp new file mode 100644 index 0000000..9d5d7a5 --- /dev/null +++ b/src/syncer.cpp @@ -0,0 +1,234 @@ +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#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 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::iterator it(_timers.begin()); + std::list::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 switches; + if (!getSwitchesState(switches)) { + logger << "Syncer::syncInfo() - failed to get new switch states" << std::endl; + return; + } + std::list::iterator it(_switches.begin()); + while (it != _switches.end()) { + _timers.erase(it->second); + _switches.erase(it++); + } + std::map::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(ptr); + std::string * dest = static_cast(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 & 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::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; +} diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..5ab197a --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,50 @@ +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 $@.$$$$ diff --git a/tests/test_data_parser.cpp b/tests/test_data_parser.cpp new file mode 100644 index 0000000..3c3292e --- /dev/null +++ b/tests/test_data_parser.cpp @@ -0,0 +1,40 @@ +#include + +#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; +} diff --git a/tests/test_switch.cpp b/tests/test_switch.cpp new file mode 100644 index 0000000..7d68c0f --- /dev/null +++ b/tests/test_switch.cpp @@ -0,0 +1,49 @@ +#include +#include + +#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; +} -- 2.44.2