Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2744 lines
60 KiB

/*
Copyright (c) 1992-1997 Microsoft Corporation
Module Name:
snmppdus.c
Abstract:
Contains routines for manipulating SNMP PDUs.
Environment:
User Mode - Win32
Revision History:
10-Feb-1997 DonRyan
Rewrote to implement SNMPv2 support.
*/
///////////////////////////////////////////////////////////////////////////////
// //
// Include files //
// //
///////////////////////////////////////////////////////////////////////////////
#include "globals.h"
#include "trapthrd.h" // for doing authentication in this module
#include "network.h"
#include "snmpmgmt.h"
#include "contexts.h" // for doing authentication in this module
#include "snmpthrd.h" // for doing authentication in this module
///////////////////////////////////////////////////////////////////////////////
// //
// Private definitions //
// //
///////////////////////////////////////////////////////////////////////////////
#define BERERR ((LONG)-1)
///////////////////////////////////////////////////////////////////////////////
// //
// Private procedures //
// //
///////////////////////////////////////////////////////////////////////////////
LONG
DoLenLen(
LONG lLen
)
/*
Routine Description:
Calculates number of bytes required to encode length.
Arguments:
lLen - length of interest.
Return Values:
Returns BERERR if unsuccessful.
*/
{
// determine len length
if (0x80 > lLen) return (1);
if (0x100 > lLen) return (2);
if (0x10000 > lLen) return (3);
if (0x1000000 > lLen) return (4);
SNMPDBG((
SNMP_LOG_ERROR,
"SNMP: SVC: length field too large.\n"
));
// failure
return BERERR;
}
LONG
FindLenInt(
AsnInteger32 nValue
)
/*
Routine Description:
Calculates length of integer.
Arguments:
nValue - integer data.
Return Values:
Returns BERERR if unsuccessful.
*/
{
// negative?
if (nValue < 0) {
// determine length of negative int
if ((ULONG)0x80 >= -nValue) return (1);
if ((ULONG)0x8000 >= -nValue) return (2);
if ((ULONG)0x800000 >= -nValue) return (3);
} else {
// determine length of positive int
if ((ULONG)0x80 > nValue) return (1);
if ((ULONG)0x8000 > nValue) return (2);
if ((ULONG)0x800000 > nValue) return (3);
}
// default
return (4);
}
LONG
FindLenIntEx(
AsnInteger32 nValue
)
/*
Routine Description:
Calculates length of integer (including type and lenlen).
Arguments:
nValue - integer data.
Return Values:
Returns BERERR if unsuccessful.
*/
{
// negative?
if (nValue < 0) {
// determine length of negative int
if ((ULONG)0x80 >= -nValue) return (3);
if ((ULONG)0x8000 >= -nValue) return (4);
if ((ULONG)0x800000 >= -nValue) return (5);
} else {
// determine length of positive int
if ((ULONG)0x80 > nValue) return (3);
if ((ULONG)0x8000 > nValue) return (4);
if ((ULONG)0x800000 > nValue) return (5);
}
// default
return (6);
}
LONG
FindLenUInt(
AsnUnsigned32 nValue
)
/*
Routine Description:
Calculates encoded length of unsigned integer.
Arguments:
nValue - integer data.
Return Values:
Returns BERERR if unsuccessful.
*/
{
// determine length of unsigned int
if ((ULONG)0x80 > nValue) return (1);
if ((ULONG)0x8000 > nValue) return (2);
if ((ULONG)0x800000 > nValue) return (3);
if ((ULONG)0x80000000 > nValue) return (4);
// default
return (5);
}
LONG
FindLenUIntEx(
AsnUnsigned32 nValue
)
/*
Routine Description:
Calculates encoded length of unsigned integer (including type and lenlen).
Arguments:
nValue - integer data.
Return Values:
Returns BERERR if unsuccessful.
*/
{
// determine length of unsigned int
if ((ULONG)0x80 > nValue) return (3);
if ((ULONG)0x8000 > nValue) return (4);
if ((ULONG)0x800000 > nValue) return (5);
if ((ULONG)0x80000000 > nValue) return (6);
// default
return (7);
}
LONG
FindLenCntr64(
AsnCounter64 * pCntr64
)
/*
Routine Description:
Calculates encoded length of 64-bit counter.
Arguments:
pCntr64 - counter data.
Return Values:
Returns BERERR if unsuccessful.
*/
{
// retrieve 64-bit unsigned value
ULONGLONG nValue = pCntr64->QuadPart;
// determine length of unsigned int
if ((ULONGLONG)0x80 > nValue) return (1);
if ((ULONGLONG)0x8000 > nValue) return (2);
if ((ULONGLONG)0x800000 > nValue) return (3);
if ((ULONGLONG)0x80000000 > nValue) return (4);
if ((ULONGLONG)0x8000000000 > nValue) return (5);
if ((ULONGLONG)0x800000000000 > nValue) return (6);
if ((ULONGLONG)0x80000000000000 > nValue) return (7);
if ((ULONGLONG)0x8000000000000000 > nValue) return (8);
// default
return (9);
}
LONG
FindLenCntr64Ex(
AsnCounter64 * pCntr64
)
/*
Routine Description:
Calculates encoded length of 64-bit counter (including type and lenlen).
Arguments:
pCntr64 - counter data.
Return Values:
Returns BERERR if unsuccessful.
*/
{
// retrieve 64-bit unsigned value
ULONGLONG nValue = pCntr64->QuadPart;
// determine length of unsigned int
if ((ULONGLONG)0x80 > nValue) return (3);
if ((ULONGLONG)0x8000 > nValue) return (4);
if ((ULONGLONG)0x800000 > nValue) return (5);
if ((ULONGLONG)0x80000000 > nValue) return (6);
if ((ULONGLONG)0x8000000000 > nValue) return (7);
if ((ULONGLONG)0x800000000000 > nValue) return (8);
if ((ULONGLONG)0x80000000000000 > nValue) return (9);
if ((ULONGLONG)0x8000000000000000 > nValue) return (10);
// default
return (11);
}
LONG
FindLenOctets(
AsnOctetString * pOctets
)
/*
Routine Description:
Calculates length of octet string.
Arguments:
pOctets - pointer to octet string.
Return Values:
Returns BERERR if unsuccessful.
*/
{
// return size
return pOctets->length;
}
LONG
FindLenOctetsEx(
AsnOctetString * pOctets
)
/*
Routine Description:
Calculates length of octet string (including type and lenlen).
Arguments:
pOctets - pointer to octet string.
Return Values:
Returns BERERR if unsuccessful.
*/
{
LONG lLenLen;
// calculate bytes needed to encode
lLenLen = DoLenLen(pOctets->length);
// return total size
return (lLenLen != BERERR)
? (pOctets->length + lLenLen + 1)
: BERERR
;
}
LONG
FindLenOid(
AsnObjectIdentifier * pOid
)
/*
Routine Description:
Calculates length of object identifier.
Arguments:
pOid - pointer object identifier.
Return Values:
Returns BERERR if unsuccessful.
*/
{
UINT i;
LONG lDataLen;
// first two
lDataLen = 1;
// assume first two oids present
for (i = 2; i < pOid->idLength; i++) {
if (0x80 > pOid->ids[i]) {
lDataLen += 1;
} else if (0x4000 > pOid->ids[i]) {
lDataLen += 2;
} else if (0x200000 > pOid->ids[i]) {
lDataLen += 3;
} else if (0x10000000 > pOid->ids[i]) {
lDataLen += 4;
} else {
lDataLen += 5;
}
}
// return size
return (pOid->idLength >= 2) ? lDataLen : BERERR;
}
LONG
FindLenOidEx(
AsnObjectIdentifier * pOid
)
/*
Routine Description:
Calculates length of object identifier (including type and lenlen).
Arguments:
pOid - pointer object identifier.
Return Values:
Returns BERERR if unsuccessful.
*/
{
UINT i;
LONG lLenLen;
LONG lDataLen;
// first two
lDataLen = 1;
// assume first two oids present
for (i = 2; i < pOid->idLength; i++) {
if (0x80 > pOid->ids[i]) {
lDataLen += 1;
} else if (0x4000 > pOid->ids[i]) {
lDataLen += 2;
} else if (0x200000 > pOid->ids[i]) {
lDataLen += 3;
} else if (0x10000000 > pOid->ids[i]) {
lDataLen += 4;
} else {
lDataLen += 5;
}
}
// calculate len length
lLenLen = DoLenLen(lDataLen);
// return total size
return ((lLenLen != BERERR) &&
(pOid->idLength >= 2))
? (lDataLen + lLenLen + 1)
: BERERR
;
}
LONG
FindLenAsnAny(
AsnAny * pAny
)
/*
Routine Description:
Find length of variable binding value.
Arguments:
pAny - pointer to variable binding value.
Return Values:
Returns BERERR if unsuccessful.
*/
{
// determine syntax
switch (pAny->asnType) {
case ASN_OCTETSTRING:
case ASN_IPADDRESS:
case ASN_OPAQUE:
return FindLenOctets(&pAny->asnValue.string);
case ASN_OBJECTIDENTIFIER:
return FindLenOid(&pAny->asnValue.object);
case ASN_NULL:
case SNMP_EXCEPTION_NOSUCHOBJECT:
case SNMP_EXCEPTION_NOSUCHINSTANCE:
case SNMP_EXCEPTION_ENDOFMIBVIEW:
return (0);
case ASN_INTEGER32:
return FindLenInt(pAny->asnValue.number);
case ASN_COUNTER32:
case ASN_GAUGE32:
case ASN_TIMETICKS:
case ASN_UNSIGNED32:
return FindLenUInt(pAny->asnValue.unsigned32);
case ASN_COUNTER64:
return FindLenCntr64(&pAny->asnValue.counter64);
}
return BERERR;
}
LONG
FindLenAsnAnyEx(
AsnAny * pAny
)
/*
Routine Description:
Find length of variable binding value (including type and lenlen).
Arguments:
pAny - pointer to variable binding value.
Return Values:
Returns BERERR if unsuccessful.
*/
{
// determine syntax
switch (pAny->asnType) {
case ASN_OCTETSTRING:
case ASN_IPADDRESS:
case ASN_OPAQUE:
return FindLenOctetsEx(&pAny->asnValue.string);
case ASN_OBJECTIDENTIFIER:
return FindLenOidEx(&pAny->asnValue.object);
case ASN_NULL:
case SNMP_EXCEPTION_NOSUCHOBJECT:
case SNMP_EXCEPTION_NOSUCHINSTANCE:
case SNMP_EXCEPTION_ENDOFMIBVIEW:
return (2);
case ASN_INTEGER32:
return FindLenIntEx(pAny->asnValue.number);
case ASN_COUNTER32:
case ASN_GAUGE32:
case ASN_TIMETICKS:
case ASN_UNSIGNED32:
return FindLenUIntEx(pAny->asnValue.unsigned32);
case ASN_COUNTER64:
return FindLenCntr64Ex(&pAny->asnValue.counter64);
}
return BERERR;
}
LONG
FindLenVarBind(
SnmpVarBind * pVb
)
/*
Routine Description:
Find length of variable binding.
Arguments:
pVb - pointer to variable binding.
Return Values:
Returns BERERR if unsuccessful.
*/
{
LONG lLenLen;
LONG lOidLen;
LONG lValueLen;
// determine length of name
lOidLen = FindLenOidEx(&pVb->name);
// determine length of value
lValueLen = FindLenAsnAnyEx(&pVb->value);
// return total size
return ((lOidLen != BERERR) &&
(lValueLen != BERERR))
? (lOidLen + lValueLen)
: BERERR
;
}
LONG
FindLenVarBindEx(
SnmpVarBind * pVb
)
/*
Routine Description:
Find length of variable binding (including type and lenlen).
Arguments:
pVb - pointer to variable binding.
Return Values:
Returns BERERR if unsuccessful.
*/
{
LONG lLenLen;
LONG lOidLen;
LONG lValueLen;
// determine length of name
lOidLen = FindLenOidEx(&pVb->name);
// determine length of value
lValueLen = FindLenAsnAnyEx(&pVb->value);
// determine length of varbind length
lLenLen = DoLenLen(lOidLen + lValueLen);
// return total size
return ((lLenLen != BERERR) &&
(lOidLen != BERERR) &&
(lValueLen != BERERR))
? (lOidLen + lValueLen + lLenLen + 1)
: BERERR
;
}
LONG
FindLenVarBindList(
SnmpVarBindList * pVbl
)
/*
Routine Description:
Find length of variable binding list.
Arguments:
pVbl - pointer to variable binding list.
Return Values:
Returns BERERR if unsuccessful.
*/
{
UINT i;
LONG lVbLen = 0;
LONG lVblLen = 0;
// process each variable binding in the list
for (i = 0; (lVbLen != BERERR) && (i < pVbl->len); i++) {
// determine length of variable binding
lVbLen = FindLenVarBindEx(&pVbl->list[i]);
// add to total
lVblLen += lVbLen;
}
// return total size
return (lVbLen != BERERR)
? lVblLen
: BERERR
;
}
LONG
FindLenVarBindListEx(
SnmpVarBindList * pVbl
)
/*
Routine Description:
Find length of variable binding list (including type and lenlen).
Arguments:
pVbl - pointer to variable binding list.
Return Values:
Returns BERERR if unsuccessful.
*/
{
UINT i;
LONG lVbLen = 0;
LONG lVblLen = 0;
LONG lLenLen;
// process each variable binding in the list
for (i = 0; (lVbLen != BERERR) && (i < pVbl->len); i++) {
// determine length of variable binding
lVbLen = FindLenVarBindEx(&pVbl->list[i]);
// add to total
lVblLen += lVbLen;
}
// determine list length
lLenLen = DoLenLen(lVblLen);
// return total size
return ((lVbLen != BERERR) &&
(lLenLen != BERERR))
? (lVblLen + lLenLen + 1)
: BERERR
;
}
VOID
AddNull(
LPBYTE * ppByte,
INT nType
)
/*
Routine Description:
Adds null into stream.
Arguments:
ppByte - pointer to pointer to current stream.
nType - exact syntax.
Return Values:
None.
*/
{
// encode actual syntax
*(*ppByte)++ = (BYTE)(0xFF & nType);
*(*ppByte)++ = 0x00;
}
VOID
AddLen(
LPBYTE * ppByte,
LONG lLenLen,
LONG lDataLen
)
/*
Routine Description:
Adds data length field to current stream.
Arguments:
ppByte - pointer to pointer to current stream.
lLenLen - length of data length.
lDataLen - actual data length.
Return Values:
None.
*/
{
LONG i;
if (lLenLen == 1) {
*(*ppByte)++ = (BYTE)lDataLen;
} else {
*(*ppByte)++ = (BYTE)(0x80 + lLenLen - 1);
for (i = 1; i < lLenLen; i++) {
*(*ppByte)++ = (BYTE)((lDataLen >>
(8 * (lLenLen - i - 1))) & 0xFF);
}
}
}
LONG
AddInt(
LPBYTE * ppByte,
INT nType,
AsnInteger32 nInteger32
)
/*
Routine Description:
Adds integer to current stream.
Arguments:
ppByte - pointer to pointer to current stream.
nType - exact syntax of integer.
nInteger32 - actual data.
Return Values:
Returns BERERR if unsuccessful.
*/
{
LONG i;
LONG lDataLen;
LONG lLenLen;
// determine length of integer
lDataLen = FindLenInt(nInteger32);
// lenlen
lLenLen = 1;
// encode nType of integer
*(*ppByte)++ = (BYTE)(0xFF & nType);
// encode length of integer
AddLen(ppByte, lLenLen, lDataLen);
// add encoded integer
for (i = 0; i < lDataLen; i++) {
*(*ppByte)++ = (BYTE)(nInteger32 >>
(8 * ((lDataLen - 1) - i) & 0xFF));
}
return (0);
}
LONG
AddUInt(
LPBYTE * ppByte,
INT nType,
AsnUnsigned32 nUnsigned32
)
/*
Routine Description:
Adds unsigned integer to current stream.
Arguments:
ppByte - pointer to pointer to current stream.
nType - exact syntax of integer.
nUnsigned32 - actual data.
Return Values:
Returns BERERR if unsuccessful.
*/
{
LONG i;
LONG lDataLen;
LONG lLenLen;
// determine length of integer
lDataLen = FindLenUInt(nUnsigned32);
// < 127 octets
lLenLen = 1;
// encode actual syntax
*(*ppByte)++ = (BYTE)(0xFF & nType);
// encode data length
AddLen(ppByte, lLenLen, lDataLen);
// analyze length
if (lDataLen == 5) {
// put 00 in first octet
*(*ppByte)++ = (BYTE)0;
// encode unsigned integer
for (i = 1; i < lDataLen; i++) {
*(*ppByte)++ = (BYTE)(nUnsigned32 >>
(8 * ((lDataLen - 1) - i) & 0xFF));
}
} else {
// encode unsigned integer
for (i = 0; i < lDataLen; i++) {
*(*ppByte)++ = (BYTE)(nUnsigned32 >>
(8 * ((lDataLen - 1) - i) & 0xFF));
}
}
return (0);
}
LONG
AddCntr64(
LPBYTE * ppByte,
INT nType,
AsnCounter64 * pCntr64
)
/*
Routine Description:
Adds 64-bit counter to current stream.
Arguments:
ppByte - pointer to pointer to current stream.
nType - exact syntax of counter.
pCntr64 - actual data.
Return Values:
Returns BERERR if unsuccessful.
*/
{
LONG i;
LONG lDataLen;
LONG lLenLen;
// determine length of counter64
lDataLen = FindLenCntr64(pCntr64);
// < 127 octets
lLenLen = 1;
// encode actual syntax
*(*ppByte)++ = (BYTE)(0xFF & nType);
// encode data length
AddLen(ppByte, lLenLen, lDataLen);
// adjust lDataLen
if (lDataLen == 9) {
// put 00 in first octet
*(*ppByte)++ = (BYTE)0;
lDataLen--;
}
// encode counter data
for (i = lDataLen; i > 4; i--) {
*(*ppByte)++ = (BYTE)(pCntr64->HighPart >>
(8 * (i - 5) & 0xFF));
}
for (; i > 0; i--) {
*(*ppByte)++ = (BYTE)(pCntr64->LowPart >>
(8 * (i - 1) & 0xFF));
}
return (0);
}
LONG
AddOctets(
LPBYTE * ppByte,
INT nType,
AsnOctetString * pOctets
)
/*
Routine Description:
Adds octet string to current stream.
Arguments:
ppByte - pointer to pointer to current stream.
nType - exact syntax of string.
pOctets - actual data.
Return Values:
Returns BERERR if unsuccessful.
*/
{
UINT i;
LONG lLenLen;
LONG lDataLen;
// determine oid length
if ((lDataLen = FindLenOctets(pOctets)) == BERERR)
return BERERR;
// calculate octet string length
if ((lLenLen = DoLenLen(lDataLen)) == BERERR)
return BERERR;
// encode actual syntax
*(*ppByte)++ = (BYTE)(0xFF & nType);
// encode octet string length
AddLen(ppByte, lLenLen, lDataLen);
// usless copy avoided
if (*ppByte != pOctets->stream)
{
// encode actual octets
for (i = 0; i < pOctets->length; i++)
*(*ppByte)++ = pOctets->stream[i];
}
else
{
(*ppByte) += pOctets->length;
}
return (0);
}
LONG
AddOid(
LPBYTE * ppByte,
INT nType,
AsnObjectIdentifier * pOid
)
/*
Routine Description:
Adds object identifier to current stream.
Arguments:
ppByte - pointer to pointer to current stream.
nType - exact syntax of object identifier.
pOid - pointer to object identifier.
Return Values:
Returns BERERR if unsuccessful.
*/
{
UINT i;
LONG lLenLen = 0;
LONG lDataLen;
// determine oid length
if ((lDataLen = FindLenOid(pOid)) == BERERR)
return BERERR;
// calculate number of bytes required for length
if ((lLenLen = DoLenLen(lDataLen)) == BERERR)
return BERERR;
// add syntax to stream
*(*ppByte)++ = (BYTE)(0xFF & nType);
// add object identifier length
AddLen(ppByte, lLenLen, lDataLen);
// add first subid
if (pOid->idLength < 2)
*(*ppByte)++ = (BYTE)(pOid->ids[0] * 40);
else
*(*ppByte)++ = (BYTE)((pOid->ids[0] * 40) + pOid->ids[1]);
// walk remaining subidentifiers
for (i = 2; i < pOid->idLength; i++) {
if (pOid->ids[i] < 0x80) {
// 0 - 0x7f
*(*ppByte)++ = (BYTE)pOid->ids[i];
} else if (pOid->ids[i] < 0x4000) {
// 0x80 - 0x3fff
*(*ppByte)++ = (BYTE)
(((pOid->ids[i]) >> 7) | 0x80); // set high bit
*(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
} else if (pOid->ids[i] < 0x200000) {
// 0x4000 - 0x1FFFFF
*(*ppByte)++ = (BYTE)
(((pOid->ids[i]) >> 14) | 0x80); // set high bit
*(*ppByte)++ = (BYTE)
(((pOid->ids[i]) >> 7) | 0x80); // set high bit
*(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
} else if (pOid->ids[i] < 0x10000000) {
// 0x200000 - 0xFFfffff
*(*ppByte)++ = (BYTE)
(((pOid->ids[i]) >> 21) | 0x80); // set high bit
*(*ppByte)++ = (BYTE)
(((pOid->ids[i]) >> 14) | 0x80); // set high bit
*(*ppByte)++ = (BYTE)
(((pOid->ids[i]) >> 7) | 0x80); // set high bit
*(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
} else {
*(*ppByte)++ = (BYTE)
(((pOid->ids[i]) >> 28) | 0x80); // set high bit
*(*ppByte)++ = (BYTE)
(((pOid->ids[i]) >> 21) | 0x80); // set high bit
*(*ppByte)++ = (BYTE)
(((pOid->ids[i]) >> 14) | 0x80); // set high bit
*(*ppByte)++ = (BYTE)
(((pOid->ids[i]) >> 7) | 0x80); // set high bit
*(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
}
}
return (0);
}
LONG
AddAsnAny(
LPBYTE * ppByte,
AsnAny * pAny
)
/*
Routine Description:
Adds variable binding value to current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pAny - variable binding value.
Return Values:
Returns BERERR if unsuccessful.
*/
{
// determine syntax
switch (pAny->asnType) {
case ASN_COUNTER32:
case ASN_GAUGE32:
case ASN_TIMETICKS:
case ASN_UNSIGNED32:
return AddUInt(
ppByte,
(INT)pAny->asnType,
pAny->asnValue.unsigned32
);
case ASN_INTEGER32:
return AddInt(
ppByte,
(INT)pAny->asnType,
pAny->asnValue.number
);
case ASN_OBJECTIDENTIFIER:
return AddOid(
ppByte,
(INT)pAny->asnType,
&pAny->asnValue.object
);
case ASN_COUNTER64:
return AddCntr64(
ppByte,
(INT)pAny->asnType,
&pAny->asnValue.counter64
);
case ASN_OCTETSTRING:
case ASN_IPADDRESS:
case ASN_OPAQUE:
return AddOctets(
ppByte,
(INT)pAny->asnType,
&pAny->asnValue.string
);
case ASN_NULL:
case SNMP_EXCEPTION_NOSUCHOBJECT:
case SNMP_EXCEPTION_NOSUCHINSTANCE:
case SNMP_EXCEPTION_ENDOFMIBVIEW:
AddNull(ppByte, (INT)pAny->asnType);
return (0);
}
return BERERR;
}
LONG
AddVarBind(
LPBYTE * ppByte,
SnmpVarBind * pVb
)
/*
Routine Description:
Adds variable binding to current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pVb - pointer to variable binding.
Return Values:
Returns BERERR if unsuccessful.
*/
{
LONG lLenLen;
LONG lDataLen;
// determine actual length of varbind data
if ((lDataLen = FindLenVarBind(pVb)) == BERERR)
return BERERR;
// determine length of varbind data length
if ((lLenLen = DoLenLen(lDataLen)) == BERERR)
return BERERR;
// encode as sequence
*(*ppByte)++ = ASN_SEQUENCE;
// encode data length
AddLen(ppByte, lLenLen, lDataLen);
// encode variable binding name
if (AddOid(ppByte, ASN_OBJECTIDENTIFIER, &pVb->name) == BERERR)
return BERERR;
// encode variable binding value
if (AddAsnAny(ppByte, &pVb->value) == BERERR)
return BERERR;
return (0);
}
LONG
AddVarBindList(
LPBYTE * ppByte,
SnmpVarBindList * pVbl
)
/*
Routine Description:
Adds variable binding list to current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pVbl - pointer to variable binding list.
Return Values:
Returns BERERR if unsuccessful.
*/
{
UINT i;
// add each variable binding
for (i = 0; i < pVbl->len; i++) {
if (AddVarBind(ppByte, &pVbl->list[i]) == BERERR)
return BERERR;
}
return (0);
}
LONG
ParseLength(
LPBYTE * ppByte,
LPBYTE pLastByte
)
/*
Routine Description:
Parse length from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
Return Values:
Returns BERERR if unsuccessful.
*/
{
LONG i;
LONG lLenLen;
LONG lDataLen;
if (*ppByte >= pLastByte)
return BERERR;
lDataLen = (LONG)*(*ppByte)++;
if (lDataLen < 0x80)
return (lDataLen);
// check for long form
lLenLen = lDataLen & 0x7f;
// validate long form and bounds checking
if ((lLenLen > 4) || (lLenLen < 1) || (lLenLen > (pLastByte - (*ppByte))))
return BERERR;
lDataLen = 0L;
for (i = 0; i < lLenLen; i++) {
lDataLen = (lDataLen << 8) + *(*ppByte)++;
}
return (lDataLen);
}
LONG
ParseType(
LPBYTE * ppByte,
LPBYTE pLastByte
)
/*
Routine Description:
Parse type from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
Return Values:
Returns BERERR if unsuccessful.
*/
{
SHORT nType = BERERR;
if (*ppByte >= pLastByte)
return BERERR;
nType = *(*ppByte)++;
switch (nType) {
case ASN_INTEGER32:
case ASN_OCTETSTRING:
case ASN_OBJECTIDENTIFIER:
case ASN_SEQUENCE:
case ASN_IPADDRESS:
case ASN_COUNTER32:
case ASN_GAUGE32:
case ASN_TIMETICKS:
case ASN_OPAQUE:
case ASN_UNSIGNED32:
case ASN_COUNTER64:
case ASN_NULL:
case SNMP_EXCEPTION_NOSUCHOBJECT:
case SNMP_EXCEPTION_NOSUCHINSTANCE:
case SNMP_EXCEPTION_ENDOFMIBVIEW:
case SNMP_PDU_GET:
case SNMP_PDU_GETNEXT:
case SNMP_PDU_RESPONSE:
case SNMP_PDU_SET:
case SNMP_PDU_V1TRAP:
case SNMP_PDU_GETBULK:
case SNMP_PDU_INFORM:
case SNMP_PDU_TRAP:
break;
default:
nType = BERERR;
break;
}
return (LONG)(SHORT)(nType);
}
BOOL
ParseNull(
LPBYTE * ppByte,
LPBYTE pLastByte
)
/*
Routine Description:
Parse null from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
Return Values:
Returns FALSE if unsuccessful.
*/
{
LONG lDataLen;
if (ParseType(ppByte, pLastByte) == BERERR)
return (FALSE);
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
return (FALSE);
if (lDataLen != 0)
return (FALSE);
return (TRUE);
}
BOOL
ParseSequence(
LPBYTE * ppByte,
LPBYTE pLastByte,
LONG * plDataLen
)
/*
Routine Description:
Parse sequence from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
plDataLen - pointer to receive sequence length.
Return Values:
Returns FALSE if unsuccessful.
*/
{
LONG lDataLen;
if ((ParseType(ppByte, pLastByte)) != ASN_SEQUENCE)
return (FALSE);
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
return (FALSE);
if (plDataLen)
*plDataLen = lDataLen;
return (TRUE);
}
BOOL
ParseInt(
LPBYTE * ppByte,
LPBYTE pLastByte,
AsnInteger32 * pInteger32
)
/*
Routine Description:
Parse integer from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
pInteger32 - pointer to receive integer.
Return Values:
Returns FALSE if unsuccessful.
*/
{
LONG i;
LONG lSign;
LONG lDataLen;
if (ParseType(ppByte, pLastByte) == BERERR)
return (FALSE);
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
return (FALSE);
if ((lDataLen <= 0) || (lDataLen > (pLastByte - (*ppByte))))
return (FALSE);
if (lDataLen > 4)
return (FALSE);
lSign = ((*(*ppByte) & 0x80) == 0x00) ? 0x00 : 0xFF;
*pInteger32 = 0;
for (i = 0; i < lDataLen; i++)
*pInteger32 = (*pInteger32 << 8) + (UINT)*(*ppByte)++;
// sign-extend upper bits
for (i = lDataLen; i < 4; i++)
*pInteger32 = *pInteger32 + (lSign << i * 8);
return (TRUE);
}
BOOL
ParseUInt(
LPBYTE * ppByte,
LPBYTE pLastByte,
AsnUnsigned32 * pUnsigned32
)
/*
Routine Description:
Parse unsigned integer from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
pUnsigned32 - pointer to receive integer.
Return Values:
Returns FALSE if unsuccessful.
*/
{
LONG i;
LONG lDataLen;
if (ParseType(ppByte, pLastByte) == BERERR)
return (FALSE);
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
return (FALSE);
if ((lDataLen <= 0) || (lDataLen > (pLastByte - (*ppByte))))
return (FALSE);
if ((lDataLen > 5) || ((lDataLen > 4) && (*(*ppByte) != 0x00)))
return (FALSE);
// leading null octet?
if (*(*ppByte) == 0x00) {
(*ppByte)++; // if so, skip it
lDataLen--; // and don't count it
}
*pUnsigned32 = 0;
for (i = 0; i < lDataLen; i++)
*pUnsigned32 = (*pUnsigned32 << 8) + (UINT)*(*ppByte)++;
return (TRUE);
}
BOOL
ParseCntr64(
LPBYTE * ppByte,
LPBYTE pLastByte,
AsnCounter64 * pCntr64
)
/*
Routine Description:
Parse 64-bit counter from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
pCntr64 - pointer to receive counter.
Return Values:
Returns FALSE if unsuccessful.
*/
{
LONG i;
LONG lDataLen;
LONG nType;
// initialize
pCntr64->HighPart = 0L;
pCntr64->LowPart = 0L;
if ((nType = ParseType(ppByte, pLastByte)) == BERERR)
return (FALSE);
if (nType != ASN_COUNTER64)
return (FALSE);
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
return (FALSE);
if ((lDataLen <= 0) || (lDataLen > (pLastByte - (*ppByte))))
return (FALSE);
if ((lDataLen > 9) || ((lDataLen > 8) && (*(*ppByte) != 0x00)))
return (FALSE);
// leading null octet?
if (*(*ppByte) == 0x00) {
(*ppByte)++; // if so, skip it
lDataLen--; // and don't count it
}
for (i = 0; i < lDataLen; i++) {
pCntr64->HighPart = (pCntr64->HighPart << 8) +
(pCntr64->LowPart >> 24);
pCntr64->LowPart = (pCntr64->LowPart << 8) +
(unsigned long) *(*ppByte)++;
}
return TRUE;
}
BOOL
ParseOctets(
LPBYTE * ppByte,
LPBYTE pLastByte,
AsnOctetString * pOctets
)
/*
Routine Description:
Parse octet string from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
pOctets - pointer to receive string.
Return Values:
Returns FALSE if unsuccessful.
*/
{
LONG lDataLen;
// initialize
pOctets->length = 0;
pOctets->stream = NULL;
pOctets->dynamic = FALSE;
if (ParseType(ppByte, pLastByte) == BERERR)
return (FALSE);
// make sure no conversion to UINT is done before testing
// (pOctets->length is UINT)
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
return (FALSE);
// note: we don't reject zero length Octet String
if ((lDataLen < 0) || (lDataLen > (pLastByte - (*ppByte))))
return (FALSE);
pOctets->length = (UINT)lDataLen;
// validate length
if (pOctets->length) {
// point into buffer
pOctets->stream = *ppByte; // WARNING! WARNING!
}
*ppByte += pOctets->length;
return (TRUE);
}
BOOL
ParseOid(
LPBYTE * ppByte,
LPBYTE pLastByte,
AsnObjectIdentifier * pOid
)
/*
Routine Description:
Parse object identifier from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
pOid - pointer to receive oid.
Return Values:
Returns FALSE if unsuccessful.
*/
{
LONG i;
LONG lDataLen;
LONG nType;
// initialize
pOid->idLength = 0;
pOid->ids = NULL;
if ((nType = ParseType(ppByte, pLastByte)) == BERERR)
return (FALSE);
if (nType != ASN_OBJECTIDENTIFIER)
return (FALSE);
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
return (FALSE);
if (lDataLen <= 0) //--ft 03/02/98 removed trailing "|| lDataLen > SNMP_MAX_OID_LEN)"
{ // check is done in the while loop below
SNMPDBG((
SNMP_LOG_ERROR,
"SNMP: SVC: ParseOid: lDataLen <= 0, lDataLen=%d.\n",
lDataLen
));
return (FALSE);
}
// BUG# 486089
// the ((lDataLen + 2) * sizeof(UINT)) expression might cause overflow in
// SnmpUtilMemAlloc below. adding one more check to limit its max. value.
if ( lDataLen > (pLastByte - (*ppByte)) )
{
SNMPDBG((
SNMP_LOG_ERROR,
"SNMP: SVC: ParseOid: invalid lDataLen=%d, pLastByte=%p, *ppByte=%p.\n",
lDataLen, pLastByte, *ppByte
));
return (FALSE);
}
pOid->ids = SnmpUtilMemAlloc((DWORD)((lDataLen + 2) * sizeof(UINT)));
if (pOid->ids == NULL)
return (FALSE);
// pOid->ids array space is pre-zero'd via SnmpUtilMemAlloc()
while (lDataLen && (pOid->idLength < SNMP_MAX_OID_LEN))
{
if (pOid->ids[pOid->idLength] & 0xFE000000)
{
// overflow in the next left shift
SnmpUtilMemFree(pOid->ids);
pOid->ids = NULL;
pOid->idLength = 0;
return (FALSE);
}
pOid->ids[pOid->idLength] =
(pOid->ids[pOid->idLength] << 7) | (*(*ppByte) & 0x7F);
if ((*(*ppByte)++ & 0x80) == 0)
{ // on the last octet of this sub-id
if (pOid->idLength == 0) // check for first sub-id
{ // ASN.1/BER packs two into it
pOid->ids[1] = pOid->ids[0];
pOid->ids[0] /= 40;
if (pOid->ids[0] > 2)
pOid->ids[0] = 2;
pOid->ids[1] -= (pOid->ids[0] * 40);
pOid->idLength++; // extra bump
}
pOid->idLength++; // increment the count on sub-id
}
lDataLen--;
} // end_while (lDataLen)
// BUG 506192
// Invalid OID BER of the form like "06 07 FF FF FF FF FF FF FF"
// causes pOid->idLength becomes 0. Each subidentifier should be
// encoded as a non-negative integer using as few 7-bit blocks as possible.
// The blocks are packed in octets with the first bit of each octet equal
// to 1 except for the last octet of each subidentifier. The example above
// does not have the last octet. Added the (0 == pOid->idLength) test below.
if (lDataLen || (0 == pOid->idLength))
{
// the above while loop is terminated without finishing the parsing of the stream
SnmpUtilMemFree(pOid->ids);
pOid->ids = NULL;
pOid->idLength = 0;
return (FALSE);
}
return (TRUE);
}
BOOL
ParseAsnAny(
LPBYTE * ppByte,
LPBYTE pLastByte,
AsnAny * pAny
)
/*
Routine Description:
Parse variable binding value from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
pAny - pointer to variable binding value.
Return Values:
Returns FALSE if unsuccessful.
*/
{
// determine asn type
switch (pAny->asnType) {
case ASN_COUNTER32:
case ASN_GAUGE32:
case ASN_TIMETICKS:
case ASN_UNSIGNED32:
return ParseUInt(
ppByte,
pLastByte,
&pAny->asnValue.unsigned32
);
case ASN_INTEGER32:
return ParseInt(
ppByte,
pLastByte,
&pAny->asnValue.number
);
case ASN_OBJECTIDENTIFIER:
return ParseOid(
ppByte,
pLastByte,
&pAny->asnValue.object
);
case ASN_COUNTER64:
return ParseCntr64(
ppByte,
pLastByte,
&pAny->asnValue.counter64
);
case ASN_OCTETSTRING:
case ASN_IPADDRESS:
case ASN_OPAQUE:
return ParseOctets(
ppByte,
pLastByte,
&pAny->asnValue.string
);
case ASN_NULL:
case SNMP_EXCEPTION_NOSUCHOBJECT:
case SNMP_EXCEPTION_NOSUCHINSTANCE:
case SNMP_EXCEPTION_ENDOFMIBVIEW:
return ParseNull(ppByte, pLastByte);
}
return (FALSE);
}
BOOL
ValidateContext(
PNETWORK_LIST_ENTRY pNLE
)
/*++
Routine Description:
Checks access rights of given context.
Arguments:
pNLE - pointer to network list entry.
Return Values:
Returns true if manager allowed access.
Also, pNLE->fAccessOk is TRUE if manager allowed access.
--*/
{
PCOMMUNITY_LIST_ENTRY pCLE = NULL;
AsnOctetString unicodeCommunity;
LPWSTR pUnicodeName;
pNLE->fAccessOk = TRUE;
if (pNLE->Community.length != 0)
{
unicodeCommunity.length = pNLE->Community.length * sizeof(WCHAR);
unicodeCommunity.stream = SnmpUtilMemAlloc(unicodeCommunity.length);
unicodeCommunity.dynamic = TRUE;
if (unicodeCommunity.stream == NULL) {
SNMPDBG((
SNMP_LOG_ERROR,
"SNMP: SVC: ValidateContext: SnmpUtilMemAlloc failed to allocate %u bytes.\n",
unicodeCommunity.length
));
pNLE->fAccessOk = FALSE;
return pNLE->fAccessOk;
}
pNLE->fAccessOk = (MultiByteToWideChar(
CP_ACP,
MB_PRECOMPOSED,
pNLE->Community.stream, // lpMultiByteStr
pNLE->Community.length, // cbMultiByte
(LPWSTR)(unicodeCommunity.stream), // lpWideCharStr
pNLE->Community.length) != 0); // cchWideChar
if (!pNLE->fAccessOk) {
SNMPDBG((
SNMP_LOG_ERROR,
"SNMP: SVC: ValidateContext: MultiByteToWideChar returns 0 for request from community %s.\n",
CommunityOctetsToString(&(pNLE->Community), FALSE)
));
goto Error;
}
}
else
{
unicodeCommunity.length = 0;
unicodeCommunity.stream = NULL;
unicodeCommunity.dynamic = FALSE;
}
// search for community string
if (FindValidCommunity(&pCLE, &unicodeCommunity))
{
// check access per pdu type
if (pNLE->Pdu.nType == SNMP_PDU_SET) {
// check flags for write privileges
pNLE->fAccessOk = (pCLE->dwAccess >= SNMP_ACCESS_READ_WRITE);
} else {
// check flags for read privileges
pNLE->fAccessOk = (pCLE->dwAccess >= SNMP_ACCESS_READ_ONLY);
}
if (!pNLE->fAccessOk) {
// Community does not have the right access
// register wrong operation for specified community into management structure
mgmtCTick(CsnmpInBadCommunityUses);
}
}
else
{
pNLE->fAccessOk = FALSE;
// register community name failure into the management structure
mgmtCTick(CsnmpInBadCommunityNames);
}
// see if access attempt should be logged
if (!pNLE->fAccessOk && snmpMgmtBase.AsnIntegerPool[IsnmpEnableAuthenTraps].asnValue.number) {
// send authentication trap
GenerateAuthenticationTrap();
}
Error:
SNMPDBG((
SNMP_LOG_TRACE,
"SNMP: SVC: %s request from community %s.\n",
pNLE->fAccessOk
? "accepting"
: "rejecting"
,
CommunityOctetsToString(&(pNLE->Community), FALSE)
));
SnmpUtilOctetsFree(&unicodeCommunity);
return (pNLE->fAccessOk);
}
BOOL
ParseVarBind(
LPBYTE * ppByte,
LPBYTE pLastByte,
SnmpVarBind * pVb
)
/*
Routine Description:
Parse variable binding from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
pVb - pointer to variable binding.
Return Values:
Returns FALSE if unsuccessful.
*/
{
if (!(ParseSequence(ppByte, pLastByte, NULL)))
return (FALSE);
if (!(ParseOid(ppByte, pLastByte, &pVb->name)))
return (FALSE);
if (*ppByte >= pLastByte)
{
// free memory allocated by ParseOid
SnmpUtilOidFree(&pVb->name);
return (FALSE);
}
pVb->value.asnType = (UINT)*(*ppByte);
if (!(ParseAsnAny(ppByte, pLastByte, &pVb->value)))
{
// free memory allocated by ParseOid
SnmpUtilOidFree(&pVb->name);
return (FALSE);
}
return TRUE;
}
BOOL
ParseVarBindList(
LPBYTE * ppByte,
LPBYTE pLastByte,
SnmpVarBindList * pVbl
)
/*
Routine Description:
Parse variable binding from current stream.
Arguments:
ppByte - pointer to pointer to current stream.
pLastByte - pointer to end of current stream.
pVbl - pointer to variable binding list.
Return Values:
Returns FALSE if unsuccessful.
*/
{
SnmpVarBind Vb;
SnmpVarBind * pVb = NULL;
// initialize
pVbl->list = NULL;
pVbl->len = 0;
// loop while data is left
while (*ppByte < pLastByte) {
if (!(ParseVarBind(ppByte, pLastByte, &Vb)))
return (FALSE);
// copy pointer
pVb = pVbl->list;
// attempt to allocate new variable binding
pVb = SnmpUtilMemReAlloc(pVb, (pVbl->len + 1) * sizeof(SnmpVarBind));
// validate
if (pVb == NULL)
{
SnmpUtilVarBindFree(&Vb);
return FALSE;
}
// update varbind
pVb[pVbl->len] = Vb;
// update list
pVbl->list = pVb;
pVbl->len++;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
// //
// Public procedures (based on snmp\manager\winsnmp\dll\wsnmp_bn.c) //
// //
///////////////////////////////////////////////////////////////////////////////
BOOL
BuildMessage(
AsnInteger32 nVersion,
AsnOctetString * pCommunity,
PSNMP_PDU pPdu,
PBYTE pMessage,
PDWORD pMessageSize
)
/*
Routine Description:
Builds outgoing SNMP PDU based on structure.
Arguments:
nVersion - SNMP version.
pCommunity - pointer to community string.
pPdu - pointer to PDU data structure.
pMessage - pointer to buffer in which to build message.
pMessageSize - pointer to receive size of message.
Return Values:
Returns true if successful.
*/
{
LONG nVbDataLength;
LONG nVbLenLength;
LONG nVbTotalLength;
LONG nPduDataLength;
LONG nPduLenLength;
LONG nPduTotalLength;
LONG nMsgDataLength;
LONG nMsgLenLength;
LONG nMsgTotalLength;
LONG nMsgAvailLength;
LONG nTmpDataLength;
LPBYTE tmpPtr = pMessage;
// determine bytes available
nMsgAvailLength = *pMessageSize;
// find length of variable bindings list
if ((nVbDataLength = FindLenVarBindList(&pPdu->Vbl)) == BERERR)
return FALSE;
// find length of length of variable bindings
if ((nVbLenLength = DoLenLen(nVbDataLength)) == BERERR)
return FALSE;
// calculate total bytes required to encode varbinds
nVbTotalLength = 1 + nVbLenLength + nVbDataLength;
// determine pdu nType
switch (pPdu->nType) {
case SNMP_PDU_GET:
case SNMP_PDU_GETNEXT:
case SNMP_PDU_RESPONSE:
case SNMP_PDU_SET:
case SNMP_PDU_GETBULK:
case SNMP_PDU_INFORM:
case SNMP_PDU_TRAP:
// calculate bytes required to encode pdu entries
nPduDataLength = FindLenIntEx(pPdu->Pdu.NormPdu.nRequestId)
+ FindLenIntEx(pPdu->Pdu.NormPdu.nErrorStatus)
+ FindLenIntEx(pPdu->Pdu.NormPdu.nErrorIndex)
+ nVbTotalLength;
break;
case SNMP_PDU_V1TRAP:
// calculate bytes required to encode pdu entries
nPduDataLength = FindLenIntEx(pPdu->Pdu.TrapPdu.nGenericTrap)
+ FindLenIntEx(pPdu->Pdu.TrapPdu.nSpecificTrap)
+ FindLenUIntEx(pPdu->Pdu.TrapPdu.nTimeticks)
+ nVbTotalLength;
// find oid length
if ((nTmpDataLength =
FindLenOidEx(&pPdu->Pdu.TrapPdu.EnterpriseOid)) == BERERR)
return FALSE;
// add EnterpriseOid oid length
nPduDataLength += nTmpDataLength;
// find address length
if ((nTmpDataLength =
FindLenOctetsEx(&pPdu->Pdu.TrapPdu.AgentAddr)) == BERERR)
return FALSE;
// add agent address length
nPduDataLength += nTmpDataLength;
break;
default:
return FALSE;
}
// find length of pdu length
if ((nPduLenLength = DoLenLen(nPduDataLength)) == BERERR)
return FALSE;
// calculate total bytes required to encode pdu
nPduTotalLength = 1 + nPduLenLength + nPduDataLength;
// find community string length
if ((nTmpDataLength = FindLenOctetsEx(pCommunity)) == BERERR)
return FALSE;
// find length of message data
nMsgDataLength = FindLenUIntEx(nVersion)
+ nTmpDataLength
+ nPduTotalLength;
// find length of message data length
if ((nTmpDataLength = DoLenLen(nMsgDataLength)) == BERERR)
return FALSE;
nMsgLenLength = nTmpDataLength;
// calculate total bytes required to encode message
nMsgTotalLength = 1 + nMsgLenLength + nMsgDataLength;
// record bytes required
*pMessageSize = nMsgTotalLength;
// make sure message fits in buffer
if (nMsgTotalLength <= nMsgAvailLength) {
LONG oldLength; // the length of the request PDU
LONG delta; // difference between the request PDU length and the responce PDU length
BYTE *newStream;// new location for the community stream inside the response PDU.
// encode message as asn sequence
*tmpPtr++ = ASN_SEQUENCE;
// the pointer to the community string points either directly in the incoming buffer
// (for req PDUs) or in the TRAP_DESTINATION_LIST_ENTRY for the outgoing traps.
// In the first case, when building the outgoing message on the same buffer as the
// incoming message, we need to take care not to overwrite the community name (in case
// the length field is larger than for the initial message). Hence, in this case only
// we shift the community name with a few octets, as many as the difference between the
// encodings of the two lengths (the length of the outgoing response - the length of the
// incoming request).
if (pPdu->nType != SNMP_PDU_V1TRAP)
{
// here tmpPtr points exactly to the length of the request pdu
oldLength = (LONG)(*tmpPtr); // bug# 176433
// compute the offset the community stream should be shifted with
delta = nMsgLenLength - ((oldLength & 0x80) ? (oldLength & 0x7f) + 1 : 1);
if (delta > 0)
{ // move memory in case the response nMsgLenLength > oldLength
newStream = pCommunity->stream + delta;
// pCommunity->stream is shifted regardles memory regions overlapp
memmove(newStream, pCommunity->stream, pCommunity->length);
// make old community to point to the new location
pCommunity->stream = newStream;
}
}
// encode global message information
AddLen(&tmpPtr, nMsgLenLength, nMsgDataLength);
AddUInt(&tmpPtr, ASN_INTEGER32, nVersion);
if (AddOctets(&tmpPtr, ASN_OCTETSTRING, pCommunity) == BERERR)
return (FALSE);
// encode pdu header information
*tmpPtr++ = (BYTE)pPdu->nType;
AddLen(&tmpPtr, nPduLenLength, nPduDataLength);
// determine pdu nType
switch (pPdu->nType) {
case SNMP_PDU_RESPONSE:
case SNMP_PDU_TRAP:
AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.NormPdu.nRequestId);
AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.NormPdu.nErrorStatus);
AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.NormPdu.nErrorIndex);
break;
case SNMP_PDU_V1TRAP:
if (AddOid(
&tmpPtr,
ASN_OBJECTIDENTIFIER,
&pPdu->Pdu.TrapPdu.EnterpriseOid)== BERERR)
return FALSE;
if (AddOctets(
&tmpPtr,
ASN_IPADDRESS,
&pPdu->Pdu.TrapPdu.AgentAddr) == BERERR)
return FALSE;
AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.TrapPdu.nGenericTrap);
AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.TrapPdu.nSpecificTrap);
AddUInt(&tmpPtr, ASN_TIMETICKS, pPdu->Pdu.TrapPdu.nTimeticks);
break;
case SNMP_PDU_GET:
case SNMP_PDU_GETNEXT:
case SNMP_PDU_SET:
case SNMP_PDU_INFORM:
case SNMP_PDU_GETBULK:
default:
return FALSE;
}
// encode variable bindings
*tmpPtr++ = ASN_SEQUENCE;
AddLen(&tmpPtr, nVbLenLength, nVbDataLength);
if (AddVarBindList(&tmpPtr, &pPdu->Vbl) == BERERR)
return FALSE;
// success
return TRUE;
}
// failure
return FALSE;
}
BOOL
ParseMessage(
PNETWORK_LIST_ENTRY pNLE
)
/*
Routine Description:
Parses incoming SNMP PDU into structure.
Arguments:
pNLE - pointer to network list entry.
Return Values:
Returns true if successful.
Note:
When TRUE is returned, pNLE->nVersion, pNLE->Community, pNLE->Pdu are
updated with structure data parsed from pNLE->Buffer.buf.
When FALSE is returned AND pNLE->fAccessOk is FALSE, the failure is due to
authentication instead of ASN parsing errors.
*/
{
LONG lLength;
LPBYTE pByte;
LPBYTE pLastByte;
AsnInteger32 * pVersion = &pNLE->nVersion; // pointer to receive SNMP version.
AsnOctetString * pCommunity = &pNLE->Community; // pointer to receive community string.
PSNMP_PDU pPdu = &pNLE->Pdu; // pointer to receive remaining PDU data.
PBYTE pMessage = pNLE->Buffer.buf; // pointer to message to parse.
DWORD dwMessageSize = pNLE->dwBytesTransferred; // number of bytes in message.
// initialize authentication to a successful state
pNLE->fAccessOk = TRUE;
// initialize community
pCommunity->stream = NULL;
pCommunity->length = 0;
// initialize vbl
pPdu->Vbl.len = 0;
pPdu->Vbl.list = NULL;
// validate pointer
if (!(pByte = pMessage))
goto cleanup;
// set limit based on packet size
pLastByte = pByte + dwMessageSize;
// decode asn sequence message wrapper
if (!(ParseSequence(&pByte, pLastByte, &lLength)))
goto cleanup;
// check for packet fragments
if ( (lLength <= 0) || (lLength > (pLastByte - pByte)) )
goto cleanup;
// re-adjust based on data
pLastByte = pByte + lLength;
// decode snmp version
if (!(ParseUInt(&pByte, pLastByte, pVersion)))
goto cleanup;
// validate snmp version
if ((*pVersion != SNMP_VERSION_1) &&
(*pVersion != SNMP_VERSION_2C))
{
// register version mismatch into the management structure
mgmtCTick(CsnmpInBadVersions);
goto cleanup;
}
// decode community string
if (!(ParseOctets(&pByte, pLastByte, pCommunity)))
goto cleanup;
// decode nType of incoming pdu
if ((pPdu->nType = ParseType(&pByte, pLastByte)) == BERERR)
goto cleanup;
// decode length of incoming pdu
if ((lLength = ParseLength(&pByte, pLastByte)) == BERERR)
goto cleanup;
// validate length
if ( (lLength <= 0) || (lLength > (pLastByte - pByte)) )
goto cleanup;
// BUG# 552295 validate context before parsing the PDU
switch (pPdu->nType) {
case SNMP_PDU_GET:
case SNMP_PDU_GETNEXT:
case SNMP_PDU_SET:
case SNMP_PDU_GETBULK:
if (!ValidateContext(pNLE)) {
goto cleanup;
}
break;
case SNMP_PDU_INFORM:
case SNMP_PDU_RESPONSE:
case SNMP_PDU_TRAP:
case SNMP_PDU_V1TRAP:
default:
goto cleanup;
}
// determine pdu nType
switch (pPdu->nType) {
case SNMP_PDU_GET:
case SNMP_PDU_GETNEXT:
case SNMP_PDU_SET:
// decode the pdu header information
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.NormPdu.nRequestId)))
goto cleanup;
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.NormPdu.nErrorStatus)))
goto cleanup;
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.NormPdu.nErrorIndex)))
goto cleanup;
// update the management counters for the incoming errorStatus coding
mgmtUtilUpdateErrStatus(IN_errStatus, pPdu->Pdu.NormPdu.nErrorStatus);
// no reason here to have any ErrorStatus and ErrorIndex.
// initialize error status variables to NOERROR
pPdu->Pdu.NormPdu.nErrorStatus = SNMP_ERRORSTATUS_NOERROR;
pPdu->Pdu.NormPdu.nErrorIndex = 0;
break;
case SNMP_PDU_GETBULK:
// decode the getbulk pdu header information
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.BulkPdu.nRequestId)))
goto cleanup;
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.BulkPdu.nNonRepeaters)))
goto cleanup;
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.BulkPdu.nMaxRepetitions)))
goto cleanup;
// see if value needs to be adjusted
if (pPdu->Pdu.BulkPdu.nNonRepeaters < 0) {
// adjust non-repeaters to zero
pPdu->Pdu.BulkPdu.nNonRepeaters = 0;
}
// see if value needs to be adjusted
if (pPdu->Pdu.BulkPdu.nMaxRepetitions < 0) {
// adjust max-repetitions to zero
pPdu->Pdu.BulkPdu.nMaxRepetitions = 0;
}
// initialize status information
pPdu->Pdu.BulkPdu.nErrorStatus = SNMP_ERRORSTATUS_NOERROR;
pPdu->Pdu.BulkPdu.nErrorIndex = 0;
break;
case SNMP_PDU_INFORM:
case SNMP_PDU_RESPONSE:
case SNMP_PDU_TRAP:
case SNMP_PDU_V1TRAP:
default:
goto cleanup;
}
// parse over sequence
if (!(ParseSequence(&pByte, pLastByte, NULL)))
goto cleanup;
// parse variable binding list
if (!(ParseVarBindList(&pByte, pLastByte, &pPdu->Vbl)))
goto cleanup;
// success
return TRUE;
cleanup:
// cleanup community string
SnmpUtilOctetsFree(pCommunity);
// cleanup any allocated varbinds
SnmpUtilVarBindListFree(&pPdu->Vbl);
// failure
return FALSE;
}