|
|
/*
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; }
|