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.
 
 
 
 
 
 

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