477 lines
16 KiB
C++
477 lines
16 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (C) 1996-2001 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
PROVSNMP.CPP
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Purpose: Defines the acutal "Put" and "Get" functions for the
|
||
|
"SNMP" file provider. The syntax of the mapping string is;
|
||
|
"TBD"
|
||
|
|
||
|
History:
|
||
|
|
||
|
TBD 4-5-96 v0.01.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#include "stdafx.h"
|
||
|
#include <wbemidl.h>
|
||
|
#include "impdyn.h"
|
||
|
|
||
|
// This max size just prevents the read from incrementing to the point
|
||
|
// where CStrings no longer work
|
||
|
|
||
|
#define MAXSIZE 0x4FFF
|
||
|
|
||
|
//SNMP specific constants
|
||
|
#define TIMEOUT 500
|
||
|
#define RETRIES 3
|
||
|
#define IPADDRESSSTRLEN 16
|
||
|
//Indexes of SNMP parameters in the provider string
|
||
|
#define AGENT_INX 0
|
||
|
#define COMMUNITY_INX 1
|
||
|
#define OID_INX 2
|
||
|
|
||
|
BYTE HEXCHAR[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||
|
|
||
|
|
||
|
BOOL IsDisplayable(AsnOctetString OctetString)
|
||
|
{
|
||
|
BYTE *p;
|
||
|
UINT i;
|
||
|
|
||
|
for (i=0, p=OctetString.stream;
|
||
|
((i<OctetString.length) && ((*p >= 0x20) && (*p <= 0x7E)));
|
||
|
i++, p++);
|
||
|
if (i == OctetString.length)
|
||
|
return(TRUE);
|
||
|
else
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
//***************************************************************************
|
||
|
//
|
||
|
// CImpSNMP::CImpSNMP
|
||
|
//
|
||
|
// Constructor. Only current purpose is to call its base class constructor.
|
||
|
//
|
||
|
//***************************************************************************
|
||
|
|
||
|
CImpSNMP::CImpSNMP(LPUNKNOWN pUnkOuter) : CImpDyn(pUnkOuter)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//***************************************************************************
|
||
|
//
|
||
|
// CImpSNMP::StartBatch
|
||
|
//
|
||
|
// Called at the start of a batch of gets or puts.
|
||
|
// Retrieve agent & community from first provider string (ignore all other)
|
||
|
// and open a session with this agent for SNMP requests.
|
||
|
//
|
||
|
//***************************************************************************
|
||
|
|
||
|
void CImpSNMP::StartBatch(MODYNPROP * pMo,CObject **pObj,DWORD dwListSize,BOOL bGet)
|
||
|
{
|
||
|
TCHAR *agentStr; //IP address as String
|
||
|
TCHAR *communityStr; //Community String
|
||
|
|
||
|
*pObj = NULL;
|
||
|
generalError = 0;
|
||
|
Session = NULL;
|
||
|
//Reset variable binding list
|
||
|
variableBindings.list = NULL;
|
||
|
variableBindings.len = 0;
|
||
|
TCHAR * pMapString;
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
pMapString = pMo->pProviderString;
|
||
|
#else
|
||
|
pMapString = WideToNarrow(pMo->pProviderString);
|
||
|
#endif
|
||
|
|
||
|
//Retrieve agent & community information from 1st property structure :
|
||
|
//Create token object and make sure it has enough tokens
|
||
|
CProvObj ProvObj(pMapString,MAIN_DELIM);
|
||
|
if(ProvObj.dwGetStatus() != WBEM_NO_ERROR)
|
||
|
{
|
||
|
generalError = ProvObj.dwGetStatus();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(ProvObj.iGetNumTokens() < iGetMinTokens())
|
||
|
{
|
||
|
generalError = M_MISSING_INFORMATION;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//Provider string seems OK -
|
||
|
//Extract agent address & community name and open SNMP session with agent
|
||
|
agentStr = new TCHAR[lstrlen(ProvObj.sGetToken(AGENT_INX))+1];
|
||
|
//(TCHAR *)CoTaskMemAlloc(lstrlen(ProvObj.sGetToken(AGENT_INX))+1);
|
||
|
if (agentStr == NULL)
|
||
|
{
|
||
|
generalError = WBEM_E_OUT_OF_MEMORY;
|
||
|
return;
|
||
|
}
|
||
|
lstrcpy(agentStr, ProvObj.sGetToken(AGENT_INX));
|
||
|
|
||
|
communityStr = new TCHAR[lstrlen(ProvObj.sGetToken(COMMUNITY_INX))+1];
|
||
|
//(TCHAR *)CoTaskMemAlloc(lstrlen(ProvObj.sGetToken(COMMUNITY_INX)));
|
||
|
if (communityStr == NULL)
|
||
|
{
|
||
|
generalError = WBEM_E_OUT_OF_MEMORY;
|
||
|
delete agentStr;
|
||
|
//CoTaskMemFree(agentStr);
|
||
|
return;
|
||
|
}
|
||
|
lstrcpy(communityStr, ProvObj.sGetToken(COMMUNITY_INX));
|
||
|
|
||
|
Session = SnmpMgrOpen(agentStr, communityStr, TIMEOUT, RETRIES);
|
||
|
if (Session == NULL) //error
|
||
|
{
|
||
|
generalError = GetLastError();
|
||
|
delete agentStr; delete communityStr;
|
||
|
//CoTaskMemFree(agentStr); CoTaskMemFree(communityStr);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//Set requestType value
|
||
|
requestType = (bGet ? ASN_RFC1157_GETREQUEST : ASN_RFC1157_SETREQUEST);
|
||
|
|
||
|
//Free allocated buffers for agent & community - not needed once the session is open
|
||
|
delete agentStr; delete communityStr;
|
||
|
//CoTaskMemFree(agentStr); CoTaskMemFree(communityStr);
|
||
|
|
||
|
//Free pMapString
|
||
|
#ifndef UNICODE
|
||
|
if(pMapString)
|
||
|
CoTaskMemFree(pMapString);
|
||
|
#endif
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//***************************************************************************
|
||
|
//
|
||
|
// CImpSNMP::EndBatch
|
||
|
//
|
||
|
// Called at the end of a batch of gets or puts.
|
||
|
// At this point we should have a valid session open and a variable binding
|
||
|
// constructed. If so, send the SNMP request, and after receiving the answer
|
||
|
// close the session with this agent.
|
||
|
//
|
||
|
//***************************************************************************
|
||
|
|
||
|
void CImpSNMP::EndBatch(MODYNPROP *pMo,CObject *pObj,DWORD dwListSize,BOOL bGet)
|
||
|
{
|
||
|
AsnInteger errorStatus;
|
||
|
AsnInteger errorIndex;
|
||
|
DWORD reqCnt;
|
||
|
DWORD varBindCnt;
|
||
|
DWORD allocatedLength;
|
||
|
|
||
|
//temps to hold values for conversion
|
||
|
AsnObjectSyntax *SNMPValue;
|
||
|
BYTE *OLESMValue;
|
||
|
|
||
|
if ((Session == NULL) || (generalError != 0))
|
||
|
return;
|
||
|
|
||
|
//Carry out request
|
||
|
if (!SnmpMgrRequest(Session, requestType, &variableBindings, &errorStatus, &errorIndex))
|
||
|
//API error occured
|
||
|
generalError = GetLastError();
|
||
|
|
||
|
|
||
|
varBindCnt = 0;
|
||
|
for (reqCnt = 0; reqCnt < dwListSize; reqCnt++, pMo++)
|
||
|
{
|
||
|
//if request failed above, need to set all dwResults to the failure code
|
||
|
if (generalError != 0)
|
||
|
{
|
||
|
pMo->dwResult = generalError;
|
||
|
continue;
|
||
|
}
|
||
|
//if dwResult was already set to an error, this request was not sent in the SNMP message
|
||
|
// in the first place, so skip to the next one
|
||
|
if (pMo->dwResult != WBEM_NO_ERROR)
|
||
|
continue;
|
||
|
|
||
|
if (errorStatus != SNMP_ERRORSTATUS_NOERROR)
|
||
|
{
|
||
|
//There was an SNMP error - no values are returned
|
||
|
pMo->pPropertyValue = NULL;
|
||
|
pMo->dwResult = WBEM_E_FAILED;
|
||
|
//should I return specific SNMP error ?????
|
||
|
//the errorIndex information is lost here !!!!
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//Value is valid - try converting to supported types
|
||
|
SNMPValue = &(variableBindings.list[varBindCnt].value);
|
||
|
generalError = CopySNMPValToOLESMVal(SNMPValue, &OLESMValue, pMo->dwType, &allocatedLength);
|
||
|
if (generalError != 0)
|
||
|
{ //error detected when converting types
|
||
|
pMo->pPropertyValue = NULL;
|
||
|
pMo->dwBufferSize = 0;
|
||
|
pMo->dwResult = generalError;
|
||
|
}
|
||
|
else
|
||
|
{ //types converted OK, so OLESMValue is pointing to the newly allocated value
|
||
|
pMo->pPropertyValue = OLESMValue;
|
||
|
pMo->dwBufferSize = allocatedLength;
|
||
|
pMo->dwResult = WBEM_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
varBindCnt++;
|
||
|
}//for
|
||
|
|
||
|
//Free variable bindings structure
|
||
|
if (variableBindings.list != NULL)
|
||
|
CoTaskMemFree(variableBindings.list);
|
||
|
|
||
|
//Close session with agent (don't check status since we can't return error anyway....????)
|
||
|
SnmpMgrClose(Session);
|
||
|
|
||
|
return;
|
||
|
|
||
|
}//EndBatch
|
||
|
|
||
|
//***************************************************************************
|
||
|
//
|
||
|
// CImpSNMP::GetProp
|
||
|
//
|
||
|
// Builds a variable binding for the current property
|
||
|
//
|
||
|
//***************************************************************************
|
||
|
|
||
|
void CImpSNMP::GetProp(MODYNPROP * pMo, CProvObj & ProvObj,CObject * pPackage)
|
||
|
{
|
||
|
TCHAR * oidStr;
|
||
|
AsnObjectIdentifier reqObject;
|
||
|
|
||
|
pMo->dwResult = WBEM_NO_ERROR; //To be checked in EndBatch()
|
||
|
|
||
|
//If Session is not open - error !
|
||
|
if ((Session == NULL) || (generalError != 0))
|
||
|
{
|
||
|
pMo->dwResult = generalError;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//Extract OID of property from provider string
|
||
|
oidStr = new TCHAR[lstrlen(ProvObj.sGetToken(OID_INX))+1];
|
||
|
//(TCHAR *)CoTaskMemAlloc(lstrlen(ProvObj.sGetToken(OID_INX)));
|
||
|
if (oidStr == NULL)
|
||
|
{
|
||
|
pMo->dwResult = WBEM_E_OUT_OF_MEMORY;
|
||
|
return;
|
||
|
}
|
||
|
lstrcpy(oidStr, ProvObj.sGetToken(OID_INX)); //oid is the 3rd parameter in the provider string
|
||
|
|
||
|
//Convert string representation of OID to internal rep.
|
||
|
if (!SnmpMgrStrToOid(oidStr, &reqObject))
|
||
|
{
|
||
|
pMo->dwResult = M_MISSING_INFORMATION;
|
||
|
delete oidStr;
|
||
|
//CoTaskMemFree(oidStr);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//If conversion successful, free OID string - not needed once we have the OID in internal rep.
|
||
|
delete oidStr;
|
||
|
//CoTaskMemFree(oidStr);
|
||
|
|
||
|
//Allocate new variable binding in list
|
||
|
variableBindings.list =
|
||
|
(RFC1157VarBind *)CoTaskMemRealloc(variableBindings.list,
|
||
|
sizeof(RFC1157VarBind) * (variableBindings.len+1));
|
||
|
if (variableBindings.list == NULL) //allocation failed
|
||
|
{
|
||
|
pMo->dwResult = WBEM_E_OUT_OF_MEMORY;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//if allocation succesful, copy info to new variable binding
|
||
|
variableBindings.len++;
|
||
|
variableBindings.list[variableBindings.len - 1].name = reqObject; //structure copy !!
|
||
|
variableBindings.list[variableBindings.len - 1].value.asnType = ASN_NULL;
|
||
|
return;
|
||
|
}//GetProp
|
||
|
|
||
|
|
||
|
//***************************************************************************
|
||
|
//
|
||
|
// CImpSNMP::SetProp
|
||
|
//
|
||
|
// Writes the value of a single property
|
||
|
//
|
||
|
//***************************************************************************
|
||
|
|
||
|
void CImpSNMP::SetProp(MODYNPROP * pMo, CProvObj & ProvObj,CObject * pPackage)
|
||
|
{
|
||
|
CString sString;
|
||
|
|
||
|
sString = ProvObj.sGetToken(0);
|
||
|
pMo->dwResult = 0 ;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
//***************************************************************************
|
||
|
//
|
||
|
// CImpSNMP::CopySNMPValToOLESMVal
|
||
|
//
|
||
|
// Converts an SNMP value to an OLESM supported type, allocates and sets
|
||
|
// the value in the property structure.
|
||
|
// The pLen parameter outputs the length of the allocated memory
|
||
|
// The return value specifies the outcome of the function (0 for success)
|
||
|
//
|
||
|
//***************************************************************************
|
||
|
|
||
|
DWORD CImpSNMP::CopySNMPValToOLESMVal(AsnAny *fromVal, BYTE **pToVal, DWORD OLESMType, DWORD *pLen)
|
||
|
{
|
||
|
DWORD ret = WBEM_NO_ERROR;
|
||
|
UINT i;
|
||
|
BYTE *pSrc, *pDst;
|
||
|
|
||
|
switch (OLESMType)
|
||
|
{
|
||
|
case M_TYPE_DWORD :
|
||
|
if ((fromVal->asnType == ASN_INTEGER) || (fromVal->asnType == ASN_RFC1155_COUNTER) ||
|
||
|
(fromVal->asnType == ASN_RFC1155_GAUGE) || (fromVal->asnType == ASN_RFC1155_TIMETICKS))
|
||
|
{
|
||
|
if (!(*pToVal = (BYTE *)CoTaskMemAlloc(sizeof(DWORD))))
|
||
|
ret = WBEM_E_OUT_OF_MEMORY;
|
||
|
else
|
||
|
{ //allocation succeeded
|
||
|
*pLen = sizeof(DWORD);
|
||
|
switch (fromVal->asnType)
|
||
|
{
|
||
|
case ASN_INTEGER : *(DWORD *)(*pToVal) = fromVal->asnValue.number; break;
|
||
|
case ASN_RFC1155_COUNTER : *(DWORD *)(*pToVal) = fromVal->asnValue.counter; break;
|
||
|
case ASN_RFC1155_GAUGE : *(DWORD *)(*pToVal) = fromVal->asnValue.gauge; break;
|
||
|
case ASN_RFC1155_TIMETICKS : *(DWORD *)(*pToVal) = fromVal->asnValue.ticks; break;
|
||
|
default : break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
ret = M_TYPE_MISMATCH;
|
||
|
break;
|
||
|
|
||
|
case M_TYPE_LPSTR :
|
||
|
switch (fromVal->asnType)
|
||
|
{
|
||
|
case ASN_OCTETSTRING :
|
||
|
if (IsDisplayable(fromVal->asnValue.string))
|
||
|
//Need to add '\0' only
|
||
|
if (!(*pToVal = (BYTE *)CoTaskMemAlloc(fromVal->asnValue.string.length+1)))
|
||
|
ret = WBEM_E_OUT_OF_MEMORY;
|
||
|
else
|
||
|
{ //allocation succeeded
|
||
|
*pLen = fromVal->asnValue.string.length+1;
|
||
|
memcpy(*pToVal, fromVal->asnValue.string.stream, fromVal->asnValue.string.length);
|
||
|
*(*pToVal + (*pLen-1)) = '\0';
|
||
|
}
|
||
|
else //String is stream of bytes (non-displayable)
|
||
|
//Need to copy non-displayable characters to "^XX" format
|
||
|
//Allocate 3 chars for every byte in the stream + '\0'
|
||
|
if (!(*pToVal = (BYTE *)CoTaskMemAlloc((fromVal->asnValue.string.length * 3) + 1)))
|
||
|
ret = WBEM_E_OUT_OF_MEMORY;
|
||
|
else
|
||
|
{ //allocation succeeded
|
||
|
*pLen = (fromVal->asnValue.string.length * 3) + 1;
|
||
|
for (i=0, pSrc=fromVal->asnValue.string.stream, pDst=*pToVal;
|
||
|
i<fromVal->asnValue.string.length;
|
||
|
i++, pSrc++)
|
||
|
{
|
||
|
*(pDst++) = '^';
|
||
|
*(pDst++) = HEXCHAR[(*pSrc & 0x0F)];
|
||
|
*(pDst++) = HEXCHAR[((*pSrc & 0xF0) >> 4)];
|
||
|
}
|
||
|
*(*pToVal + (*pLen-1)) = '\0';
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
case ASN_OBJECTIDENTIFIER :
|
||
|
{
|
||
|
TCHAR *oidStr = NULL;
|
||
|
SnmpMgrOidToStr(&(fromVal->asnValue.object), &oidStr);
|
||
|
if (!oidStr)
|
||
|
ret = WBEM_E_OUT_OF_MEMORY;
|
||
|
else
|
||
|
{
|
||
|
if (!(*pToVal = (BYTE *)CoTaskMemAlloc(lstrlen(oidStr)+1)))
|
||
|
ret = WBEM_E_OUT_OF_MEMORY;
|
||
|
else
|
||
|
{
|
||
|
*pLen = lstrlen(oidStr)+1;
|
||
|
memcpy(*pToVal, oidStr, *pLen);
|
||
|
}
|
||
|
GlobalFree(oidStr);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case ASN_SEQUENCE :
|
||
|
if (!(*pToVal = (BYTE *)CoTaskMemAlloc(fromVal->asnValue.sequence.length)))
|
||
|
ret = WBEM_E_OUT_OF_MEMORY;
|
||
|
else
|
||
|
{
|
||
|
*pLen = fromVal->asnValue.sequence.length;
|
||
|
memcpy(*pToVal, fromVal->asnValue.sequence.stream, fromVal->asnValue.sequence.length);
|
||
|
}
|
||
|
break;
|
||
|
case ASN_RFC1155_IPADDRESS :
|
||
|
//allocate a string for string representation of IP address
|
||
|
if (!(*pToVal = (BYTE *)CoTaskMemAlloc(IPADDRESSSTRLEN)))
|
||
|
ret = WBEM_E_OUT_OF_MEMORY;
|
||
|
else
|
||
|
{ //allocation succeeded
|
||
|
//Copy IP address to formatted string
|
||
|
sprintf((TCHAR *)*pToVal, "%u.%u.%u.%u\0", *(fromVal->asnValue.address.stream),
|
||
|
*(fromVal->asnValue.address.stream+1),
|
||
|
*(fromVal->asnValue.address.stream+2),
|
||
|
*(fromVal->asnValue.address.stream+3));
|
||
|
*pLen = lstrlen((TCHAR *)*pToVal)+1;
|
||
|
//*pLen = fromVal->asnValue.address.length;
|
||
|
//memcpy(*pToVal, fromVal->asnValue.address.stream, fromVal->asnValue.address.length);
|
||
|
}
|
||
|
break;
|
||
|
case ASN_RFC1155_OPAQUE :
|
||
|
if (!(*pToVal = (BYTE *)CoTaskMemAlloc(fromVal->asnValue.arbitrary.length)))
|
||
|
ret = WBEM_E_OUT_OF_MEMORY;
|
||
|
else
|
||
|
{
|
||
|
*pLen = fromVal->asnValue.arbitrary.length;
|
||
|
memcpy(*pToVal, fromVal->asnValue.arbitrary.stream, fromVal->asnValue.arbitrary.length);
|
||
|
}
|
||
|
break;
|
||
|
default :
|
||
|
ret = M_TYPE_MISMATCH;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
default :
|
||
|
ret = M_TYPE_NOT_SUPPORTED;
|
||
|
break;
|
||
|
}//switch (OLESMType)
|
||
|
|
||
|
if (ret != WBEM_NO_ERROR) //error
|
||
|
{
|
||
|
*pToVal = NULL;
|
||
|
*pLen = 0;
|
||
|
}
|
||
|
|
||
|
return(ret);
|
||
|
|
||
|
}//CopySNMPValToOLESMVal()
|
||
|
|