int snmp_preview(u_char *data, unsigned length, struct SnmpObjects *vbinds) { int i = 0; /* number of varbinds parsed */ unsigned tmp; struct SnmpObject *obj; vbinds->num=0; /* number of varbinds present in vbinds */ while (length) { /* parse the name, value pair */ obj = &(vbinds->objs[i]); obj->namelen = MAX_NAME_LEN; data = snmp_parse_var_op(data, obj->name, &obj->namelen, &obj->valuetype, &obj->valuelen, &obj->value, &length); if (data == NULL) return -1; /* obj->value points to ASN encoded value * - skip past "type" and "len" fields, so that "value" * points to received value. */ tmp = data - obj->value; obj->value = asn_parse_header(obj->value, &tmp, &obj->valuetype); if (obj->value == NULL) return -1; i++; /* test which verifies that SET command contains valid VB ammount */ if((i >= SNMP_MAX_OIDS) && (length > 0)) return -1 ; } vbinds->num=i; /* number of varbinds present in vbinds */ return 0; }
//* //*--------------------------------------------------------------------------------- //* Function Name: snmp_parse_auth //* Description : Get the community name and version number by parsing snmp //* message. The message is decoded in BER deconding rules. //* Return Value : Community Name and its length, version number and new pointer to //* next snmp fields //* Calling To : asn_parse_header, asn_parse_int, asn_parse_string //* Called By : snmp_parse //*--------------------------------------------------------------------------------- //* uint8 *snmp_parse_auth( uint8 *data, int *length, uint8 *community, int *community_len, long *version ) { uint8 type; data = asn_parse_header(data, length, &type); if (data == NULL) { return (NULL); //------SNMP: Parse authority failure. } if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) return (NULL); //------SNMP: Wrong auth header type. data = asn_parse_int(data, length, &type, version, sizeof(*version)); if (data == NULL) return (NULL); //------SNMP: Bad parse of version. data = asn_parse_string(data, length, &type, community, community_len); if (data == NULL) return (NULL); //------SNMP: Bad parse of community. community[*community_len] = '\0'; return (data); }
//* //* create a packet identical to the input packet, except for the error status //* and the error index which are set according to the input variables. //* Returns 1 upon success and 0 upon failure. //* int create_identical( snmp_session *session, uint8 *snmp_in, uint8 *snmp_out, int snmp_length, long errstat, long errindex ) { uint8 *data; uint8 type; uint32 dummy; uint8 *headerPtr, *reqidPtr, *errstatPtr, *errindexPtr, *varListPtr; int headerLength, length; bcopy((char *)snmp_in, (char *)snmp_out, snmp_length); length = snmp_length; headerPtr = snmp_parse_auth(snmp_out, &length, community, &session->community_len, (long *)&dummy); community[session->community_len] = 0; if (headerPtr == NULL) return 0; reqidPtr = asn_parse_header(headerPtr, &length, (uint8 *)&dummy); if (reqidPtr == NULL) return 0; headerLength = length; errstatPtr = asn_parse_int(reqidPtr, &length, &type, (long *)&dummy, sizeof dummy); // request id if (errstatPtr == NULL) return 0; errindexPtr = asn_parse_int(errstatPtr, &length, &type, (long *)&dummy, sizeof dummy); // error status if (errindexPtr == NULL) return 0; varListPtr = asn_parse_int(errindexPtr, &length, &type, (long *)&dummy, sizeof dummy); // error index if (varListPtr == NULL) return 0; #if 0 data = asn_build_header(headerPtr, &headerLength, GET_RSP_MSG, headerLength); if (data != reqidPtr) return 0; #else /*bug fixed */ *headerPtr = GET_RSP_MSG; #endif length = snmp_length; type = (uint8)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER); data = asn_build_int(errstatPtr, &length, type, &errstat, sizeof errstat); if (data != errindexPtr) return 0; data = asn_build_int(errindexPtr, &length, type, &errindex, sizeof errindex); if (data != varListPtr) return 0; packet_end = snmp_out + snmp_length; return 1; }
u_char * snmp_msg_Decode(u_char * Packet, int *PacketLenP, u_char * Community, int *CommLenP, int *Version, struct snmp_pdu * PDU) { u_char *bufp; u_char type; bufp = asn_parse_header(Packet, PacketLenP, &type); if (bufp == NULL) { snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Header)!\n"); ASN_PARSE_ERROR(NULL); } if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) { snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Header)!\n"); ASN_PARSE_ERROR(NULL); } bufp = asn_parse_int(bufp, PacketLenP, &type, (int *) Version, sizeof(*Version)); if (bufp == NULL) { snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Version)!\n"); ASN_PARSE_ERROR(NULL); } bufp = asn_parse_string(bufp, PacketLenP, &type, Community, CommLenP); if (bufp == NULL) { snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Message Header (Community)!\n"); ASN_PARSE_ERROR(NULL); } Community[*CommLenP] = '\0'; if ((*Version != SNMP_VERSION_1) && (*Version != SNMP_VERSION_2)) { /* Don't know how to handle this one. */ snmplib_debug(4, "snmp_msg_Decode:Unable to parse Version %u\n", *Version); snmplib_debug(4, "snmp_msg_Decode:Continuing anyway\n"); } /* Now that we know the header, decode the PDU */ /* XXXXX -- More than one PDU? */ bufp = snmp_pdu_decode(bufp, PacketLenP, PDU); if (bufp == NULL) /* snmp_pdu_decode registered failure */ return (NULL); bufp = snmp_var_DecodeVarBind(bufp, PacketLenP, &(PDU->variables), *Version); if (bufp == NULL) /* snmp_var_DecodeVarBind registered failure */ return (NULL); return (u_char *) bufp; }
// 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(loggerModuleName, WARNING_LOG | 1); LOG("Testing for v3 message: Bad header"); LOG_END; return false; } if (type != ASN_SEQ_CON) { LOG_BEGIN(loggerModuleName, 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(loggerModuleName, WARNING_LOG | 1); LOG("Testing for v3 message: Bad parse of version"); LOG_END; return 0; } return (version == SNMP_VERSION_3); }
u_char * snmp_parse_var_op(u_char *data, oid *var_name, size_t *var_name_len, u_char *var_val_type, size_t *var_val_len, u_char **var_val, size_t *listlength) { u_char var_op_type; size_t var_op_len = *listlength; u_char *var_op_start = data; data = asn_parse_sequence(data, &var_op_len, &var_op_type, (ASN_SEQUENCE | ASN_CONSTRUCTOR), "var_op"); if (data == NULL) { /* msg detail is set */ return NULL; } data = asn_parse_objid(data, &var_op_len, &var_op_type, var_name, var_name_len); if (data == NULL) { ERROR_MSG("No OID for variable"); return NULL; } if (var_op_type != (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | 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) { ERROR_MSG("No header for value"); return NULL; } /* XXX no check for type! */ *var_val_len = var_op_len; data += var_op_len; *listlength -= (int)(data - var_op_start); return data; }
/* Parse SMUX message. */ int smux_parse (char *ptr, size_t len) { /* This buffer we'll use for SOUT message. We could allocate it with malloc and save only static pointer/lenght, but IMHO static buffer is a faster solusion. */ static u_char sout_save_buff[SMUXMAXPKTSIZE]; static int sout_save_len = 0; int len_income = len; /* see note below: YYY */ u_char type; u_char rollback; rollback = ptr[2]; /* important only for SMUX_SOUT */ process_rest: /* see note below: YYY */ /* Parse SMUX message type and subsequent length. */ ptr = asn_parse_header (ptr, &len, &type); if (debug_smux) zlog_debug ("SMUX message received type: %d rest len: %ld", type, len); switch (type) { case SMUX_OPEN: /* Open must be not send from SNMP agent. */ zlog_warn ("SMUX_OPEN received: resetting connection."); return -1; break; case SMUX_RREQ: /* SMUX_RREQ message is invalid for us. */ zlog_warn ("SMUX_RREQ received: resetting connection."); return -1; break; case SMUX_SOUT: /* SMUX_SOUT message is now valied for us. */ if (debug_smux) zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit"); if (sout_save_len > 0) { smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT); sout_save_len = 0; } else zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len); if (len_income > 3) { /* YYY: this strange code has to solve the "slow peer" problem: When agent sends SMUX_SOUT message it doesn't wait any responce and may send some next message to subagent. Then the peer in 'smux_read()' will recieve from socket the 'concatenated' buffer, contaning both SMUX_SOUT message and the next one (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if the buffer is longer than 3 ( length of SMUX_SOUT ), we must process the rest of it. This effect may be observed if 'debug_smux' is set to '1' */ ptr++; len = len_income - 3; goto process_rest; } break; case SMUX_GETRSP: /* SMUX_GETRSP message is invalid for us. */ zlog_warn ("SMUX_GETRSP received: resetting connection."); return -1; break; case SMUX_CLOSE: /* Close SMUX connection. */ if (debug_smux) zlog_debug ("SMUX_CLOSE"); smux_parse_close (ptr, len); return -1; break; case SMUX_RRSP: /* This is response for register message. */ if (debug_smux) zlog_debug ("SMUX_RRSP"); smux_parse_rrsp (ptr, len); break; case SMUX_GET: /* Exact request for object id. */ if (debug_smux) zlog_debug ("SMUX_GET"); smux_parse_get (ptr, len, 1); break; case SMUX_GETNEXT: /* Next request for object id. */ if (debug_smux) zlog_debug ("SMUX_GETNEXT"); smux_parse_get (ptr, len, 0); break; case SMUX_SET: /* SMUX_SET is supported with some limitations. */ if (debug_smux) zlog_debug ("SMUX_SET"); /* save the data for future SMUX_SOUT */ memcpy (sout_save_buff, ptr, len); sout_save_len = len; smux_parse_set (ptr, len, RESERVE1); break; default: zlog_info ("Unknown type: %d", type); break; } return 0; }
char * smux_var (char *ptr, size_t len, oid objid[], size_t *objid_len, size_t *var_val_len, u_char *var_val_type, void **var_value) { u_char type; u_char val_type; size_t val_len; u_char *val; if (debug_smux) zlog_debug ("SMUX var parse: len %ld", len); /* Parse header. */ ptr = asn_parse_header (ptr, &len, &type); if (debug_smux) { zlog_debug ("SMUX var parse: type %d len %ld", type, len); zlog_debug ("SMUX var parse: type must be %d", (ASN_SEQUENCE | ASN_CONSTRUCTOR)); } /* Parse var option. */ *objid_len = MAX_OID_LEN; ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type, &val_len, &val, &len); if (var_val_len) *var_val_len = val_len; if (var_value) *var_value = (void*) val; if (var_val_type) *var_val_type = val_type; /* Requested object id length is objid_len. */ if (debug_smux) smux_oid_dump ("Request OID", objid, *objid_len); if (debug_smux) zlog_debug ("SMUX val_type: %d", val_type); /* Check request value type. */ if (debug_smux) switch (val_type) { case ASN_NULL: /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to ASN_NULL. */ zlog_debug ("ASN_NULL"); break; case ASN_INTEGER: zlog_debug ("ASN_INTEGER"); break; case ASN_COUNTER: case ASN_GAUGE: case ASN_TIMETICKS: case ASN_UINTEGER: zlog_debug ("ASN_COUNTER"); break; case ASN_COUNTER64: zlog_debug ("ASN_COUNTER64"); break; case ASN_IPADDRESS: zlog_debug ("ASN_IPADDRESS"); break; case ASN_OCTET_STR: zlog_debug ("ASN_OCTET_STR"); break; case ASN_OPAQUE: case ASN_NSAP: case ASN_OBJECT_ID: zlog_debug ("ASN_OPAQUE"); break; case SNMP_NOSUCHOBJECT: zlog_debug ("SNMP_NOSUCHOBJECT"); break; case SNMP_NOSUCHINSTANCE: zlog_debug ("SNMP_NOSUCHINSTANCE"); break; case SNMP_ENDOFMIBVIEW: zlog_debug ("SNMP_ENDOFMIBVIEW"); break; case ASN_BIT_STR: zlog_debug ("ASN_BIT_STR"); break; default: zlog_debug ("Unknown type"); break; } return ptr; }
// 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; }
/* Parse all Vars from the buffer */ u_char *snmp_var_DecodeVarBind(u_char *Buffer, int *BufLen, struct variable_list **VarP, int Version) { struct variable_list *Var, **VarLastP; u_char *bufp, *tmp; u_char VarBindType; u_char *DataPtr; int DataLen; oid TmpBuf[MAX_NAME_LEN]; int AllVarLen = *BufLen; int ThisVarLen = 0; VarLastP = VarP; #ifdef DEBUG_VARS_DECODE printf("VARS: Decoding buffer of length %d\n", *BufLen); #endif /* Now parse the variables */ bufp = asn_parse_header(Buffer, &AllVarLen, &VarBindType); if (bufp == NULL) ASN_PARSE_ERROR(NULL); if (VarBindType != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR)) { snmp_set_api_error(SNMPERR_PDU_PARSE); ASN_PARSE_ERROR(NULL); } #ifdef DEBUG_VARS_DECODE printf("VARS: All Variable length %d\n", AllVarLen); #endif /* We know how long the variable list is. Parse it. */ while ((int)AllVarLen > 0) { /* Create a new variable */ Var = snmp_var_new(NULL, MAX_NAME_LEN); if (Var == NULL) return(NULL); /* Parse the header to find out the length of this variable. */ ThisVarLen = AllVarLen; tmp = asn_parse_header(bufp, &ThisVarLen, &VarBindType); if (tmp == NULL) ASN_PARSE_ERROR(NULL); /* Now that we know the length , figure out how it relates to * the entire variable list */ AllVarLen = AllVarLen - (ThisVarLen + (tmp - bufp)); bufp = tmp; /* Is it valid? */ if (VarBindType != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR)) { snmp_set_api_error(SNMPERR_PDU_PARSE); ASN_PARSE_ERROR(NULL); } #ifdef DEBUG_VARS_DECODE printf("VARS: Header type 0x%x (%d bytes left)\n", VarBindType, ThisVarLen); #endif /* Parse the OBJID */ bufp = asn_parse_objid(bufp, &ThisVarLen, &VarBindType, Var->name, &(Var->name_length)); if (bufp == NULL) ASN_PARSE_ERROR(NULL); if (VarBindType != (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID)) { snmp_set_api_error(SNMPERR_PDU_PARSE); ASN_PARSE_ERROR(NULL); } #ifdef DEBUG_VARS_DECODE printf("VARS: Decoded OBJID (%d bytes). (%d bytes left)\n", Var->name_length, ThisVarLen); #endif /* Keep a pointer to this object */ DataPtr = bufp; DataLen = ThisVarLen; /* find out type of object */ bufp = asn_parse_header(bufp, &ThisVarLen, &(Var->type)); if (bufp == NULL) ASN_PARSE_ERROR(NULL); ThisVarLen = DataLen; #ifdef DEBUG_VARS_DECODE printf("VARS: Data type %d\n", Var->type); #endif /* Parse the type */ switch((short)Var->type){ case ASN_INTEGER: Var->val.integer = (int *)malloc(sizeof(int)); if (Var->val.integer == NULL) { snmp_set_api_error(SNMPERR_OS_ERR); return(NULL); } Var->val_len = sizeof(int); bufp = asn_parse_int(DataPtr, &ThisVarLen, &Var->type, (int *)Var->val.integer, Var->val_len); #ifdef DEBUG_VARS_DECODE printf("VARS: Decoded integer '%d' (%d bytes left)\n", *(Var->val.integer), ThisVarLen); #endif break; case SMI_COUNTER32: case SMI_GAUGE32: /* case SMI_UNSIGNED32: */ case SMI_TIMETICKS: Var->val.integer = (int *)malloc(sizeof(u_int)); if (Var->val.integer == NULL) { snmp_set_api_error(SNMPERR_OS_ERR); return(NULL); } Var->val_len = sizeof(u_int); bufp = asn_parse_unsigned_int(DataPtr, &ThisVarLen, &Var->type, (u_int *)Var->val.integer, Var->val_len); #ifdef DEBUG_VARS_DECODE printf("VARS: Decoded timeticks '%d' (%d bytes left)\n", *(Var->val.integer), ThisVarLen); #endif break; case ASN_OCTET_STR: case SMI_IPADDRESS: case SMI_OPAQUE: Var->val_len = *&ThisVarLen; /* String is this at most */ Var->val.string = (u_char *)malloc((unsigned)Var->val_len); if (Var->val.string == NULL) { snmp_set_api_error(SNMPERR_OS_ERR); return(NULL); } bufp = asn_parse_string(DataPtr, &ThisVarLen, &Var->type, Var->val.string, &Var->val_len); #ifdef DEBUG_VARS_DECODE printf("VARS: Decoded string '%s' (length %d) (%d bytes left)\n", (Var->val.string), Var->val_len, ThisVarLen); #endif break; case ASN_OBJECT_ID: Var->val_len = MAX_NAME_LEN; bufp = asn_parse_objid(DataPtr, &ThisVarLen, &Var->type, TmpBuf, &Var->val_len); Var->val_len *= sizeof(oid); Var->val.objid = (oid *)malloc((unsigned)Var->val_len); if (Var->val.integer == NULL) { snmp_set_api_error(SNMPERR_OS_ERR); return(NULL); } /* Only copy if we successfully decoded something */ if (bufp) { memcpy((char *)Var->val.objid, (char *)TmpBuf, Var->val_len); } #ifdef DEBUG_VARS_DECODE printf("VARS: Decoded OBJID (length %d) (%d bytes left)\n", Var->val_len, ThisVarLen); #endif break; case ASN_NULL: case SMI_NOSUCHINSTANCE: case SMI_NOSUCHOBJECT: case SMI_ENDOFMIBVIEW: Var->val_len = 0; Var->val.objid = NULL; bufp = asn_parse_null(DataPtr, &ThisVarLen, &Var->type); #ifdef DEBUG_VARS_DECODE printf("VARS: Decoded ASN_NULL (length %d) (%d bytes left)\n", Var->val_len, ThisVarLen); #endif break; case SMI_COUNTER64: #ifdef STDERR_OUTPUT fprintf(stderr, WIDE("Unable to parse type SMI_COUNTER64!\n")); #endif snmp_set_api_error(SNMPERR_UNSUPPORTED_TYPE); return(NULL); break; default: #ifdef STDERR_OUTPUT fprintf(stderr, WIDE("bad type returned (%x)\n"), Var->type); #endif snmp_set_api_error(SNMPERR_PDU_PARSE); return(NULL); break; } /* End of var type switch */ /* Why is this here? XXXXX */ if (bufp == NULL) return(NULL); #ifdef DEBUG_VARS_DECODE printf("VARS: Adding to list of decoded variables. (%d bytes remain.)\n", AllVarLen); #endif /* Add variable to the list */ *VarLastP = Var; VarLastP = &(Var->next_variable); } return(bufp); }
//* //* Parse_var_op_list goes through the list of variables and retrieves each one, //* placing it's value in the output packet. In the case of a set request, //* if action is RESERVE, the value is just checked for correct type and //* value, and resources may need to be reserved. If the action is COMMIT, //* the variable is set. If the action is FREE, an error was discovered //* somewhere in the previous RESERVE pass, so any reserved resources //* should be FREE'd. //* If any error occurs, an error code is returned. //* int parse_var_op_list( snmp_session *session, uint8 *data, //point to variable-binding of in-packet data int length, //in packet data length uint8 *out_data, //point to variable-binding of out-packet data int out_length, //out packet buffer length long *index, //error-index (output) int msgtype, //message type int action //??? ) { uint8 type; oid var_name[SNMP_MAX_NAME_LEN]; int var_name_len, var_val_len; uint8 var_val_type, *var_val, statType; uint8 *statP; int statLen; uint16 acl; int (*write_method)(); uint8 *headerP, *var_list_start; int dummyLen; #ifdef WEBADMIN int dummyLen1; // add -- By arius 5/17/2000 uint8 *newpacket_end; // add -- By arius 5/17/2000 #endif WEBADMIN int noSuchObject; int (*WriteMethod)(int,uint8 *,uint8,int,uint8 *,oid *,int); int err, exact; // if (msgtype== SET_REQ_MSG) rw = SNMP_WRITE; // else rw = SNMP_READ; if (msgtype == GETNEXT_REQ_MSG) exact = FALSE; else exact = TRUE; //Parse variable-binging header data = asn_parse_header(data, &length, &type); if (data == NULL){ ERROR("not enough space for varlist"); return PARSE_ERROR; } if (type != (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR)){ ERROR("wrong type"); return PARSE_ERROR; } headerP = out_data; //Set Resp variable-binging header out_data = asn_build_sequence(out_data, &out_length, (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0); if (out_data == NULL){ ERROR("not enough space in output packet"); return BUILD_ERROR; } var_list_start = out_data; *index = 1; while((int)length > 0){ // parse the name, value pair var_name_len = SNMP_MAX_NAME_LEN; data = snmp_parse_var_op(data, var_name, &var_name_len, &var_val_type, &var_val_len, &var_val, (int *)&length); if (data == NULL) return PARSE_ERROR; // now attempt to retrieve the variable on the local entity statP = getStatPtr(var_name, &var_name_len, &statType, &statLen, &acl, exact, &write_method, SNMP_VERSION_1, &noSuchObject, (msgtype==SET_REQ_MSG? (session->access & SNMP_ACCESS_WRITE): (session->access & SNMP_ACCESS_READ) ) ); if (/* session->version == SNMP_VERSION_1 &&*/ statP == NULL && (msgtype != SET_REQ_MSG || !write_method)) { //** XXX: happens when running // XXX: snmpwalk localhost public .1 // XXX: fix me some day. //** //** ERROR("warning: internal v1_error"); ** return SNMP_ERR_NOSUCHNAME; } // check if this variable is read-write (in the MIB sense). if( msgtype == SET_REQ_MSG && acl != RWRITE ) return SNMP_ERR_READONLY; // return session->version == SNMP_VERSION_1 ? SNMP_ERR_NOSUCHNAME : SNMP_ERR_NOTWRITABLE; //* Its bogus to check here on getnexts - the whole packet shouldn't // be dumped - this should should be the loop in getStatPtr // luckily no objects are set unreadable. This can still be // useful for sets to determine which are intrinsically writable if (msgtype== SET_REQ_MSG){ if (write_method == NULL){ if (statP != NULL){ // see if the type and value is consistent with this entity's variable if (!goodValue(var_val_type, var_val_len, statType,statLen)) { // if (session->version != SNMP_VERSION_1) // return SNMP_ERR_WRONGTYPE; // poor approximation // else { snmp_inbadvalues++; return SNMP_ERR_BADVALUE; } } // actually do the set if necessary if (action == COMMIT) setVariable(var_val, var_val_type, var_val_len,statP, statLen); } else { // if (session->version != SNMP_VERSION_1) // return SNMP_ERR_NOCREATION; // else return SNMP_ERR_NOSUCHNAME; } } else { WriteMethod = (int (*)(int,uint8 *,uint8,int,uint8 *,oid *,int)) write_method; err = (*WriteMethod)(action, var_val, var_val_type, var_val_len, statP, var_name, var_name_len); //* //* Map the SNMPv2 error codes to SNMPv1 error codes (RFC 2089). //* // if (session->version == SNMP_VERSION_1) { switch (err) { case SNMP_ERR_NOERROR: // keep the no-error error: break; case SNMP_ERR_WRONGVALUE: case SNMP_ERR_WRONGENCODING: case SNMP_ERR_WRONGTYPE: case SNMP_ERR_WRONGLENGTH: case SNMP_ERR_INCONSISTENTVALUE: err = SNMP_ERR_BADVALUE; break; case SNMP_ERR_NOACCESS: case SNMP_ERR_NOTWRITABLE: case SNMP_ERR_NOCREATION: case SNMP_ERR_INCONSISTENTNAME: case SNMP_ERR_AUTHORIZATIONERROR: err = SNMP_ERR_NOSUCHNAME; break; default: err = SNMP_ERR_GENERR; break; // } }//if(session->version == SNMP_VERSION_1) .... if (err != SNMP_ERR_NOERROR){ // if (session->version == SNMP_VERSION_1) { snmp_inbadvalues++; // } return err; } } } else { //* retrieve the value of the variable and place it into the //* outgoing packet if (statP == NULL){ statLen = 0; if (exact){ if (noSuchObject == TRUE){ statType = SNMP_NOSUCHOBJECT; } else { statType = SNMP_NOSUCHINSTANCE; } } else { statType = SNMP_ENDOFMIBVIEW; } } //if (statP == NULL) ... out_data = snmp_build_var_op(out_data, var_name, &var_name_len, statType, statLen, statP, &out_length); if (out_data == NULL){ return SNMP_ERR_TOOBIG; } } //if (msgtype== SET_REQ_MSG) ... (*index)++; } //while((int)length > 0) .... if(msgtype!= SET_REQ_MSG){ // save a pointer to the end of the packet packet_end = out_data; // Now rebuild header with the actual lengths dummyLen = packet_end - var_list_start; // modified by ---- Arius 5/17/2000 #ifdef WEBADMIN dummyLen1 = packet_end - headerP; newpacket_end = asn_build_sequence(headerP, &dummyLen1, (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR), dummyLen); var_list_start -= (packet_end - newpacket_end); out_length += (packet_end - newpacket_end); // save new pointer to the end of the packet when the sapces will be adjust packet_end = newpacket_end; if (headerP == NULL) #else if (asn_build_sequence(headerP, &dummyLen, (uint8)(ASN_SEQUENCE | ASN_CONSTRUCTOR), dummyLen) == NULL) #endif WEBADMIN // end of here { return SNMP_ERR_TOOBIG; // bogus error ???? } } *index = 0; return SNMP_ERR_NOERROR; }
int snmp_agent_parse( snmp_session *session, uint8 *indata, int inlength, uint8 *outdata, int *outlength ) { uint8 msgtype, type; long zero = 0; long reqid, errstat, errindex, dummyindex; uint8 *out_auth, *out_header, *out_reqid; uint8 *startData = indata; int startLength = inlength; long version; uint8 *origdata = indata; int origlen = inlength; // usecEntry *ue; int packet_len, ret = 0; #ifdef WEBADMIN int newoutdata; // add -- by arius 5/17/2000 int len; // add -- by arius 5/17/2000 #endif WEBADMIN session->community_len = COMMUNITY_MAX_LEN; //get community name indata = snmp_parse_auth(indata, &inlength, community, &session->community_len, &version); if (indata == NULL){ // increment_stat( SNMP_STAT_ENCODING_ERRORS ); ERROR("bad auth encoding"); return 0; } #if 1 //ONLY SUPPORT VERSION 1 if(version != SNMP_VERSION_1) { ERROR("wrong version"); snmp_inbadversions++; return 0; } #else //////////////////////////////////////////// if( version != SNMP_VERSION_1 && version != SNMP_VERSION_2C && version != SNMP_VERSION_2 ) { // increment_stat( SNMP_STAT_ENCODING_ERRORS ); ERROR("wrong version"); snmp_inbadversions++; return 0; } if( version == SNMP_VERSION_2C || version == SNMP_VERSION_2 ) { if( version == SNMP_VERSION_2 ) { ret = check_auth( session, origdata, origlen, indata - session->community_len, session->community_len, &ue ); *outlength = (SNMP_MAX_LEN < session->MMS) ? SNMP_MAX_LEN : session->MMS; session->MMS = SNMP_MAX_LEN; } else if( version == SNMP_VERSION_2C ) { ret = community_auth( session ); session->version = SNMP_VERSION_2C; } if( ret < 0 ) { // increment_stat( -ret ); if( (indata=asn_parse_header(indata, &inlength, &msgtype)) && asn_parse_int(indata, &inlength, &type, &reqid, sizeof(reqid)) ) { if( msgtype == REPORT_MSG ) return 0; if( !(session->qoS & USEC_QOS_GENREPORT) ) return 0; session->agentBoots = _agentBoots; session->agentClock = _agentStartTime; memcpy( session->agentID, _agentID, 12 ); session->MMS = SNMP_MAX_LEN; create_report( session, outdata, outlength, -ret, reqid ); return 1; } else { return 0; } } else if( ret > 0 ) { // increment_stat( ret ); return 0; } } else { #endif ///////////////////////////////////////////////////// //VERSION 1 if(community_auth( session )==0) return 0; // session->version = SNMP_VERSION_1; #if 0 //////// } #endif /////// indata = asn_parse_header(indata, &inlength, &msgtype); if (indata == NULL){ // increment_stat( SNMP_STAT_ENCODING_ERRORS ); ERROR("bad header"); return 0; } // XXX: increment by total number of vars at correct place: snmp_intotalreqvars++; if(msgtype == GET_REQ_MSG) snmp_ingetrequests++; else if (msgtype == GETNEXT_REQ_MSG) snmp_ingetnexts++; else if (msgtype == SET_REQ_MSG) snmp_insetrequests++; else return 0; // if (msgtype == GETBULK_REQ_MSG: //version 2 // Request ID indata = asn_parse_int(indata, &inlength, &type, &reqid, sizeof(reqid)); if (indata == NULL){ // increment_stat( SNMP_STAT_ENCODING_ERRORS ); ERROR("bad parse of reqid"); return 0; } //Error Status indata = asn_parse_int(indata, &inlength, &type, &errstat, sizeof(errstat)); if (indata == NULL){ // increment_stat( SNMP_STAT_ENCODING_ERRORS ); ERROR("bad parse of errstat"); snmp_inasnparseerrors++; return 0; } //Error Index indata = asn_parse_int(indata, &inlength, &type, &errindex, sizeof(errindex)); if (indata == NULL){ // increment_stat( SNMP_STAT_ENCODING_ERRORS ); ERROR("bad parse of errindex"); return 0; } // // Now start cobbling together what is known about the output packet. // The final lengths are not known now, so they will have to be recomputed // later. // // setup for response //Simon time( (time_t *) &session->agentTime ); //Simon session->agentClock = _agentStartTime; //Simon session->agentBoots = _agentBoots; //Simon memcpy( session->agentID, _agentID, 12 ); out_auth = outdata; //Set Resp Community out_header = snmp_build_auth(out_auth, outlength, community,session->community_len, (long)SNMP_VERSION_1,0); if (out_header == NULL){ ERROR("snmp_build_auth failed"); snmp_inasnparseerrors++; return 0; } out_reqid = asn_build_sequence(out_header, outlength, (uint8)GET_RSP_MSG, 0); if (out_reqid == NULL){ ERROR("out_reqid == NULL"); return 0; } //Set Resp ID type = (uint8)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER); // return identical request id outdata = asn_build_int(out_reqid, outlength, type, &reqid, sizeof(reqid)); if (outdata == NULL){ ERROR("build reqid failed"); return 0; } // assume that error status will be zero outdata = asn_build_int(outdata, outlength, type, &zero, sizeof(zero)); if (outdata == NULL){ ERROR("build errstat failed"); return 0; } // assume that error index will be zero outdata = asn_build_int(outdata, outlength, type, &zero, sizeof(zero)); if (outdata == NULL){ ERROR("build errindex failed"); return 0; } #if 0 /////////////////////////////////////////// if (msgtype == GETBULK_REQ_MSG) errstat = bulk_var_op_list(indata, inlength, outdata, *outlength, errstat, errindex, &errindex ); else #endif 0 //////////////////////////////////////// errstat = parse_var_op_list(session, indata, inlength, outdata, *outlength, &errindex, msgtype, RESERVE1); if (msgtype== SET_REQ_MSG){ if (errstat == SNMP_ERR_NOERROR) errstat = parse_var_op_list(session, indata, inlength, outdata, *outlength, &errindex, msgtype, RESERVE2); if (errstat == SNMP_ERR_NOERROR){ // //* SETS require 3-4 passes through the var_op_list. The first two //* passes verify that all types, lengths, and values are valid //* and may reserve resources and the third does the set and a //* fourth executes any actions. Then the identical GET RESPONSE //* packet is returned. //* If either of the first two passes returns an error, another //* pass is made so that any reserved resources can be freed. //* parse_var_op_list(session, indata, inlength, outdata, *outlength, &dummyindex, msgtype, COMMIT); parse_var_op_list(session, indata, inlength, outdata, *outlength, &dummyindex, msgtype, ACTION); if (create_identical(session, startData, out_auth, startLength, 0L, 0L )){ *outlength = packet_end - out_auth; return 1; } return 0; } else { parse_var_op_list(session, indata, inlength, outdata, *outlength, &dummyindex, msgtype, COMM_FREE); } } switch((short)errstat){ case SNMP_ERR_NOERROR: // re-encode the headers with the real lengths *outlength = packet_end - out_header; packet_len = *outlength; outdata = asn_build_sequence(out_header, outlength, GET_RSP_MSG, packet_end - out_reqid); // add --- By arius 5/17/2000 #ifdef WEBADMIN newoutdata = packet_end - outdata; // how many shifts len = packet_end - out_reqid; packet_end = outdata; // save new pointer end of packet outdata -= len; out_reqid = out_reqid - newoutdata; #endif WEBADMIN // end of here if (outdata != out_reqid){ ERROR("internal error: header"); return 0; } *outlength = packet_end - out_auth; outdata = snmp_build_auth(out_auth, outlength, community, session->community_len, (long)SNMP_VERSION_1, packet_end - out_header ); // add --- By arius 5/17/2000 #ifdef WEBADMIN out_header -= (packet_end - outdata); packet_end = outdata; // save new pointer end of packet #endif WEBADMIN // end of here *outlength = packet_end - out_auth; #if 0 // packet_end is correct for old SNMP. This dichotomy needs to be fixed. if (session->version == SNMP_VERSION_2) packet_end = out_auth + packet_len; #endif break; case SNMP_ERR_TOOBIG: snmp_intoobigs++; #if notdone if (session->version == SNMP_VERSION_2){ create_toobig(out_auth, *outlength, reqid, pi); break; } // else FALLTHRU #endif case SNMP_ERR_NOACCESS: case SNMP_ERR_WRONGTYPE: case SNMP_ERR_WRONGLENGTH: case SNMP_ERR_WRONGENCODING: case SNMP_ERR_WRONGVALUE: case SNMP_ERR_NOCREATION: case SNMP_ERR_INCONSISTENTVALUE: case SNMP_ERR_RESOURCEUNAVAILABLE: case SNMP_ERR_COMMITFAILED: case SNMP_ERR_UNDOFAILED: case SNMP_ERR_AUTHORIZATIONERROR: case SNMP_ERR_NOTWRITABLE: case SNMP_ERR_INCONSISTENTNAME: case SNMP_ERR_NOSUCHNAME: case SNMP_ERR_BADVALUE: case SNMP_ERR_READONLY: case SNMP_ERR_GENERR: if (create_identical(session, startData, out_auth, startLength, errstat, errindex)){ *outlength = packet_end - out_auth; return 1; } return 0; default: return 0; } #if 0 if( session->qoS & USEC_QOS_AUTH ) { md5Digest( out_auth, *outlength, outdata - (session->contextLen + 16), outdata - (session->contextLen + 16) ); } #endif return 1; }
char * snmp_parse_trap(u_char * trapdata, /* IN - actual trap data from packet */ unsigned datalen, /* IN - length of trapdata */ struct trap_info * trapInfo) /* IN/OUT - struct to fill in */ { u_char * more; /* pointer to next unparsed PDU data */ u_char * nextVar; /* pointer to next unparsed TRAP variable */ unsigned left; /* length of more */ long version; /* SNMP version, always v1 */ u_char type; /* data types for checking */ u_char * varValPtr; int vars_in_struct; struct trapVar * vars; /* trap variables data structures */ u_long trapType; unsigned length; /* scratch for passing to asn1 */ /* do some basic setup of the passed data structures */ vars_in_struct = trapInfo->trapVars; trapInfo->trapVars = 0; /* bump later if vars are present */ left = datalen; more = snmp_auth_parse(trapdata, &left, (u_char*)trapInfo->community, (unsigned*)&trapInfo->commLen, &version); if (!more) return "community parse"; more = asn_parse_header(more, &left, &type); if (!more || type != TRP_REQ_MSG) return "trap pdu header"; more = asn_parse_objid(more, &left, &type, &trapInfo->objId[0], (unsigned*)&trapInfo->objLen); if (!more || type != ASN_OBJECT_ID) return "sys ObjId"; length = 4; /* number of bytes in IP address buffer */ more = asn_parse_string(more, &left, &type, (u_char*)(&trapInfo->agent_ip), &length); if (!more || type != IPADDRESS) return "agent's IP address"; more = asn_parse_int(more, &left, &type, (long*)&trapType, sizeof(long)); if (!more || type != ASN_INTEGER || trapType > 6) return "trap type"; trapInfo->trapType = trapType; more = asn_parse_int(more, &left, &type, (long*)&trapType, sizeof(long)); if (!more || type != ASN_INTEGER) return "specific type"; trapInfo->trapSpecific = trapType; more = asn_parse_int(more, &left, &type, (long*)&trapInfo->time, sizeof(long)); if (!more || type != TIMETICKS) return "timestamp"; if (!left) /* no variables in trap ? */ return NULL; /* rest of packet is a sequence of variables */ more = asn_parse_header(more, &left, &type); /* strip off leading SEQ */ if (!more || type != SEQUENCE) return "trap vars header"; vars = trapInfo->vars; /* set pointer array to receive variables data */ while (left) /* keep parsing & counting vars as long as there's data */ { /* extract variable info for this var */ length = left; /* number of valid bytes left in packet buffer */ varNameLen = MAX_OID_LEN ; /* define the max size of varName */ nextVar = snmp_parse_var_op(more, varName, &varNameLen, &varType, &varLen, &varValPtr, &left); if (!nextVar) /* quit if parse failed */ return ("var_op header"); /* extract the variable's value; pointed to by varValPtr: */ length -= more - nextVar; /* deduct size of header -> max. length of var */ switch (varType) { case ASN_INTEGER: case GAUGE: case COUNTER: case TIMETICKS: varLen = sizeof(long); /* size required by asn_parse_int() */ nextVar = asn_parse_int(varValPtr, &length, &varType, (long *)(&varVal[0]), varLen); break; case ASN_OCTET_STR: case IPADDRESS: case OPAQUE: varLen = MAX_TRAP_VAR; nextVar = asn_parse_string(varValPtr, &length, &varType, varVal, &varLen); break; case ASN_OBJECT_ID: varLen = MAX_TRAP_VAR; nextVar = asn_parse_objid(varValPtr, &length, &varType, (oid *)(&varVal[0]), &varLen); break; case ASN_NULL: nextVar = asn_parse_null(varValPtr, &length, &varType); break; default: SNMPERROR("wrong type"); return NULL; } if (!nextVar) return("variable"); /* if another trap variable info slot is available, fill it in */ if (trapInfo->trapVars <= vars_in_struct) { oidcpy(vars->varName, varName, varNameLen); if (vars->varBufLen <= varLen) /* need to truncate? */ vars->varValLen = vars->varBufLen-1; else /* we have room for the full variable data field */ vars->varValLen = varLen; MEMCPY(vars->varBuf, varVal, vars->varValLen); vars->varNameLen = varNameLen; vars->varType = varType; vars++; /* point to next variable info structure */ } trapInfo->trapVars++; /* another var */ more = nextVar; /* bump pointer to pdu */ } return NULL; }
//* //*--------------------------------------------------------------------------------- //* Function Name: snmp_parse_var //* Description : Get variables by parsing snmp message. The message is decoded in //* BER deconding rules. //* Return Value : Pointer of decoding variables //* Calling To : asn_parse_header, asn_parse_objid, asn_parse_int, //* asn_parse_string //* Called By : snmp_parse //*--------------------------------------------------------------------------------- //* variable_list *snmp_parse_var(uint8 *data,int length) { uint8 type; variable_list vh, *vp; uint8 *varBindP; int varBind_len; uint8 objId[SNMP_MAX_NAME_LEN]; uint8 *varVal; int parse_ok; data = asn_parse_header(data, &length, &type); if ((data == NULL) || (type != (uint8) (ASN_SEQUENCE | ASN_CONSTRUCTOR))) return ( NULL ); vh.next = NULL; vp = &vh; varBindP = data; parse_ok = TRUE; while (length > 0) { varBind_len = length; vp->next = (variable_list *) malloc(sizeof(variable_list)); if (vp->next == NULL) { parse_ok = FALSE; break; //---SNMP: Memory allocation error on 'snmp_parse_var'. } else { vp = vp->next; vp->next = NULL; vp->name = NULL; vp->name_len = SNMP_MAX_NAME_LEN; vp->val.string = NULL; } varBindP = asn_parse_header(varBindP, &varBind_len, &type); if ((varBindP == NULL) || (type != (uint8) (ASN_SEQUENCE | ASN_CONSTRUCTOR))) { parse_ok = FALSE; break; } //* //* Parse variable bind name. //* varBindP = asn_parse_objid(varBindP, &varBind_len, &type, objId, &vp->name_len); if ((varBindP == NULL) || (type != (uint8) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID))) { parse_ok = FALSE; break; } vp->name = (oid *) malloc((unsigned) vp->name_len * sizeof(oid)); if (vp->name == NULL) { parse_ok = FALSE; break; //-----SNMP: Memory alloc error on 'snmp_parse_var'. } else { bcopy((char *) objId, (char *) vp->name, vp->name_len * sizeof(oid)); } //* //* Parse variable bind value. //* varVal = varBindP; varBindP = asn_parse_header(varBindP, &varBind_len, &vp->type); if (varBindP == NULL) { parse_ok = FALSE; break; } else { vp->val_len = varBind_len; varBindP = varBindP + varBind_len; // skip value body to next variable length = length - (int)(varBindP - data); data = varBindP; varBind_len = SNMP_MAX_LEN; } switch (vp->type) { case ASN_INTEGER: case COUNTER: case GAUGE: case TIMETICKS: vp->val_len = sizeof(long); // support long intger only vp->val.integer = (long *) malloc(vp->val_len); if (vp->val.integer == NULL) { parse_ok = FALSE; break; //---SNMP:Memory alloc error on 'snmp_parse_var'. } asn_parse_int(varVal, &varBind_len, &vp->type, (long *) vp->val.integer, vp->val_len); break; case ASN_OCTET_STRING: case IPADDRESS: case OPAQUE: vp->val.string = (uint8 *) malloc(vp->val_len); if (vp->val.string == NULL) { parse_ok = FALSE; break; //----SNMP:Memory alloc error on 'snmp_parse_var'. } asn_parse_string(varVal, &varBind_len, &vp->type, vp->val.string, &vp->val_len); break; case ASN_OBJECT_ID: vp->val_len = SNMP_MAX_NAME_LEN; asn_parse_objid(varVal, &varBind_len, &vp->type, objId, &vp->val_len); vp->val_len = vp->val_len * sizeof(oid); vp->val.objid = (oid *) malloc((unsigned) vp->val_len); if (vp->val.objid == NULL) { parse_ok = FALSE; break; //---SNMP:Memory alloc error on 'snmp_parse_var'. } bcopy((char *) objId, (char *) vp->val.objid, vp->val_len); break; case ASN_NULL: break; default: parse_ok = FALSE; //-----Warning: Bad type received. break; } if ( ! parse_ok ) break; } if ( parse_ok ) { return( vh.next ); } else { while ( vh.next ) { vp = vh.next; vh.next = vp->next; if (vp->name != NULL) free((char *) vp->name); if (vp->val.string != NULL) free((char *) vp->val.string); free((char *) vp); } return ( NULL ); } }
/* Decodes PDU from Packet into PDU. * * Returns a pointer to the next byte of the packet, which is where the * Variable Bindings start. */ u_char *snmp_pdu_decode(u_char *Packet, /* data */ int *Length, /* &length */ struct snmp_pdu *PDU) /* pdu */ { u_char *bufp; u_char PDUType; int four; u_char ASNType; oid objid[MAX_NAME_LEN]; bufp = asn_parse_header(Packet, Length, &PDUType); if (bufp == NULL) ASN_PARSE_ERROR(NULL); #ifdef DEBUG_PDU_DECODE printf("PDU Type: %d\n", PDUType); #endif PDU->command = PDUType; switch (PDUType) { case TRP_REQ_MSG: /* SNMPv1 Trap Message */ /* enterprise */ PDU->enterprise_length = MAX_NAME_LEN; bufp = asn_parse_objid(bufp, Length, &ASNType, objid, &PDU->enterprise_length); if (bufp == NULL) ASN_PARSE_ERROR(NULL); PDU->enterprise = (oid *)malloc(PDU->enterprise_length * sizeof(oid)); if (PDU->enterprise == NULL) { snmp_set_api_error(SNMPERR_OS_ERR); return(NULL); } memcpy((char *)PDU->enterprise, (char *)objid, PDU->enterprise_length * sizeof(oid)); /* Agent-addr */ four = 4; bufp = asn_parse_string(bufp, Length, &ASNType, (u_char *)&PDU->agent_addr.sin_addr.s_addr, &four); if (bufp == NULL) ASN_PARSE_ERROR(NULL); /* Generic trap */ bufp = asn_parse_int(bufp, Length, &ASNType, (int *)&PDU->trap_type, sizeof(PDU->trap_type)); if (bufp == NULL) ASN_PARSE_ERROR(NULL); /* Specific Trap */ bufp = asn_parse_int(bufp, Length, &ASNType, (int *)&PDU->specific_type, sizeof(PDU->specific_type)); if (bufp == NULL) ASN_PARSE_ERROR(NULL); /* Timestamp */ bufp = asn_parse_unsigned_int(bufp, Length, &ASNType, &PDU->time, sizeof(PDU->time)); if (bufp == NULL) ASN_PARSE_ERROR(NULL); break; /**********************************************************************/ case SNMP_PDU_GETBULK: /* SNMPv2 Bulk Request */ /* request id */ bufp = asn_parse_int(bufp, Length, &ASNType, &PDU->reqid, sizeof(PDU->reqid)); if (bufp == NULL) ASN_PARSE_ERROR(NULL); /* non-repeaters */ bufp = asn_parse_int(bufp, Length, &ASNType, &PDU->non_repeaters, sizeof(PDU->non_repeaters)); if (bufp == NULL) ASN_PARSE_ERROR(NULL); /* max-repetitions */ bufp = asn_parse_int(bufp, Length, &ASNType, &PDU->max_repetitions, sizeof(PDU->max_repetitions)); if (bufp == NULL) ASN_PARSE_ERROR(NULL); break; /**********************************************************************/ default: /* Normal PDU Encoding */ /* request id */ bufp = asn_parse_int(bufp, Length, &ASNType, &PDU->reqid, sizeof(PDU->reqid)); if (bufp == NULL) ASN_PARSE_ERROR(NULL); #ifdef DEBUG_PDU_DECODE printf("PDU Request ID: %d\n", PDU->reqid); #endif /* error status */ bufp = asn_parse_int(bufp, Length, &ASNType, &PDU->errstat, sizeof(PDU->errstat)); if (bufp == NULL) ASN_PARSE_ERROR(NULL); #ifdef DEBUG_PDU_DECODE printf("PDU Error Status: %d\n", PDU->errstat); #endif /* error index */ bufp = asn_parse_int(bufp, Length, &ASNType, &PDU->errindex, sizeof(PDU->errindex)); if (bufp == NULL) ASN_PARSE_ERROR(NULL); #ifdef DEBUG_PDU_DECODE printf("PDU Error Index: %d\n", PDU->errindex); #endif break; } return(bufp); }