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.
1270 lines
36 KiB
1270 lines
36 KiB
// wsnmp_bn.c
|
|
//
|
|
// WinSNMP Low-Level SNMP/ASN.1/BER Functions and helpers
|
|
// Copyright 1995-1997 ACE*COMM Corp
|
|
// Rleased to Microsoft under Contract
|
|
// Beta 1 version, 970228
|
|
// Bob Natale ([email protected])
|
|
//
|
|
// 980424 - Received msgLen may be larger than pduLen
|
|
// - ParsePduHdr() and ParseMessage() now accommodate this.
|
|
// 980420 - Mods related to ParseCntr64() inspired by
|
|
// MS bug ID 127357 (removal of temp64 variable)
|
|
// - Mod to ParseOID() for MS bug ID 127353
|
|
// (reset os_ptr->ptr to NULL on error)
|
|
//
|
|
// 970310 - Typographical changes
|
|
//
|
|
#include "winsnmp.inc"
|
|
|
|
long FindLenVarBind (LPVARBIND vb_ptr);
|
|
long FindLenVALUE (smiLPVALUE);
|
|
long FindLenOctetString (smiLPOCTETS os_ptr);
|
|
long FindLenOID (smiLPCOID oid_ptr);
|
|
long FindLenUInt (smiUINT32 value);
|
|
long FindLenInt (smiINT32 value);
|
|
long FindLenCntr64 (smiLPCNTR64 value);
|
|
long DoLenLen (smiINT32 len);
|
|
void AddLen (smiLPBYTE *tmpPtr, smiINT32 lenlen, smiINT32 data_len);
|
|
long AddVarBind (smiLPBYTE *tmpPtr, LPVARBIND vb_ptr);
|
|
long AddOctetString (smiLPBYTE *tmpPtr, int type, smiLPOCTETS os_ptr);
|
|
long AddOID (smiLPBYTE *tmpPtr, smiLPOID oid_ptr);
|
|
long AddUInt (smiLPBYTE *tmpPtr, int type, smiUINT32 value);
|
|
long AddInt (smiLPBYTE *tmpPtr, smiINT32 value);
|
|
long AddCntr64 (smiLPBYTE *tmpPtr, smiLPCNTR64 value);
|
|
void AddNull (smiLPBYTE *tmpPtr, int type);
|
|
LPVARBIND ParseVarBind (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen);
|
|
BOOL ParseOctetString (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen, smiLPOCTETS os_ptr);
|
|
BOOL ParseOID (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen, smiLPOID oid_ptr);
|
|
BOOL ParseCntr64 (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen, smiLPCNTR64 cntr64_ptr);
|
|
BOOL ParseUInt (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen, smiLPUINT32 value);
|
|
BOOL ParseInt (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen, smiLPINT value);
|
|
BOOL ParseNull (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen);
|
|
BOOL ParseSequence (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen);
|
|
smiINT32 ParseType (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen);
|
|
smiINT32 ParseLength (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen);
|
|
|
|
void FreeOctetString (smiLPOCTETS os_ptr)
|
|
{
|
|
if (os_ptr)
|
|
{
|
|
if (os_ptr->ptr)
|
|
GlobalFree (os_ptr->ptr);
|
|
GlobalFree (os_ptr);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void FreeVarBindList (LPVARBIND vb_ptr)
|
|
{
|
|
if (vb_ptr)
|
|
{ // NULLs are handled by downstream call
|
|
FreeVarBindList (vb_ptr->next_var);
|
|
FreeVarBind (vb_ptr);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void FreeVarBind (LPVARBIND vb_ptr)
|
|
{
|
|
if (vb_ptr)
|
|
{
|
|
if (vb_ptr->name.ptr)
|
|
GlobalFree (vb_ptr->name.ptr);
|
|
switch (vb_ptr->value.syntax)
|
|
{
|
|
case SNMP_SYNTAX_OID:
|
|
if (vb_ptr->value.value.oid.ptr)
|
|
GlobalFree (vb_ptr->value.value.oid.ptr);
|
|
break;
|
|
|
|
case SNMP_SYNTAX_OCTETS:
|
|
case SNMP_SYNTAX_IPADDR:
|
|
case SNMP_SYNTAX_OPAQUE:
|
|
if (vb_ptr->value.value.string.ptr)
|
|
GlobalFree (vb_ptr->value.value.string.ptr);
|
|
break;
|
|
|
|
default: // Remaining types do not have 'ptr' members
|
|
break;
|
|
} // end_switch
|
|
GlobalFree (vb_ptr);
|
|
} // end_if (vb_ptr)
|
|
return;
|
|
} // end_FreeVarBind
|
|
|
|
void FreeV1Trap (LPV1TRAP v1Trap_ptr)
|
|
{
|
|
if (v1Trap_ptr)
|
|
{
|
|
if (v1Trap_ptr->enterprise.ptr)
|
|
GlobalFree (v1Trap_ptr->enterprise.ptr);
|
|
if (v1Trap_ptr->agent_addr.ptr)
|
|
GlobalFree (v1Trap_ptr->agent_addr.ptr);
|
|
GlobalFree (v1Trap_ptr);
|
|
}
|
|
} // end_FreeV1Trap
|
|
|
|
void AddLen (smiLPBYTE *tmpPtr, long lenlen, long data_len)
|
|
{
|
|
long i;
|
|
if (lenlen == 1)
|
|
*(*tmpPtr)++ = (smiBYTE)data_len;
|
|
else
|
|
{
|
|
*(*tmpPtr)++ = (smiBYTE)(0x80 + lenlen - 1);
|
|
for (i = 1; i < lenlen; i++)
|
|
{
|
|
*(*tmpPtr)++ = (smiBYTE)((data_len >>
|
|
(8 * (lenlen - i - 1))) & 0xFF);
|
|
} // end_for
|
|
} // end_else
|
|
return;
|
|
} // end_AddLen
|
|
|
|
long AddVarBind (smiLPBYTE *tmpPtr, LPVARBIND vb_ptr)
|
|
{
|
|
long lenlen;
|
|
if (vb_ptr == NULL)
|
|
return (0);
|
|
if ((lenlen = DoLenLen(vb_ptr->data_length)) == -1)
|
|
return (-1);
|
|
*(*tmpPtr)++ = SNMP_SYNTAX_SEQUENCE;
|
|
AddLen (tmpPtr, lenlen, vb_ptr->data_length);
|
|
if (AddOID (tmpPtr, &vb_ptr->name) == -1)
|
|
return (-1);
|
|
|
|
switch (vb_ptr->value.syntax)
|
|
{
|
|
case SNMP_SYNTAX_CNTR32:
|
|
case SNMP_SYNTAX_GAUGE32:
|
|
case SNMP_SYNTAX_TIMETICKS:
|
|
case SNMP_SYNTAX_UINT32:
|
|
AddUInt (tmpPtr, (int)vb_ptr->value.syntax, vb_ptr->value.value.uNumber);
|
|
break;
|
|
|
|
case SNMP_SYNTAX_INT:
|
|
AddInt (tmpPtr, vb_ptr->value.value.sNumber);
|
|
break;
|
|
|
|
case SNMP_SYNTAX_OID:
|
|
if (AddOID (tmpPtr, (smiLPOID)&(vb_ptr->value.value.oid)) == -1)
|
|
return (-1);
|
|
break;
|
|
|
|
case SNMP_SYNTAX_CNTR64:
|
|
AddCntr64 (tmpPtr, (smiLPCNTR64)&(vb_ptr->value.value.hNumber));
|
|
break;
|
|
|
|
case SNMP_SYNTAX_OCTETS:
|
|
case SNMP_SYNTAX_IPADDR:
|
|
case SNMP_SYNTAX_OPAQUE:
|
|
if (AddOctetString (tmpPtr, (int)vb_ptr->value.syntax,
|
|
(smiLPOCTETS)&(vb_ptr->value.value.string)) == -1)
|
|
return -1;
|
|
break;
|
|
|
|
case SNMP_SYNTAX_NULL:
|
|
case SNMP_SYNTAX_NOSUCHOBJECT:
|
|
case SNMP_SYNTAX_NOSUCHINSTANCE:
|
|
case SNMP_SYNTAX_ENDOFMIBVIEW:
|
|
AddNull (tmpPtr, (int)vb_ptr->value.syntax);
|
|
break;
|
|
|
|
default:
|
|
return (-1);
|
|
} // end_switch
|
|
return (AddVarBind (tmpPtr, vb_ptr->next_var));
|
|
}
|
|
|
|
long AddOctetString (smiLPBYTE *tmpPtr, int type, smiLPOCTETS os_ptr)
|
|
{
|
|
UINT i;
|
|
long lenlen;
|
|
if ((lenlen = DoLenLen ((long)os_ptr->len)) == -1)
|
|
return (-1);
|
|
*(*tmpPtr)++ = (smiBYTE)(0xFF & type);
|
|
AddLen (tmpPtr, lenlen, os_ptr->len);
|
|
for (i = 0; i < os_ptr->len; i++)
|
|
*(*tmpPtr)++ = os_ptr->ptr[i];
|
|
return (0);
|
|
}
|
|
|
|
long AddOID (smiLPBYTE *tmpPtr, smiLPOID oid_ptr)
|
|
{
|
|
UINT i;
|
|
long lenlen = 0;
|
|
long encoded_len;
|
|
encoded_len = 1; // for first two SID's
|
|
for (i = 2; i < oid_ptr->len; i++)
|
|
{
|
|
if (oid_ptr->ptr[i] < 0x80) // 0 - 0x7F
|
|
encoded_len += 1;
|
|
else if (oid_ptr->ptr[i] < 0x4000) // 0x80 - 0x3FFF
|
|
encoded_len += 2;
|
|
else if (oid_ptr->ptr[i] < 0x200000) // 0x4000 - 0x1FFFFF
|
|
encoded_len += 3;
|
|
else if (oid_ptr->ptr[i] < 0x10000000) // 0x200000 - 0xFFFFFFF
|
|
encoded_len += 4;
|
|
else
|
|
encoded_len += 5;
|
|
}
|
|
if ((lenlen = DoLenLen (encoded_len)) == -1)
|
|
return (-1);
|
|
*(*tmpPtr)++ = (smiBYTE)(0xFF & SNMP_SYNTAX_OID);
|
|
AddLen (tmpPtr, lenlen, encoded_len);
|
|
if (oid_ptr->len < 2)
|
|
*(*tmpPtr)++ = (smiBYTE)(oid_ptr->ptr[0] * 40);
|
|
else
|
|
*(*tmpPtr)++ = (smiBYTE)((oid_ptr->ptr[0] * 40) + oid_ptr->ptr[1]);
|
|
for (i = 2; i < oid_ptr->len; i++)
|
|
{
|
|
if (oid_ptr->ptr[i] < 0x80)
|
|
{ // 0 - 0x7F
|
|
*(*tmpPtr)++ = (smiBYTE)oid_ptr->ptr[i];
|
|
}
|
|
else if (oid_ptr->ptr[i] < 0x4000)
|
|
{ // 0x80 - 0x3FFF
|
|
*(*tmpPtr)++ = (smiBYTE)
|
|
(((oid_ptr->ptr[i]) >> 7) | 0x80); // set high bit
|
|
*(*tmpPtr)++ = (smiBYTE)(oid_ptr->ptr[i] & 0x7f);
|
|
}
|
|
else if (oid_ptr->ptr[i] < 0x200000)
|
|
{ // 0x4000 - 0x1FFFFF
|
|
*(*tmpPtr)++ = (smiBYTE)
|
|
(((oid_ptr->ptr[i]) >> 14) | 0x80); // set high bit
|
|
*(*tmpPtr)++ = (smiBYTE)
|
|
(((oid_ptr->ptr[i]) >> 7) | 0x80); // set high bit
|
|
*(*tmpPtr)++ = (smiBYTE)(oid_ptr->ptr[i] & 0x7f);
|
|
}
|
|
else if (oid_ptr->ptr[i] < 0x10000000)
|
|
{ // 0x200000 - 0xFFFFFFF
|
|
*(*tmpPtr)++ = (smiBYTE)
|
|
(((oid_ptr->ptr[i]) >> 21) | 0x80); // set high bit
|
|
*(*tmpPtr)++ = (smiBYTE)
|
|
(((oid_ptr->ptr[i]) >> 14) | 0x80); // set high bit
|
|
*(*tmpPtr)++ = (smiBYTE)
|
|
(((oid_ptr->ptr[i]) >> 7) | 0x80); // set high bit
|
|
*(*tmpPtr)++ = (smiBYTE)(oid_ptr->ptr[i] & 0x7f);
|
|
}
|
|
else
|
|
{
|
|
*(*tmpPtr)++ = (smiBYTE)
|
|
(((oid_ptr->ptr[i]) >> 28) | 0x80); // set high bit
|
|
*(*tmpPtr)++ = (smiBYTE)
|
|
(((oid_ptr->ptr[i]) >> 21) | 0x80); // set high bit
|
|
*(*tmpPtr)++ = (smiBYTE)
|
|
(((oid_ptr->ptr[i]) >> 14) | 0x80); // set high bit
|
|
*(*tmpPtr)++ = (smiBYTE)
|
|
(((oid_ptr->ptr[i]) >> 7) | 0x80); // set high bit
|
|
*(*tmpPtr)++ = (smiBYTE)(oid_ptr->ptr[i] & 0x7f);
|
|
}
|
|
} // end_for
|
|
return (0);
|
|
} // end_AddOID
|
|
|
|
long AddUInt (smiLPBYTE *tmpPtr, int type, smiUINT32 value)
|
|
{
|
|
long i;
|
|
long datalen;
|
|
long lenlen;
|
|
// if high bit one, must use 5 octets (first with 00)
|
|
if (((value >> 24) & 0xFF) != 0)
|
|
datalen = 4;
|
|
else if (((value >> 16) & 0xFF) != 0)
|
|
datalen = 3;
|
|
else if (((value >> 8) & 0xFF) != 0)
|
|
datalen = 2;
|
|
else
|
|
datalen = 1;
|
|
if (((value >> (8 * (datalen - 1))) & 0x80) != 0)
|
|
datalen++;
|
|
lenlen = 1; // < 127 octets
|
|
*(*tmpPtr)++ = (smiBYTE)(0xFF & type);
|
|
AddLen(tmpPtr, lenlen, datalen);
|
|
if (datalen == 5)
|
|
{ // gotta put a 00 in first octet
|
|
*(*tmpPtr)++ = (smiBYTE)0;
|
|
for (i = 1; i < datalen; i++)
|
|
{
|
|
*(*tmpPtr)++ = (smiBYTE)(value >>
|
|
(8 * ((datalen - 1) - i) & 0xFF));
|
|
}
|
|
} // end_if
|
|
else
|
|
{
|
|
for (i = 0; i < datalen; i++)
|
|
{
|
|
*(*tmpPtr)++ = (smiBYTE)(value >>
|
|
(8 * ((datalen - 1) - i) & 0xFF));
|
|
}
|
|
} // end_else
|
|
return (0);
|
|
} // end_AddUInt
|
|
|
|
long AddInt (smiLPBYTE *tmpPtr, smiINT32 value)
|
|
{
|
|
long i;
|
|
long datalen;
|
|
long lenlen;
|
|
switch ((smiBYTE) ((value >> 24) & 0xFF))
|
|
{
|
|
case 0x00:
|
|
if (((value >> 16) & 0xFF) != 0)
|
|
datalen = 3;
|
|
else if (((value >> 8) & 0xFF) != 0)
|
|
datalen = 2;
|
|
else
|
|
datalen = 1;
|
|
if (((value >> (8 * (datalen - 1))) & 0x80) != 0)
|
|
datalen++;
|
|
break;
|
|
|
|
case 0xFF:
|
|
if (((value >> 16) & 0xFF) != 0xFF)
|
|
datalen = 3;
|
|
else if (((value >> 8) & 0xFF) != 0xFF)
|
|
datalen = 2;
|
|
else
|
|
datalen = 1;
|
|
if (((value >> (8 * (datalen - 1))) & 0x80) == 0)
|
|
datalen++;
|
|
break;
|
|
|
|
default:
|
|
datalen = 4;
|
|
} // end_switch
|
|
lenlen = 1; // < 127 octets
|
|
*(*tmpPtr)++ = (smiBYTE)(0xFF & SNMP_SYNTAX_INT);
|
|
AddLen(tmpPtr, lenlen, datalen);
|
|
for (i = 0; i < datalen; i++)
|
|
{
|
|
*(*tmpPtr)++ = (smiBYTE) (value >>
|
|
(8 * ((datalen - 1) - i) & 0xFF));
|
|
}
|
|
return (0);
|
|
} // end_AddInt()
|
|
|
|
long AddCntr64 (smiLPBYTE *tmpPtr, smiLPCNTR64 value)
|
|
{
|
|
long i;
|
|
long datalen;
|
|
long lenlen;
|
|
datalen = FindLenCntr64(value) - 2;
|
|
lenlen = 1; // < 127 octets
|
|
*(*tmpPtr)++ = (smiBYTE)(0xFF & SNMP_SYNTAX_CNTR64);
|
|
AddLen(tmpPtr, lenlen, datalen);
|
|
if (datalen == 9)
|
|
{ // gotta put a 00 in first octet
|
|
*(*tmpPtr)++ = (smiBYTE)0;
|
|
datalen--;
|
|
}
|
|
for (i = datalen; i > 4; i--)
|
|
{
|
|
*(*tmpPtr)++ = (smiBYTE)(value->hipart >>
|
|
(8 * (i - 5) & 0xFF));
|
|
}
|
|
for (; i > 0; i--)
|
|
{
|
|
*(*tmpPtr)++ = (smiBYTE)(value->lopart >>
|
|
(8 * (i - 1) & 0xFF));
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
long FindLenVarBind (LPVARBIND vb_ptr)
|
|
{
|
|
long lenlen;
|
|
long tot_so_far;
|
|
long lOidLen;
|
|
long lValueLen;
|
|
if (!vb_ptr) return (0);
|
|
tot_so_far = FindLenVarBind (vb_ptr->next_var);
|
|
if (tot_so_far == -1)
|
|
return (-1);
|
|
if ((lOidLen = FindLenOID (&vb_ptr->name)) == -1)
|
|
return (-1);
|
|
if ((lValueLen = FindLenVALUE (&vb_ptr->value)) == -1)
|
|
return (-1);
|
|
vb_ptr->data_length = lOidLen +
|
|
lValueLen;
|
|
if ((lenlen = DoLenLen (vb_ptr->data_length)) == -1)
|
|
return (-1);
|
|
return (1 + lenlen + vb_ptr->data_length + tot_so_far);
|
|
} // end_FindLenVarBind
|
|
|
|
long FindLenVALUE (smiLPVALUE value_ptr)
|
|
{
|
|
if (value_ptr)
|
|
{
|
|
switch (value_ptr->syntax)
|
|
{
|
|
case SNMP_SYNTAX_OCTETS:
|
|
case SNMP_SYNTAX_IPADDR:
|
|
case SNMP_SYNTAX_OPAQUE:
|
|
return (FindLenOctetString (&value_ptr->value.string));
|
|
|
|
case SNMP_SYNTAX_OID:
|
|
return (FindLenOID (&value_ptr->value.oid));
|
|
|
|
case SNMP_SYNTAX_NULL:
|
|
case SNMP_SYNTAX_NOSUCHOBJECT:
|
|
case SNMP_SYNTAX_NOSUCHINSTANCE:
|
|
case SNMP_SYNTAX_ENDOFMIBVIEW:
|
|
return (2);
|
|
|
|
case SNMP_SYNTAX_INT:
|
|
return (FindLenInt (value_ptr->value.sNumber));
|
|
|
|
case SNMP_SYNTAX_CNTR32:
|
|
case SNMP_SYNTAX_GAUGE32:
|
|
case SNMP_SYNTAX_TIMETICKS:
|
|
case SNMP_SYNTAX_UINT32:
|
|
return (FindLenUInt (value_ptr->value.uNumber));
|
|
|
|
case SNMP_SYNTAX_CNTR64:
|
|
return (FindLenCntr64 (&value_ptr->value.hNumber));
|
|
} // end_switch
|
|
} // end_if
|
|
return (-1);
|
|
} // end_FindLenVALUE
|
|
|
|
long FindLenOctetString (smiLPOCTETS os_ptr)
|
|
{
|
|
long lenlen;
|
|
if (!os_ptr) return (-1);
|
|
if ((lenlen = DoLenLen (os_ptr->len)) == -1)
|
|
return (-1);
|
|
return (1 + lenlen + os_ptr->len);
|
|
}
|
|
|
|
long FindLenOID (smiLPCOID oid_ptr)
|
|
{
|
|
long lenlen;
|
|
UINT i;
|
|
UINT encoded_len;
|
|
encoded_len = 1; // for first two Sub-IDs
|
|
// beware of i = 2
|
|
for (i = 2; i < oid_ptr->len; i++)
|
|
{
|
|
if (oid_ptr->ptr[i] < 0x80) // 0 - 0x7F
|
|
encoded_len += 1;
|
|
else if (oid_ptr->ptr[i] < 0x4000) // 0x80 - 0x3FFF
|
|
encoded_len += 2;
|
|
else if (oid_ptr->ptr[i] < 0x200000) // 0x4000 - 0x1FFFFF
|
|
encoded_len += 3;
|
|
else if (oid_ptr->ptr[i] < 0x10000000) // 0x200000 - 0xFFFFFFF
|
|
encoded_len += 4;
|
|
else
|
|
encoded_len += 5;
|
|
} // end_for
|
|
if ((lenlen = DoLenLen (encoded_len)) == -1)
|
|
return (-1);
|
|
return (1 + lenlen + encoded_len);
|
|
} // end_FindLenOID
|
|
|
|
long FindLenUInt (smiUINT32 value)
|
|
{
|
|
long datalen;
|
|
// if high bit one, must use 5 octets (first with 00)
|
|
if (((value >> 24) & 0xFF) != 0)
|
|
datalen = 4;
|
|
else if (((value >> 16) & 0xFF) != 0)
|
|
datalen = 3;
|
|
else if (((value >> 8) & 0xFF) != 0)
|
|
datalen = 2;
|
|
else
|
|
datalen = 1;
|
|
if (((value >> (8 * (datalen - 1))) & 0x80) != 0)
|
|
datalen++;
|
|
// length of length < 127 octets
|
|
return (1 + 1 + datalen);
|
|
}
|
|
|
|
long FindLenInt (smiINT32 value)
|
|
{
|
|
long datalen;
|
|
switch ((smiBYTE) ((value >> 24) & 0xFF))
|
|
{
|
|
case 0x00:
|
|
if (((value >> 16) & 0xFF) != 0)
|
|
datalen = 3;
|
|
else if (((value >> 8) & 0xFF) != 0)
|
|
datalen = 2;
|
|
else
|
|
datalen = 1;
|
|
if (((value >> (8 * (datalen - 1))) & 0x80) != 0)
|
|
datalen++;
|
|
break;
|
|
|
|
case 0xFF:
|
|
if (((value >> 16) & 0xFF) != 0xFF)
|
|
datalen = 3;
|
|
else if (((value >> 8) & 0xFF) != 0xFF)
|
|
datalen = 2;
|
|
else
|
|
datalen = 1;
|
|
if (((value >> (8 * (datalen - 1))) & 0x80) == 0)
|
|
datalen++;
|
|
break;
|
|
|
|
default:
|
|
datalen = 4;
|
|
} // end_switch
|
|
return (1 + 1 + datalen);
|
|
}
|
|
|
|
long FindLenCntr64 (smiLPCNTR64 value)
|
|
{
|
|
long datalen;
|
|
|
|
// if high bit one, must use 5 octets (first with 00)
|
|
if (((value->hipart >> 24) & 0xFF) != 0)
|
|
{
|
|
datalen = 8;
|
|
if (((value->hipart >> 24) & 0x80) != 0) datalen++;
|
|
}
|
|
else if (((value->hipart >> 16) & 0xFF) != 0)
|
|
{
|
|
datalen = 7;
|
|
if (((value->hipart >> 16) & 0x80) != 0) datalen++;
|
|
}
|
|
else if (((value->hipart >> 8) & 0xFF) != 0)
|
|
{
|
|
datalen = 6;
|
|
if (((value->hipart >> 8) & 0x80) != 0) datalen++;
|
|
}
|
|
else if (((value->hipart) & 0xFF) != 0)
|
|
{
|
|
datalen = 5;
|
|
if (((value->hipart) & 0x80) != 0) datalen++;
|
|
}
|
|
else if (((value->lopart>> 24) & 0xFF) != 0)
|
|
{
|
|
datalen = 4;
|
|
if (((value->lopart >> 24) & 0x80) != 0) datalen++;
|
|
}
|
|
else if (((value->lopart >> 16) & 0xFF) != 0)
|
|
{
|
|
datalen = 3;
|
|
if (((value->lopart >> 16) & 0x80) != 0) datalen++;
|
|
}
|
|
else if (((value->lopart >> 8) & 0xFF) != 0)
|
|
{
|
|
datalen = 2;
|
|
if (((value->lopart >> 8) & 0x80) != 0) datalen++;
|
|
}
|
|
else
|
|
{
|
|
datalen = 1;
|
|
if (((value->lopart) & 0x80) != 0) datalen++;
|
|
}
|
|
// length of length < 127 octets
|
|
return (1 + 1 + datalen);
|
|
}
|
|
|
|
long DoLenLen (long len)
|
|
{
|
|
// short form?
|
|
if (len < 128) return (1);
|
|
if (len < 0x100) return (2);
|
|
if (len < 0x10000) return (3);
|
|
if (len < 0x1000000) return (4);
|
|
return (-1);
|
|
}
|
|
|
|
void AddNull (smiLPBYTE *tmpPtr, int type)
|
|
{
|
|
*(*tmpPtr)++ = (smiBYTE)(0xFF & type);
|
|
*(*tmpPtr)++ = 0x00;
|
|
return;
|
|
}
|
|
|
|
BOOL BuildMessage (smiUINT32 version, smiLPOCTETS community,
|
|
LPPDUS pdu, smiINT32 requestId,
|
|
smiLPBYTE *msgAddr, smiLPUINT32 msgSize)
|
|
{
|
|
LPVARBIND vbList = NULL;
|
|
long nVbDataLen, nVbLenLen, nVbTotalLen;
|
|
long nPduDataLen, nPduLenLen, nPduTotalLen;
|
|
long nMsgDataLen, nMsgLenLen, nMsgTotalLen;
|
|
long nTmpDataLen;
|
|
smiLPBYTE tmpPtr = NULL;
|
|
*msgAddr = NULL;
|
|
*msgSize = 0;
|
|
if (pdu == NULL || community == NULL)
|
|
return (FALSE);
|
|
// Determine length of VarBind list part
|
|
vbList = pdu->VBL_addr;
|
|
if (vbList == NULL && pdu->VBL != 0)
|
|
vbList = ((LPVBLS)snmpGetTableEntry(&VBLsDescr, HandleToUlong(pdu->VBL)-1))->vbList;
|
|
// vbList == NULL is ok
|
|
if ((nVbDataLen = FindLenVarBind (vbList)) == -1)
|
|
return (FALSE);
|
|
if ((nVbLenLen = DoLenLen (nVbDataLen)) == -1)
|
|
return (FALSE);
|
|
nVbTotalLen = 1 + nVbLenLen + nVbDataLen;
|
|
// Determine length of PDU overhead part
|
|
switch (pdu->type)
|
|
{
|
|
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:
|
|
nPduDataLen = FindLenInt (requestId)
|
|
+ FindLenInt (pdu->errStatus)
|
|
+ FindLenInt (pdu->errIndex)
|
|
+ nVbTotalLen;
|
|
break;
|
|
|
|
case SNMP_PDU_V1TRAP:
|
|
if (!pdu->v1Trap)
|
|
return (FALSE);
|
|
nPduDataLen = FindLenInt (pdu->v1Trap->generic_trap)
|
|
+ FindLenInt (pdu->v1Trap->specific_trap)
|
|
+ FindLenUInt (pdu->v1Trap->time_ticks)
|
|
+ nVbTotalLen;
|
|
if ((nTmpDataLen = FindLenOID (&pdu->v1Trap->enterprise)) == -1)
|
|
return (FALSE);
|
|
nPduDataLen += nTmpDataLen;
|
|
if ((nTmpDataLen = FindLenOctetString (&pdu->v1Trap->agent_addr)) == -1)
|
|
return (FALSE);
|
|
nPduDataLen += nTmpDataLen;
|
|
break;
|
|
|
|
default:
|
|
return (FALSE);
|
|
} // end_switch
|
|
if ((nPduLenLen = DoLenLen(nPduDataLen)) == -1)
|
|
return (FALSE);
|
|
nPduTotalLen = 1 + nPduLenLen + nPduDataLen;
|
|
if ((nTmpDataLen = FindLenOctetString (community)) == -1)
|
|
return (FALSE);
|
|
nMsgDataLen = FindLenUInt (version)
|
|
+ nTmpDataLen
|
|
+ nPduTotalLen;
|
|
if ((nMsgLenLen = DoLenLen (nMsgDataLen)) == -1)
|
|
return (FALSE);
|
|
nMsgTotalLen = 1 + nMsgLenLen + nMsgDataLen;
|
|
// Allocate the necessary memory for the message
|
|
tmpPtr = GlobalAlloc (GPTR, nMsgTotalLen);
|
|
if (tmpPtr == NULL)
|
|
return (FALSE);
|
|
*msgAddr = tmpPtr;
|
|
*msgSize = nMsgTotalLen;
|
|
// Now plug in the values in the message bytes
|
|
*tmpPtr++ = SNMP_SYNTAX_SEQUENCE;
|
|
// Wrapper portion
|
|
AddLen (&tmpPtr, nMsgLenLen, nMsgDataLen);
|
|
AddInt (&tmpPtr, version);
|
|
if (AddOctetString (&tmpPtr, SNMP_SYNTAX_OCTETS, community) == -1)
|
|
goto error_out;
|
|
// PDU header portion
|
|
// "Downgrade" GetBulk to GetNext if target is SNMPv1
|
|
if (pdu->type == SNMP_PDU_GETBULK && version == 0)
|
|
*tmpPtr++ = SNMP_PDU_GETNEXT;
|
|
else
|
|
*tmpPtr++ = (BYTE) pdu->type;
|
|
AddLen (&tmpPtr, nPduLenLen, nPduDataLen);
|
|
switch (pdu->type)
|
|
{
|
|
case SNMP_PDU_GET:
|
|
case SNMP_PDU_GETNEXT:
|
|
case SNMP_PDU_RESPONSE:
|
|
case SNMP_PDU_SET:
|
|
case SNMP_PDU_INFORM:
|
|
case SNMP_PDU_TRAP:
|
|
case SNMP_PDU_GETBULK:
|
|
AddInt (&tmpPtr, requestId);
|
|
AddInt (&tmpPtr, pdu->errStatus);
|
|
AddInt (&tmpPtr, pdu->errIndex);
|
|
break;
|
|
|
|
case SNMP_PDU_V1TRAP:
|
|
if (AddOID (&tmpPtr, &pdu->v1Trap->enterprise)== -1)
|
|
goto error_out;
|
|
if (AddOctetString (&tmpPtr, SNMP_SYNTAX_IPADDR, &pdu->v1Trap->agent_addr) == -1)
|
|
goto error_out;
|
|
AddInt (&tmpPtr, pdu->v1Trap->generic_trap);
|
|
AddInt (&tmpPtr, pdu->v1Trap->specific_trap);
|
|
AddUInt (&tmpPtr, SNMP_SYNTAX_TIMETICKS, pdu->v1Trap->time_ticks);
|
|
break;
|
|
|
|
default:
|
|
goto error_out;
|
|
} // end_switch
|
|
// VarBindList portion
|
|
*tmpPtr++ = SNMP_SYNTAX_SEQUENCE;
|
|
AddLen (&tmpPtr, nVbLenLen, nVbDataLen);
|
|
if (AddVarBind (&tmpPtr, vbList) == -1)
|
|
{
|
|
error_out:
|
|
if (*msgAddr)
|
|
GlobalFree (*msgAddr);
|
|
*msgAddr = NULL;
|
|
*msgSize = 0;
|
|
return (FALSE);
|
|
}
|
|
// Success
|
|
return (TRUE);
|
|
} // end_BuildMessage()
|
|
|
|
|
|
BOOL SetPduType (smiLPBYTE msgPtr, smiUINT32 msgLen, int pduType)
|
|
{
|
|
smiLPBYTE tmpPtr;
|
|
smiINT32 tmp;
|
|
if (!(tmpPtr = msgPtr)) // Deliberate assignment
|
|
return (FALSE);
|
|
if (!(ParseSequence (&tmpPtr, &msgLen))) // sequence
|
|
return (FALSE);
|
|
if (!(ParseUInt (&tmpPtr, &msgLen, &tmp))) // version
|
|
return (FALSE);
|
|
// Jump over communityString...not needed here
|
|
if (ParseType (&tmpPtr, &msgLen) == -1)
|
|
return (FALSE);
|
|
// -1 is error, we also reject 0 and -ve length commuityString
|
|
if ((tmp = ParseLength (&tmpPtr, &msgLen)) <= 0)
|
|
return (FALSE);
|
|
if ((smiUINT32)tmp > msgLen)
|
|
return (FALSE);
|
|
tmpPtr += (smiUINT32)tmp; // Jump!
|
|
// Set the PDU type byte
|
|
*tmpPtr = (smiBYTE)pduType;
|
|
return (TRUE);
|
|
} // End_SetPduType()
|
|
|
|
|
|
smiUINT32 ParsePduHdr (smiLPBYTE msgPtr, smiUINT32 msgLen,
|
|
smiLPUINT32 version, smiLPINT32 type, smiLPUINT32 reqID)
|
|
{
|
|
// This is a private function (not exported via WinSNMP)
|
|
// It is called only once by msgNotify() (another private function)
|
|
// to "peek ahead" at certain PDU attributes to determine the next
|
|
// procesing steps.
|
|
smiINT32 pduLen;
|
|
smiINT32 length;
|
|
long errcode = 1;
|
|
if (msgPtr == NULL)
|
|
goto DONE;
|
|
errcode++; // 2
|
|
// Parse initial Sequence field...
|
|
if (ParseType (&msgPtr, &msgLen) != SNMP_SYNTAX_SEQUENCE)
|
|
goto DONE;
|
|
errcode++; // 3
|
|
// ...to get the remaining pduLen out of it
|
|
pduLen = ParseLength (&msgPtr, &msgLen);
|
|
if (pduLen <= 0)
|
|
goto DONE;
|
|
errcode++; // 4
|
|
if ((smiUINT32)pduLen > msgLen)
|
|
goto DONE;
|
|
errcode++; // 5
|
|
msgLen = (smiUINT32)pduLen; // Only pduLen counts now
|
|
if (!(ParseUInt (&msgPtr, &msgLen, version)))
|
|
goto DONE;
|
|
errcode++; // 6
|
|
// Jump over communityString...not needed here
|
|
if (ParseType (&msgPtr, &msgLen) == -1)
|
|
goto DONE;
|
|
errcode++; // 7
|
|
// -1 is error, we also reject 0 and -ve length commuityString
|
|
if ((length = ParseLength (&msgPtr, &msgLen)) <= 0)
|
|
goto DONE;
|
|
errcode++; // 8
|
|
if ((smiUINT32)length > msgLen)
|
|
goto DONE;
|
|
errcode++; // 9
|
|
msgPtr += (smiUINT32)length; // Jump!
|
|
msgLen -= (smiUINT32)length;
|
|
// Get PDU type
|
|
if ((*type = ParseType (&msgPtr, &msgLen)) == -1)
|
|
goto DONE;
|
|
errcode++; // 10
|
|
// Check PDU type for requestID semantics
|
|
if (*type == SNMP_PDU_V1TRAP)
|
|
*reqID = 0; // No requestID on v1 trapPDU
|
|
else // Not a v1 trapPDU, therefore
|
|
{ // must get requestID
|
|
// -1 is error, reject 0 and any -ve values too.
|
|
if ((ParseLength (&msgPtr, &msgLen)) <= 0)
|
|
goto DONE;
|
|
errcode++; // 11
|
|
if (!(ParseInt (&msgPtr, &msgLen, reqID)))
|
|
goto DONE;
|
|
}
|
|
errcode = 0;
|
|
DONE:
|
|
return (errcode);
|
|
} // end_ParsePduHdr
|
|
|
|
smiUINT32 ParseMessage (smiLPBYTE msgPtr, smiUINT32 msgLen,
|
|
smiLPUINT32 version, smiLPOCTETS *community, LPPDUS pdu)
|
|
{
|
|
smiINT32 pduLen;
|
|
smiLPOCTETS os_ptr;
|
|
LPVARBIND vb_ptr;
|
|
LPVARBIND vb_end_ptr;
|
|
long errcode = 1;
|
|
if (msgPtr == NULL)
|
|
goto DONE;
|
|
errcode++; // 2
|
|
// Parse initial Sequence field...
|
|
if (ParseType (&msgPtr, &msgLen) != SNMP_SYNTAX_SEQUENCE)
|
|
goto DONE;
|
|
errcode++; // 3
|
|
// ...to get the remaining pduLen out of it
|
|
pduLen = ParseLength (&msgPtr, &msgLen);
|
|
if (pduLen <= 0)
|
|
goto DONE;
|
|
errcode++; // 4
|
|
if ((smiUINT32)pduLen > msgLen)
|
|
goto DONE;
|
|
errcode++; // 5
|
|
msgLen = (smiUINT32)pduLen; // Only pduLen counts now
|
|
if (!(ParseUInt (&msgPtr, &msgLen, version)))
|
|
goto DONE;
|
|
errcode++; // 5
|
|
if (*version != 0 && *version != 1) // SNMPv1 or SNMPv2c
|
|
goto DONE;
|
|
errcode++; // 6
|
|
if (!(os_ptr = GlobalAlloc (GPTR, sizeof(smiOCTETS))))
|
|
goto DONE;
|
|
errcode++; // 7
|
|
if (!(ParseOctetString (&msgPtr, &msgLen, os_ptr)))
|
|
goto DONE_OS;
|
|
// reject 0 length community string
|
|
if (os_ptr->len == 0)
|
|
goto DONE_OS;
|
|
errcode++; // 8
|
|
if (pdu == NULL)
|
|
goto DONE_OS;
|
|
ZeroMemory (pdu, sizeof(PDUS));
|
|
if ((pdu->type = ParseType (&msgPtr, &msgLen)) == -1)
|
|
goto DONE_PDU;
|
|
errcode++; // 9
|
|
pduLen = ParseLength (&msgPtr, &msgLen);
|
|
if ((pduLen <= 0) || (smiUINT32)pduLen > msgLen)
|
|
goto DONE_PDU;
|
|
errcode++; // 10
|
|
switch (pdu->type)
|
|
{
|
|
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:
|
|
if (!(ParseInt (&msgPtr, &msgLen, &pdu->appReqId)))
|
|
goto DONE_PDU;
|
|
errcode++; // 11
|
|
if (!(ParseInt (&msgPtr, &msgLen, &pdu->errStatus)))
|
|
goto DONE_PDU;
|
|
errcode++; // 12
|
|
if (!(ParseInt (&msgPtr, &msgLen, &pdu->errIndex)))
|
|
goto DONE_PDU;
|
|
errcode++; // 13
|
|
break;
|
|
|
|
case SNMP_PDU_V1TRAP:
|
|
pdu->v1Trap = GlobalAlloc (GPTR, sizeof(V1TRAP));
|
|
if (pdu->v1Trap == NULL)
|
|
goto DONE_PDU;
|
|
errcode++; // 11
|
|
if (!(ParseOID (&msgPtr, &msgLen, &pdu->v1Trap->enterprise)))
|
|
goto DONE_PDU;
|
|
errcode++; // 12
|
|
if (!(ParseOctetString (&msgPtr, &msgLen, &pdu->v1Trap->agent_addr)))
|
|
goto DONE_PDU;
|
|
errcode++; // 13
|
|
if (!(ParseInt (&msgPtr, &msgLen, &pdu->v1Trap->generic_trap)))
|
|
goto DONE_PDU;
|
|
errcode++; // 14
|
|
if (!(ParseInt (&msgPtr, &msgLen, &pdu->v1Trap->specific_trap)))
|
|
goto DONE_PDU;
|
|
errcode++; // 15
|
|
if (!(ParseUInt (&msgPtr, &msgLen, &pdu->v1Trap->time_ticks)))
|
|
goto DONE_PDU;
|
|
errcode++; // 16
|
|
break;
|
|
|
|
default:
|
|
goto DONE_PDU;
|
|
} // end_switch
|
|
errcode = 20; // re-normalize
|
|
// Waste the SEQUENCE tag
|
|
if (!(ParseSequence (&msgPtr, &msgLen)))
|
|
goto DONE_PDU;
|
|
errcode++; // 21
|
|
// Parse the varbind list
|
|
pdu->VBL = 0;
|
|
pdu->VBL_addr = NULL;
|
|
while (msgLen)
|
|
{
|
|
if (!(vb_ptr = ParseVarBind (&msgPtr, &msgLen)))
|
|
goto DONE_PDU;
|
|
errcode++; // 22+
|
|
if (!pdu->VBL_addr) // Is this the first one?
|
|
vb_end_ptr = pdu->VBL_addr = vb_ptr; // If so, start a list
|
|
else
|
|
{ // tack onto end of list
|
|
vb_end_ptr->next_var = vb_ptr;
|
|
vb_end_ptr = vb_ptr;
|
|
}
|
|
} // end_while
|
|
errcode = 0;
|
|
*community = os_ptr;
|
|
goto DONE;
|
|
DONE_PDU:
|
|
FreeVarBindList (pdu->VBL_addr); // Checks for NULL
|
|
FreeV1Trap (pdu->v1Trap); // Checks for NULL
|
|
ZeroMemory (pdu, sizeof(PDUS));
|
|
DONE_OS:
|
|
FreeOctetString (os_ptr);
|
|
DONE:
|
|
return (errcode);
|
|
} // end_ParseMessage
|
|
|
|
LPVARBIND ParseVarBind (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen)
|
|
{
|
|
LPVARBIND vb_ptr;
|
|
if (!(ParseSequence (tmpPtr, tmpLen)))
|
|
return (NULL);
|
|
if ((vb_ptr = (LPVARBIND)GlobalAlloc(GPTR, sizeof(VARBIND))) == NULL)
|
|
return (NULL);
|
|
if (!(ParseOID(tmpPtr, tmpLen, &vb_ptr->name)))
|
|
goto ERROROUT;
|
|
//we're going to derefrence (*tmpPtr), check length left first
|
|
if (*tmpLen == 0)
|
|
goto ERROROUT;
|
|
vb_ptr->value.syntax = (smiUINT32)*(*tmpPtr);
|
|
switch (vb_ptr->value.syntax)
|
|
{
|
|
case SNMP_SYNTAX_CNTR32:
|
|
case SNMP_SYNTAX_GAUGE32:
|
|
case SNMP_SYNTAX_TIMETICKS:
|
|
case SNMP_SYNTAX_UINT32:
|
|
if (!(ParseUInt (tmpPtr, tmpLen, &vb_ptr->value.value.uNumber)))
|
|
goto ERROROUT;
|
|
break;
|
|
|
|
case SNMP_SYNTAX_INT:
|
|
if (!(ParseInt (tmpPtr, tmpLen, &vb_ptr->value.value.sNumber)))
|
|
goto ERROROUT;
|
|
break;
|
|
|
|
case SNMP_SYNTAX_OID:
|
|
if (!(ParseOID (tmpPtr, tmpLen, &vb_ptr->value.value.oid)))
|
|
goto ERROROUT;
|
|
break;
|
|
|
|
case SNMP_SYNTAX_CNTR64:
|
|
if (!(ParseCntr64 (tmpPtr, tmpLen, &vb_ptr->value.value.hNumber)))
|
|
goto ERROROUT;
|
|
break;
|
|
|
|
case SNMP_SYNTAX_OCTETS:
|
|
case SNMP_SYNTAX_IPADDR:
|
|
case SNMP_SYNTAX_OPAQUE:
|
|
if (!(ParseOctetString (tmpPtr, tmpLen, &vb_ptr->value.value.string)))
|
|
goto ERROROUT;
|
|
break;
|
|
|
|
case SNMP_SYNTAX_NULL:
|
|
case SNMP_SYNTAX_NOSUCHOBJECT:
|
|
case SNMP_SYNTAX_NOSUCHINSTANCE:
|
|
case SNMP_SYNTAX_ENDOFMIBVIEW:
|
|
if (!(ParseNull (tmpPtr, tmpLen)))
|
|
goto ERROROUT;
|
|
break;
|
|
|
|
default:
|
|
goto ERROROUT;
|
|
} // end_switch
|
|
return (vb_ptr); // Success
|
|
//
|
|
ERROROUT:
|
|
FreeVarBind(vb_ptr);
|
|
return (NULL); // Failure
|
|
} // end_ParseVarBind
|
|
|
|
BOOL ParseOctetString
|
|
(smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen, smiLPOCTETS os_ptr)
|
|
{
|
|
smiINT32 length;
|
|
|
|
if (!os_ptr)
|
|
return (FALSE);
|
|
os_ptr->ptr = NULL;
|
|
os_ptr->len = 0;
|
|
if (ParseType (tmpPtr, tmpLen) == -1)
|
|
return (FALSE);
|
|
// make sure no conversion to UINT is done before testing
|
|
// because os_ptr->len is of UINT type
|
|
length = ParseLength (tmpPtr, tmpLen);
|
|
// note: we don't reject zero length Octet String
|
|
if (length < 0 || (smiUINT32)length > *tmpLen)
|
|
return (FALSE);
|
|
os_ptr->len = (smiUINT32)length;
|
|
if (os_ptr->len)
|
|
{ // Does not allocate "string" space on "length = 0"
|
|
if (!(os_ptr->ptr = (smiLPBYTE)GlobalAlloc (GPTR, os_ptr->len)))
|
|
return (FALSE);
|
|
CopyMemory (os_ptr->ptr, *tmpPtr, os_ptr->len);
|
|
}
|
|
*tmpPtr += os_ptr->len;
|
|
*tmpLen -= os_ptr->len;
|
|
return (TRUE);
|
|
} // end_ParseOctetString
|
|
|
|
BOOL ParseOID (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen, smiLPOID oid_ptr)
|
|
{
|
|
smiINT32 length;
|
|
|
|
if (!oid_ptr)
|
|
return (FALSE);
|
|
oid_ptr->ptr = NULL;
|
|
oid_ptr->len = 0;
|
|
if (ParseType (tmpPtr, tmpLen) != SNMP_SYNTAX_OID)
|
|
return (FALSE);
|
|
length = ParseLength (tmpPtr, tmpLen);
|
|
// -1 is error return from ParseLength()
|
|
|
|
// BUG# 347175 this is just the length in bytes for the BER encoded OID in the stream,
|
|
// this code should be the same as in %sdxroot%\net\snmp\newagent\exe\snmppdus.c!ParseOid.
|
|
// removed the (|| length > MAXOBJIDSIZE) condition from the following test. It should be
|
|
// moved to the while loop to test the number of sub-ids instead of bytes in stream.
|
|
if (length <= 0)
|
|
return (FALSE);
|
|
if ((smiUINT32)length > *tmpLen)
|
|
return (FALSE);
|
|
// the sub-id array will by 1 longer than the ASN.1/BER array
|
|
oid_ptr->ptr = (smiLPUINT32)GlobalAlloc (GPTR, sizeof(smiUINT32) * (length+1));
|
|
if (oid_ptr->ptr == NULL)
|
|
return (FALSE);
|
|
|
|
// oid_ptr structure space is pre-zero'd via GlobalAlloc()
|
|
while (length && (oid_ptr->len < MAXOBJIDSIZE))
|
|
{
|
|
if (oid_ptr->ptr[oid_ptr->len] & 0xFE000000)
|
|
{
|
|
// overflow in the next left shift
|
|
GlobalFree(oid_ptr->ptr);
|
|
oid_ptr->ptr = NULL;
|
|
oid_ptr->len = 0;
|
|
return (FALSE);
|
|
}
|
|
oid_ptr->ptr[oid_ptr->len] =
|
|
(oid_ptr->ptr[oid_ptr->len] << 7) + (*(*tmpPtr) & 0x7F);
|
|
if ((*(*tmpPtr)++ & 0x80) == 0)
|
|
{ // on the last octet of this sub-id
|
|
if (oid_ptr->len == 0) // check for first sub-id
|
|
{ // ASN.1/BER packs two into it
|
|
oid_ptr->ptr[1] = oid_ptr->ptr[0];
|
|
oid_ptr->ptr[0] /= 40;
|
|
if (oid_ptr->ptr[0] > 2)
|
|
oid_ptr->ptr[0] = 2;
|
|
oid_ptr->ptr[1] -= (oid_ptr->ptr[0] * 40);
|
|
oid_ptr->len++; // extra bump
|
|
}
|
|
oid_ptr->len++; // increment the count on sub-id
|
|
}
|
|
length--;
|
|
(*tmpLen)--;
|
|
} // end_while (length)
|
|
|
|
// BUG 506192
|
|
// Invalid OID BER of the form like "06 07 FF FF FF FF FF FF FF"
|
|
// causes oid_ptr->len 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 == oid_ptr->len) test below.
|
|
if (length || (0 == oid_ptr->len))
|
|
{
|
|
// the above while loop is terminated without finishing the parsing of the stream
|
|
GlobalFree(oid_ptr->ptr);
|
|
oid_ptr->ptr = NULL;
|
|
oid_ptr->len = 0;
|
|
return (FALSE);
|
|
}
|
|
|
|
return (TRUE);
|
|
} // end_ParseOID
|
|
|
|
BOOL ParseCntr64 (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen, smiLPCNTR64 Cntr64_ptr)
|
|
{
|
|
smiINT32 i;
|
|
smiINT32 length;
|
|
if (ParseType (tmpPtr, tmpLen) != SNMP_SYNTAX_CNTR64)
|
|
return (FALSE);
|
|
length = ParseLength(tmpPtr, tmpLen);
|
|
if (length <= 0)
|
|
return (FALSE);
|
|
if ((smiUINT32)length > *tmpLen || length > 9 ||
|
|
(length == 9 && *(*tmpPtr) != 0x00))
|
|
return (FALSE);
|
|
while (length && *(*tmpPtr) == 0x00)
|
|
{ // leading null octet?
|
|
(*tmpPtr)++; // if so, skip it
|
|
length--; // and don't count it
|
|
(*tmpLen)--; // Adjust remaining msg length
|
|
}
|
|
Cntr64_ptr->hipart = Cntr64_ptr->lopart = 0;
|
|
for (i = 0; i < length; i++)
|
|
{
|
|
Cntr64_ptr->hipart = (Cntr64_ptr->hipart << 8) +
|
|
(Cntr64_ptr->lopart >> 24);
|
|
Cntr64_ptr->lopart = (Cntr64_ptr->lopart << 8) +
|
|
(smiUINT32) *(*tmpPtr)++;
|
|
}
|
|
*tmpLen -= length;
|
|
return (TRUE);
|
|
} // end_ParseCntr64
|
|
|
|
BOOL ParseUInt (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen, smiLPUINT32 value)
|
|
{
|
|
smiINT32 length;
|
|
smiINT32 i;
|
|
if (ParseType (tmpPtr, tmpLen) == -1)
|
|
return (FALSE);
|
|
length = ParseLength(tmpPtr, tmpLen);
|
|
if (length <= 0)
|
|
return (FALSE);
|
|
if ((smiUINT32)length > *tmpLen)
|
|
return (FALSE);
|
|
if ((length > 5) || ((length > 4) && (*(*tmpPtr) != 0x00)))
|
|
return (FALSE);
|
|
while (length && *(*tmpPtr) == 0x00)
|
|
{ // leading null octet?
|
|
(*tmpPtr)++; // if so, skip it
|
|
length--; // and don't count it
|
|
(*tmpLen)--; // Adjust remaining msg length
|
|
}
|
|
*value = 0;
|
|
for (i = 0; i < length; i++)
|
|
*value = (*value << 8) + (smiUINT32)*(*tmpPtr)++;
|
|
*tmpLen -= length;
|
|
return (TRUE);
|
|
} // end_ParseUInt()
|
|
|
|
BOOL ParseInt (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen, smiLPINT value)
|
|
{
|
|
smiINT32 length;
|
|
smiINT32 i;
|
|
smiINT32 sign;
|
|
if (ParseType (tmpPtr, tmpLen) != SNMP_SYNTAX_INT)
|
|
return (FALSE);
|
|
length = ParseLength (tmpPtr, tmpLen);
|
|
if (length <= 0)
|
|
return (FALSE);
|
|
if ((smiUINT32)length > *tmpLen || length > 4)
|
|
return (FALSE);
|
|
sign = ((*(*tmpPtr) & 0x80) == 0x00) ? 0x00 : 0xFF;
|
|
*value = 0;
|
|
for (i = 0; i < length; i++)
|
|
*value = (*value << 8) + (smiUINT32) *(*tmpPtr)++;
|
|
// sign-extend upper bits
|
|
for (i = length; i < 4; i++)
|
|
*value = *value + (sign << i * 8);
|
|
*tmpLen -= length;
|
|
return (TRUE);
|
|
} // end_ParseInt()
|
|
|
|
BOOL ParseNull (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen)
|
|
{
|
|
smiINT32 length;
|
|
if (ParseType (tmpPtr, tmpLen) == -1)
|
|
return (FALSE);
|
|
length = ParseLength (tmpPtr, tmpLen);
|
|
if (length != 0) // NULLs have no length
|
|
return (FALSE);
|
|
return (TRUE);
|
|
} // end_ParseNull
|
|
|
|
BOOL ParseSequence (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen)
|
|
{
|
|
if (ParseType (tmpPtr, tmpLen) != SNMP_SYNTAX_SEQUENCE)
|
|
return (FALSE);
|
|
if (ParseLength (tmpPtr, tmpLen) == -1)
|
|
return (FALSE);
|
|
return (TRUE);
|
|
} // end_ParseSequence
|
|
|
|
smiINT32 ParseType (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen)
|
|
{
|
|
// 980421 - BobN
|
|
// - replaced tmpLen logic with working_len logic
|
|
// - working_len is always checked on entry into a
|
|
// - Parse<xxx> function
|
|
smiINT32 type;
|
|
if (*tmpLen == 0)
|
|
return (-1);
|
|
type = *(*tmpPtr)++;
|
|
(*tmpLen)--; // Adjust remaining msg length
|
|
switch (type)
|
|
{
|
|
case SNMP_SYNTAX_INT:
|
|
case SNMP_SYNTAX_OCTETS:
|
|
case SNMP_SYNTAX_OID:
|
|
case SNMP_SYNTAX_SEQUENCE:
|
|
case SNMP_SYNTAX_IPADDR:
|
|
case SNMP_SYNTAX_CNTR32:
|
|
case SNMP_SYNTAX_GAUGE32:
|
|
case SNMP_SYNTAX_TIMETICKS:
|
|
case SNMP_SYNTAX_OPAQUE:
|
|
case SNMP_SYNTAX_UINT32:
|
|
case SNMP_SYNTAX_CNTR64:
|
|
case SNMP_SYNTAX_NULL:
|
|
case SNMP_SYNTAX_NOSUCHOBJECT:
|
|
case SNMP_SYNTAX_NOSUCHINSTANCE:
|
|
case SNMP_SYNTAX_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:
|
|
type = -1;
|
|
break;
|
|
}
|
|
return (type);
|
|
} // end_ParseType
|
|
|
|
smiINT32 ParseLength (smiLPBYTE *tmpPtr, smiLPUINT32 tmpLen)
|
|
{
|
|
// 980421 - BobN
|
|
// - replaced end_ptr logic with tmpLen logic
|
|
// - tmpLen is always checked on entry into a Parse<xxx>
|
|
// - function and is decremented as used therein.
|
|
smiINT32 length;
|
|
smiINT32 lenlen;
|
|
if (*tmpLen == 0)
|
|
return (-1);
|
|
length = (smiINT32) *(*tmpPtr)++;
|
|
(*tmpLen)--; // Adjust remaining msg length
|
|
// Check for short-form value
|
|
if (length < 0x80)
|
|
return (length);
|
|
// Long form
|
|
lenlen = length & 0x7F;
|
|
if ((smiUINT32)lenlen > *tmpLen || lenlen > 4 || lenlen < 1)
|
|
return (-1); // Out of bounds
|
|
*tmpLen -= lenlen; // Adjust remaining msg length
|
|
length = 0;
|
|
while (lenlen)
|
|
{
|
|
length = (length << 8) + *(*tmpPtr)++;
|
|
lenlen--;
|
|
}
|
|
return (length);
|
|
} // end_ParseLength
|