//================[ 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; }
//===============[ 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; validity = true; } return *this; }
// Parse the given buffer as a SNMPv3-Message. int v3MP::snmp_parse(Snmp *snmp_session, struct snmp_pdu *pdu, unsigned char *inBuf, int inBufLength, OctetStr &securityEngineID, OctetStr &securityName, OctetStr &contextEngineID, OctetStr &contextName, long &securityLevel, long &msgSecurityModel, snmp_version &spp_version, UdpAddress from_address) { debugprintf(3, "mp is parsing incoming message:"); debughexprintf(25, inBuf, inBufLength); if (inBufLength > MAX_SNMP_PACKET) return SNMPv3_MP_ERROR; unsigned char type; long version; int origLength = inBufLength; unsigned char *inBufPtr = inBuf; long msgID, msgMaxSize; unsigned char msgFlags; Buffer<unsigned char> msgSecurityParameters(MAX_SNMP_PACKET); Buffer<unsigned char> msgData(MAX_SNMP_PACKET); int msgSecurityParametersLength = inBufLength, msgDataLength = inBufLength; Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET); int scopedPDULength = MAX_SNMP_PACKET; long maxSizeResponseScopedPDU = 0; struct SecurityStateReference *securityStateReference = NULL; int securityParametersPosition; int rc; int errorCode = 0; // get the type inBuf = asn_parse_header( inBuf, &inBufLength, &type); if (inBuf == NULL){ debugprintf(0, "snmp_parse: bad header"); return SNMPv3_MP_PARSE_ERROR; } if (type != (ASN_SEQ_CON)){ debugprintf(0, "snmp_parse: wrong auth header type"); return SNMPv3_MP_PARSE_ERROR; } if (origLength != inBufLength + (inBuf - inBufPtr)) { debugprintf(0, "snmp_parse: wrong length of received packet"); return SNMPv3_MP_PARSE_ERROR; } // get the version inBuf = asn_parse_int(inBuf, &inBufLength, &type, &version); if (inBuf == NULL){ debugprintf(0, "snmp_parse: bad parse of version"); return SNMPv3_MP_PARSE_ERROR; } debugprintf(3, "Parsed length(%x), version(0x%lx)", inBufLength, version); if ( version != SNMP_VERSION_3 ) return SNMPv3_MP_PARSE_ERROR; spp_version = (snmp_version) version; inBuf = asn1_parse_header_data(inBuf, &inBufLength, &msgID, &msgMaxSize, &msgFlags, &msgSecurityModel); if (inBuf == NULL){ debugprintf(0, "snmp_parse: bad parse of msgHeaderData"); return SNMPv3_MP_PARSE_ERROR; } pdu->msgid = msgID; if ((msgMaxSize < 484) || (msgMaxSize > 0x7FFFFFFF)) { debugprintf(0, "snmp_parse: bad parse of msgMaxSize"); return SNMPv3_MP_PARSE_ERROR; } // do not allow larger messages than this entity can handle if (msgMaxSize > MAX_SNMP_PACKET) msgMaxSize = MAX_SNMP_PACKET; pdu->maxsize_scopedpdu = msgMaxSize; inBuf = asn_parse_string( inBuf, &inBufLength, &type, msgSecurityParameters.get_ptr(), &msgSecurityParametersLength); if (inBuf == NULL){ debugprintf(0, "snmp_parse: bad parse of msgSecurityParameters"); return SNMPv3_MP_PARSE_ERROR; } securityParametersPosition= SAFE_INT_CAST(inBuf - inBufPtr) - msgSecurityParametersLength; // the rest of the message is passed directly to the security module msgDataLength = origLength - SAFE_INT_CAST(inBuf - inBufPtr); memcpy(msgData.get_ptr(), inBuf, msgDataLength); debugprintf(3, "Parsed msgdata length(0x%x), " "msgSecurityParameters length(0x%x)", msgDataLength, msgSecurityParametersLength); switch (msgFlags & 0x03) { case 3: { securityLevel = SNMP_SECURITY_LEVEL_AUTH_PRIV; break;} case 0: { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV; break;} case 1: { securityLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV; break;} default: { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV; snmpInvalidMsgs++; // do not send back report return SNMPv3_MP_INVALID_MESSAGE; break; } } bool reportableFlag; if (msgFlags & 0x04) reportableFlag = true; else reportableFlag = false; securityStateReference = usm->get_new_sec_state_reference(); if (!securityStateReference) return SNMPv3_MP_ERROR; switch (msgSecurityModel) { case SNMP_SECURITY_MODEL_USM: { rc = usm->process_msg( msgMaxSize, msgSecurityParameters.get_ptr(), msgSecurityParametersLength, securityParametersPosition, securityLevel, inBufPtr, origLength, //wholeMsg msgData.get_ptr(), msgDataLength, securityEngineID, securityName, scopedPDU.get_ptr(), &scopedPDULength, &maxSizeResponseScopedPDU, securityStateReference, from_address); pdu->maxsize_scopedpdu = maxSizeResponseScopedPDU; if (rc != SNMPv3_USM_OK) { if (rc == SNMPv3_USM_NOT_IN_TIME_WINDOW) { errorCode = SNMPv3_MP_NOT_IN_TIME_WINDOW; } else { // error handling! rfc2262 page 31 debugprintf(0, "mp: error while executing USM::process_msg"); errorCode = rc; } } if (errorCode != SNMPv3_USM_PARSE_ERROR) if (securityEngineID.len() == 0) errorCode = SNMPv3_MP_INVALID_ENGINEID; break; } default: { snmpUnknownSecurityModels++; usm->delete_sec_state_reference(securityStateReference); debugprintf(0, "SecurityModel of incomming Message not supported!"); // Message should be dropped without a report return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL; } } // process scopedPDU debughexcprintf(21, "scoped PDU", scopedPDU.get_ptr(), scopedPDULength); unsigned char *scopedPDUPtr= scopedPDU.get_ptr(); unsigned char tmp_contextEngineID[MAXLENGTH_ENGINEID]; unsigned char tmp_contextName[MAXLENGTH_CONTEXT_NAME]; int tmp_contextEngineIDLength = MAXLENGTH_ENGINEID; int tmp_contextNameLength = MAXLENGTH_CONTEXT_NAME; unsigned char *data; int dataLength; debugprintf(1,"ErrorCode is %i",errorCode); if (!errorCode) { data = asn1_parse_scoped_pdu(scopedPDUPtr, &scopedPDULength, tmp_contextEngineID, &tmp_contextEngineIDLength, tmp_contextName, &tmp_contextNameLength); if (data == NULL) { debugprintf(0, "mp: Error Parsing scopedPDU!"); usm->delete_sec_state_reference(securityStateReference); return SNMPv3_MP_PARSE_ERROR; } dataLength = scopedPDULength; contextEngineID.set_data(tmp_contextEngineID, tmp_contextEngineIDLength); contextName.set_data(tmp_contextName, tmp_contextNameLength); // parse data of scopedPDU if (snmp_parse_data_pdu(pdu, data, dataLength) != SNMP_CLASS_SUCCESS) { debugprintf(0, "mp: Error parsing PDU!"); usm->delete_sec_state_reference(securityStateReference); return SNMPv3_MP_PARSE_ERROR; } if (SNMP_CLASS_SUCCESS != snmp_parse_vb(pdu, data, dataLength)) { debugprintf(0, "mp: Error parsing Vb"); usm->delete_sec_state_reference(securityStateReference); return SNMPv3_MP_PARSE_ERROR; } if ((tmp_contextEngineIDLength == 0) && ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) || (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) || (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG) || (pdu->command == TRP2_REQ_MSG))) { // RFC 2572 � 4.2.2.1 (2a) debugprintf(2, "mp: received request message with zero length" " contextEngineID -> unknownPduHandlers."); inc_stats_unknown_pdu_handlers(); errorCode = SNMPv3_MP_UNKNOWN_PDU_HANDLERS; } } if (errorCode) { if ((reportableFlag) && (errorCode != SNMPv3_USM_PARSE_ERROR)) { // error occured: prepare reportpdu in agent cache.add_entry(msgID, pdu->reqid, securityEngineID, msgSecurityModel, securityName, securityLevel, "", "", securityStateReference, errorCode, CACHE_REMOTE_REQ); send_report(scopedPDUPtr, scopedPDULength, pdu, errorCode, securityLevel, msgSecurityModel, securityName, from_address, snmp_session); clear_pdu(pdu, true); // Clear pdu and free all content AND IDs! } else { usm->delete_sec_state_reference(securityStateReference); } return errorCode; } struct Cache::Entry_T centry; if ((pdu->command == GET_RSP_MSG) || (pdu->command == REPORT_MSG)) { rc = cache.get_entry(msgID, true, ¢ry); if (rc != SNMPv3_MP_OK) { // RFC 2572 � 4 debugprintf(2, "Received rspMsg without outstanding request." " -> SnmpUnknownPduHandler"); usm->delete_sec_state_reference(securityStateReference); inc_stats_unknown_pdu_handlers(); return SNMPv3_MP_UNKNOWN_PDU_HANDLERS; } if (((pdu->reqid == 0) || (pdu->reqid == 0x7fffffff)) && (pdu->command == REPORT_MSG)) pdu->reqid = centry.req_id; #ifdef BUGGY_REPORT_REQID if ((pdu->reqid != centry.req_id) && (pdu->command == REPORT_MSG)) { debugprintf(0, "WARNING: setting reqid of REPORT PDU (from) (to): (%ld) (%ld)", pdu->reqid, centry.req_id); pdu->reqid = centry.req_id; } #endif } if (pdu->command == REPORT_MSG) { // !! rfc2262 page 33 debugprintf(2, "*** Receiving a ReportPDU ***"); if (/*((securityEngineID != centry.sec_engine_id) && (centry.sec_engine_id.len() != 0)) ||*/ ((msgSecurityModel != centry.sec_model) && (msgSecurityModel != SNMP_SECURITY_MODEL_USM)) || ((securityName != centry.sec_name) && (securityName.len() != 0))) { debugprintf(0, "Received report message doesn't match sent message!"); usm->delete_sec_state_reference(securityStateReference); return SNMPv3_MP_MATCH_ERROR; } usm->delete_sec_state_reference(securityStateReference); cache.delete_content(centry); debugprintf(1, "mp finished (OK)"); return SNMPv3_MP_OK; } if (pdu->command == GET_RSP_MSG) { if (((securityEngineID != centry.sec_engine_id) && (centry.sec_engine_id.len() != 0)) || (msgSecurityModel != centry.sec_model) || (securityName != centry.sec_name) || (securityLevel != centry.sec_level) || ((contextEngineID != centry.context_engine_id) && (centry.context_engine_id.len() != 0))|| ((contextName != centry.context_name) && (centry.context_name.len() != 0))) { debugprintf(0, "Received response message doesn't match sent message!"); usm->delete_sec_state_reference(securityStateReference); cache.delete_content(centry); return SNMPv3_MP_MATCH_ERROR; } usm->delete_sec_state_reference(securityStateReference); cache.delete_content(centry); debugprintf(1, "mp finished (OK)"); return SNMPv3_MP_OK; } if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) || (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) || (pdu->command == INFORM_REQ_MSG)) { if (securityEngineID.len() == 0) { debugprintf(2, "Received Message with engineID = 0."); } else { if (!(unsignedCharCompare(securityEngineID.data(), securityEngineID.len(), own_engine_id, own_engine_id_len))) { debugprintf(0, "snmp_parse: securityEngineID doesn't match own_engine_id."); /* we are authoritative but engine id of message is wrong if discovery in USM is enabled: - remove automatically added illegal engine id from USM tables - send a report */ if (usm->is_discovery_enabled()) { // TODO: try to remove engine id from USM if (reportableFlag) { cache.add_entry(msgID, pdu->reqid, securityEngineID, msgSecurityModel, securityName, securityLevel, "", "", securityStateReference, SNMPv3_MP_INVALID_ENGINEID, CACHE_REMOTE_REQ); send_report(0, MAX_SNMP_PACKET, pdu, SNMPv3_MP_INVALID_ENGINEID, SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV, msgSecurityModel, securityName, from_address, snmp_session); clear_pdu(pdu, true); // Clear pdu and free all content AND IDs! } else { usm->delete_sec_state_reference(securityStateReference); } return SNMPv3_MP_INVALID_ENGINEID; } usm->delete_sec_state_reference(securityStateReference); return SNMPv3_MP_MATCH_ERROR; } } int ret = cache.add_entry(msgID, pdu->reqid, securityEngineID, msgSecurityModel, securityName, securityLevel, contextEngineID, contextName, securityStateReference, SNMPv3_MP_OK, CACHE_REMOTE_REQ); if (ret == SNMPv3_MP_DOUBLED_MESSAGE) { debugprintf(0, "*** received doubled message ***"); // message will be ignored so return OK usm->delete_sec_state_reference(securityStateReference); } debugprintf(1, "mp: parsing finished (ok)."); return SNMPv3_MP_OK; } if ((pdu->command == TRP_REQ_MSG) || (pdu->command == TRP2_REQ_MSG)) { usm->delete_sec_state_reference(securityStateReference); return SNMPv3_MP_OK; } debugprintf(0, "mp error: This line should not be executed."); usm->delete_sec_state_reference(securityStateReference); return SNMPv3_MP_ERROR; }
// Do the complete process of encoding the given values into the buffer // ready to send to the target. int v3MP::snmp_build(struct snmp_pdu *pdu, unsigned char *packet, int *out_length, // maximum Bytes in packet const OctetStr &securityEngineID, const OctetStr &securityName, int securityModel, int securityLevel, const OctetStr &contextEngineID, const OctetStr &contextName) { Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET); unsigned char *scopedPDUPtr = scopedPDU.get_ptr(); unsigned char globalData[MAXLENGTH_GLOBALDATA]; int globalDataLength = MAXLENGTH_GLOBALDATA; int scopedPDULength, maxLen = *out_length; Buffer<unsigned char> buf(MAX_SNMP_PACKET); unsigned char *bufPtr = buf.get_ptr(); long bufLength = 0, rc; int msgID; int cachedErrorCode = SNMPv3_MP_OK; struct SecurityStateReference *securityStateReference = NULL; int isRequestMessage = 0; if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) || (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) || (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG) || (pdu->command == TRP2_REQ_MSG)) isRequestMessage = 1; if (isRequestMessage) { if (securityEngineID.len() == 0) { // First Contact => use user noAuthNoPriv and USM securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV; securityModel = SNMP_SECURITY_MODEL_USM; } cur_msg_id_lock.lock(); msgID = cur_msg_id; cur_msg_id++; if (cur_msg_id >= MAX_MPMSGID) cur_msg_id = 1; cur_msg_id_lock.unlock(); #ifdef INVALID_MSGID LOG_BEGIN(loggerModuleName, 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(loggerModuleName, 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(loggerModuleName, 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(loggerModuleName, 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(loggerModuleName, 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(loggerModuleName, 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(loggerModuleName, 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(loggerModuleName, INFO_LOG | 3); LOG("v3MP: Message built OK"); LOG_END; return SNMPv3_MP_OK; } else { LOG_BEGIN(loggerModuleName, WARNING_LOG | 1); LOG("v3MP: Returning error for building message"); LOG(rc); LOG_END; return rc; } } default: { LOG_BEGIN(loggerModuleName, WARNING_LOG | 1); LOG("v3MP: Should build message with unsupported securityModel"); LOG(securityModel); LOG_END; return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL; } } }