mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1300 lines
32 KiB
1300 lines
32 KiB
/*++
|
|
|
|
Copyright (c) 1992-1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
berapi.c
|
|
|
|
Abstract:
|
|
|
|
ASN.1 BER Encode/Decode APIs
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
10-May-1996 DonRyan
|
|
Removed banner from Technology Dynamics, Inc.
|
|
|
|
--*/
|
|
|
|
//--------------------------- WINDOWS DEPENDENCIES --------------------------
|
|
|
|
//--------------------------- STANDARD DEPENDENCIES -- #include<xxxxx.h> ----
|
|
|
|
#include <stdlib.h>
|
|
|
|
//--------------------------- MODULE DEPENDENCIES -- #include"xxxxx.h" ------
|
|
|
|
#include <snmp.h>
|
|
#include <snmputil.h>
|
|
|
|
#include "authapi.h"
|
|
|
|
//--------------------------- SELF-DEPENDENCY -- ONE #include"module.h" -----
|
|
|
|
#include "berapi.h"
|
|
|
|
//--------------------------- PUBLIC VARIABLES --(same as in module.h file)--
|
|
|
|
//--------------------------- PRIVATE CONSTANTS -----------------------------
|
|
|
|
// BER limits
|
|
#define BER_OCTET_LEN 8 // 8 bits in an octet
|
|
#define BER_OCTET_SIZE 256 // 8 bits make an octet
|
|
#define BER_MAX_INT_OCTETS 4 // 4 octets - 32 bit integer
|
|
#define BER_MAX_LEN_OCTETS 2 // 2 octets - 16 bit integer length
|
|
#define BER_MAX_STREAM_LEN 0xffff // 16 bit unsigned integer
|
|
#define BER_MIN_HEADER_LEN 2 // 2 octets
|
|
#define BER_MAX_SIMPLE_LEN 127 // SNMP BER definition
|
|
|
|
// Buffer offsets for info.
|
|
#define BER_TAG_OFFSET 0
|
|
#define BER_LENGTH_OFFSET 1
|
|
|
|
// Meaningful bit definitions
|
|
#define BER_EXTENDED_TAG 0x1f // 00011111
|
|
#define BER_OCTET_CONT_BIT 0x80 // 10000000
|
|
|
|
// BER OBJECTIDENTIFIER limits
|
|
#define BER_MAX_FIRST_ELEM 2 // Obj Id's 1st element must be 0-2
|
|
#define BER_MAX_SECOND_ELEM 39 // Obj Id's 2nd element must be 0-40
|
|
#define BER_SUBOID_BLK_SIZE 20 // Number of Sub OID's to alloc at once.
|
|
|
|
|
|
//--------------------------- PRIVATE STRUCTS -------------------------------
|
|
|
|
//--------------------------- PRIVATE VARIABLES -----------------------------
|
|
|
|
//--------------------------- PRIVATE MACROS --------------------------------
|
|
|
|
// This macro requires that a label named 'Exit' exists in the function
|
|
// and handles any cleanup procedures the function needs to do
|
|
// before exiting.
|
|
#define BERAPI_ERROR( X ) \
|
|
SetLastError( X ); \
|
|
nResult = SNMPAPI_ERROR; \
|
|
goto Exit \
|
|
|
|
//--------------------------- PRIVATE PROTOTYPES ----------------------------
|
|
|
|
SNMPAPI BER_CreateHeader(
|
|
IN BYTE nTag,
|
|
IN UINT nObjLen,
|
|
IN OUT BYTE **pBuffer,
|
|
IN OUT UINT *nStart
|
|
);
|
|
|
|
SNMPAPI BER_ProcessHeader(
|
|
IN BYTE nTag,
|
|
IN BYTE *BufPtr,
|
|
IN UINT BufLen,
|
|
OUT UINT *StrLen,
|
|
OUT UINT *HeadLen
|
|
);
|
|
|
|
SNMPAPI BER_DecodeAsnInteger(
|
|
IN BYTE nTag, // Expect type of integer
|
|
IN OUT BYTE **pBuffer, // Buffer to decode
|
|
IN OUT UINT *nLength, // Length of buffer
|
|
IN OUT AsnAny *pResult // Contains decoded integer and specific type
|
|
);
|
|
|
|
SNMPAPI BER_DecodeAsnOctetStr(
|
|
IN BYTE nTag, // Expect type of OctetStr
|
|
IN OUT BYTE **pBuffer, // Buffer to decode
|
|
IN OUT UINT *nLength, // Length of buffer
|
|
IN OUT AsnAny *pResult // Contains decoded OctetStr and specific type
|
|
);
|
|
|
|
SNMPAPI BER_DecodeAsnNull(
|
|
IN BYTE nTag, // Expect type of NULL
|
|
IN OUT BYTE **pBuffer, // Buffer to decode
|
|
IN OUT UINT *nLength, // Length of buffer
|
|
IN OUT AsnAny *pResult // Contains decoded NULL and specific type
|
|
);
|
|
|
|
SNMPAPI BER_DecodeAsnObjectId(
|
|
IN BYTE nTag, // Expect type of ObjectId
|
|
IN OUT BYTE **pBuffer, // Buffer to decode
|
|
IN OUT UINT *nLength, // Length of buffer
|
|
IN OUT AsnAny *pResult // Contains decoded ObjectId and specific type
|
|
);
|
|
|
|
SNMPAPI BER_DecodeAsnImplicitSeq(
|
|
IN BYTE nTag, // Expected type of sequence
|
|
IN OUT BYTE **pBuffer, // Buffer to decode
|
|
IN OUT UINT *nLength, // Length of buffer
|
|
IN OUT AsnAny *pResult // Contains decoded sequence and specific type
|
|
);
|
|
|
|
//--------------------------- PRIVATE PROCEDURES ----------------------------
|
|
|
|
//--------------------------- PUBLIC PROCEDURES -----------------------------
|
|
|
|
//
|
|
// SnmpBerDecodeAsnStream
|
|
// Will decode next object in stream, based on expected type.
|
|
//
|
|
// Notes:
|
|
// If expected type does not match what is in buffer, an error is generated.
|
|
//
|
|
// "Extended Tags" (tags requiring more than one octet) are invalid.
|
|
//
|
|
// Return Codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error Codes:
|
|
// SNMP_BERAPI_INVALID_TAG
|
|
//
|
|
SNMPAPI SnmpBerDecodeAsnStream(
|
|
IN BYTE idExpectedAsnType, // Expected type of ASN object
|
|
IN OUT BYTE **pBuffer, // Buffer to decode
|
|
IN OUT UINT *nLength, // Length of buffer
|
|
OUT AsnAny *pResult // Contains decoded object and type
|
|
)
|
|
|
|
{
|
|
SNMPAPI nResult;
|
|
|
|
|
|
// Call appropriate routine to convert ASN.1 type
|
|
switch ( idExpectedAsnType )
|
|
{
|
|
case ASN_RFC1155_COUNTER:
|
|
case ASN_RFC1155_GAUGE:
|
|
case ASN_RFC1155_TIMETICKS:
|
|
case ASN_INTEGER:
|
|
nResult = BER_DecodeAsnInteger( idExpectedAsnType,
|
|
pBuffer, nLength, pResult );
|
|
break;
|
|
|
|
case ASN_RFC1155_IPADDRESS:
|
|
case ASN_RFC1155_OPAQUE:
|
|
case ASN_OCTETSTRING:
|
|
nResult = BER_DecodeAsnOctetStr( idExpectedAsnType,
|
|
pBuffer, nLength, pResult );
|
|
break;
|
|
|
|
case ASN_NULL:
|
|
nResult = BER_DecodeAsnNull( idExpectedAsnType,
|
|
pBuffer, nLength, pResult );
|
|
break;
|
|
|
|
case ASN_OBJECTIDENTIFIER:
|
|
nResult = BER_DecodeAsnObjectId( idExpectedAsnType,
|
|
pBuffer, nLength, pResult );
|
|
break;
|
|
|
|
case ASN_SEQUENCE:
|
|
case ASN_RFC1157_GETREQUEST:
|
|
case ASN_RFC1157_GETNEXTREQUEST:
|
|
case ASN_RFC1157_GETRESPONSE:
|
|
case ASN_RFC1157_SETREQUEST:
|
|
case ASN_RFC1157_TRAP:
|
|
case ASN_RFCxxxx_PRIVDATA:
|
|
nResult = BER_DecodeAsnImplicitSeq( idExpectedAsnType,
|
|
pBuffer, nLength, pResult );
|
|
break;
|
|
|
|
default:
|
|
BERAPI_ERROR( SNMP_BERAPI_INVALID_TAG );
|
|
}
|
|
|
|
Exit:
|
|
return nResult;
|
|
} // end SnmpBerDecodeAsnStream()
|
|
|
|
|
|
|
|
//
|
|
// SnmpBerEncodeAsnAny
|
|
// Encodes any ASN type, except sequences, implicit or normal.
|
|
//
|
|
// Notes:
|
|
// "Extended Tags" are invalid.
|
|
//
|
|
// Return Codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error Codes:
|
|
// SNMP_BERAPI_INVALID_TAG
|
|
//
|
|
SNMPAPI SnmpBerEncodeAsnAny(
|
|
IN AsnAny *pItem,
|
|
IN OUT BYTE **pBuffer,
|
|
IN OUT UINT *nLength
|
|
)
|
|
|
|
{
|
|
SNMPAPI nResult;
|
|
|
|
|
|
// Call appropriate routine to convert ASN.1 type
|
|
switch ( pItem->asnType )
|
|
{
|
|
case ASN_RFC1155_COUNTER:
|
|
case ASN_RFC1155_GAUGE:
|
|
case ASN_RFC1155_TIMETICKS:
|
|
case ASN_INTEGER:
|
|
nResult = SnmpBerEncodeAsnInteger( pItem->asnType,
|
|
pItem->asnValue.number,
|
|
pBuffer, nLength );
|
|
break;
|
|
|
|
case ASN_RFC1155_IPADDRESS:
|
|
case ASN_RFC1155_OPAQUE:
|
|
case ASN_OCTETSTRING:
|
|
nResult = SnmpBerEncodeAsnOctetStr( pItem->asnType,
|
|
&pItem->asnValue.string,
|
|
pBuffer, nLength );
|
|
break;
|
|
|
|
case ASN_NULL:
|
|
nResult = SnmpBerEncodeAsnNull( pItem->asnType, pBuffer, nLength );
|
|
break;
|
|
|
|
case ASN_OBJECTIDENTIFIER:
|
|
nResult = SnmpBerEncodeAsnObjectId( pItem->asnType,
|
|
&pItem->asnValue.object,
|
|
pBuffer, nLength );
|
|
break;
|
|
|
|
|
|
default:
|
|
BERAPI_ERROR( SNMP_BERAPI_INVALID_TAG );
|
|
}
|
|
|
|
Exit:
|
|
return nResult;
|
|
} // SnmpBerEncodeAsnAny
|
|
|
|
|
|
|
|
//
|
|
// BER_CreateHeader
|
|
//
|
|
// Notes:
|
|
// If an error occurs during this routine, it is the responsibility of
|
|
// the calling routine to free any memory that may or may not have
|
|
// been realloc'ed by BER_CreateHeader.
|
|
//
|
|
// The buffer information must be initialized before calling this routine.
|
|
// If this is the first routine to alloc memory for the buffer, it must be
|
|
// initialized to NULL.
|
|
//
|
|
SNMPAPI BER_CreateHeader(
|
|
IN BYTE nTag,
|
|
IN UINT nObjLen,
|
|
IN OUT BYTE **pBuffer,
|
|
IN OUT UINT *nStart
|
|
)
|
|
|
|
{
|
|
UINT nHeadLen;
|
|
UINT nStrLen;
|
|
BYTE nExtLen;
|
|
SNMPAPI nResult;
|
|
UINT tLen;
|
|
|
|
|
|
// Check for extended length
|
|
nExtLen = 0;
|
|
if ( nObjLen > BER_MAX_SIMPLE_LEN ) {
|
|
tLen = nObjLen;
|
|
|
|
while (tLen > 0) {
|
|
nExtLen++;
|
|
tLen /= BER_OCTET_SIZE;
|
|
}
|
|
}
|
|
|
|
// Calculate the length of the header
|
|
nHeadLen = BER_MIN_HEADER_LEN + nExtLen;
|
|
|
|
// Re-Alloc the buffer to hold the header
|
|
*pBuffer = SnmpUtilMemReAlloc( *pBuffer, (*nStart + nObjLen + nHeadLen) );
|
|
if ( *pBuffer == NULL )
|
|
{
|
|
BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR );
|
|
}
|
|
|
|
// Save start position of buffer
|
|
nStrLen = *nStart + nObjLen;
|
|
|
|
// Adjust overall length of buffer
|
|
*nStart += nObjLen + nHeadLen;
|
|
|
|
// Put Tag at end of buffer
|
|
(*pBuffer)[nStrLen+nHeadLen-BER_TAG_OFFSET-1] = nTag;
|
|
|
|
// Place Extended length indicator in stream if needed
|
|
if ( nExtLen > 0 )
|
|
{
|
|
(*pBuffer)[nStrLen+nHeadLen-BER_LENGTH_OFFSET-1] =
|
|
(BYTE) (nExtLen | BER_OCTET_CONT_BIT);
|
|
}
|
|
|
|
// Put stream length in buffer (reverse order)
|
|
(*pBuffer)[nStrLen] = 0;
|
|
while ( nObjLen > 0 )
|
|
{
|
|
(*pBuffer)[nStrLen++] = (BYTE) (nObjLen % BER_OCTET_SIZE);
|
|
nObjLen /= BER_OCTET_SIZE;
|
|
}
|
|
|
|
nResult = SNMPAPI_NOERROR;
|
|
|
|
Exit:
|
|
// Memory is released if 'realloc' fails, leaving buffer pointing to NULL.
|
|
|
|
return nResult;
|
|
} // CreateHeader
|
|
|
|
|
|
|
|
//
|
|
// BER_ProcessHeader:
|
|
// Calculates the length of the ASN.1 object. Does not change any
|
|
// buffer information.
|
|
//
|
|
// Notes:
|
|
// If an error occurs, the values of StrLen and HeadLen are
|
|
// invalid.
|
|
//
|
|
// Return codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error codes:
|
|
// SNMP_BERAPI_INVALID_TAG
|
|
// SNMP_BERAPI_OVERFLOW
|
|
// SNMP_BERAPI_SHORT_BUFFER
|
|
//
|
|
//
|
|
//
|
|
SNMPAPI BER_ProcessHeader(
|
|
IN BYTE nTag,
|
|
IN BYTE *BufPtr,
|
|
IN UINT BufLen,
|
|
OUT UINT *StrLen,
|
|
OUT UINT *HeadLen
|
|
)
|
|
|
|
{
|
|
UINT ExtLen;
|
|
UINT I;
|
|
SNMPAPI nResult;
|
|
|
|
|
|
// Check for short buffer
|
|
if ( BufLen < BER_MIN_HEADER_LEN )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_SHORT_BUFFER );
|
|
}
|
|
|
|
// Check for correct tag
|
|
if ( BufPtr[BER_TAG_OFFSET] != nTag )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_INVALID_TAG );
|
|
}
|
|
|
|
// Check for extended 'length' octets
|
|
*StrLen = BufPtr[BER_LENGTH_OFFSET] & ~BER_OCTET_CONT_BIT;
|
|
|
|
// if extended length, calculate length
|
|
if ( BufPtr[BER_LENGTH_OFFSET] & BER_OCTET_CONT_BIT )
|
|
{
|
|
ExtLen = *StrLen;
|
|
*StrLen = 0;
|
|
|
|
// Check for short buffer
|
|
if ( BufLen < (UINT)BER_MIN_HEADER_LEN+ExtLen )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_SHORT_BUFFER );
|
|
}
|
|
|
|
// Check for string length overflow
|
|
if ( ExtLen > BER_MAX_LEN_OCTETS )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_OVERFLOW );
|
|
}
|
|
|
|
// Build length
|
|
for ( I=0;I < ExtLen;I++ )
|
|
{
|
|
*StrLen = *StrLen * BER_OCTET_SIZE + BufPtr[I+BER_MIN_HEADER_LEN];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtLen = 0;
|
|
}
|
|
|
|
// Calculate header length
|
|
*HeadLen = BER_MIN_HEADER_LEN + ExtLen;
|
|
|
|
// Check for short buffer
|
|
if ( (ULONG)BufLen < (ULONG)*HeadLen + (ULONG)*StrLen )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_SHORT_BUFFER );
|
|
}
|
|
|
|
// Signal success
|
|
nResult = SNMPAPI_NOERROR;
|
|
|
|
Exit:
|
|
return nResult;
|
|
} // BER_ProcessHeader
|
|
|
|
|
|
|
|
//
|
|
// SnmpBerEncodeAsnInteger
|
|
//
|
|
// Notes:
|
|
// If an error occurs during this routine, it is the responsibility of
|
|
// the calling routine to free any memory that may or may not have
|
|
// been realloc'ed by this routine.
|
|
//
|
|
// The buffer information must be initialized before calling this routine.
|
|
// If this is the first routine to alloc memory for the buffer, it must be
|
|
// initialized to NULL.
|
|
//
|
|
// Return Codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error Codes:
|
|
// SNMP_MEM_ALLOC_ERROR
|
|
//
|
|
SNMPAPI SnmpBerEncodeAsnInteger(
|
|
IN BYTE nTag,
|
|
IN AsnInteger lInteger,
|
|
IN OUT BYTE **pBuffer,
|
|
IN OUT UINT *nLength
|
|
)
|
|
|
|
{
|
|
BYTE *pTemp;
|
|
UINT nIntLen;
|
|
ULONG ULTemp;
|
|
UINT I;
|
|
SNMPAPI nResult;
|
|
|
|
|
|
ULTemp = (ULONG) lInteger;
|
|
|
|
switch ( nTag )
|
|
{
|
|
case ASN_RFC1155_COUNTER:
|
|
case ASN_RFC1155_GAUGE:
|
|
case ASN_RFC1155_TIMETICKS:
|
|
if ( (ULONG)0x80 > (ULONG)lInteger )
|
|
{
|
|
nIntLen = 1;
|
|
}
|
|
else if ( (ULONG)0x8000 > (ULONG)lInteger )
|
|
{
|
|
nIntLen = 2;
|
|
}
|
|
else if ( 0x800000 > (ULONG)lInteger )
|
|
{
|
|
nIntLen = 3;
|
|
}
|
|
else if ( 0x80000000 > (ULONG)lInteger )
|
|
{
|
|
nIntLen = 4;
|
|
}
|
|
else
|
|
{
|
|
nIntLen = 5;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ( (AsnInteger)0 > lInteger )
|
|
{
|
|
if ( (ULONG)0x80 >= -lInteger )
|
|
{
|
|
nIntLen = 1;
|
|
}
|
|
else if ( (ULONG)0x8000 >= -lInteger )
|
|
{
|
|
nIntLen = 2;
|
|
}
|
|
else if ( (ULONG)0x800000 >= -lInteger )
|
|
{
|
|
nIntLen = 3;
|
|
}
|
|
else
|
|
{
|
|
nIntLen = 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( (ULONG)0x80 > lInteger )
|
|
{
|
|
nIntLen = 1;
|
|
}
|
|
else if ( (ULONG)0x8000 > lInteger )
|
|
{
|
|
nIntLen = 2;
|
|
}
|
|
else if ( (ULONG)0x800000 > lInteger )
|
|
{
|
|
nIntLen = 3;
|
|
}
|
|
else
|
|
{
|
|
nIntLen = 4;
|
|
}
|
|
}
|
|
} // case
|
|
|
|
// Alloc maximum memory for stream. BER_CreateHeader will adjust to fit
|
|
*pBuffer = SnmpUtilMemReAlloc( *pBuffer, (*nLength + nIntLen + BER_MIN_HEADER_LEN) );
|
|
if ( *pBuffer == NULL )
|
|
{
|
|
BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR );
|
|
}
|
|
|
|
// Alias the start position in buffer
|
|
pTemp = *pBuffer + *nLength;
|
|
|
|
// Encode the ASN integer
|
|
for ( I=0;I < min(nIntLen, BER_MAX_INT_OCTETS);I++ )
|
|
{
|
|
pTemp[I] = (BYTE) (ULTemp % BER_OCTET_SIZE);
|
|
ULTemp = ULTemp / BER_OCTET_SIZE;
|
|
}
|
|
|
|
// Check for the necessary fifth bit on unsigned integers
|
|
if ( nIntLen > BER_MAX_INT_OCTETS )
|
|
{
|
|
pTemp[BER_MAX_INT_OCTETS] = 0;
|
|
}
|
|
|
|
// Create header
|
|
nResult = BER_CreateHeader( nTag, nIntLen, pBuffer, nLength );
|
|
|
|
Exit:
|
|
// Memory is released if 'realloc' fails, leaving buffer pointing to NULL.
|
|
|
|
return nResult;
|
|
} // SnmpBerEncodeAsnInteger
|
|
|
|
|
|
|
|
//
|
|
// BER_DecodeAsnInteger:
|
|
// Decodes an integer. If the integer cannot be decoded, an error message
|
|
// is returned and the buffer information remains unchanged.
|
|
//
|
|
// Notes: Considers integers over 32 bits (4 Octets) as an error.
|
|
//
|
|
// Return codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error codes:
|
|
// SNMP_BERAPI_INVALID_TAG
|
|
// SNMP_BERAPI_OVERFLOW
|
|
// SNMP_BERAPI_SHORT_BUFFER
|
|
//
|
|
SNMPAPI BER_DecodeAsnInteger(
|
|
IN BYTE nTag, // Expect type of integer
|
|
IN OUT BYTE **pBuffer, // Buffer to decode
|
|
IN OUT UINT *nLength, // Length of buffer
|
|
IN OUT AsnAny *pResult // Contains decoded integer and specific type
|
|
)
|
|
|
|
{
|
|
UINT StrLen;
|
|
UINT HeadLen;
|
|
UINT I;
|
|
AsnInteger IntResult;
|
|
SNMPAPI nResult;
|
|
|
|
|
|
// Process header of ASN.1 INTEGER
|
|
nResult = BER_ProcessHeader( nTag, *pBuffer, *nLength, &StrLen, &HeadLen );
|
|
if ( nResult != SNMPAPI_NOERROR )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Check length based on signed or unsigned expected
|
|
switch( nTag )
|
|
{
|
|
case ASN_RFC1155_COUNTER:
|
|
case ASN_RFC1155_GAUGE:
|
|
case ASN_RFC1155_TIMETICKS:
|
|
if ( StrLen > BER_MAX_INT_OCTETS+1 )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_OVERFLOW );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ( StrLen > BER_MAX_INT_OCTETS )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_OVERFLOW );
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Save sign information
|
|
if ( (*pBuffer)[HeadLen] & 0x80 )
|
|
{
|
|
IntResult = -1;
|
|
}
|
|
else
|
|
{
|
|
IntResult = 0;
|
|
}
|
|
|
|
// Convert integer
|
|
for ( I=0;I < StrLen;I++ )
|
|
{
|
|
IntResult = IntResult << BER_OCTET_LEN | (*pBuffer)[HeadLen+I];
|
|
}
|
|
|
|
// Extend sign if necessary
|
|
// Assign completed conversion to return structure
|
|
pResult->asnType = nTag;
|
|
pResult->asnValue.number = IntResult;
|
|
|
|
// Adjust buffer info
|
|
*nLength -= HeadLen + StrLen;
|
|
*pBuffer += HeadLen + StrLen;
|
|
|
|
// Signal successful conversion
|
|
nResult = SNMPAPI_NOERROR;
|
|
|
|
Exit:
|
|
return nResult;
|
|
} // BER_DecodeAsnInteger
|
|
|
|
|
|
|
|
//
|
|
// SnmpBerEncodeAsnOctetStr
|
|
//
|
|
// Notes:
|
|
// If an error occurs during this routine, it is the responsibility of
|
|
// the calling routine to free any memory that may or may not have
|
|
// been realloc'ed by this routine.
|
|
//
|
|
// The buffer information must be initialized before calling this routine.
|
|
// If this is the first routine to alloc memory for the buffer, it must be
|
|
// initialized to NULL.
|
|
//
|
|
// Return Codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error Codes:
|
|
// SNMP_MEM_ALLOC_ERROR
|
|
//
|
|
SNMPAPI SnmpBerEncodeAsnOctetStr(
|
|
IN BYTE nTag,
|
|
IN AsnOctetString *String,
|
|
IN OUT BYTE **pBuffer,
|
|
IN OUT UINT *nLength
|
|
)
|
|
|
|
{
|
|
BYTE *pTemp;
|
|
SNMPAPI nResult;
|
|
|
|
|
|
// Alloc maximum memory for stream. BER_CreateHeader will adjust to fit
|
|
*pBuffer = SnmpUtilMemReAlloc( *pBuffer,
|
|
(*nLength + String->length + BER_MIN_HEADER_LEN) );
|
|
if ( *pBuffer == NULL )
|
|
{
|
|
BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR );
|
|
}
|
|
|
|
// Alias the start position in buffer
|
|
pTemp = *pBuffer + *nLength;
|
|
|
|
// Encode stream (reverse order)
|
|
SnmpSvcBufRevAndCpy( pTemp, String->stream, String->length );
|
|
|
|
// Create header
|
|
nResult = BER_CreateHeader( nTag, String->length, pBuffer, nLength );
|
|
|
|
Exit:
|
|
// Memory is released if 'realloc' fails, leaving buffer pointing to NULL.
|
|
|
|
return nResult;
|
|
} // SnmpBerEncodeAsnOctetStr
|
|
|
|
|
|
|
|
//
|
|
// BER_DecodeAsnOctetStr:
|
|
// Decodes an octet string. If the octet string cannot be decoded, an
|
|
// error message is returned and the buffer information remains unchanged.
|
|
// Returns a pointer into the message buffer which points to the
|
|
// octet string. This routine does not allocate any memory to hold the
|
|
// octet string.
|
|
//
|
|
// Notes: Considers octet strings longer than 65535 as an an error.
|
|
//
|
|
// Return codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error codes:
|
|
// SNMP_BERAPI_INVALID_TAG
|
|
// SNMP_BERAPI_OVERFLOW
|
|
// SNMP_BERAPI_SHORT_BUFFER
|
|
//
|
|
SNMPAPI BER_DecodeAsnOctetStr(
|
|
IN BYTE nTag, // Expect type of OctetStr
|
|
IN OUT BYTE **pBuffer, // Buffer to decode
|
|
IN OUT UINT *nLength, // Length of buffer
|
|
IN OUT AsnAny *pResult // Contains decoded OctetStr and specific type
|
|
)
|
|
|
|
{
|
|
UINT StrLen;
|
|
UINT HeadLen;
|
|
SNMPAPI nResult;
|
|
|
|
|
|
// Process header of ASN.1 OCTET STRING
|
|
nResult = BER_ProcessHeader( nTag, *pBuffer, *nLength, &StrLen, &HeadLen );
|
|
if ( nResult == SNMPAPI_ERROR )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Set result type
|
|
pResult->asnType = nTag;
|
|
|
|
// Set return values
|
|
pResult->asnValue.string.length = StrLen;
|
|
pResult->asnValue.string.stream = *pBuffer + HeadLen;
|
|
pResult->asnValue.string.dynamic = FALSE;
|
|
|
|
// Adjust buffer info
|
|
*nLength -= HeadLen + StrLen;
|
|
*pBuffer += HeadLen + StrLen;
|
|
|
|
// Signal successful conversion
|
|
nResult = SNMPAPI_NOERROR;
|
|
|
|
Exit:
|
|
return nResult;
|
|
} // BER_DecodeAsnOctetStr
|
|
|
|
|
|
|
|
//
|
|
// SnmpBerEncodeAsnNull
|
|
// Encodes an ASN NULL into the buffer.
|
|
//
|
|
// Notes:
|
|
//
|
|
// Return Codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error Codes:
|
|
// SNMP_MEM_ALLOC_ERROR
|
|
//
|
|
SNMPAPI SnmpBerEncodeAsnNull(
|
|
IN BYTE nTag,
|
|
IN OUT BYTE **pBuffer,
|
|
IN OUT UINT *nLength
|
|
)
|
|
|
|
{
|
|
// Create header
|
|
return BER_CreateHeader( nTag, 0, pBuffer, nLength );
|
|
} // SnmpBerEncodeAsnNull
|
|
|
|
|
|
|
|
//
|
|
// BER_DecodeAsnNull:
|
|
// Decodes an NULL. If the NULL cannot be decoded, an error message is
|
|
// returned and the buffer information remains unchanged.
|
|
//
|
|
// Return codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error codes:
|
|
// SNMP_BERAPI_INVALID_TAG
|
|
// SNMP_BERAPI_OVERFLOW
|
|
// SNMP_BERAPI_SHORT_BUFFER
|
|
// SNMP_BERAPI_INVALID_LENGTH
|
|
//
|
|
//
|
|
//
|
|
SNMPAPI BER_DecodeAsnNull(
|
|
IN BYTE nTag, // Expect type of NULL
|
|
IN OUT BYTE **pBuffer, // Buffer to decode
|
|
IN OUT UINT *nLength, // Length of buffer
|
|
IN OUT AsnAny *pResult // Contains decoded NULL and specific type
|
|
)
|
|
|
|
{
|
|
UINT StrLen;
|
|
UINT HeadLen;
|
|
SNMPAPI nResult;
|
|
|
|
|
|
// Get length of ASN.1 NULL
|
|
nResult = BER_ProcessHeader( nTag, *pBuffer, *nLength, &StrLen, &HeadLen );
|
|
if ( nResult == SNMPAPI_ERROR )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Check for correct length
|
|
if ( StrLen != 0 )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_INVALID_LENGTH );
|
|
}
|
|
|
|
// Set return type
|
|
pResult->asnType = nTag;
|
|
|
|
// Adjust buffer info
|
|
*nLength -= HeadLen + StrLen;
|
|
*pBuffer += HeadLen + StrLen;
|
|
|
|
// Signal successful conversion
|
|
nResult = SNMPAPI_NOERROR;
|
|
|
|
Exit:
|
|
return nResult;
|
|
} // BER_DecodeAsnNull
|
|
|
|
|
|
|
|
//
|
|
// SnmpBerEncodeAsnObjectId
|
|
//
|
|
// Notes:
|
|
// If an error occurs during this routine, it is the responsibility of
|
|
// the calling routine to free any memory that may or may not have
|
|
// been realloc'ed by this routine.
|
|
//
|
|
// The buffer information must be initialized before calling this routine.
|
|
// If this is the first routine to alloc memory for the buffer, it must be
|
|
// initialized to NULL.
|
|
//
|
|
// Return Codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error Codes:
|
|
// SNMP_MEM_ALLOC_ERROR
|
|
// SNMP_BERAPI_INVALID_OBJELEM
|
|
//
|
|
SNMPAPI SnmpBerEncodeAsnObjectId(
|
|
IN BYTE nTag,
|
|
IN AsnObjectIdentifier *ObjectId,
|
|
IN OUT BYTE **pBuffer,
|
|
IN OUT UINT *nLength
|
|
)
|
|
|
|
{
|
|
UINT nObjIdLen;
|
|
UINT nTemp;
|
|
BYTE *pTemp;
|
|
UINT I;
|
|
SNMPAPI nResult;
|
|
|
|
|
|
// Check for error on number of SUB ID's
|
|
if ( ObjectId->idLength < 2 )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_INVALID_LENGTH );
|
|
}
|
|
|
|
// Alloc maximum memory for stream. BER_CreateHeader will adjust to fit
|
|
*pBuffer = SnmpUtilMemReAlloc( *pBuffer,
|
|
(*nLength + ObjectId->idLength*3 + BER_MIN_HEADER_LEN) );
|
|
if ( *pBuffer == NULL )
|
|
{
|
|
BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR );
|
|
}
|
|
|
|
// Alias start position in buffer
|
|
pTemp = *pBuffer + *nLength;
|
|
|
|
// Encode stream (reverse order) and calculate length
|
|
nObjIdLen = 0;
|
|
I = ObjectId->idLength;
|
|
while ( I - 2 > 0 )
|
|
{
|
|
nTemp = ObjectId->ids[--I];
|
|
if ( nTemp )
|
|
{
|
|
pTemp[nObjIdLen] = 0;
|
|
while ( nTemp )
|
|
{
|
|
pTemp[nObjIdLen++] |= nTemp % BER_OCTET_CONT_BIT;
|
|
if ( nTemp /= BER_OCTET_CONT_BIT )
|
|
{
|
|
pTemp[nObjIdLen] = BER_OCTET_CONT_BIT;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pTemp[nObjIdLen++] = 0;
|
|
}
|
|
}
|
|
|
|
// Check for invalid first and second element
|
|
if ( (ObjectId->ids[0] > BER_MAX_FIRST_ELEM) ||
|
|
(ObjectId->idLength > 1 && ObjectId->ids[1] > BER_MAX_SECOND_ELEM) )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_INVALID_OBJELEM );
|
|
}
|
|
|
|
// Setup the first two elements of the object ID
|
|
pTemp[nObjIdLen++] = (BYTE) (ObjectId->ids[0] * 40 + ObjectId->ids[1]);
|
|
|
|
// Create header
|
|
nResult = BER_CreateHeader( nTag, nObjIdLen, pBuffer, nLength );
|
|
|
|
Exit:
|
|
if ( nResult == SNMPAPI_ERROR )
|
|
{
|
|
SnmpUtilMemFree( *pBuffer );
|
|
|
|
*pBuffer = NULL;
|
|
*nLength = 0;
|
|
}
|
|
|
|
return nResult;
|
|
} // SnmpBerEncodeAsnObjectId
|
|
|
|
|
|
#define MAX_SNMPOID 0XFFFFFFFF
|
|
|
|
//
|
|
// BER_DecodeAsnObjectId:
|
|
// Decodes an object identifier. If the object identifier cannot be
|
|
// decoded, an error message is returned and the buffer information
|
|
// remains unchanged.
|
|
//
|
|
// Notes: Considers object identifiers that have over 65535 elements
|
|
// as an error.
|
|
//
|
|
// Return codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error codes:
|
|
// SNMP_BERAPI_INVALID_TAG
|
|
// SNMP_BERAPI_OVERFLOW
|
|
// SNMP_BERAPI_SHORT_BUFFER
|
|
// SNMP_BERAPI_INVALID_LENGTH
|
|
//
|
|
SNMPAPI BER_DecodeAsnObjectId(
|
|
IN BYTE nTag, // Expect type of ObjectId
|
|
IN OUT BYTE **pBuffer, // Buffer to decode
|
|
IN OUT UINT *nLength, // Length of buffer
|
|
IN OUT AsnAny *pResult // Contains decoded ObjectId and specific type
|
|
)
|
|
|
|
{
|
|
UINT StrLen;
|
|
UINT HeadLen;
|
|
UINT I;
|
|
UINT *TempObjId;
|
|
UINT ElemTemp;
|
|
UINT nLen;
|
|
SNMPAPI nResult;
|
|
|
|
|
|
// Initialize
|
|
TempObjId = pResult->asnValue.object.ids = NULL;
|
|
|
|
// Get length of ASN.1 OBJECT IDENTIFIER
|
|
nResult = BER_ProcessHeader( nTag, *pBuffer, *nLength, &StrLen, &HeadLen );
|
|
if ( nResult == SNMPAPI_ERROR )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Check for invalid length
|
|
if ( StrLen < 1 )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_INVALID_LENGTH );
|
|
}
|
|
|
|
// Alloc space for at least 2 elements
|
|
if ( NULL == (TempObjId = SnmpUtilMemAlloc((BER_SUBOID_BLK_SIZE*sizeof(UINT)))) )
|
|
{
|
|
BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR );
|
|
}
|
|
|
|
// Get first two elements of the object identifier
|
|
I = HeadLen;
|
|
TempObjId[0] = (*pBuffer)[I] / 40;
|
|
TempObjId[1] = (*pBuffer)[I] % 40;
|
|
nLen = 2;
|
|
|
|
// Check first element for error
|
|
if ( TempObjId[0] > BER_MAX_FIRST_ELEM )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_INVALID_OBJELEM );
|
|
}
|
|
|
|
// Get rest of elements
|
|
I++;
|
|
while ( I < (UINT)HeadLen+StrLen && nLen < SNMP_MAX_OID_LEN )
|
|
{
|
|
ElemTemp = 0;
|
|
do
|
|
{
|
|
ElemTemp = (ElemTemp << 7) | ((*pBuffer)[I] & ~BER_OCTET_CONT_BIT);
|
|
++I;
|
|
|
|
// Check for invalid length
|
|
if ( I > StrLen + HeadLen )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_INVALID_LENGTH );
|
|
}
|
|
|
|
} while((*pBuffer)[I - 1] & BER_OCTET_CONT_BIT);
|
|
|
|
// Check for 32 bit overflow
|
|
if ( (ElemTemp > MAX_SNMPOID) )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_OVERFLOW );
|
|
}
|
|
|
|
#if 0
|
|
ElemTemp = (*pBuffer)[I] & ~BER_OCTET_CONT_BIT;
|
|
|
|
// Check for 16 bit element
|
|
if ( (*pBuffer)[I++] & BER_OCTET_CONT_BIT )
|
|
{
|
|
// Check for invalid length
|
|
if ( I == StrLen + HeadLen )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_INVALID_LENGTH );
|
|
}
|
|
|
|
// Check for 16 bit overflow
|
|
if ( (*pBuffer)[I] & BER_OCTET_CONT_BIT )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_OVERFLOW );
|
|
}
|
|
|
|
// Build element
|
|
ElemTemp = ElemTemp * BER_OCTET_CONT_BIT + (*pBuffer)[I++];
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
// alloc memory for object ids
|
|
if ( !(nLen % BER_SUBOID_BLK_SIZE) )
|
|
{
|
|
if ( NULL ==
|
|
(TempObjId = SnmpUtilMemReAlloc(TempObjId,
|
|
((UINT)(nLen+BER_SUBOID_BLK_SIZE) *
|
|
sizeof(UINT)))) )
|
|
{
|
|
BERAPI_ERROR( SNMP_MEM_ALLOC_ERROR );
|
|
}
|
|
}
|
|
|
|
// Assign element to the object id struct
|
|
TempObjId[nLen++] = ElemTemp;
|
|
}
|
|
|
|
// Check for object id too long - overflow
|
|
if ( I < (UINT)StrLen+HeadLen )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_OVERFLOW );
|
|
}
|
|
|
|
// Set result type
|
|
pResult->asnType = nTag;
|
|
|
|
// Set result - Realloc to perfect fit
|
|
pResult->asnValue.object.ids = SnmpUtilMemReAlloc( TempObjId,
|
|
(nLen * sizeof(UINT)) );
|
|
pResult->asnValue.object.idLength = nLen;
|
|
|
|
// Adjust buffer info
|
|
*nLength -= HeadLen + StrLen;
|
|
*pBuffer += HeadLen + StrLen;
|
|
|
|
// Signal successful conversion
|
|
nResult = SNMPAPI_NOERROR;
|
|
|
|
Exit:
|
|
if ( nResult == SNMPAPI_ERROR )
|
|
{
|
|
SnmpUtilMemFree( TempObjId );
|
|
}
|
|
|
|
return nResult;
|
|
} // BER_DecodeAsnObjectId
|
|
|
|
|
|
|
|
//
|
|
// SnmpBerEncodeAsnImplicitSeq
|
|
//
|
|
// Notes:
|
|
// The buffer passed as the encoding buffer is considered as the data to
|
|
// be encoded as a sequence. The data must already be in reverse order
|
|
// (probably from a previous call to an encoding routine.) The encoding
|
|
// algorithm will fool the 'BER_CreateHeader' routine into thinking that the
|
|
// information in the buffer has just been encoded, just like the
|
|
// other encoding routines. The result will be 'BER_CreateHeader' appending
|
|
// the header (in reverse order) onto the buffer referenced by *pBuffer.
|
|
//
|
|
// Return Codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error Codes:
|
|
// None.
|
|
//
|
|
SNMPAPI SnmpBerEncodeAsnImplicitSeq(
|
|
IN BYTE nTag,
|
|
IN UINT nSeqLen,
|
|
IN OUT BYTE **pBuffer,
|
|
IN OUT UINT *nLength
|
|
)
|
|
|
|
{
|
|
// Fool CreateHeader into thinking that this routine just encoded
|
|
// the items in the sequence
|
|
*nLength -= nSeqLen;
|
|
|
|
// Create header
|
|
return BER_CreateHeader( nTag, nSeqLen, pBuffer, nLength );
|
|
} // SnmpBerEncodeAsnImplicitSeq
|
|
|
|
|
|
|
|
//
|
|
// BER_DecodeAsnImplicitSeq:
|
|
// Decodes a sequence. Returns a pointer into the message buffer which
|
|
// which points to the first object in the sequence. NO new memory is
|
|
// allocated to hold the sequence objects. If an error occurs, one of
|
|
// the following error codes is returned and the buffer information
|
|
// remains unchanged.
|
|
//
|
|
// Notes:
|
|
// To decode the individual objects, call the main decode routine passing
|
|
// the sequence buffer pointer (stream) and the sequence length.
|
|
//
|
|
// Return codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error codes:
|
|
// SNMP_BERAPI_INVALID_TAG
|
|
// SNMP_BERAPI_OVERFLOW
|
|
// SNMP_BERAPI_SHORT_BUFFER
|
|
//
|
|
SNMPAPI BER_DecodeAsnImplicitSeq(
|
|
IN BYTE nTag, // Expected type of sequence
|
|
IN OUT BYTE **pBuffer, // Buffer to decode
|
|
IN OUT UINT *nLength, // Length of buffer
|
|
IN OUT AsnAny *pResult // Contains decoded sequence and specific type
|
|
)
|
|
|
|
{
|
|
UINT StrLen;
|
|
UINT HeadLen;
|
|
SNMPAPI nResult;
|
|
|
|
|
|
// Process header of IMPLICIT SEQUENCE
|
|
nResult = BER_ProcessHeader( nTag, *pBuffer, *nLength, &StrLen, &HeadLen );
|
|
if ( nResult == SNMPAPI_ERROR )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Set result type
|
|
pResult->asnType = nTag;
|
|
|
|
// Set return values
|
|
pResult->asnValue.sequence.length = StrLen;
|
|
pResult->asnValue.sequence.stream = *pBuffer + HeadLen;
|
|
|
|
// Adjust buffer info
|
|
*nLength -= HeadLen + StrLen;
|
|
*pBuffer += HeadLen + StrLen;
|
|
|
|
// Signal successful conversion
|
|
nResult = SNMPAPI_NOERROR;
|
|
|
|
Exit:
|
|
return nResult;
|
|
} // BER_DecodeAsnImplicitSeq
|
|
|
|
|
|
|
|
//
|
|
// SnmpBerQueryAsnType:
|
|
// Examines the buffer to determine the type of the next object
|
|
// in the buffer.
|
|
//
|
|
// Notes:
|
|
// If any of the ASN types are equal to SNMPAPI_ERROR or SNMPAPI_NOERROR,
|
|
// then this routine will fail to perform accurately.
|
|
//
|
|
// Return codes:
|
|
// SNMPAPI_NOERROR
|
|
// SNMPAPI_ERROR
|
|
//
|
|
// Error codes:
|
|
// SNMP_BERAPI_SHORT_BUFFER
|
|
// SNMP_BERAPI_INVALID_TAG
|
|
//
|
|
SNMPAPI SnmpBerQueryAsnType( BYTE *pBuffer, /* in */
|
|
UINT nLength /* in */ )
|
|
|
|
{
|
|
SNMPAPI nResult;
|
|
|
|
|
|
// Check for short buffer
|
|
if ( !nLength )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_SHORT_BUFFER );
|
|
}
|
|
|
|
// Check for extended tag
|
|
if ( (pBuffer[BER_TAG_OFFSET] & BER_EXTENDED_TAG) == BER_EXTENDED_TAG )
|
|
{
|
|
BERAPI_ERROR( SNMP_BERAPI_INVALID_TAG );
|
|
}
|
|
|
|
nResult = pBuffer[BER_TAG_OFFSET];
|
|
|
|
Exit:
|
|
return nResult;
|
|
} // SnmpBerQueryAsnType
|
|
|
|
//-------------------------------- END --------------------------------------
|
|
|