1 /*_############################################################################
6 _## -----------------------------------------------
7 _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
9 _## This software is based on SNMP++2.6 from Hewlett Packard:
11 _## Copyright (c) 1996
12 _## Hewlett-Packard Company
14 _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
15 _## Permission to use, copy, modify, distribute and/or sell this software
16 _## and/or its documentation is hereby granted without fee. User agrees
17 _## to display the above copyright notice and this license notice in all
18 _## copies of the software and any documentation of the software. User
19 _## agrees to assume all liability for the use of the software;
20 _## Hewlett-Packard and Jochen Katz make no representations about the
21 _## suitability of this software for any purpose. It is provided
22 _## "AS-IS" without warranty of any kind, either express or implied. User
23 _## hereby grants a royalty-free license to any and all derivatives based
24 _## upon this software code base.
26 _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
28 _##########################################################################*/
29 char mp_v3_cpp_version[]="@(#) SNMP++ $Id: mp_v3.cpp 1686 2009-11-24 13:47:44Z katz $";
33 #include "snmp_pp/config_snmp_pp.h"
36 #include "snmp_pp/v3.h"
37 #include "snmp_pp/mp_v3.h"
38 #include "snmp_pp/usm_v3.h"
39 #include "snmp_pp/notifyqueue.h"
40 #include "snmp_pp/snmpmsg.h"
41 #include "snmp_pp/uxsnmp.h"
42 #include "snmp_pp/eventlistholder.h"
43 #include "snmp_pp/asn1.h"
44 #include "snmp_pp/vb.h"
45 #include "snmp_pp/log.h"
47 #ifdef SNMP_PP_NAMESPACE
51 #define MAX_MPMSGID 2147483647
53 #define CACHE_LOCAL_REQ true
54 #define CACHE_REMOTE_REQ false
58 // Use locking on access methods in an multithreaded environment.
60 #define BEGIN_REENTRANT_CODE_BLOCK SnmpSynchronize auto_lock(lock)
61 #define BEGIN_REENTRANT_CODE_BLOCK_CONST \
62 SnmpSynchronize auto_lock(*(PP_CONST_CAST(SnmpSynchronized*, &lock)))
64 #define BEGIN_REENTRANT_CODE_BLOCK
65 #define BEGIN_REENTRANT_CODE_BLOCK_CONST
68 // ========================[ Engine id table ]=============================
70 // Construct engine id table
71 v3MP::EngineIdTable::EngineIdTable(int initial_size)
76 if (!initialize_table(initial_size))
78 LOG_BEGIN(ERROR_LOG | 0);
79 LOG("v3MP::EngineIdTable: Error creating empty table.");
84 // Destruct enigne id table
85 v3MP::EngineIdTable::~EngineIdTable()
92 // Add an entry to the table.
93 int v3MP::EngineIdTable::add_entry(const OctetStr &engine_id,
94 const OctetStr &host, int port)
97 return SNMPv3_MP_NOT_INITIALIZED;
99 LOG_BEGIN(INFO_LOG | 9);
100 LOG("v3MP::EngineIdTable: adding new entry (id) (host) (port)");
101 LOG(engine_id.get_printable());
102 LOG(host.get_printable());
106 BEGIN_REENTRANT_CODE_BLOCK;
108 for (int i = 0; i < entries; i++)
109 if (((table[i].port == port) &&
110 (table[i].host == host)) ||
111 (table[i].engine_id == engine_id))
113 LOG_BEGIN(INFO_LOG | 2);
114 LOG("v3MP::EngineIdTable: replace entry (old id) (old host) (old port) (id) (host) (port)");
115 LOG(table[i].engine_id.get_printable());
116 LOG(table[i].host.get_printable());
118 LOG(engine_id.get_printable());
119 LOG(host.get_printable());
123 table[i].engine_id = engine_id;
124 table[i].host = host;
125 table[i].port = port;
127 return SNMPv3_MP_OK; // host is in table
130 table[entries].engine_id = engine_id;
131 table[entries].host = host;
132 table[entries].port = port;
135 if (entries == max_entries)
139 tmp = new struct Entry_T[2 * max_entries];
143 return SNMPv3_MP_ERROR;
145 for (int i = 0; i < entries; i++)
156 // Get the engine_id of the SNMP entity at the given host/port.
157 int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
158 const OctetStr &hostport) const
161 char host[MAX_HOST_NAME_LENGTH + 1];
165 if (hostport.len() > MAX_HOST_NAME_LENGTH)
166 return SNMPv3_MP_ERROR;
168 /* split up port from hostport */
169 strcpy(host, hostport.get_printable());
171 ptr = strstr((char*)host,"/");
173 return SNMPv3_MP_ERROR;
176 port = atol(ptr + 1);
178 /* Check for IPv6 address with [] */
181 if (*(ptr -1) == ']')
184 return get_entry(engine_id, &(host[1]), port);
187 return SNMPv3_MP_ERROR;
189 return get_entry(engine_id, host, port);
192 // Get the engineID of the SNMP entity at the given host/port.
193 int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
194 const OctetStr &host, int port) const
197 return SNMPv3_MP_NOT_INITIALIZED;
199 BEGIN_REENTRANT_CODE_BLOCK_CONST;
203 for (i = 0; i < entries; i++)
204 if ((table[i].port == port) &&
205 (table[i].host == host))
212 LOG_BEGIN(INFO_LOG | 4);
213 LOG("v3MP::EngineIdTable: Dont know engine id for (host) (port)");
214 LOG(host.get_printable());
218 return SNMPv3_MP_ERROR;
221 engine_id = table[i].engine_id;
226 // Remove all entries from the engine id table.
227 int v3MP::EngineIdTable::reset()
230 return SNMPv3_MP_NOT_INITIALIZED;
232 LOG_BEGIN(INFO_LOG | 1);
233 LOG("v3MP::EngineIdTable: Resetting table.");
236 BEGIN_REENTRANT_CODE_BLOCK;
243 // Remove the given engine id from the table.
244 int v3MP::EngineIdTable::delete_entry(const OctetStr &engine_id)
247 return SNMPv3_MP_NOT_INITIALIZED;
251 BEGIN_REENTRANT_CODE_BLOCK;
253 for (i = 0; i < entries; i++)
254 if (table[i].engine_id == engine_id)
261 LOG_BEGIN(WARNING_LOG | 4);
262 LOG("v3MP::EngineIdTable: cannot remove nonexisting entry (engine id)");
263 LOG(engine_id.get_printable());
266 return SNMPv3_MP_ERROR;
269 /* i is the entry to remove */
270 if (i != entries - 1)
271 table[i] = table[entries-1];
278 // Remove the entry for the given address/port from the table.
279 int v3MP::EngineIdTable::delete_entry(const OctetStr &host, int port)
282 return SNMPv3_MP_NOT_INITIALIZED;
286 BEGIN_REENTRANT_CODE_BLOCK;
288 for (i = 0; i < entries; i++)
289 if ((table[i].port == port) &&
290 (table[i].host == host))
297 LOG_BEGIN(WARNING_LOG | 4);
298 LOG("v3MP::EngineIdTable: cannot remove nonexisting entry (host) (port)");
299 LOG(host.get_printable());
303 return SNMPv3_MP_ERROR;
306 /* i is the entry to remove */
307 if (i != entries - 1)
308 table[i] = table[entries-1];
315 int v3MP::EngineIdTable::initialize_table(const int size)
317 table = new struct Entry_T[size];
328 // ===============================[ Cache ]==================================
333 table = new struct Entry_T[5];
336 LOG_BEGIN(ERROR_LOG | 1);
337 LOG("v3MP::Cache: could not create empty table.");
348 v3MP::Cache::~Cache()
352 for (int i = 0; i < entries; i++)
353 usm->delete_sec_state_reference(table[i].sec_state_ref);
361 // Add an entry to the cache.
362 int v3MP::Cache::add_entry(int msg_id, unsigned long req_id,
363 const OctetStr &sec_engine_id,
365 const OctetStr &sec_name,
367 const OctetStr &context_engine_id,
368 const OctetStr &context_name,
369 struct SecurityStateReference *sec_state_ref,
370 int error_code, bool local_request)
373 return SNMPv3_MP_ERROR;
375 LOG_BEGIN(INFO_LOG | 8);
376 LOG("v3MP::Cache: adding new entry (n) (msg id) (req id) (type)");
380 LOG(local_request ? "local" : "remote");
383 BEGIN_REENTRANT_CODE_BLOCK;
385 for (int i = 0; i < entries; i++)
386 if ((table[i].msg_id == msg_id) &&
387 (table[i].req_id == req_id) &&
388 (table[i].local_request == local_request) &&
389 (table[i].sec_engine_id == sec_engine_id) &&
390 (table[i].sec_model == sec_model) &&
391 (table[i].sec_name == sec_name) &&
392 (table[i].sec_level == sec_level) &&
393 (table[i].context_engine_id == context_engine_id) &&
394 (table[i].context_name == context_name))
396 LOG_BEGIN(WARNING_LOG | 3);
397 LOG("v3MP::Cache: Dont add doubled entry (msg id) (req id)");
402 return SNMPv3_MP_DOUBLED_MESSAGE;
405 table[entries].msg_id = msg_id;
406 table[entries].req_id = req_id;
407 table[entries].local_request = local_request;
408 table[entries].sec_engine_id = sec_engine_id;
409 table[entries].sec_model = sec_model;
410 table[entries].sec_name = sec_name;
411 table[entries].sec_level = sec_level;
412 table[entries].context_engine_id = context_engine_id;
413 table[entries].context_name = context_name;
414 table[entries].sec_state_ref = sec_state_ref;
415 table[entries].error_code = error_code;
418 if (entries == max_entries)
422 tmp = new struct Entry_T[2 * max_entries];
426 return SNMPv3_MP_ERROR;
428 for (int i=0; i<entries;i++)
437 // Search the cache for a message id, return the error code and
438 int v3MP::Cache::get_entry(int msg_id, bool local_request, int *error_code,
439 struct SecurityStateReference **sec_state_ref)
441 if (!table) return SNMPv3_MP_ERROR;
443 BEGIN_REENTRANT_CODE_BLOCK;
445 for (int i=0; i < entries; i++)
447 if ((msg_id == table[i].msg_id) &&
448 (local_request == table[i].local_request))
450 *error_code = table[i].error_code;
451 *sec_state_ref = table[i].sec_state_ref;
454 LOG_BEGIN(INFO_LOG | 8);
455 LOG("v3MP::Cache: Found entry (n) (msg id) (type)");
458 LOG(local_request ? "local" : "remote");
463 table[i] = table[entries];
465 LOG_BEGIN(INFO_LOG | 10);
466 LOG("v3MP::Cache: Moving entry (from) (to)");
475 LOG_BEGIN(WARNING_LOG | 5);
476 LOG("v3MP::Cache: Entry not found (msg id) (type)");
478 LOG(local_request ? "local" : "remote");
481 return SNMPv3_MP_ERROR;
484 // Delete the entry with the given request id from the cache.
485 void v3MP::Cache::delete_entry(unsigned long req_id, bool local_request)
489 BEGIN_REENTRANT_CODE_BLOCK;
491 for (int i=0; i<entries; i++)
492 if ((table[i].req_id == req_id) &&
493 (table[i].local_request == local_request))
495 LOG_BEGIN(INFO_LOG | 8);
496 LOG("v3MP::Cache: Delete unprocessed entry (n) (req id) (type)");
499 LOG(local_request ? "local" : "remote");
502 usm->delete_sec_state_reference(table[i].sec_state_ref);
506 table[i] = table[entries];
508 LOG_BEGIN(INFO_LOG | 10);
509 LOG("v3MP::Cache: Moving entry (from) (to)");
517 LOG_BEGIN(INFO_LOG | 8);
518 LOG("v3MP::Cache: Entry to delete not found (req id) (type)");
520 LOG(local_request ? "local" : "remote");
526 // Delete the entry with the given request ans message id from the cache.
527 void v3MP::Cache::delete_entry(unsigned long req_id, int msg_id,
532 BEGIN_REENTRANT_CODE_BLOCK;
534 for (int i=0; i<entries; i++)
535 if ((table[i].req_id == req_id) &&
536 (table[i].msg_id == msg_id) &&
537 (table[i].local_request == local_request))
539 LOG_BEGIN(INFO_LOG | 8);
540 LOG("v3MP::Cache: Delete unprocessed entry (n) (req id) (msg id) (type)");
544 LOG(local_request ? "local" : "remote");
547 usm->delete_sec_state_reference(table[i].sec_state_ref);
551 table[i] = table[entries];
553 LOG_BEGIN(INFO_LOG | 10);
554 LOG("v3MP::Cache: Moving entry (from) (to)");
562 LOG_BEGIN(INFO_LOG | 8);
563 LOG("v3MP::Cache: Entry to delete not found (req id) (msg id) (type)");
566 LOG(local_request ? "local" : "remote");
572 // Search the cache for a message id, return it and remove it from the cache
573 int v3MP::Cache::get_entry(int searchedID, bool local_request,
574 struct Cache::Entry_T *res)
576 if ((!table) || (!res)) return SNMPv3_MP_ERROR;
578 BEGIN_REENTRANT_CODE_BLOCK;
580 for (int i=0; i < entries; i++)
581 if ((table[i].msg_id == searchedID) &&
582 (table[i].local_request == local_request))
584 res->msg_id = table[i].msg_id;
585 res->req_id = table[i].req_id;
586 res->local_request = table[i].local_request;
587 res->sec_engine_id = table[i].sec_engine_id;
588 res->sec_model = table[i].sec_model;
589 res->sec_name = table[i].sec_name;
590 res->sec_level = table[i].sec_level;
591 res->context_engine_id = table[i].context_engine_id;
592 res->context_name = table[i].context_name;
593 res->sec_state_ref = table[i].sec_state_ref;
594 res->error_code = table[i].error_code;
596 LOG_BEGIN(INFO_LOG | 8);
597 LOG("v3MP::Cache: Found entry (n) (msg id) (type)");
600 LOG(local_request ? "local" : "remote");
607 table[i] = table[entries];
609 LOG_BEGIN(INFO_LOG | 10);
610 LOG("v3MP::Cache: Moving entry (from) (to)");
618 LOG_BEGIN(WARNING_LOG | 5);
619 LOG("v3MP::Cache: Entry not found (msg id) (type)");
621 LOG(local_request ? "local" : "remote");
624 return SNMPv3_MP_ERROR;
627 void v3MP::Cache::delete_content(struct v3MP::Cache::Entry_T &ce)
629 if (ce.sec_state_ref)
630 usm->delete_sec_state_reference(ce.sec_state_ref);
633 // ==========================[ class v3MP ]===============================
635 // Initialize the v3MP.
636 v3MP::v3MP(const OctetStr& snmpEngineID,
637 unsigned int engineBoots, int &construct_status)
638 : own_engine_id(0), usm(0)
642 debugprintf(0, "v3MP: You must not create two objects of this class!");
643 construct_status = SNMPv3_MP_ERROR;
649 snmpUnknownSecurityModels = 0;
651 snmpUnknownPDUHandlers = 0;
653 int length = snmpEngineID.len();
654 if (length > MAXLENGTH_ENGINEID)
655 length = MAXLENGTH_ENGINEID;
657 own_engine_id = v3strcpy(snmpEngineID.data(), length);
658 own_engine_id_len = length;
659 own_engine_id_oct = snmpEngineID;
662 usm = new USM(engineBoots, snmpEngineID, this, &cur_msg_id, result);
664 if (cur_msg_id >= MAX_MPMSGID)
667 if ((!own_engine_id) || (!usm) || (result != SNMPv3_USM_OK))
669 construct_status = SNMPv3_MP_ERROR;
674 construct_status = SNMPv3_MP_OK;
677 // Free all allocated ressources of the v3MP.
681 delete [] own_engine_id;
693 // Remove all occurences of this engine id from v3MP and USM.
694 int v3MP::remove_engine_id(const OctetStr &engine_id)
696 int retval1, retval2;
698 retval1 = engine_id_table.delete_entry(engine_id);
700 retval2 = usm->remove_engine_id(engine_id);
702 if ((retval1 == SNMPv3_MP_NOT_INITIALIZED) ||
703 (retval2 == SNMPv3_USM_ERROR))
704 return SNMPv3_MP_NOT_INITIALIZED;
709 // Send a report message.
710 int v3MP::send_report(unsigned char* scopedPDU, int scopedPDULength,
711 struct snmp_pdu *pdu, int errorCode, int sLevel,
712 int sModel, OctetStr &sName,
713 UdpAddress &destination, Snmp *snmp_session)
715 debugprintf(2, "v3MP::send_report: Sending report message.");
720 unsigned char cEngineID[MAXLENGTH_ENGINEID+1];
721 unsigned char cName[MAXLENGTH_CONTEXT_NAME+1];
722 int cEngineIDLength = MAXLENGTH_ENGINEID+1;
723 int cNameLength = MAXLENGTH_CONTEXT_NAME+1;
725 if (scopedPDULength != MAX_SNMP_PACKET)
727 // try to get scopedPDU and PDU
728 data = asn1_parse_scoped_pdu(scopedPDU, &scopedPDULength,
729 cEngineID, &cEngineIDLength,
730 cName, &cNameLength);
732 debugprintf(1, "mp: Error while trying to parse scopedPDU!");
737 // Dont send encrypted report if decryption failed:
738 if (sLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
739 sLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV;
741 else { // data != NULL
742 dataLength = scopedPDULength;
744 // parse data of scopedPDU
745 snmp_parse_data_pdu(pdu, data, dataLength);
746 pdu_type = pdu->command;
749 debugprintf(0, "mp: Error while trying to parse PDU!");
751 } // end of: if (data == NULL)
752 } // end if (scopedPDULength != MAX_SNMP_PACKET)
753 else { // scopedPDULength == MAX_SNMP_PACKET
761 clear_pdu(pdu); // Clear pdu and free all content
763 debugprintf(4, "pdu->reqid = %ld",pdu->reqid);
766 pdu->command = REPORT_MSG;
774 case SNMPv3_MP_INVALID_MESSAGE:
775 case SNMPv3_USM_PARSE_ERROR: {
776 counterVb.set_oid(oidSnmpInvalidMsgs);
777 counterVb.set_value(Counter32(get_stats_invalid_msgs()));
780 case SNMPv3_USM_NOT_IN_TIME_WINDOW:
781 case SNMPv3_MP_NOT_IN_TIME_WINDOW: {
782 counterVb.set_oid(oidUsmStatsNotInTimeWindows);
783 counterVb.set_value(Counter32(usm->get_stats_not_in_time_windows()));
786 case SNMPv3_USM_DECRYPTION_ERROR: {
787 counterVb.set_oid(oidUsmStatsDecryptionErrors);
788 counterVb.set_value(Counter32(usm->get_stats_decryption_errors()));
789 sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
792 case SNMPv3_USM_AUTHENTICATION_ERROR:
793 case SNMPv3_USM_AUTHENTICATION_FAILURE: {
794 counterVb.set_oid(oidUsmStatsWrongDigests);
795 counterVb.set_value(Counter32(usm->get_stats_wrong_digests()));
796 sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
799 case SNMPv3_USM_UNKNOWN_ENGINEID:
800 case SNMPv3_MP_INVALID_ENGINEID: {
801 sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
802 counterVb.set_oid(oidUsmStatsUnknownEngineIDs);
803 counterVb.set_value(Counter32(usm->get_stats_unknown_engine_ids()));
806 case SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL: {
807 counterVb.set_oid(oidSnmpUnknownSecurityModels);
808 counterVb.set_value(Counter32(get_stats_unknown_security_models()));
809 sModel = SNMP_SECURITY_MODEL_USM;
810 sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
813 case SNMPv3_USM_UNKNOWN_SECURITY_NAME: {
814 counterVb.set_oid(oidUsmStatsUnknownUserNames);
815 counterVb.set_value(Counter32(usm->get_stats_unknown_user_names()));
816 sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
817 debugprintf(2, "Report: SecurityName: %s",sName.get_printable());
820 case SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL: {
821 counterVb.set_oid(oidUsmStatsUnsupportedSecLevels);
822 counterVb.set_value(Counter32(usm->get_stats_unsupported_sec_levels()));
823 sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
827 counterVb.set_oid(oidSnmpInvalidMsgs);
828 counterVb.set_value(Counter32(get_stats_invalid_msgs()));
829 sModel = SNMP_SECURITY_MODEL_USM;
830 sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
831 sName.set_data(0, 0);
833 debugprintf(2, "ErrorCode was %i in snmp_parse", errorCode);
837 counterVb.get_oid(counterOid);
838 smioid = counterOid.oidval();
840 int status = convertVbToSmival(counterVb, &smival);
841 if (status != SNMP_CLASS_SUCCESS) {
842 return SNMPv3_MP_ERROR;
844 snmp_add_var(pdu, smioid->ptr,
845 (int) smioid->len, &smival);
846 freeSmivalDescriptor(&smival);
848 Buffer<unsigned char> sendbuffer(MAX_SNMP_PACKET);
849 int sendbufferlen= MAX_SNMP_PACKET;
850 status = snmp_build( pdu, sendbuffer.get_ptr(), &sendbufferlen,
851 own_engine_id_oct, sName, sModel, sLevel,
852 OctetStr(cEngineID, cEngineIDLength),
853 OctetStr(cName, cNameLength));
854 if (status != SNMPv3_MP_OK) {
855 debugprintf(2, "v3MP::send_report: error serializing message (mpSnmpBuild returns: %i).", status);
856 return SNMPv3_MP_ERROR;
858 SnmpSocket send_fd = INVALID_SOCKET;
859 if (pdu_type == sNMP_PDU_INFORM)
861 debugprintf(4, "Received a snmpInform pdu.");
862 if (snmp_session->get_eventListHolder()->notifyEventList())
863 send_fd = snmp_session->get_eventListHolder()->notifyEventList()->get_notify_fd();
866 status = snmp_session->send_raw_data(sendbuffer.get_ptr(),
867 (size_t)sendbufferlen,// pdu to send
868 destination, // target address
869 send_fd); // the fd to use
872 debugprintf(1, "v3MP::send_report: error sending message (%i)", status);
873 return SNMPv3_MP_ERROR;
875 debugprintf(3, "v3MP::send_report: Report sent.");
879 // Parse the given buffer as a SNMPv3-Message.
880 int v3MP::snmp_parse(Snmp *snmp_session,
881 struct snmp_pdu *pdu,
882 unsigned char *inBuf,
884 OctetStr &securityEngineID,
885 OctetStr &securityName,
886 OctetStr &contextEngineID,
887 OctetStr &contextName,
889 long &msgSecurityModel,
890 snmp_version &spp_version,
891 UdpAddress from_address)
893 debugprintf(3, "mp is parsing incoming message:");
894 debughexprintf(25, inBuf, inBufLength);
896 if (inBufLength > MAX_SNMP_PACKET)
897 return SNMPv3_MP_ERROR;
901 int origLength = inBufLength;
902 unsigned char *inBufPtr = inBuf;
903 long msgID, msgMaxSize;
904 unsigned char msgFlags;
905 Buffer<unsigned char> msgSecurityParameters(MAX_SNMP_PACKET);
906 Buffer<unsigned char> msgData(MAX_SNMP_PACKET);
907 int msgSecurityParametersLength = inBufLength, msgDataLength = inBufLength;
908 Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
909 int scopedPDULength = MAX_SNMP_PACKET;
910 long maxSizeResponseScopedPDU = 0;
911 struct SecurityStateReference *securityStateReference = NULL;
912 int securityParametersPosition;
917 inBuf = asn_parse_header( inBuf, &inBufLength, &type);
919 debugprintf(0, "snmp_parse: bad header");
920 return SNMPv3_MP_PARSE_ERROR;
923 if (type != (ASN_SEQ_CON)){
924 debugprintf(0, "snmp_parse: wrong auth header type");
925 return SNMPv3_MP_PARSE_ERROR;
928 if (origLength != inBufLength + (inBuf - inBufPtr)) {
929 debugprintf(0, "snmp_parse: wrong length of received packet");
930 return SNMPv3_MP_PARSE_ERROR;
934 inBuf = asn_parse_int(inBuf, &inBufLength, &type, &version);
936 debugprintf(0, "snmp_parse: bad parse of version");
937 return SNMPv3_MP_PARSE_ERROR;
940 debugprintf(3, "Parsed length(%x), version(0x%lx)", inBufLength, version);
942 if ( version != SNMP_VERSION_3 )
943 return SNMPv3_MP_PARSE_ERROR;
945 spp_version = (snmp_version) version;
947 inBuf = asn1_parse_header_data(inBuf, &inBufLength,
949 &msgFlags, &msgSecurityModel);
952 debugprintf(0, "snmp_parse: bad parse of msgHeaderData");
953 return SNMPv3_MP_PARSE_ERROR;
957 if ((msgMaxSize < 484) || (msgMaxSize > 0x7FFFFFFF)) {
958 debugprintf(0, "snmp_parse: bad parse of msgMaxSize");
959 return SNMPv3_MP_PARSE_ERROR;
962 // do not allow larger messages than this entity can handle
963 if (msgMaxSize > MAX_SNMP_PACKET) msgMaxSize = MAX_SNMP_PACKET;
964 pdu->maxsize_scopedpdu = msgMaxSize;
966 inBuf = asn_parse_string( inBuf, &inBufLength, &type,
967 msgSecurityParameters.get_ptr(),
968 &msgSecurityParametersLength);
971 debugprintf(0, "snmp_parse: bad parse of msgSecurityParameters");
972 return SNMPv3_MP_PARSE_ERROR;
975 securityParametersPosition= SAFE_INT_CAST(inBuf - inBufPtr) - msgSecurityParametersLength;
977 // the rest of the message is passed directly to the security module
979 msgDataLength = origLength - SAFE_INT_CAST(inBuf - inBufPtr);
980 memcpy(msgData.get_ptr(), inBuf, msgDataLength);
982 debugprintf(3, "Parsed msgdata length(0x%x), "
983 "msgSecurityParameters length(0x%x)", msgDataLength,
984 msgSecurityParametersLength);
986 switch (msgFlags & 0x03) {
987 case 3: { securityLevel = SNMP_SECURITY_LEVEL_AUTH_PRIV; break;}
988 case 0: { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV; break;}
989 case 1: { securityLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV; break;}
990 default: { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
992 // do not send back report
993 return SNMPv3_MP_INVALID_MESSAGE;
1000 if (msgFlags & 0x04) reportableFlag = TRUE;
1001 else reportableFlag = FALSE;
1003 securityStateReference = usm->get_new_sec_state_reference();
1004 if (!securityStateReference)
1005 return SNMPv3_MP_ERROR;
1007 switch (msgSecurityModel) {
1008 case SNMP_SECURITY_MODEL_USM:
1010 rc = usm->process_msg(
1012 msgSecurityParameters.get_ptr(),
1013 msgSecurityParametersLength,
1014 securityParametersPosition,
1016 inBufPtr, origLength, //wholeMsg
1017 msgData.get_ptr(), msgDataLength,
1020 scopedPDU.get_ptr(), &scopedPDULength,
1021 &maxSizeResponseScopedPDU,
1022 securityStateReference,
1024 pdu->maxsize_scopedpdu = maxSizeResponseScopedPDU;
1025 if (rc != SNMPv3_USM_OK) {
1026 if (rc == SNMPv3_USM_NOT_IN_TIME_WINDOW) {
1027 errorCode = SNMPv3_MP_NOT_IN_TIME_WINDOW;
1030 // error handling! rfc2262 page 31
1031 debugprintf(0, "mp: error while executing USM::process_msg");
1035 if (errorCode != SNMPv3_USM_PARSE_ERROR)
1036 if (securityEngineID.len() == 0)
1037 errorCode = SNMPv3_MP_INVALID_ENGINEID;
1041 snmpUnknownSecurityModels++;
1042 usm->delete_sec_state_reference(securityStateReference);
1043 debugprintf(0, "SecurityModel of incomming Message not supported!");
1044 // Message should be dropped without a report
1045 return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
1048 // process scopedPDU
1049 debughexcprintf(21, "scoped PDU", scopedPDU.get_ptr(), scopedPDULength);
1051 unsigned char *scopedPDUPtr= scopedPDU.get_ptr();
1052 unsigned char tmp_contextEngineID[MAXLENGTH_ENGINEID];
1053 unsigned char tmp_contextName[MAXLENGTH_CONTEXT_NAME];
1054 int tmp_contextEngineIDLength = MAXLENGTH_ENGINEID;
1055 int tmp_contextNameLength = MAXLENGTH_CONTEXT_NAME;
1057 unsigned char *data;
1060 debugprintf(1,"ErrorCode is %i",errorCode);
1063 data = asn1_parse_scoped_pdu(scopedPDUPtr, &scopedPDULength,
1064 tmp_contextEngineID,
1065 &tmp_contextEngineIDLength,
1066 tmp_contextName, &tmp_contextNameLength);
1068 debugprintf(0, "mp: Error Parsing scopedPDU!");
1069 usm->delete_sec_state_reference(securityStateReference);
1070 return SNMPv3_MP_PARSE_ERROR;
1072 dataLength = scopedPDULength;
1073 contextEngineID.set_data(tmp_contextEngineID, tmp_contextEngineIDLength);
1074 contextName.set_data(tmp_contextName, tmp_contextNameLength);
1076 // parse data of scopedPDU
1077 if (snmp_parse_data_pdu(pdu, data, dataLength) != SNMP_CLASS_SUCCESS) {
1078 debugprintf(0, "mp: Error parsing PDU!");
1079 usm->delete_sec_state_reference(securityStateReference);
1080 return SNMPv3_MP_PARSE_ERROR;
1082 if (SNMP_CLASS_SUCCESS != snmp_parse_vb(pdu, data, dataLength)) {
1083 debugprintf(0, "mp: Error parsing Vb");
1084 usm->delete_sec_state_reference(securityStateReference);
1085 return SNMPv3_MP_PARSE_ERROR;
1087 if ((tmp_contextEngineIDLength == 0) &&
1088 ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
1089 (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
1090 (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG) ||
1091 (pdu->command == TRP2_REQ_MSG)))
1093 // RFC 2572 � 4.2.2.1 (2a)
1094 debugprintf(2, "mp: received request message with zero length"
1095 " contextEngineID -> unknownPduHandlers.");
1096 inc_stats_unknown_pdu_handlers();
1097 errorCode = SNMPv3_MP_UNKNOWN_PDU_HANDLERS;
1101 if ((reportableFlag) && (errorCode != SNMPv3_USM_PARSE_ERROR)) {
1102 // error occured: prepare reportpdu in agent
1103 cache.add_entry(msgID, pdu->reqid, securityEngineID,
1105 securityName, securityLevel, "", "",
1106 securityStateReference, errorCode, CACHE_REMOTE_REQ);
1108 send_report(scopedPDUPtr, scopedPDULength, pdu, errorCode,
1109 securityLevel, msgSecurityModel, securityName,
1110 from_address, snmp_session);
1111 clear_pdu(pdu, true); // Clear pdu and free all content AND IDs!
1114 usm->delete_sec_state_reference(securityStateReference);
1119 struct Cache::Entry_T centry;
1121 if ((pdu->command == GET_RSP_MSG) || (pdu->command == REPORT_MSG)) {
1122 rc = cache.get_entry(msgID, true, ¢ry);
1123 if (rc != SNMPv3_MP_OK) {
1125 debugprintf(2, "Received rspMsg without outstanding request."
1126 " -> SnmpUnknownPduHandler");
1127 usm->delete_sec_state_reference(securityStateReference);
1128 inc_stats_unknown_pdu_handlers();
1129 return SNMPv3_MP_UNKNOWN_PDU_HANDLERS;
1131 if (((pdu->reqid == 0) || (pdu->reqid == 0x7fffffff))
1132 && (pdu->command == REPORT_MSG))
1133 pdu->reqid = centry.req_id;
1134 #ifdef BUGGY_REPORT_REQID
1135 if ((pdu->reqid != centry.req_id) && (pdu->command == REPORT_MSG))
1137 debugprintf(0, "WARNING: setting reqid of REPORT PDU (from) (to): (%ld) (%ld)", pdu->reqid, centry.req_id);
1138 pdu->reqid = centry.req_id;
1143 if (pdu->command == REPORT_MSG) {
1144 // !! rfc2262 page 33
1146 debugprintf(2, "*** Receiving a ReportPDU ***");
1147 if (/*((securityEngineID != centry.sec_engine_id)
1148 && (centry.sec_engine_id.len() != 0)) ||*/
1149 ((msgSecurityModel != centry.sec_model)
1150 && (msgSecurityModel != SNMP_SECURITY_MODEL_USM)) ||
1151 ((securityName != centry.sec_name)
1152 && (securityName.len() != 0)))
1154 debugprintf(0, "Received report message doesn't match sent message!");
1155 usm->delete_sec_state_reference(securityStateReference);
1156 return SNMPv3_MP_MATCH_ERROR;
1158 usm->delete_sec_state_reference(securityStateReference);
1159 cache.delete_content(centry);
1160 debugprintf(1, "mp finished (OK)");
1161 return SNMPv3_MP_OK;
1164 if (pdu->command == GET_RSP_MSG) {
1165 if (((securityEngineID != centry.sec_engine_id)
1166 && (centry.sec_engine_id.len() != 0)) ||
1167 (msgSecurityModel != centry.sec_model) ||
1168 (securityName != centry.sec_name) ||
1169 (securityLevel != centry.sec_level) ||
1170 ((contextEngineID != centry.context_engine_id)
1171 && (centry.context_engine_id.len() != 0))||
1172 ((contextName != centry.context_name)
1173 && (centry.context_name.len() != 0))) {
1174 debugprintf(0, "Received response message doesn't match sent message!");
1175 usm->delete_sec_state_reference(securityStateReference);
1176 cache.delete_content(centry);
1177 return SNMPv3_MP_MATCH_ERROR;
1179 usm->delete_sec_state_reference(securityStateReference);
1180 cache.delete_content(centry);
1181 debugprintf(1, "mp finished (OK)");
1182 return SNMPv3_MP_OK;
1185 if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
1186 (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
1187 (pdu->command == INFORM_REQ_MSG)) {
1188 if (securityEngineID.len() == 0) {
1189 debugprintf(2, "Received Message with engineID = 0.");
1192 if (!(unsignedCharCompare(securityEngineID.data(), securityEngineID.len(),
1193 own_engine_id, own_engine_id_len))) {
1194 debugprintf(0, "snmp_parse: securityEngineID doesn't match own_engine_id.");
1195 /* we are authoritative but engine id of message is wrong
1196 if discovery in USM is enabled:
1197 - remove automatically added illegal engine id from USM tables
1200 if (usm->is_discovery_enabled())
1202 // TODO: try to remove engine id from USM
1205 cache.add_entry(msgID, pdu->reqid, securityEngineID,
1207 securityName, securityLevel, "", "",
1208 securityStateReference,
1209 SNMPv3_MP_INVALID_ENGINEID,
1212 send_report(0, MAX_SNMP_PACKET, pdu, SNMPv3_MP_INVALID_ENGINEID,
1213 SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV, msgSecurityModel,
1214 securityName, from_address, snmp_session);
1215 clear_pdu(pdu, true); // Clear pdu and free all content AND IDs!
1219 usm->delete_sec_state_reference(securityStateReference);
1221 return SNMPv3_MP_INVALID_ENGINEID;
1224 usm->delete_sec_state_reference(securityStateReference);
1225 return SNMPv3_MP_MATCH_ERROR;
1228 int ret = cache.add_entry(msgID, pdu->reqid, securityEngineID,
1229 msgSecurityModel, securityName,
1230 securityLevel, contextEngineID,
1231 contextName, securityStateReference,
1232 SNMPv3_MP_OK, CACHE_REMOTE_REQ);
1233 if (ret == SNMPv3_MP_DOUBLED_MESSAGE) {
1234 debugprintf(0, "*** received doubled message ***");
1235 // message will be ignored so return OK
1236 usm->delete_sec_state_reference(securityStateReference);
1239 debugprintf(1, "mp: parsing finished (ok).");
1240 return SNMPv3_MP_OK;
1243 if ((pdu->command == TRP_REQ_MSG) || (pdu->command == TRP2_REQ_MSG))
1245 usm->delete_sec_state_reference(securityStateReference);
1246 return SNMPv3_MP_OK;
1249 debugprintf(0, "mp error: This line should not be executed.");
1250 usm->delete_sec_state_reference(securityStateReference);
1251 return SNMPv3_MP_ERROR;
1255 // Tests if the given buffer contains a SNMPv3-Message.
1256 bool v3MP::is_v3_msg(unsigned char *buffer, int length)
1262 buffer = asn_parse_header(buffer, &length, &type);
1265 LOG_BEGIN(WARNING_LOG | 1);
1266 LOG("Testing for v3 message: Bad header");
1272 if (type != ASN_SEQ_CON)
1274 LOG_BEGIN(WARNING_LOG | 1);
1275 LOG("Testing for v3 message: Wrong auth header type");
1283 buffer = asn_parse_int(buffer, &length, &type, &version);
1286 LOG_BEGIN(WARNING_LOG | 1);
1287 LOG("Testing for v3 message: Bad parse of version");
1293 return (version == SNMP_VERSION_3);
1298 // Do the complete process of encoding the given values into the buffer
1299 // ready to send to the target.
1300 int v3MP::snmp_build(struct snmp_pdu *pdu,
1301 unsigned char *packet,
1302 int *out_length, // maximum Bytes in packet
1303 const OctetStr &securityEngineID,
1304 const OctetStr &securityName,
1307 const OctetStr &contextEngineID,
1308 const OctetStr &contextName)
1310 Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
1311 unsigned char *scopedPDUPtr = scopedPDU.get_ptr();
1312 unsigned char globalData[MAXLENGTH_GLOBALDATA];
1313 int globalDataLength = MAXLENGTH_GLOBALDATA;
1314 int scopedPDULength, maxLen = *out_length;
1315 Buffer<unsigned char> buf(MAX_SNMP_PACKET);
1316 unsigned char *bufPtr = buf.get_ptr();
1317 long bufLength = 0, rc;
1319 int cachedErrorCode = SNMPv3_MP_OK;
1320 struct SecurityStateReference *securityStateReference = NULL;
1321 int isRequestMessage = 0;
1323 if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
1324 (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
1325 (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG) ||
1326 (pdu->command == TRP2_REQ_MSG))
1327 isRequestMessage = 1;
1329 if (isRequestMessage) {
1330 if (securityEngineID.len() == 0) {
1331 // First Contact => use user noAuthNoPriv and USM
1332 securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
1333 securityModel = SNMP_SECURITY_MODEL_USM;
1336 cur_msg_id_lock.lock();
1339 if (cur_msg_id >= MAX_MPMSGID)
1341 cur_msg_id_lock.unlock();
1343 #ifdef INVALID_MSGID
1344 LOG_BEGIN(ERROR_LOG | 1);
1345 LOG("*** WARNING: Using constant MessageID! ***");
1351 if (securityEngineID.len() == 0) {
1352 // length==0 => SecurityLevel == noAuthNoPriv
1353 // => we do not send any management information
1354 // => delete VariableBinding
1359 // it is a response => search for request
1360 debugprintf(3, "Looking up cache");
1362 rc = cache.get_entry(msgID, CACHE_REMOTE_REQ,
1363 &cachedErrorCode, &securityStateReference);
1365 if (rc != SNMPv3_MP_OK) {
1367 debugprintf(0, "mp: Cache lookup error");
1368 return SNMPv3_MP_MATCH_ERROR;
1372 LOG_BEGIN(DEBUG_LOG | 5);
1373 LOG("v3MP: Building message with (SecurityEngineID) (securityName) (securityLevel) (contextEngineID) (contextName)");
1374 LOG(securityEngineID.get_printable());
1375 LOG(securityName.get_printable());
1377 LOG(contextEngineID.get_printable());
1378 LOG(contextName.get_printable());
1382 scopedPDUPtr = build_vb(pdu, scopedPDUPtr, &maxLen);
1385 LOG_BEGIN(WARNING_LOG | 1);
1386 LOG("v3MP: Error encoding vbs into buffer");
1389 return SNMPv3_MP_BUILD_ERROR;
1391 scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());
1393 //build dataPDU in buf
1394 maxLen = *out_length;
1395 scopedPDUPtr = scopedPDU.get_ptr();
1396 bufPtr = build_data_pdu(pdu, bufPtr, &maxLen, scopedPDUPtr, scopedPDULength);
1400 LOG_BEGIN(WARNING_LOG | 1);
1401 LOG("v3MP: Error encoding data pdu into buffer");
1404 return SNMPv3_MP_BUILD_ERROR;
1407 bufLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());
1409 // serialize scopedPDU
1410 maxLen = *out_length;
1411 scopedPDUPtr = asn1_build_scoped_pdu(scopedPDUPtr, &maxLen,
1412 contextEngineID.data(),
1413 contextEngineID.len(),
1414 contextName.data(), contextName.len(),
1415 buf.get_ptr(), bufLength);
1419 LOG_BEGIN(WARNING_LOG | 1);
1420 LOG("v3MP: Error encoding scoped pdu into buffer");
1423 return SNMPv3_MP_BUILD_ERROR;
1426 scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());
1428 // build msgGlobalData
1429 unsigned char *globalDataPtr = (unsigned char *)&globalData;
1430 unsigned char msgFlags;
1431 switch (securityLevel) {
1432 case SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV:
1433 { msgFlags = 0 ; break;}
1434 case SNMP_SECURITY_LEVEL_AUTH_NOPRIV:
1435 { msgFlags = SNMPv3_AUTHFLAG; break;}
1436 case SNMP_SECURITY_LEVEL_AUTH_PRIV:
1437 { msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG; break;}
1440 LOG_BEGIN(WARNING_LOG | 1);
1441 LOG("v3MP: Unknown security level requested, will use authPriv");
1445 msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG;
1449 if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
1450 (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
1451 (pdu->command == INFORM_REQ_MSG))
1452 msgFlags = msgFlags | SNMPv3_REPORTABLEFLAG;
1454 globalDataPtr = asn1_build_header_data(globalDataPtr, &globalDataLength,
1455 msgID, *out_length, // maxMessageSize
1456 msgFlags, securityModel);
1459 LOG_BEGIN(ERROR_LOG | 1);
1460 LOG("v3MP: Error building header data");
1463 return SNMPv3_MP_BUILD_ERROR;
1465 globalDataLength = SAFE_INT_CAST(globalDataPtr - (unsigned char *)&globalData);
1467 switch (securityModel) {
1468 case SNMP_SECURITY_MODEL_USM: {
1469 int use_own_engine_id = 0;
1470 if ((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
1471 (pdu->command == REPORT_MSG) || (pdu->command == TRP2_REQ_MSG)) {
1472 use_own_engine_id = 1;
1475 rc = usm->generate_msg(globalData, globalDataLength, *out_length,
1476 (use_own_engine_id ?
1477 own_engine_id_oct : securityEngineID),
1478 securityName, securityLevel,
1479 scopedPDU.get_ptr(), scopedPDULength,
1480 securityStateReference, packet, out_length);
1482 if ( rc == SNMPv3_USM_OK ) {
1484 if (!((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
1485 (pdu->command == REPORT_MSG) || (pdu->command == TRP2_REQ_MSG)))
1486 cache.add_entry(msgID, pdu->reqid, securityEngineID,
1487 securityModel, securityName, securityLevel,
1488 contextEngineID, contextName, securityStateReference,
1489 SNMPv3_MP_OK, CACHE_LOCAL_REQ);
1491 LOG_BEGIN(INFO_LOG | 3);
1492 LOG("v3MP: Message built OK");
1495 return SNMPv3_MP_OK;
1499 LOG_BEGIN(WARNING_LOG | 1);
1500 LOG("v3MP: Returning error for building message");
1509 LOG_BEGIN(WARNING_LOG | 1);
1510 LOG("v3MP: Should build message with unsupported securityModel");
1514 return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
1519 #ifdef SNMP_PP_NAMESPACE
1520 }; // end of namespace Snmp_pp