|
|
// wsnmp_ut.c
//
// WinSNMP Utility Functions and helpers
// Copyright 1995-1997 ACE*COMM Corp
// Rleased to Microsoft under Contract
// Beta 1 version, 970228
// Bob Natale ([email protected])
//
// 980424 - BobN
// - Mods to SnmpStrToIpxAddress() to permit '.' char
// - as netnum/nodenum separator
// 970310 - Removed extraneous functions
//
#include "winsnmp.inc"
SNMPAPI_STATUS SNMPAPI_CALL SnmpGetLastError (IN HSNMP_SESSION hSession) { DWORD nSes;
if (TaskData.hTask == 0) return (SNMPAPI_NOT_INITIALIZED); nSes = HandleToUlong(hSession) - 1; if (snmpValidTableEntry(&SessDescr, nSes)) { LPSESSION pSession = snmpGetTableEntry(&SessDescr, nSes); return pSession->nLastError; } else return (TaskData.nLastError); } // end_SnmpGetLastError
SNMPAPI_STATUS SNMPAPI_CALL SnmpStrToOid (IN LPCSTR string, OUT smiLPOID dstOID) { smiUINT32 i; smiUINT32 compIdx; SNMPAPI_STATUS lError; CHAR c; LPSTR pSep;
// Must be initialized
if (TaskData.hTask == 0) { lError = SNMPAPI_NOT_INITIALIZED; goto ERROR_OUT; }
// use __try, __except to figure out if 'string' is a
// valid pointer. We cannot use IsBadReadPtr() here, as far as
// we have no idea for how many octets we should look.
__try { smiUINT32 sLen;
sLen = strlen(string); if (sLen == 0 || sLen >= MAXOBJIDSTRSIZE) { lError = SNMPAPI_OID_INVALID; goto ERROR_OUT; } } __except(EXCEPTION_EXECUTE_HANDLER) { lError = SNMPAPI_ALLOC_ERROR; goto ERROR_OUT; }
// see if the dstOID pointer provided by the caller points to
// a valid memory range. If null is provided, there is nothing
// the API was requested to do!
if (IsBadWritePtr (dstOID, sizeof(smiOID))) { lError = (dstOID == NULL) ? SNMPAPI_NOOP : SNMPAPI_ALLOC_ERROR; goto ERROR_OUT; }
// Ignore initial '.' in string (UNIX-ism)
if (string[0] == '.') string++;
// figure out how many components this OID has
// count the number of '.' in the string. The OID should
// contain this count + 1 components
dstOID->len = 0; pSep = (LPSTR)string; while((pSep = strchr(pSep, '.')) != NULL) { pSep++; dstOID->len++; } dstOID->len++;
// don't allow less than 2 components
if (dstOID->len < 2) { lError = SNMPAPI_OID_INVALID; goto ERROR_OUT; }
// allocate memory for holding the numeric OID components
// this should be released by the caller, through 'SnmpFreeDescriptor()'
dstOID->ptr = (smiLPUINT32)GlobalAlloc(GPTR, dstOID->len * sizeof(smiUINT32)); if (dstOID->ptr == NULL) { lError = SNMPAPI_ALLOC_ERROR; goto ERROR_OUT; }
compIdx = 0; // when entering the loop, 'string' doesn't have a heading '.'
// NOTE: 123. will be accepted as 123.0
// (123.. a12.3.4 1234....5.6) are considered as invalid OIDs instead
// of truncated to (123.0 0 1234.0).
while (*string != '\0') { dstOID->ptr[compIdx++] = strtoul(string, &pSep, 10);
// if one of the components was overflowing, release the memory and bail out.
if (errno == ERANGE) { errno = 0; lError = SNMPAPI_OID_INVALID; GlobalFree(dstOID->ptr); dstOID->ptr = NULL; goto ERROR_OUT; }
// if strtoul did not make any progress on the string (two successive dots)
// or it was blocked on something else than a separator or null-termination, then
// there was an error. The OID is invalid. API return failure
if (pSep == string || (*pSep != '.' && *pSep != '\0')) { lError = SNMPAPI_OID_INVALID; // invalid char in sequence
if (GlobalFree (dstOID->ptr)) // returns not-NULL on error
{ lError = SNMPAPI_OTHER_ERROR; goto ERROR_OUT; } dstOID->ptr = NULL; dstOID->len = 0; goto ERROR_OUT; }
// pSep can point only to '.' or '\0'
if (*pSep == '.') pSep++;
// restart with string from this point
string = pSep; }
if (dstOID->len < 2) { GlobalFree(dstOID->ptr); dstOID->ptr = NULL; lError = SNMPAPI_OID_INVALID; goto ERROR_OUT; }
return dstOID->len;
ERROR_OUT: return (SaveError (0, lError)); } // end_SnmpStrToOid()
SNMPAPI_STATUS SNMPAPI_CALL SnmpOidToStr (IN smiLPCOID srcOID, IN smiUINT32 strLen, OUT LPSTR strPtr) { SNMPAPI_STATUS lError; smiUINT32 retLen = 0; // used for successful return
smiUINT32 oidIdx = 0; // max subids is 128
smiUINT32 tmpLen; // used for size of decoded string (with '.')
LPSTR tmpPtr = strPtr; // used for advancing strPtr
char tmpBuf[64]; // enough room for 1 32-bit decode and '.'
if (TaskData.hTask == 0) { lError = SNMPAPI_NOT_INITIALIZED; goto ERROR_OUT; }
if (!strLen) { lError = SNMPAPI_SIZE_INVALID; goto ERROR_OUT; }
if (IsBadReadPtr(srcOID, sizeof(smiOID)) || IsBadWritePtr(strPtr, strLen)) { lError = (strPtr == NULL) ? SNMPAPI_NOOP : SNMPAPI_ALLOC_ERROR; goto ERROR_OUT; }
if (srcOID->len == 0 || srcOID->len > 128 || IsBadReadPtr (srcOID->ptr, srcOID->len * sizeof(smiUINT32))) { lError = SNMPAPI_OID_INVALID; goto ERROR_OUT; }
while (oidIdx < srcOID->len) { _ultoa (srcOID->ptr[oidIdx++], tmpBuf, 10); lstrcat (tmpBuf, "."); tmpLen = lstrlen (tmpBuf); if (strLen < (tmpLen + 1)) { tmpBuf[strLen] = '\0'; lstrcpy (tmpPtr, tmpBuf); lError = SNMPAPI_OUTPUT_TRUNCATED; goto ERROR_OUT; } lstrcpy (tmpPtr, tmpBuf); strLen -= tmpLen; tmpPtr += tmpLen; retLen += tmpLen; } // end_while
*(--tmpPtr) = '\0'; return (retLen); //
ERROR_OUT: return (SaveError (0, lError)); } // end_SnmpOidToStr
SNMPAPI_STATUS SNMPAPI_CALL SnmpOidCopy (IN smiLPCOID srcOID, OUT smiLPOID dstOID) { SNMPAPI_STATUS lError; if (TaskData.hTask == 0) { lError = SNMPAPI_NOT_INITIALIZED; goto ERROR_OUT; } if (IsBadReadPtr (srcOID, sizeof(smiOID)) || IsBadReadPtr (srcOID->ptr, srcOID->len) || IsBadWritePtr (dstOID, sizeof(smiOID))) { lError = (dstOID == NULL) ? SNMPAPI_NOOP : SNMPAPI_ALLOC_ERROR; goto ERROR_OUT; } // Check input OID size
if ((srcOID->len == 0) ||(srcOID->len > MAXOBJIDSIZE)) { lError = SNMPAPI_OID_INVALID; goto ERROR_OUT; } // Using dstOID-> temporarily for byte count
dstOID->len = srcOID->len * sizeof(smiUINT32); // App must free following alloc via SnmpFreeDescriptor()
if (!(dstOID->ptr = (smiLPUINT32)GlobalAlloc (GPTR, dstOID->len))) { lError = SNMPAPI_ALLOC_ERROR; goto ERROR_OUT; } CopyMemory (dstOID->ptr, srcOID->ptr, dstOID->len); // Now make dstOID->len mean the right thing
dstOID->len = srcOID->len; return (dstOID->len); //
ERROR_OUT: return (SaveError (0, lError)); } // end_SnmpOidCopy()
SNMPAPI_STATUS SNMPAPI_CALL SnmpFreeDescriptor (IN smiUINT32 syntax, IN smiLPOPAQUE ptr) { SNMPAPI_STATUS lError; if (TaskData.hTask == 0) { lError = SNMPAPI_NOT_INITIALIZED; goto ERROR_OUT; } if (!syntax || !ptr || !ptr->ptr) { lError = SNMPAPI_OPERATION_INVALID; goto ERROR_OUT; } switch (syntax) { case SNMP_SYNTAX_OCTETS: case SNMP_SYNTAX_IPADDR: case SNMP_SYNTAX_OPAQUE: case SNMP_SYNTAX_OID: if (GlobalFree (ptr->ptr)) // returns not-NULL on error
{ lError = SNMPAPI_OTHER_ERROR; goto ERROR_OUT; } ptr->ptr = NULL; ptr->len = 0; break;
default: lError = SNMPAPI_SYNTAX_INVALID; goto ERROR_OUT; } // end_switch
return (SNMPAPI_SUCCESS); //
ERROR_OUT: return (SaveError (0, lError)); } // end_SnmpFreeDescriptor
// SnmpOidCompare
//
// Re-worked by 3/17/95 BobN
SNMPAPI_STATUS SNMPAPI_CALL SnmpOidCompare (IN smiLPCOID xOID, IN smiLPCOID yOID, IN smiUINT32 maxlen, OUT smiLPINT result) { smiUINT32 i = 0; smiUINT32 j = 0; SNMPAPI_STATUS lError; if (TaskData.hTask == 0) { lError = SNMPAPI_NOT_INITIALIZED; goto ERROR_OUT; } if (maxlen > MAXOBJIDSIZE) { lError = SNMPAPI_SIZE_INVALID; goto ERROR_OUT; }
if (IsBadReadPtr (xOID, sizeof(smiOID)) || IsBadReadPtr (yOID, sizeof(smiOID))) { lError = SNMPAPI_ALLOC_ERROR; goto ERROR_OUT; }
if (IsBadReadPtr (xOID->ptr, xOID->len * sizeof(UINT)) || IsBadReadPtr (yOID->ptr, yOID->len * sizeof(UINT))) { lError = SNMPAPI_OID_INVALID; goto ERROR_OUT; }
// Test input pointers for readability
if (IsBadWritePtr (result, sizeof(smiINT))) { lError = (result == NULL) ? SNMPAPI_NOOP : SNMPAPI_ALLOC_ERROR; goto ERROR_OUT; }
j = min(xOID->len, yOID->len); if (maxlen) j = min(j, maxlen); while (i < j) { if (*result = xOID->ptr[i] - yOID->ptr[i]) // deliberate assignment
return (SNMPAPI_SUCCESS); // not equal...got a winner!
i++; } if (j == maxlen) // asked for a limit
return (SNMPAPI_SUCCESS); // and...got a draw!
*result = xOID->len - yOID->len; // size matters!
return SNMPAPI_SUCCESS; //
ERROR_OUT: return (SaveError (0, lError)); } // end_SnmpOidCompare
SNMPAPI_STATUS SNMPAPI_CALL SnmpEncodeMsg (IN HSNMP_SESSION hSession, IN HSNMP_ENTITY hSrc, IN HSNMP_ENTITY hDst, IN HSNMP_CONTEXT hCtx, IN HSNMP_PDU hPdu, IN OUT smiLPOCTETS msgBufDesc) { smiUINT32 version = 0; DWORD nCtx; DWORD nPdu; DWORD nVbl; smiOCTETS tmpContext; smiLPBYTE msgAddr = NULL; smiUINT32 lError = SNMPAPI_SUCCESS; HSNMP_SESSION lSession = 0; LPPDUS pPdu; LPENTITY pEntSrc, pEntDst; LPCTXT pCtxt;
// Basic error checks
if (TaskData.hTask == 0) { lError = SNMPAPI_NOT_INITIALIZED; goto ERROR_OUT; } if (!snmpValidTableEntry(&SessDescr, HandleToUlong(hSession)-1)) { lError = SNMPAPI_SESSION_INVALID; goto ERROR_OUT; } // We have a valid session at this point...
lSession = hSession; // save it for possible error return
// Check for writable output buffer
if (IsBadWritePtr (msgBufDesc, sizeof(smiOCTETS))) { lError = (msgBufDesc == NULL) ? SNMPAPI_NOOP : SNMPAPI_ALLOC_ERROR; goto ERROR_OUT; } // srcEntity not currently used
if (hSrc) { if (!snmpValidTableEntry(&EntsDescr, HandleToUlong(hSrc)-1)) { lError = SNMPAPI_ENTITY_INVALID; goto ERROR_OUT; } pEntSrc = snmpGetTableEntry(&EntsDescr, HandleToUlong(hSrc)-1); } // dstEntity is required for *accurate* msg version info
if (hDst) { if (!snmpValidTableEntry(&EntsDescr, HandleToUlong(hDst)-1)) { lError = SNMPAPI_ENTITY_INVALID; goto ERROR_OUT; } pEntDst = snmpGetTableEntry(&EntsDescr, HandleToUlong(hDst)-1); version = pEntDst->version-1; } nCtx = HandleToUlong(hCtx) - 1; if (!snmpValidTableEntry(&CntxDescr, nCtx)) { lError = SNMPAPI_CONTEXT_INVALID; goto ERROR_OUT; } pCtxt = snmpGetTableEntry(&CntxDescr, nCtx);
nPdu = HandleToUlong(hPdu) - 1; if (!snmpValidTableEntry(&PDUsDescr, nPdu)) { ERROR_PDU: lError = SNMPAPI_PDU_INVALID; goto ERROR_OUT; } pPdu = snmpGetTableEntry(&PDUsDescr, nPdu);
// Necessary PDU data checks
nVbl = HandleToUlong(pPdu->VBL); if (!snmpValidTableEntry(&VBLsDescr, nVbl-1)) goto ERROR_PDU; // Check out for SNMPv1 Trap PDU type...uses different PDU structure!
// ???
// Check for SNMPv2c PDU types
if (pPdu->type == SNMP_PDU_TRAP || pPdu->type == SNMP_PDU_INFORM) version = 1; // Now Build it
tmpContext.len = pCtxt->commLen; tmpContext.ptr = pCtxt->commStr; if (!(BuildMessage (version, &tmpContext, pPdu, pPdu->appReqId, &msgAddr, &msgBufDesc->len))) goto ERROR_PDU; // Copy Snmp message to caller's buffer...
// App must free following alloc via SnmpFreeDescriptor()
if (!(msgBufDesc->ptr = (smiLPBYTE)GlobalAlloc (GPTR, msgBufDesc->len))) lError = SNMPAPI_ALLOC_ERROR; else // SUCCESS
CopyMemory (msgBufDesc->ptr, msgAddr, msgBufDesc->len); ERROR_OUT: // Clean up
if (msgAddr) GlobalFree (msgAddr); if (lError == SNMPAPI_SUCCESS) return (msgBufDesc->len); else // Failure cases
return (SaveError (lSession, lError)); }
SNMPAPI_STATUS SNMPAPI_CALL SnmpDecodeMsg (IN HSNMP_SESSION hSession, OUT LPHSNMP_ENTITY hSrc, OUT LPHSNMP_ENTITY hDst, OUT LPHSNMP_CONTEXT hCtx, OUT LPHSNMP_PDU hPdu, IN smiLPCOCTETS msgPtr) { DWORD nPdu; smiLPOCTETS community; smiUINT32 version; SNMPAPI_STATUS lError = SNMPAPI_SUCCESS; HSNMP_SESSION lSession = 0; LPPDUS pPdu;
if (TaskData.hTask == 0) { lError = SNMPAPI_NOT_INITIALIZED; goto ERROR_OUT; } if (!snmpValidTableEntry(&SessDescr, HandleToUlong(hSession)-1)) { lError = SNMPAPI_SESSION_INVALID; goto ERROR_OUT; } // Valid session...save for possible error return
lSession = hSession;
if (IsBadReadPtr(msgPtr, sizeof(smiOCTETS)) || IsBadReadPtr(msgPtr->ptr, msgPtr->len)) { lError = SNMPAPI_ALLOC_ERROR; goto ERROR_OUT; }
if (hSrc == NULL && hDst == NULL && hCtx == NULL && hPdu == NULL) { lError = SNMPAPI_NOOP; goto ERROR_OUT; }
if ((hDst != NULL && IsBadWritePtr(hDst, sizeof(HSNMP_ENTITY))) || (hSrc != NULL && IsBadWritePtr(hSrc, sizeof(HSNMP_ENTITY)))) { lError = SNMPAPI_ENTITY_INVALID; goto ERROR_OUT; }
if (hCtx != NULL && IsBadWritePtr(hCtx, sizeof(HSNMP_CONTEXT))) { lError = SNMPAPI_CONTEXT_INVALID; goto ERROR_OUT; }
if (IsBadWritePtr(hPdu, sizeof(HSNMP_PDU))) { lError = SNMPAPI_PDU_INVALID; goto ERROR_OUT; }
EnterCriticalSection (&cs_PDU); lError = snmpAllocTableEntry(&PDUsDescr, &nPdu); if (lError != SNMPAPI_SUCCESS) goto ERROR_PRECHECK; pPdu = snmpGetTableEntry(&PDUsDescr, nPdu);
if (ParseMessage (msgPtr->ptr, msgPtr->len, &version, &community, pPdu)) { // non-zero = some error code
lError = SNMPAPI_MESSAGE_INVALID; SnmpFreePdu((HSNMP_PDU) ULongToPtr(nPdu+1)); goto ERROR_PRECHECK; } if (hDst != NULL) *hDst = 0; if (hSrc != NULL) *hSrc = 0; if (hCtx != NULL) { smiUINT32 nMode; EnterCriticalSection (&cs_XMODE); SnmpGetTranslateMode (&nMode); SnmpSetTranslateMode (SNMPAPI_UNTRANSLATED_V1); if ((*hCtx = SnmpStrToContext (hSession, community)) == SNMPAPI_FAILURE) { LeaveCriticalSection (&cs_XMODE); lError = SNMPAPI_OTHER_ERROR; FreeOctetString (community); SnmpFreePdu((HSNMP_PDU) ULongToPtr(nPdu+1)); goto ERROR_PRECHECK; } SnmpSetTranslateMode (nMode); LeaveCriticalSection (&cs_XMODE); } FreeOctetString (community); pPdu->Session = hSession; if (hPdu != NULL) *hPdu = (HSNMP_PDU) ULongToPtr(nPdu+1); else SnmpFreePdu((HSNMP_PDU) ULongToPtr(nPdu+1));
ERROR_PRECHECK: LeaveCriticalSection (&cs_PDU); if (lError == SNMPAPI_SUCCESS) { SaveError(lSession, lError); return (msgPtr->len); }
ERROR_OUT: return (SaveError (lSession, lError)); } // end_SnmpDecodeMsg()
#define NETLEN 4
#define NODELEN 6
char *cHexDigits = "0123456789ABCDEF"; SNMPAPI_STATUS SNMPAPI_CALL SnmpStrToIpxAddress (LPCSTR str, LPBYTE netnum, LPBYTE nodenum) { LPSTR netPtr, nodePtr, pStr; DWORD i, j; char tmpStr[24+1]; BYTE c1, c2; if (!str || !netnum || !nodenum) return (SNMPAPI_FAILURE); strncpy (tmpStr, str,24); tmpStr[24] = '\0'; netPtr = strtok (tmpStr, "-:."); if (netPtr == NULL) return (SNMPAPI_FAILURE); if (lstrlen (netPtr) != NETLEN*2) return (SNMPAPI_FAILURE); nodePtr = netPtr + (NETLEN*2) + 1; if (lstrlen (nodePtr) != NODELEN*2) return (SNMPAPI_FAILURE); _strupr (netPtr); for (i = 0, j = 0; j < NETLEN; j++) { pStr = strchr (cHexDigits, netPtr[i++]); if (pStr == NULL) return (SNMPAPI_FAILURE); c1 = (BYTE)(pStr - cHexDigits); pStr = strchr (cHexDigits, netPtr[i++]); if (pStr == NULL) return (SNMPAPI_FAILURE); c2 = (BYTE)(pStr - cHexDigits); netnum[j] = c2 | c1 << 4; } _strupr (nodePtr); for (i = 0, j = 0; j < NODELEN; j++) { pStr = strchr (cHexDigits, nodePtr[i++]); if (pStr == NULL) return (SNMPAPI_FAILURE); c1 = (BYTE)(pStr - cHexDigits); pStr = strchr (cHexDigits, nodePtr[i++]); if (pStr == NULL) return (SNMPAPI_FAILURE); c2 = (BYTE)(pStr - cHexDigits); nodenum[j] = c2 | c1 << 4; } return (SNMPAPI_SUCCESS); }
SNMPAPI_STATUS SNMPAPI_CALL SnmpIpxAddressToStr (LPBYTE netnum, LPBYTE nodenum, LPSTR str) { DWORD i, j; for (i = 0, j = 0; i < NETLEN; i++) { str[j++] = cHexDigits[(netnum[i] & 0xF0) >> 4]; str[j++] = cHexDigits[netnum[i] & 0x0F]; } str[j++] = ':'; for (i = 0; i < NODELEN; i++) { str[j++] = cHexDigits[(nodenum[i] & 0xF0) >> 4]; str[j++] = cHexDigits[nodenum[i] & 0x0F]; } str[j] = '\0'; return (SNMPAPI_SUCCESS); }
|