void gseDecodePDU(unsigned char *buf) { unsigned char tag = 0; CTYPE_INT16U lengthFieldSize = 0; CTYPE_INT16U lengthValue = 0; CTYPE_INT16U offsetForSequence = 0; CTYPE_INT16U offsetForNonSequence = 0; unsigned char *gocbRef = NULL; CTYPE_INT16U gocbRefLength = 0; CTYPE_INT32U timeAllowedToLive = 0; CTYPE_TIMESTAMP T = 0; CTYPE_INT32U sqNum = 0; CTYPE_INT32U stNum = 0; while (1) { tag = (unsigned char) buf[0]; // assumes only one byte is used lengthFieldSize = getLengthFieldSize((unsigned char) buf[1]); lengthValue = decodeLength((unsigned char *) &buf[1]); offsetForSequence = 1 + lengthFieldSize; offsetForNonSequence = 1 + lengthFieldSize + lengthValue; switch (tag) { case GSE_TAG_GOCBREF: // save pointer to gocbRef name gocbRef = &buf[offsetForSequence]; gocbRefLength = lengthValue; buf = &buf[offsetForNonSequence]; break; case GSE_TAG_TIME_ALLOWED_TO_LIVE: ber_decode_integer(&buf[offsetForSequence], lengthValue, &timeAllowedToLive, SV_GET_LENGTH_INT32U); buf = &buf[offsetForNonSequence]; break; case ASN1_TAG_SEQUENCE: buf = &buf[offsetForSequence]; break; case GSE_TAG_DATSET: buf = &buf[offsetForNonSequence]; break; case GSE_TAG_T: memcpy(&T, &buf[offsetForSequence], BER_GET_LENGTH_CTYPE_TIMESTAMP(&T)); buf = &buf[offsetForNonSequence]; break; case GSE_TAG_STNUM: ber_decode_integer(&buf[offsetForSequence], lengthValue, &stNum, SV_GET_LENGTH_INT32U); buf = &buf[offsetForNonSequence]; break; case GSE_TAG_SQNUM: ber_decode_integer(&buf[offsetForSequence], lengthValue, &sqNum, SV_GET_LENGTH_INT32U); buf = &buf[offsetForNonSequence]; break; case GSE_TAG_ALLDATA: gseDecodeDataset(&buf[offsetForSequence], lengthValue, gocbRef, gocbRefLength, timeAllowedToLive, T, stNum, sqNum); return; default: buf = &buf[offsetForNonSequence]; break; } } }
int BER_DECODE_CTYPE_ENUM(unsigned char *buf, CTYPE_ENUM *value) { // assuming enum is an int - allows any enum type to be used CTYPE_INT16U offset = 0; CTYPE_INT16U len = 0; if (buf[offset++] == ASN1_TAG_UNSIGNED) { len += decodeLength(&buf[offset]); offset += getLengthFieldSize(buf[offset]); #if GOOSE_FIXED_SIZE == 1 ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT8); #else ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT32U); #endif } return offset + len; }
int BER_DECODE_CTYPE_INT32U(unsigned char *buf, CTYPE_INT32U *value) { CTYPE_INT16U offset = 0; CTYPE_INT16U len = 0; if (buf[offset++] == ASN1_TAG_UNSIGNED) { len += decodeLength(&buf[offset]); offset += getLengthFieldSize(buf[offset]); ber_decode_integer(&buf[offset], len, value, SV_GET_LENGTH_INT32U); } return offset + len; }
static s8t decode_USM_parameters(u8t* const input, const u16t input_len, u16t* pos, message_v3_t* request) { u8t type; u16t length; /* encoded as a string value */ TRY(ber_decode_type_length(input, input_len, pos, &type, &length)); if (type != BER_TYPE_OCTET_STRING) { snmp_log("bad type, expected string: type %02X length %d\n", type, length); return FAILURE; } /* sequence */ TRY(ber_decode_sequence_length(input, input_len, pos, &length)); /* msgAuthoritativeEngineID */ TRY(ber_decode_string((u8t*)input, input_len, pos, &request->msgAuthoritativeEngineID.ptr, &request->msgAuthoritativeEngineID.len)); /* msgAuthoritativeEngineBoots */ TRY(ber_decode_integer(input, input_len, pos, (s32t*)&request->msgAuthoritativeEngineBoots)); /* msgAuthoritativeEngineTime */ TRY(ber_decode_integer(input, input_len, pos, (s32t*)&request->msgAuthoritativeEngineTime)); /* msgUserName */ TRY(ber_decode_string((u8t*)input, input_len, pos, &request->msgUserName.ptr, &request->msgUserName.len)); /* msgAuthenticationParameters */ TRY(ber_decode_string((u8t*)input, input_len, pos, &request->msgAuthenticationParameters.ptr, &request->msgAuthenticationParameters.len)); /* msgPrivacyParameters */ TRY(ber_decode_string((u8t*)input, input_len, pos, &request->msgPrivacyParameters.ptr, &request->msgPrivacyParameters.len)); if (request->msgFlags & FLAG_PRIV) { TRY(ber_decode_type_length((u8t*)input, input_len, pos, &type, &length)); if (type != BER_TYPE_OCTET_STRING || length != input_len - *pos) { return FAILURE; } } return 0; }
s8t prepareDataElements_v3(u8t* const input, const u16t input_len, u16t* pos, message_v3_t* request) { u8t type; u16t length; s32t int_value; /* msgGlobalData sequence */ TRY(ber_decode_sequence_length(input, input_len, pos, &length)); /* msgId */ TRY(ber_decode_integer(input, input_len, pos, &int_value)); request->msgId = int_value; snmp_log("msgId: %d\n", request->msgId); /* msgMaxSize */ TRY(ber_decode_integer(input, input_len, pos, &int_value)); snmp_log("msgMaxSize: %d\n", int_value); /* msgFlags */ TRY(ber_decode_type_length(input, input_len, pos, &type, &length)); if (type != BER_TYPE_OCTET_STRING || length != 1) { return FAILURE; } request->msgFlags = input[*pos]; *pos = *pos + 1; snmp_log("msgFlags: %d\n", request->msgFlags); if (!(request->msgFlags & FLAG_AUTH) && (request->msgFlags & FLAG_PRIV)) { /* If the authFlag is not set and privFlag is set, then the message is discarded without further processing */ return FAILURE; } /* msgSecurityModel */ TRY(ber_decode_integer(input, input_len, pos, &int_value)); snmp_log("msgSecurityModel: %d\n", int_value); /* treat Security Model */ s8t ret; switch (int_value) { case USM_SECURITY_MODEL: /* Authentication & Privacy validations */ ret = processIncomingMsg_USM(input, input_len, pos, request); if (ret == FAILURE) { return FAILURE; } else if (ret == ERR_USM) { /* stop processing this message, a report will be sent */ return 0; } break; default: snmp_log("unsupported security model [%d]\n", request->msgSecurityModel); return FAILURE; } /* ScopedPduData sequence */ TRY(ber_decode_sequence_length(input, input_len, pos, &length)); /* contextEngineID */ TRY(ber_decode_string((u8t*)input, input_len, pos, &request->contextEngineID.ptr, &request->contextEngineID.len)); /* contextName */ TRY(ber_decode_string((u8t*)input, input_len, pos, &request->contextName.ptr, &request->contextName.len)); /* decode PDU */ ber_decode_pdu(input, input_len, pos, &request->pdu); return 0; }
/* * Handle an SNMP request */ s8t dispatch(u8t* const input, const u16t input_len, u8t* output, u16t* output_len, const u16t max_output_len) { snmpInPkts++; snmp_log("---------------------------------\n"); /* too big incoming message */ if (input_len > MAX_BUF_SIZE) { snmp_log("discard the message, its size [%d] is too big\n", input_len); return FAILURE; } u16t pos = 0; s32t tmp; /* decode sequence & version */ if ((ber_decode_sequence(input, input_len, &pos)) != ERR_NO_ERROR || ber_decode_integer(input, input_len, &pos, &tmp) != ERR_NO_ERROR) { snmpInASNParseErrs++; return FAILURE; } /* create the right message_t data structure */ message_t* msg_ptr; switch (tmp) { #if ENABLE_SNMPv1 case SNMP_VERSION_1: msg_ptr = malloc(sizeof(message_t)); memset(msg_ptr, 0, sizeof(message_t)); break; #endif #if ENABLE_SNMPv3 case SNMP_VERSION_3: msg_ptr = malloc(sizeof(message_v3_t)); memset(msg_ptr, 0, sizeof(message_v3_t)); break; #endif default: /* If the version is not supported, it discards the datagram and performs no further actions. */ snmpInBadVersions++; snmp_log("unsupported SNMP version %d\n", tmp); return ERR_UNSUPPORTED_VERSION; } msg_ptr->version = (u8t)tmp; snmp_log("snmp version: %d\n", msg_ptr->version); /* dispatch processing to the version-specific Message Processing Model */ switch (msg_ptr->version) { #if ENABLE_SNMPv1 case SNMP_VERSION_1: tmp = prepareDataElements_v1(input, input_len, &pos, (message_t*)msg_ptr); break; #endif #if ENABLE_SNMPv3 case SNMP_VERSION_3: tmp = prepareDataElements_v3(input, input_len, &pos, (message_v3_t*)msg_ptr); break; #endif } if (tmp != ERR_NO_ERROR) { snmpInASNParseErrs++; free_message(msg_ptr); return FAILURE; } /* delegate request processing to the Command Responder */ handle(msg_ptr); /* dispatch preparing the response to the version-specific Message Processing Model */ switch (msg_ptr->version) { #if ENABLE_SNMPv1 case SNMP_VERSION_1: tmp = prepareResponseMessage_v1((message_t*)msg_ptr, output, output_len, input, input_len, max_output_len); break; #endif #if ENABLE_SNMPv3 case SNMP_VERSION_3: tmp = prepareResponseMessage_v3((message_v3_t*)msg_ptr, output, output_len, input, input_len, max_output_len); break; #endif } free_message(msg_ptr); if (tmp != ERR_NO_ERROR) { return FAILURE; } return 0; }