// 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 (bnatale@acecomm.com) // // 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); }