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.
1551 lines
46 KiB
1551 lines
46 KiB
// wsnmp_cf.c
|
|
//
|
|
// WinSNMP Communications Functions and helpers
|
|
// Copyright 1995-1998 ACE*COMM Corp
|
|
// Rleased to Microsoft under Contract
|
|
//
|
|
// Bob Natale ([email protected])
|
|
//
|
|
// 19980625 - Modified SnmpStartup() to allow for NULL
|
|
// output args and to check for IsBadWritePtr()
|
|
// when non-NULL
|
|
//
|
|
#include "winsnmp.inc"
|
|
|
|
#define SNMP_MAJOR_VERSION 2
|
|
#define SNMP_MINOR_VERSION 0
|
|
#define SNMP_SUPPORT_LEVEL SNMPAPI_V2_SUPPORT
|
|
|
|
|
|
LPPDUS MapV2TrapV1 (HSNMP_PDU hPdu);
|
|
THR_TYPE WINAPI thrManager (LPVOID);
|
|
THR_TYPE WINAPI thrTrap (LPVOID);
|
|
THR_TYPE WINAPI thrTimer (LPVOID);
|
|
THR_TYPE WINAPI thrAgent (LPVOID);
|
|
THR_TYPE WINAPI thrNotify (LPVOID);
|
|
|
|
void FreeRegister (DWORD nTrap)
|
|
{
|
|
LPTRAPNOTICE pTrap;
|
|
EnterCriticalSection (&cs_TRAP);
|
|
pTrap = snmpGetTableEntry(&TrapDescr, nTrap);
|
|
if (pTrap->ourEntity)
|
|
SnmpFreeEntity (pTrap->ourEntity);
|
|
if (pTrap->agentEntity)
|
|
SnmpFreeEntity (pTrap->agentEntity);
|
|
if (pTrap->Context)
|
|
SnmpFreeContext (pTrap->Context);
|
|
snmpFreeTableEntry(&TrapDescr, nTrap);
|
|
LeaveCriticalSection (&cs_TRAP);
|
|
return;
|
|
} // end_FreeRegister
|
|
|
|
// Exported Functions
|
|
// SnmpStartup
|
|
SNMPAPI_STATUS SNMPAPI_CALL
|
|
SnmpStartup (OUT smiLPUINT32 nMajorVersion,
|
|
OUT smiLPUINT32 nMinorVersion,
|
|
OUT smiLPUINT32 nLevel,
|
|
OUT smiLPUINT32 nTranslateMode,
|
|
OUT smiLPUINT32 nRetransmitMode)
|
|
{
|
|
WSADATA wsaData;
|
|
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
|
|
HSNMP_SESSION hTask = (HSNMP_SESSION) ULongToPtr(GetCurrentProcessId());
|
|
//
|
|
|
|
//
|
|
if (nMajorVersion)
|
|
{
|
|
if (IsBadWritePtr (nMajorVersion, sizeof(smiUINT32)))
|
|
goto ARG_ERROR;
|
|
*nMajorVersion = SNMP_MAJOR_VERSION;
|
|
}
|
|
if (nMinorVersion)
|
|
{
|
|
if (IsBadWritePtr (nMinorVersion, sizeof(smiUINT32)))
|
|
goto ARG_ERROR;
|
|
*nMinorVersion = SNMP_MINOR_VERSION;
|
|
}
|
|
if (nLevel)
|
|
{
|
|
if (IsBadWritePtr (nLevel, sizeof(smiUINT32)))
|
|
goto ARG_ERROR;
|
|
*nLevel = SNMP_SUPPORT_LEVEL;
|
|
}
|
|
if (nTranslateMode)
|
|
{
|
|
if (IsBadWritePtr (nTranslateMode, sizeof(smiUINT32)))
|
|
goto ARG_ERROR;
|
|
*nTranslateMode = SNMPAPI_UNTRANSLATED_V1;
|
|
}
|
|
if (nRetransmitMode)
|
|
{
|
|
if (IsBadWritePtr (nRetransmitMode, sizeof(smiUINT32)))
|
|
goto ARG_ERROR;
|
|
*nRetransmitMode = SNMPAPI_ON;
|
|
}
|
|
goto ARGS_OK;
|
|
ARG_ERROR:
|
|
lError = SNMPAPI_ALLOC_ERROR;
|
|
goto ERROR_OUT;
|
|
ARGS_OK:
|
|
EnterCriticalSection (&cs_TASK);
|
|
TaskData.nRetransmitMode = SNMPAPI_ON;
|
|
TaskData.nTranslateMode = SNMPAPI_UNTRANSLATED_V1;
|
|
// we need to turn this on in order to have WINSNMP to pass back not
|
|
// only the entity standing for the source Ip address but also the
|
|
// agent address as it was sent into the V1 Trap Pdu.
|
|
TaskData.conveyAddress = SNMPAPI_ON;
|
|
// SnmpStartup is idempotent...
|
|
if (TaskData.hTask == hTask)
|
|
goto DONE; // ...already called
|
|
// New task starting up...get OS info
|
|
TaskData.sEnv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (!GetVersionEx (&TaskData.sEnv))
|
|
{
|
|
lError = SNMPAPI_OTHER_ERROR;
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
// Start WinSock connection...should return 0
|
|
if (WSAStartup ((WORD)0x0101, &wsaData))
|
|
{
|
|
lError = SNMPAPI_TL_NOT_INITIALIZED;
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
// Set trapPipe (used in NT case only)
|
|
TaskData.trapPipe = INVALID_HANDLE_VALUE;
|
|
// bug# 270672
|
|
// create non-signaled event to synchronize shutdown of thrTrap
|
|
TaskData.trapEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
|
|
if (NULL == TaskData.trapEvent)
|
|
{
|
|
lError = SNMPAPI_ALLOC_ERROR;
|
|
WSACleanup();
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
// init the trapOl overlapped struct with manual reset non-signaled event
|
|
ZeroMemory(&TaskData.trapOl, sizeof(TaskData.trapOl));
|
|
TaskData.trapOl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (NULL == TaskData.trapOl.hEvent)
|
|
{
|
|
lError = SNMPAPI_ALLOC_ERROR;
|
|
CloseHandle(TaskData.trapEvent);
|
|
TaskData.trapEvent = NULL;
|
|
WSACleanup();
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
// init TaskData.hExitEvent with manual reset non-signaled event to
|
|
// synchronize shutdown of thrManager
|
|
TaskData.hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (NULL == TaskData.hExitEvent)
|
|
{
|
|
lError = SNMPAPI_ALLOC_ERROR;
|
|
CloseHandle(TaskData.trapEvent);
|
|
TaskData.trapEvent = NULL;
|
|
CloseHandle(TaskData.trapOl.hEvent);
|
|
TaskData.trapOl.hEvent = NULL;
|
|
WSACleanup();
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
// Set trapSock (used in Win95 case only)
|
|
TaskData.trapSock = INVALID_SOCKET;
|
|
// Set "manager" sockets (used at SnmpSendMsg() time)
|
|
TaskData.ipSock = TaskData.ipxSock = INVALID_SOCKET;
|
|
// Start timer thread
|
|
|
|
{
|
|
DWORD thrId;
|
|
TaskData.timerThread = (HANDLE)_beginthreadex (NULL, 0, thrTimer, NULL, 0, &thrId);
|
|
if (NULL == TaskData.timerThread)
|
|
{
|
|
lError = SNMPAPI_TL_RESOURCE_ERROR;
|
|
CloseHandle(TaskData.trapEvent);
|
|
TaskData.trapEvent = NULL;
|
|
CloseHandle(TaskData.trapOl.hEvent);
|
|
TaskData.trapOl.hEvent = NULL;
|
|
WSACleanup();
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
}
|
|
|
|
//
|
|
DONE:
|
|
TaskData.hTask = hTask;
|
|
TaskData.nLastError = SNMPAPI_SUCCESS;
|
|
ERROR_PRECHECK:
|
|
LeaveCriticalSection (&cs_TASK);
|
|
if (lError == SNMPAPI_SUCCESS)
|
|
return (SNMPAPI_SUCCESS);
|
|
ERROR_OUT:
|
|
return (SaveError (0, lError));
|
|
} // end_SnmpStartup
|
|
|
|
// SnmpCleanup
|
|
SNMPAPI_STATUS SNMPAPI_CALL SnmpCleanup (void)
|
|
{
|
|
DWORD nSession;
|
|
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
|
|
// Variables for threads not associated with a specific session
|
|
DWORD nHandles = 0;
|
|
HANDLE hTemp[4] = {NULL, NULL, NULL, NULL};
|
|
CONST HANDLE *hObjects = &hTemp[0];
|
|
//--------------------------------------------------------------
|
|
if (TaskData.hTask == 0)
|
|
{
|
|
lError = SNMPAPI_NOT_INITIALIZED;
|
|
goto ERROR_OUT;
|
|
}
|
|
EnterCriticalSection (&cs_SESSION);
|
|
// Do all Forgotten Closes
|
|
if (SessDescr.Used)
|
|
{
|
|
for (nSession = 0; nSession < SessDescr.Allocated; nSession++)
|
|
if (((LPSESSION)snmpGetTableEntry(&SessDescr, nSession))->nTask)
|
|
SnmpClose ((HSNMP_SESSION) ULongToPtr(nSession + 1));
|
|
}
|
|
LeaveCriticalSection (&cs_SESSION);
|
|
EnterCriticalSection (&cs_TASK);
|
|
SetEvent(TaskData.hExitEvent); // askes thrManager to exit
|
|
// Terminate thrTimer
|
|
if (TaskData.timerThread)
|
|
{
|
|
hTemp[nHandles++] = TaskData.timerThread;
|
|
// NULL signals the timer thread to terminate itself
|
|
TaskData.timerThread = NULL;
|
|
}
|
|
// Close "Mgr" sockets and threads
|
|
if (TaskData.ipSock != INVALID_SOCKET)
|
|
{// UDP channel
|
|
// check thrManager code to understand the lines below:
|
|
SOCKET ipSock = TaskData.ipSock;
|
|
WaitForSingleObject (TaskData.ipThread, INFINITE);
|
|
TaskData.ipSock = INVALID_SOCKET;
|
|
closesocket (ipSock);
|
|
if (TaskData.ipThread)
|
|
hTemp[nHandles++] = TaskData.ipThread;
|
|
}
|
|
if (TaskData.ipxSock != INVALID_SOCKET)
|
|
{// IPX channel
|
|
// check thrManager code to understand the lines below:
|
|
SOCKET ipxSock = TaskData.ipxSock;
|
|
WaitForSingleObject (TaskData.ipxThread, INFINITE);
|
|
TaskData.ipxSock = INVALID_SOCKET;
|
|
closesocket (ipxSock);
|
|
if (TaskData.ipxThread)
|
|
hTemp[nHandles++] = TaskData.ipxThread;
|
|
}
|
|
// Terminate thrTrap
|
|
if (TaskData.trapThread)
|
|
{
|
|
if (TaskData.sEnv.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
{ // NT-specific stuff
|
|
// set events to signal thrTrap to exit
|
|
SetEvent(TaskData.trapEvent);
|
|
// unblock thrTrap if necessary
|
|
SetEvent(TaskData.trapOl.hEvent);
|
|
}
|
|
hTemp[nHandles++] = TaskData.trapThread;
|
|
}
|
|
WaitForMultipleObjects (nHandles, hObjects, TRUE, 5000);
|
|
while (nHandles > 0)
|
|
{
|
|
nHandles--;
|
|
CloseHandle (hTemp[nHandles]);
|
|
}
|
|
if (TaskData.trapPipe != INVALID_HANDLE_VALUE)
|
|
CloseHandle (TaskData.trapPipe);
|
|
if (TaskData.trapEvent != NULL)
|
|
CloseHandle(TaskData.trapEvent);
|
|
if (TaskData.trapOl.hEvent != NULL)
|
|
CloseHandle(TaskData.trapOl.hEvent);
|
|
if (TaskData.hExitEvent)
|
|
CloseHandle(TaskData.hExitEvent);
|
|
|
|
// Do the main thing
|
|
ZeroMemory (&TaskData, sizeof(TASK));
|
|
LeaveCriticalSection (&cs_TASK);
|
|
// Close down WinSock connection
|
|
WSACleanup ();
|
|
//
|
|
|
|
//
|
|
return (SNMPAPI_SUCCESS);
|
|
ERROR_OUT:
|
|
return (SaveError (0, lError));
|
|
} // end_SnmpCleanup
|
|
|
|
// Open a session (v1 and v2)
|
|
HSNMP_SESSION SNMPAPI_CALL SnmpOpen (IN HWND hWnd, IN UINT wMsg)
|
|
{
|
|
return (SnmpCreateSession (hWnd, wMsg, NULL, NULL));
|
|
} // end_SnmpOpen
|
|
|
|
// Open a session, w/callback option (v2)
|
|
HSNMP_SESSION SNMPAPI_CALL
|
|
SnmpCreateSession (IN HWND hWnd, IN UINT wMsg,
|
|
IN SNMPAPI_CALLBACK fCallBack,
|
|
IN LPVOID lpClientData)
|
|
{
|
|
DWORD nSession;
|
|
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
|
|
LPSESSION pSession;
|
|
|
|
if (TaskData.hTask == 0)
|
|
{
|
|
lError = SNMPAPI_NOT_INITIALIZED;
|
|
goto ERROR_OUT;
|
|
}
|
|
// Check for window/message notification mode argument validity
|
|
if (fCallBack == NULL)
|
|
if (!IsWindow(hWnd))
|
|
{
|
|
lError = SNMPAPI_HWND_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
//
|
|
EnterCriticalSection (&cs_SESSION);
|
|
lError = snmpAllocTableEntry(&SessDescr, &nSession);
|
|
if (lError != SNMPAPI_SUCCESS)
|
|
goto ERROR_PRECHECK;
|
|
pSession = snmpGetTableEntry(&SessDescr, nSession);
|
|
|
|
pSession->nTask = TaskData.hTask;
|
|
pSession->hWnd = hWnd;
|
|
pSession->wMsg = wMsg;
|
|
pSession->fCallBack = fCallBack;
|
|
pSession->lpClientData = lpClientData;
|
|
if (fCallBack)
|
|
{
|
|
DWORD thrId;
|
|
pSession->thrEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
|
|
if (NULL == pSession->thrEvent)
|
|
{
|
|
lError = SNMPAPI_ALLOC_ERROR;
|
|
snmpFreeTableEntry(&SessDescr, nSession);
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
pSession->thrCount = 0;
|
|
pSession->thrHandle = (HANDLE)_beginthreadex
|
|
(NULL, 0, thrNotify, (LPVOID) ULongToPtr(nSession), 0, &thrId);
|
|
if (NULL == pSession->thrHandle)
|
|
{
|
|
lError = SNMPAPI_TL_RESOURCE_ERROR;
|
|
snmpFreeTableEntry(&SessDescr, nSession);
|
|
CloseHandle(pSession->thrEvent);
|
|
pSession->thrEvent = NULL;
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
}
|
|
pSession->nLastError = SNMPAPI_SUCCESS;
|
|
ERROR_PRECHECK:
|
|
LeaveCriticalSection (&cs_SESSION);
|
|
if (lError == SNMPAPI_SUCCESS)
|
|
return ((HSNMP_SESSION) ULongToPtr(nSession+1));
|
|
ERROR_OUT:
|
|
return ((HSNMP_SESSION) ULongToPtr(SaveError (0, lError)));
|
|
} // end_SnmpOpen
|
|
|
|
// SnmpClose
|
|
SNMPAPI_STATUS SNMPAPI_CALL
|
|
SnmpClose (IN HSNMP_SESSION hSession)
|
|
{
|
|
HANDLE thrTemp;
|
|
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
|
|
DWORD nSes = HandleToUlong(hSession) - 1;
|
|
DWORD i;
|
|
LPSESSION pSession;
|
|
|
|
if (TaskData.hTask == 0)
|
|
{
|
|
lError = SNMPAPI_NOT_INITIALIZED;
|
|
goto ERROR_OUT;
|
|
}
|
|
if (!snmpValidTableEntry(&SessDescr, nSes))
|
|
{
|
|
lError = SNMPAPI_SESSION_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
pSession = snmpGetTableEntry(&SessDescr, nSes);
|
|
|
|
// Strategy:
|
|
// 1st: Stop notifications to session
|
|
// 2nd: Stop accepting new messages
|
|
// Traps
|
|
// Agents
|
|
// 3rd: Clear out pending messages
|
|
// 4th: Free up all other resources
|
|
//
|
|
// PART_1: Stop notifications to the closing Session
|
|
// Block window/message notification (in all cases!)
|
|
pSession->hWnd = NULL;
|
|
// Block callback notification (if required)
|
|
if (pSession->fCallBack != NULL)
|
|
{
|
|
// Save thrHandle for WaitForSingleObject call
|
|
EnterCriticalSection (&cs_SESSION);
|
|
thrTemp = pSession->thrHandle;
|
|
// If this is a callback session, must stop thrNotify instance
|
|
pSession->thrHandle = NULL;
|
|
// 0xFFFFFFFF signals thrNotify instance to terminate itself
|
|
pSession->thrCount = 0xFFFFFFFF;
|
|
// SetEvent signals thrNotify instance to run
|
|
SetEvent (pSession->thrEvent);
|
|
LeaveCriticalSection (&cs_SESSION);
|
|
|
|
// Wait for termination signal from thread handle
|
|
WaitForSingleObject (thrTemp, 30000);
|
|
// Close thrNotify instance handle
|
|
CloseHandle (thrTemp);
|
|
// Close thrNotify event handle
|
|
CloseHandle (pSession->thrEvent);
|
|
}
|
|
|
|
// PART_2: Stop accepting new messages for the closing Session
|
|
// Free Notifications registered by the closing Session
|
|
EnterCriticalSection (&cs_TRAP);
|
|
for (i = 0; i < TrapDescr.Allocated && TrapDescr.Used != 0; i++)
|
|
{
|
|
LPTRAPNOTICE pTrap = snmpGetTableEntry(&TrapDescr, i);
|
|
if (pTrap->Session == hSession)
|
|
FreeRegister (i);
|
|
} // end_for (Traps)
|
|
LeaveCriticalSection (&cs_TRAP);
|
|
// Free Agents registered by the closing Session
|
|
EnterCriticalSection (&cs_AGENT);
|
|
for (i = 0; i < AgentDescr.Allocated && AgentDescr.Used != 0; i++)
|
|
{
|
|
LPAGENT pAgent = snmpGetTableEntry(&AgentDescr, i);
|
|
if (pAgent->Session == hSession)
|
|
SnmpListen (pAgent->Entity, SNMPAPI_OFF);
|
|
}
|
|
LeaveCriticalSection (&cs_AGENT);
|
|
// PART_3: Free all pending messages for the closing Session
|
|
EnterCriticalSection (&cs_MSG);
|
|
for (i = 0; i < MsgDescr.Allocated && MsgDescr.Used != 0; i++)
|
|
{
|
|
LPSNMPMSG pMsg = snmpGetTableEntry(&MsgDescr, i);
|
|
if (pMsg->Session == hSession)
|
|
FreeMsg (i);
|
|
}
|
|
LeaveCriticalSection (&cs_MSG);
|
|
// PART_4: Free all other resources
|
|
// Free Entities allocated by the closing Session
|
|
EnterCriticalSection (&cs_ENTITY);
|
|
for (i = 0; i < EntsDescr.Allocated && EntsDescr.Used != 0; i++)
|
|
{
|
|
LPENTITY pEntity = snmpGetTableEntry(&EntsDescr, i);
|
|
if (pEntity->Session == hSession)
|
|
SnmpFreeEntity ((HSNMP_ENTITY) ULongToPtr(i+1));
|
|
}
|
|
LeaveCriticalSection (&cs_ENTITY);
|
|
// Free Contexts allocated by the closing Session
|
|
EnterCriticalSection (&cs_CONTEXT);
|
|
for (i = 0; i < CntxDescr.Allocated && CntxDescr.Used != 0; i++)
|
|
{
|
|
LPCTXT pCtxt = snmpGetTableEntry(&CntxDescr, i);
|
|
if (pCtxt->Session == hSession)
|
|
SnmpFreeContext ((HSNMP_CONTEXT) ULongToPtr(i+1));
|
|
}
|
|
LeaveCriticalSection (&cs_CONTEXT);
|
|
// Free VBLs allocated by the closing Session
|
|
EnterCriticalSection (&cs_VBL);
|
|
for (i = 0; i < VBLsDescr.Allocated && VBLsDescr.Used != 0; i++)
|
|
{
|
|
LPVBLS pVbl = snmpGetTableEntry(&VBLsDescr, i);
|
|
if (pVbl->Session == hSession)
|
|
SnmpFreeVbl ((HSNMP_VBL) ULongToPtr(i+1));
|
|
}
|
|
LeaveCriticalSection (&cs_VBL);
|
|
// Free PDUs allocated by the closing Session
|
|
EnterCriticalSection (&cs_PDU);
|
|
|
|
for (i = 0; i < PDUsDescr.Allocated && PDUsDescr.Used != 0; i++)
|
|
{
|
|
LPPDUS pPDU = snmpGetTableEntry(&PDUsDescr, i);
|
|
if (pPDU->Session == hSession)
|
|
SnmpFreePdu ((HSNMP_PDU) ULongToPtr(i+1));
|
|
}
|
|
|
|
LeaveCriticalSection (&cs_PDU);
|
|
// Free the Session table entry used by the closing Session
|
|
EnterCriticalSection (&cs_SESSION);
|
|
snmpFreeTableEntry(&SessDescr, nSes);
|
|
LeaveCriticalSection (&cs_SESSION);
|
|
return (SNMPAPI_SUCCESS);
|
|
ERROR_OUT:
|
|
// As of 19980808 there are no error cases with a valid session
|
|
return (SaveError (0, lError));
|
|
} // end_SnmpClose
|
|
|
|
// SnmpSendMsg
|
|
SNMPAPI_STATUS SNMPAPI_CALL
|
|
SnmpSendMsg (IN HSNMP_SESSION hSession,
|
|
IN HSNMP_ENTITY hSrc,
|
|
IN HSNMP_ENTITY hDst,
|
|
IN HSNMP_CONTEXT hCtx,
|
|
IN HSNMP_PDU hPdu)
|
|
{
|
|
LPPDUS sendPdu;
|
|
BOOL fMsg;
|
|
DWORD nMsg;
|
|
DWORD pduType;
|
|
smiINT32 dllReqId;
|
|
smiOCTETS tmpContext;
|
|
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
|
|
HSNMP_SESSION lSession = 0;
|
|
//
|
|
DWORD thrId;
|
|
SOCKET *pSock;
|
|
int tFamily;
|
|
SOCKADDR tAddr;
|
|
HANDLE *pThread;
|
|
//
|
|
DWORD nSrc;
|
|
DWORD nDst;
|
|
DWORD nCtx;
|
|
DWORD nPdu;
|
|
//
|
|
BOOL fBroadcast;
|
|
//
|
|
LPPDUS pPdu;
|
|
LPENTITY pEntSrc, pEntDst;
|
|
LPCTXT pCtxt;
|
|
LPSNMPMSG pMsg;
|
|
|
|
if (TaskData.hTask == 0)
|
|
{
|
|
lError = SNMPAPI_NOT_INITIALIZED;
|
|
goto ERROR_OUT;
|
|
}
|
|
if (!snmpValidTableEntry(&SessDescr, HandleToUlong(hSession)-1))
|
|
{
|
|
lError = SNMPAPI_SESSION_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
|
|
// Save valid session for later error returns
|
|
lSession = hSession;
|
|
if (hSrc) // Allowed to be NULL
|
|
{
|
|
nSrc = HandleToUlong(hSrc) - 1;
|
|
if (!snmpValidTableEntry(&EntsDescr, nSrc))
|
|
{
|
|
lError = SNMPAPI_ENTITY_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
pEntSrc = snmpGetTableEntry(&EntsDescr, nSrc);
|
|
}
|
|
nDst = HandleToUlong(hDst) - 1;
|
|
if (!snmpValidTableEntry(&EntsDescr, nDst))
|
|
{
|
|
lError = SNMPAPI_ENTITY_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
pEntDst = snmpGetTableEntry(&EntsDescr, nDst);
|
|
|
|
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))
|
|
{
|
|
lError = SNMPAPI_PDU_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
pPdu = snmpGetTableEntry(&PDUsDescr, nPdu);
|
|
|
|
if (!snmpValidTableEntry(&VBLsDescr, HandleToUlong(pPdu->VBL)-1))
|
|
{
|
|
lError = SNMPAPI_VBL_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
//--------------
|
|
tFamily = pEntDst->addr.inet.sin_family;
|
|
|
|
// enter the critical section for the TaskData structure to insure
|
|
// the atomicity of the Test&Set operation of the TaskData.[ip|ipx]Thread
|
|
EnterCriticalSection (&cs_TASK);
|
|
|
|
pThread = (tFamily==AF_IPX) ? &TaskData.ipxThread : &TaskData.ipThread;
|
|
pSock = (tFamily==AF_IPX) ? &TaskData.ipxSock : &TaskData.ipSock;
|
|
|
|
if (*pThread) // ASSERT(*pSock != INVALID_SOCKET)
|
|
{
|
|
LeaveCriticalSection(&cs_TASK);
|
|
goto CHANNEL_OPEN;
|
|
}
|
|
*pSock = socket (tFamily, SOCK_DGRAM, (tFamily==AF_IPX)?NSPROTO_IPX:0);
|
|
|
|
if (*pSock == INVALID_SOCKET)
|
|
{
|
|
LeaveCriticalSection(&cs_TASK);
|
|
lError = SNMPAPI_TL_NOT_SUPPORTED;
|
|
goto ERROR_OUT;
|
|
}
|
|
|
|
// try to set the socket for broadcasts. No matter the result
|
|
// a possible error will be caught later
|
|
// The following setsockopt call will be removed in Longhorn
|
|
fBroadcast = TRUE;
|
|
setsockopt (*pSock,
|
|
SOL_SOCKET,
|
|
SO_BROADCAST,
|
|
(CHAR *) &fBroadcast,
|
|
sizeof ( BOOL )
|
|
);
|
|
|
|
// Kludge for Win95 WinSock/IPX bug...have to "bind"
|
|
ZeroMemory (&tAddr, sizeof(SOCKADDR));
|
|
tAddr.sa_family = (USHORT)tFamily;
|
|
bind (*pSock, &tAddr, (tFamily==AF_IPX)?sizeof(SOCKADDR_IPX):sizeof(SOCKADDR_IN));
|
|
// Start "listener" and timer threads
|
|
|
|
*pThread = (HANDLE)_beginthreadex (NULL, 0, thrManager, (LPVOID)pSock, 0, &thrId);
|
|
if (*pThread == NULL)
|
|
{
|
|
closesocket (*pSock);
|
|
*pSock = INVALID_SOCKET;
|
|
lError = SNMPAPI_TL_RESOURCE_ERROR;
|
|
LeaveCriticalSection (&cs_TASK);
|
|
goto ERROR_OUT;
|
|
}
|
|
LeaveCriticalSection (&cs_TASK);
|
|
//---------------
|
|
CHANNEL_OPEN:
|
|
pduType = pPdu->type;
|
|
sendPdu = pPdu;
|
|
if (pEntDst->version == 1)
|
|
{ // Test for special v2 msg -> v1 dst operations
|
|
if (pduType == SNMP_PDU_TRAP)
|
|
{ // RFC 2089 v2 to v1 trap conversion
|
|
sendPdu = MapV2TrapV1 (hPdu);
|
|
if (sendPdu == NULL)
|
|
{
|
|
lError = SNMPAPI_OTHER_ERROR;
|
|
goto ERROR_OUT;
|
|
}
|
|
pduType = SNMP_PDU_V1TRAP;
|
|
}
|
|
else if (pduType == SNMP_PDU_INFORM)
|
|
{
|
|
lError = SNMPAPI_OPERATION_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
}
|
|
// Space check
|
|
EnterCriticalSection (&cs_MSG);
|
|
lError = snmpAllocTableEntry(&MsgDescr, &nMsg);
|
|
if (lError != SNMPAPI_SUCCESS)
|
|
goto ERROR_PRECHECK;
|
|
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
|
|
|
|
// Now Build it
|
|
if (pduType == SNMP_PDU_RESPONSE || pduType == SNMP_PDU_TRAP)
|
|
dllReqId = pPdu->appReqId;
|
|
else
|
|
dllReqId = ++(TaskData.nLastReqId);
|
|
tmpContext.len = pCtxt->commLen;
|
|
tmpContext.ptr = pCtxt->commStr;
|
|
// Save BuildMessage status for later check
|
|
fMsg = BuildMessage (pEntDst->version-1, &tmpContext, sendPdu,
|
|
dllReqId, &(pMsg->Addr), &(pMsg->Size));
|
|
// If v2 to v1 trap conversion was required, then cleanup...
|
|
if (pduType == SNMP_PDU_V1TRAP)
|
|
{
|
|
FreeVarBindList (sendPdu->VBL_addr); // Checks for NULL
|
|
FreeV1Trap (sendPdu->v1Trap); // Checks for NULL
|
|
GlobalFree (sendPdu);
|
|
}
|
|
// If BuildMessage failed, that's all folks!
|
|
if (!fMsg)
|
|
{
|
|
snmpFreeTableEntry(&MsgDescr, nMsg);
|
|
lError = SNMPAPI_PDU_INVALID;
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
pMsg->Session = hSession;
|
|
pMsg->Status = NP_SEND; // "send"
|
|
pMsg->Type = pduType;
|
|
pMsg->nRetransmitMode = TaskData.nRetransmitMode;
|
|
pMsg->dllReqId = dllReqId;
|
|
pMsg->appReqId = pPdu->appReqId;
|
|
pMsg->agentEntity = hDst;
|
|
pMsg->ourEntity = hSrc;
|
|
pMsg->Context = hCtx;
|
|
LeaveCriticalSection (&cs_MSG);
|
|
// Update reference counts for entities and contexts,
|
|
EnterCriticalSection (&cs_ENTITY);
|
|
if (hSrc)
|
|
pEntSrc->refCount++;
|
|
pEntDst->refCount++;
|
|
LeaveCriticalSection (&cs_ENTITY);
|
|
EnterCriticalSection (&cs_CONTEXT);
|
|
pCtxt->refCount++;
|
|
LeaveCriticalSection (&cs_CONTEXT);
|
|
// Prepare addressing info for traps
|
|
EnterCriticalSection (&cs_MSG);
|
|
CopyMemory (&(pMsg->Host), &pEntDst->addr, sizeof(SAS));
|
|
if (pduType == SNMP_PDU_V1TRAP ||
|
|
pduType == SNMP_PDU_TRAP ||
|
|
pduType == SNMP_PDU_INFORM)
|
|
{
|
|
if (tFamily == AF_IPX)
|
|
{
|
|
if (pMsg->Host.ipx.sa_socket == ntohs (IPX_SNMP_PORT))
|
|
pMsg->Host.ipx.sa_socket = htons (IPX_TRAP_PORT);
|
|
}
|
|
else // Assume AF_INET
|
|
{
|
|
if (pMsg->Host.inet.sin_port == ntohs (IP_SNMP_PORT))
|
|
pMsg->Host.inet.sin_port = htons(IP_TRAP_PORT);
|
|
}
|
|
}
|
|
// Send the packet
|
|
thrId = sendto (*pSock, pMsg->Addr, pMsg->Size,
|
|
0, (LPSOCKADDR)&(pMsg->Host), sizeof(SAS));
|
|
if (thrId == SOCKET_ERROR)
|
|
{
|
|
FreeMsg (nMsg);
|
|
lError = SNMPAPI_TL_OTHER;
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
// Need to check for SOCKET_ERROR!
|
|
if (pduType == SNMP_PDU_TRAP ||
|
|
pduType == SNMP_PDU_V1TRAP ||
|
|
pduType == SNMP_PDU_RESPONSE)
|
|
{
|
|
FreeMsg (nMsg);
|
|
}
|
|
else
|
|
{
|
|
pMsg->Status = NP_SENT;
|
|
// Time entity's timeout value is stored as centiseconds in 32 bits
|
|
pMsg->Wait = pEntDst->nPolicyTimeout;
|
|
// Converting to milliseconds for timer operations could overflow
|
|
if (pMsg->Wait <= MAXCENTISECONDS) // So check first...if ok
|
|
pMsg->Wait *= 10; // Convert to milliseconds
|
|
else // eles...
|
|
pMsg->Wait = MAXMILLISECONDS; // Set to max milliseconds
|
|
pMsg->Tries = pMsg->PolicyTries = pEntDst->nPolicyRetry;
|
|
pMsg->Ticks = GetTickCount();
|
|
}
|
|
ERROR_PRECHECK:
|
|
LeaveCriticalSection (&cs_MSG);
|
|
if (lError == SNMPAPI_SUCCESS)
|
|
return (SNMPAPI_SUCCESS);
|
|
ERROR_OUT:
|
|
return (SaveError (lSession, lError));
|
|
} // end_SnmpSendMsg
|
|
|
|
// SnmpRecvMsg
|
|
SNMPAPI_STATUS SNMPAPI_CALL
|
|
SnmpRecvMsg (IN HSNMP_SESSION hSession,
|
|
OUT LPHSNMP_ENTITY srcEntity,
|
|
OUT LPHSNMP_ENTITY dstEntity,
|
|
OUT LPHSNMP_CONTEXT context,
|
|
OUT LPHSNMP_PDU pdu)
|
|
{
|
|
DWORD nMsg;
|
|
DWORD nPdu;
|
|
int pduType;
|
|
smiLPOCTETS community;
|
|
smiUINT32 version;
|
|
smiUINT32 nMode;
|
|
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
|
|
HSNMP_SESSION lSession = 0;
|
|
DWORD nSes = HandleToUlong(hSession) - 1;
|
|
LPPDUS pPdu;
|
|
LPENTITY pEntity;
|
|
LPSNMPMSG pMsg;
|
|
DWORD lTime; // holds the local time for updating the nActualTimeout value
|
|
|
|
if (TaskData.hTask == 0)
|
|
{
|
|
lError = SNMPAPI_NOT_INITIALIZED;
|
|
goto ERROR_OUT;
|
|
}
|
|
if (!snmpValidTableEntry(&SessDescr, nSes))
|
|
{
|
|
lError = SNMPAPI_SESSION_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
// Valid session...save for possible error return
|
|
lSession = hSession;
|
|
|
|
EnterCriticalSection (&cs_MSG);
|
|
// Find a message for the calling session
|
|
for (nMsg = 0; nMsg < MsgDescr.Allocated; nMsg++)
|
|
{
|
|
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
|
|
if (pMsg->Session == hSession &&
|
|
pMsg->Status == NP_READY)
|
|
break;
|
|
}
|
|
if (nMsg == MsgDescr.Allocated)
|
|
{
|
|
lError = SNMPAPI_NOOP;
|
|
goto ERROR_PRECHECK1;
|
|
}
|
|
if (!pMsg->Addr)
|
|
{
|
|
lError = SNMPAPI_MESSAGE_INVALID;
|
|
goto ERROR_PRECHECK1;
|
|
}
|
|
ERROR_PRECHECK1:
|
|
LeaveCriticalSection (&cs_MSG);
|
|
|
|
if (lError != SNMPAPI_SUCCESS)
|
|
goto ERROR_OUT;
|
|
|
|
// Allocate a slot in PDU table
|
|
EnterCriticalSection (&cs_PDU);
|
|
lError = snmpAllocTableEntry(&PDUsDescr, &nPdu);
|
|
if (lError != SNMPAPI_SUCCESS)
|
|
goto ERROR_PRECHECK2;
|
|
pPdu = snmpGetTableEntry(&PDUsDescr, nPdu);
|
|
|
|
nMode = ParseMessage (pMsg->Addr, pMsg->Size,
|
|
&version, &community, pPdu);
|
|
if (nMode != 0) // non-zero = error code
|
|
{
|
|
snmpFreeTableEntry(&PDUsDescr, nPdu);
|
|
FreeMsg (nMsg);
|
|
lError = SNMPAPI_PDU_INVALID;
|
|
goto ERROR_PRECHECK2;
|
|
}
|
|
pPdu->Session = hSession;
|
|
pPdu->appReqId = pMsg->appReqId;
|
|
ERROR_PRECHECK2:
|
|
LeaveCriticalSection (&cs_PDU);
|
|
|
|
if (lError != SNMPAPI_SUCCESS)
|
|
goto ERROR_OUT;
|
|
pduType = pPdu->type;
|
|
|
|
EnterCriticalSection (&cs_ENTITY);
|
|
// for RESPONSE messages only, update the 'ActualRetry' and 'ActualTimeout' parameters
|
|
// for all the other messages, these params are meaningless
|
|
if (pduType == SNMP_PDU_RESPONSE)
|
|
{
|
|
// locate the agent (source) entity here
|
|
pEntity = snmpGetTableEntry(&EntsDescr, HandleToUlong(pMsg->agentEntity)-1);
|
|
|
|
// update the nActualTimeout param of the agent (source) entity.
|
|
lTime = GetTickCount();
|
|
if (pMsg->Ticks > lTime)
|
|
// handle the time wrap case
|
|
// (~pMsg->Ticks + 1) is 2's complement of pMsg->Ticks
|
|
pEntity->nActualTimeout = (lTime + ~pMsg->Ticks + 1)/10;
|
|
else
|
|
pEntity->nActualTimeout = (lTime - pMsg->Ticks)/10;
|
|
|
|
// update the nActualRetry param of the agent (source) entity
|
|
pEntity->nActualRetry = pMsg->PolicyTries - pMsg->Tries;
|
|
}
|
|
|
|
if (srcEntity)
|
|
{
|
|
if (pduType == SNMP_PDU_TRAP ||
|
|
pduType == SNMP_PDU_INFORM ||
|
|
pduType != SNMP_PDU_RESPONSE)
|
|
{
|
|
int afType = pMsg->Host.ipx.sa_family;
|
|
char afHost[MAX_PATH+1];
|
|
afHost[MAX_PATH] = '\0';
|
|
EnterCriticalSection (&cs_XMODE);
|
|
SnmpGetTranslateMode (&nMode);
|
|
SnmpSetTranslateMode (SNMPAPI_UNTRANSLATED_V1);
|
|
if (afType == AF_IPX)
|
|
SnmpIpxAddressToStr (pMsg->Host.ipx.sa_netnum,
|
|
pMsg->Host.ipx.sa_nodenum,
|
|
afHost);
|
|
else // AF_INET
|
|
{
|
|
char * pszIpAddr;
|
|
pszIpAddr = inet_ntoa (pMsg->Host.inet.sin_addr);
|
|
if (NULL == pszIpAddr)
|
|
{
|
|
LeaveCriticalSection (&cs_XMODE);
|
|
lError = SNMPAPI_TL_OTHER;
|
|
goto ERROR_PRECHECK3;
|
|
}
|
|
strncpy (afHost, pszIpAddr, MAX_PATH);
|
|
}
|
|
if ((pMsg->agentEntity = SnmpStrToEntity (hSession, afHost)) == SNMPAPI_FAILURE)
|
|
{
|
|
LeaveCriticalSection (&cs_XMODE);
|
|
lError = SNMPAPI_OTHER_ERROR;
|
|
goto ERROR_PRECHECK3;
|
|
}
|
|
pEntity = snmpGetTableEntry(&EntsDescr, HandleToUlong(pMsg->agentEntity)-1);
|
|
if (afType == AF_IPX)
|
|
pEntity->addr.ipx.sa_socket = pMsg->Host.ipx.sa_socket;
|
|
else // AF_INET
|
|
pEntity->addr.inet.sin_port = pMsg->Host.inet.sin_port;
|
|
SnmpSetTranslateMode (nMode);
|
|
LeaveCriticalSection (&cs_XMODE);
|
|
}
|
|
// Deliberate assignment...
|
|
if (*srcEntity = pMsg->agentEntity)
|
|
{
|
|
pEntity = snmpGetTableEntry(&EntsDescr, HandleToUlong(pMsg->agentEntity)-1);
|
|
pEntity->refCount++;
|
|
}
|
|
}
|
|
|
|
if (dstEntity)
|
|
{ // Deliberate assignment...
|
|
if (*dstEntity = pMsg->ourEntity)
|
|
{
|
|
pEntity = snmpGetTableEntry(&EntsDescr, HandleToUlong(pMsg->ourEntity)-1);
|
|
pEntity->refCount++;
|
|
}
|
|
}
|
|
ERROR_PRECHECK3:
|
|
LeaveCriticalSection (&cs_ENTITY);
|
|
if (lError != SNMPAPI_SUCCESS)
|
|
{
|
|
FreeOctetString (community);
|
|
SnmpFreePdu ((HSNMP_PDU) ULongToPtr(nPdu+1));
|
|
FreeMsg (nMsg);
|
|
goto ERROR_OUT;
|
|
}
|
|
|
|
EnterCriticalSection (&cs_CONTEXT);
|
|
if (context)
|
|
{
|
|
if (pduType == SNMP_PDU_TRAP ||
|
|
pduType == SNMP_PDU_INFORM ||
|
|
pduType != SNMP_PDU_RESPONSE)
|
|
{
|
|
EnterCriticalSection (&cs_XMODE);
|
|
SnmpGetTranslateMode (&nMode);
|
|
SnmpSetTranslateMode (SNMPAPI_UNTRANSLATED_V1);
|
|
if ((pMsg->Context = SnmpStrToContext (hSession, community)) == SNMPAPI_FAILURE)
|
|
{
|
|
LeaveCriticalSection (&cs_XMODE);
|
|
lError = SNMPAPI_OTHER_ERROR;
|
|
goto ERROR_PRECHECK4;
|
|
}
|
|
SnmpSetTranslateMode (nMode);
|
|
LeaveCriticalSection (&cs_XMODE);
|
|
}
|
|
// Deliberate assignment...
|
|
if (*context = pMsg->Context)
|
|
((LPCTXT)snmpGetTableEntry(&CntxDescr, HandleToUlong(pMsg->Context)-1))->refCount++;
|
|
}
|
|
ERROR_PRECHECK4:
|
|
LeaveCriticalSection (&cs_CONTEXT);
|
|
if (lError != SNMPAPI_SUCCESS)
|
|
{
|
|
// rollback
|
|
if (context && *context)
|
|
{
|
|
SnmpFreeContext(*context);
|
|
*context = NULL;
|
|
}
|
|
if (dstEntity && *dstEntity)
|
|
{
|
|
SnmpFreeEntity(*dstEntity);
|
|
*dstEntity = NULL;
|
|
}
|
|
if (srcEntity && *srcEntity)
|
|
{
|
|
SnmpFreeEntity(*srcEntity);
|
|
*srcEntity = NULL;
|
|
}
|
|
FreeOctetString (community);
|
|
SnmpFreePdu ((HSNMP_PDU) ULongToPtr(nPdu+1));
|
|
FreeMsg (nMsg);
|
|
goto ERROR_OUT;
|
|
}
|
|
|
|
FreeOctetString (community);
|
|
if (pdu)
|
|
*pdu = (HSNMP_PDU) ULongToPtr(nPdu+1);
|
|
else
|
|
SnmpFreePdu ((HSNMP_PDU) ULongToPtr(nPdu+1));
|
|
// Mark SendRecv slot as free
|
|
FreeMsg (nMsg);
|
|
return (SNMPAPI_SUCCESS);
|
|
ERROR_OUT:
|
|
return (SaveError (lSession, lError));
|
|
} // end_SnmpRecvMsg
|
|
|
|
// Allocates a generic ACL to be used for the security descriptor of the SNMPTRAP service
|
|
PACL AllocGenericACL()
|
|
{
|
|
PACL pAcl;
|
|
PSID pSidAdmins, pSidUsers;
|
|
SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY;
|
|
DWORD dwAclLength;
|
|
|
|
pSidAdmins = pSidUsers = NULL;
|
|
|
|
if ( !AllocateAndInitializeSid( &Authority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&pSidAdmins ) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if ( !AllocateAndInitializeSid( &Authority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_USERS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&pSidUsers ))
|
|
{
|
|
FreeSid(pSidAdmins);
|
|
return NULL;
|
|
}
|
|
|
|
dwAclLength = sizeof(ACL) +
|
|
sizeof(ACCESS_ALLOWED_ACE) -
|
|
sizeof(ULONG) +
|
|
GetLengthSid(pSidAdmins) +
|
|
sizeof(ACCESS_ALLOWED_ACE) -
|
|
sizeof(ULONG) +
|
|
GetLengthSid(pSidUsers);
|
|
|
|
pAcl = GlobalAlloc (GPTR, dwAclLength);
|
|
if (pAcl != NULL)
|
|
{
|
|
if (!InitializeAcl( pAcl, dwAclLength, ACL_REVISION) ||
|
|
!AddAccessAllowedAce ( pAcl,
|
|
ACL_REVISION,
|
|
GENERIC_ALL,
|
|
pSidAdmins ) ||
|
|
!AddAccessAllowedAce ( pAcl,
|
|
ACL_REVISION,
|
|
GENERIC_READ | GENERIC_EXECUTE,
|
|
pSidUsers ))
|
|
{
|
|
GlobalFree(pAcl);
|
|
pAcl = NULL;
|
|
}
|
|
}
|
|
|
|
FreeSid(pSidAdmins);
|
|
FreeSid(pSidUsers);
|
|
|
|
return pAcl;
|
|
}
|
|
|
|
// frees a generic ACL
|
|
void FreeGenericACL( PACL pAcl)
|
|
{
|
|
if (pAcl != NULL)
|
|
GlobalFree(pAcl);
|
|
}
|
|
|
|
// SnmpRegister
|
|
SNMPAPI_STATUS SNMPAPI_CALL
|
|
SnmpRegister (IN HSNMP_SESSION hSession,
|
|
IN HSNMP_ENTITY hSrc,
|
|
IN HSNMP_ENTITY hDst,
|
|
IN HSNMP_CONTEXT hCtx,
|
|
IN smiLPCOID notification,
|
|
IN smiUINT32 status)
|
|
{
|
|
DWORD nNotice, nFound;
|
|
smiINT32 nCmp;
|
|
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
|
|
HSNMP_SESSION lSession = 0;
|
|
DWORD nSes = HandleToUlong(hSession) - 1;
|
|
DWORD nSrc;
|
|
DWORD nDst;
|
|
DWORD nCtx;
|
|
LPENTITY pEntSrc, pEntDst;
|
|
LPCTXT pCtxt;
|
|
LPTRAPNOTICE pTrap;
|
|
|
|
if (TaskData.hTask == 0)
|
|
{
|
|
lError = SNMPAPI_NOT_INITIALIZED;
|
|
goto ERROR_OUT;
|
|
}
|
|
if (status != SNMPAPI_OFF) status = SNMPAPI_ON;
|
|
if (status == SNMPAPI_ON)
|
|
{
|
|
if (!snmpValidTableEntry(&SessDescr, nSes))
|
|
{
|
|
lError = SNMPAPI_SESSION_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
else // Got a valid session...save for possible error return
|
|
lSession = hSession;
|
|
}
|
|
if (hSrc)
|
|
{
|
|
nSrc = HandleToUlong(hSrc) - 1;
|
|
if (!snmpValidTableEntry(&EntsDescr, nSrc))
|
|
{
|
|
lError = SNMPAPI_ENTITY_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
pEntSrc = snmpGetTableEntry(&EntsDescr, nSrc);
|
|
}
|
|
if (hDst)
|
|
{
|
|
nDst = HandleToUlong(hDst) - 1;
|
|
if (!snmpValidTableEntry(&EntsDescr, nDst))
|
|
{
|
|
lError = SNMPAPI_ENTITY_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
pEntDst = snmpGetTableEntry(&EntsDescr, nDst);
|
|
}
|
|
if (hCtx)
|
|
{
|
|
nCtx = HandleToUlong(hCtx) - 1;
|
|
if (!snmpValidTableEntry(&CntxDescr, nCtx))
|
|
{
|
|
lError = SNMPAPI_CONTEXT_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
pCtxt = snmpGetTableEntry(&CntxDescr, nCtx);
|
|
}
|
|
if (notification)
|
|
{
|
|
if ((!notification->len) || notification->len > MAXOBJIDSIZE)
|
|
{
|
|
lError = SNMPAPI_SIZE_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
if (!notification->ptr)
|
|
{
|
|
lError = SNMPAPI_OID_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
}
|
|
EnterCriticalSection (&cs_TRAP);
|
|
for (nNotice = 0, nFound = 0; nNotice < TrapDescr.Allocated &&
|
|
nFound < TrapDescr.Used; nNotice++)
|
|
{ // First, count now many we've tested
|
|
pTrap = snmpGetTableEntry(&TrapDescr, nNotice);
|
|
if (pTrap->Session) nFound++;
|
|
// then search for a parameter matches
|
|
if ((pTrap->Session == hSession) &&
|
|
(pTrap->ourEntity == hSrc) &&
|
|
(pTrap->agentEntity == hDst) &&
|
|
(pTrap->Context == hCtx))
|
|
{ // Ok, we found one
|
|
if (!notification)
|
|
// if the notification parameter is null, then we
|
|
// want to either turn on or turn off all notifications
|
|
// from this match...so clear any entries already in
|
|
// the table and we'll add this wildcard entry if the
|
|
// operation is SNMPAPI_ON at the end.
|
|
{
|
|
DWORD dwUsed = TrapDescr.Used;
|
|
FreeRegister (nNotice);
|
|
if (dwUsed == TrapDescr.Used+1)
|
|
{
|
|
// Adjustment to nFound because FreeRegister has just decremented
|
|
// TrapDescr.Used by 1
|
|
nFound--;
|
|
}
|
|
continue;
|
|
}
|
|
else // notification specified
|
|
{
|
|
if (!pTrap->notification.len)
|
|
{
|
|
// Redundant request (already wildcarded)
|
|
// Skip it and return!
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
else // pTrap->notification
|
|
{
|
|
// compare OIDs
|
|
SnmpOidCompare (notification, &(pTrap->notification),
|
|
0, &nCmp);
|
|
if (nCmp) // no match
|
|
continue; // ...try the next one
|
|
else // !nCcmp
|
|
{ // got a match...
|
|
// if SNMPAPI_ON, redundant request...skip it and return
|
|
// if SNMPAPI_OFF, free the entry first
|
|
if (status != SNMPAPI_ON)
|
|
FreeRegister (nNotice); // SNMPAPI_OFF
|
|
goto ERROR_PRECHECK;
|
|
} // end_else_!nCmp
|
|
} // end_else_TrapTable[nNotice].notificatin
|
|
} // end_else_notification_specified
|
|
} // end_if_we_found_one
|
|
} // end_for
|
|
if (status == SNMPAPI_OFF)
|
|
{ // Found nothing to turn off...that's ok.
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
//
|
|
|
|
// Special check for NT...is SNMPTRAP service running?
|
|
if (TaskData.trapThread == NULL &&
|
|
TaskData.sEnv.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
DWORD dwReturn = SNMPAPI_TL_NOT_INITIALIZED;
|
|
DWORD pMode = PIPE_WAIT | PIPE_READMODE_MESSAGE;
|
|
LPCTSTR svcName = "SNMPTRAP";
|
|
LPCTSTR svcDesc = "SNMP Trap Service";
|
|
LPCTSTR svcPath = "%SystemRoot%\\system32\\snmptrap.exe";
|
|
SC_HANDLE scmHandle = NULL;
|
|
SC_HANDLE svcHandle = NULL;
|
|
SERVICE_STATUS svcStatus;
|
|
BOOL fStatus;
|
|
// Minimal SCM connection, for case when SNMPTRAP is running
|
|
scmHandle = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT);
|
|
if (scmHandle == NULL)
|
|
goto DONE_SC;
|
|
svcHandle = OpenService (scmHandle, svcName, SERVICE_QUERY_STATUS);
|
|
if (svcHandle == NULL)
|
|
{
|
|
if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
|
|
goto DONE_SC;
|
|
else
|
|
{ // Must attempt to create service
|
|
PACL pAcl;
|
|
SECURITY_DESCRIPTOR S_Desc;
|
|
// Need new scmHandle with admin priv
|
|
CloseServiceHandle (scmHandle);
|
|
scmHandle = OpenSCManager (NULL, NULL, SC_MANAGER_CREATE_SERVICE);
|
|
if (scmHandle == NULL)
|
|
goto DONE_SC; // Could not open SCM with admin priv
|
|
// Bug# 179644 The SNMP trap service should not run in the LocalSystem account
|
|
// We create the service with LocalService account instead of LocalSystem.
|
|
svcHandle = CreateService (scmHandle, svcName, svcDesc,
|
|
WRITE_DAC|SERVICE_QUERY_STATUS,
|
|
SERVICE_WIN32_OWN_PROCESS,
|
|
SERVICE_DEMAND_START,
|
|
SERVICE_ERROR_NORMAL,
|
|
svcPath,
|
|
NULL, NULL,
|
|
"TCPIP\0EventLog\0\0",
|
|
"NT AUTHORITY\\LocalService", NULL);
|
|
if (svcHandle == NULL)
|
|
goto DONE_SC; // Could not create service
|
|
if (!InitializeSecurityDescriptor (&S_Desc, SECURITY_DESCRIPTOR_REVISION))
|
|
{
|
|
goto DONE_SC;
|
|
}
|
|
if ((pAcl = AllocGenericACL()) == NULL ||
|
|
!SetSecurityDescriptorDacl (&S_Desc, TRUE, pAcl, FALSE))
|
|
{
|
|
FreeGenericACL(pAcl); // will free if necessary
|
|
goto DONE_SC;
|
|
}
|
|
if (!SetServiceObjectSecurity (svcHandle, DACL_SECURITY_INFORMATION, &S_Desc))
|
|
{
|
|
FreeGenericACL(pAcl);
|
|
goto DONE_SC;
|
|
}
|
|
FreeGenericACL(pAcl);
|
|
}
|
|
}
|
|
fStatus = QueryServiceStatus (svcHandle, &svcStatus);
|
|
while (fStatus)
|
|
{
|
|
switch (svcStatus.dwCurrentState)
|
|
{
|
|
case SERVICE_RUNNING:
|
|
dwReturn = SNMPAPI_SUCCESS;
|
|
goto DONE_SC;
|
|
|
|
case SERVICE_STOPPED:
|
|
// Start SNMPTRAP service if necessary
|
|
CloseServiceHandle (svcHandle);
|
|
svcHandle = OpenService (scmHandle, svcName, SERVICE_START|SERVICE_QUERY_STATUS);
|
|
if (svcHandle == NULL)
|
|
goto DONE_SC; // Could not start service
|
|
svcStatus.dwCurrentState = SERVICE_START_PENDING;
|
|
fStatus = StartService (svcHandle, 0, NULL);
|
|
break;
|
|
|
|
case SERVICE_STOP_PENDING:
|
|
case SERVICE_START_PENDING:
|
|
Sleep (MAX_PENDING_WAIT);
|
|
fStatus = QueryServiceStatus (svcHandle, &svcStatus);
|
|
break;
|
|
|
|
case SERVICE_PAUSED:
|
|
case SERVICE_PAUSE_PENDING:
|
|
case SERVICE_CONTINUE_PENDING:
|
|
default:
|
|
fStatus = FALSE; // Nothing to do about these
|
|
break;
|
|
}
|
|
}
|
|
DONE_SC:
|
|
if (scmHandle)
|
|
CloseServiceHandle (scmHandle);
|
|
if (svcHandle)
|
|
CloseServiceHandle (svcHandle);
|
|
if (dwReturn != SNMPAPI_SUCCESS)
|
|
{
|
|
ERROR_PRECHECK1:
|
|
lError = dwReturn;
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
// Setup for pipe-oriented operations
|
|
dwReturn = SNMPAPI_TL_RESOURCE_ERROR;
|
|
// block on instance of server pipe becoming available
|
|
if (!WaitNamedPipe (SNMPTRAPPIPE, TRAPSERVERTIMEOUT))
|
|
goto ERROR_PRECHECK1;
|
|
TaskData.trapPipe =
|
|
// Bug# 270672 Change FILE_ATTRIBUTE_NORMAL to FILE_FLAG_OVERLAPPED
|
|
CreateFile (SNMPTRAPPIPE, GENERIC_READ|GENERIC_WRITE,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
|
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
|
if (TaskData.trapPipe == INVALID_HANDLE_VALUE)
|
|
goto ERROR_PRECHECK1;
|
|
if (!SetNamedPipeHandleState (TaskData.trapPipe, &pMode, NULL, NULL))
|
|
{
|
|
CloseHandle (TaskData.trapPipe);
|
|
TaskData.trapPipe = INVALID_HANDLE_VALUE;
|
|
goto ERROR_PRECHECK1;
|
|
}
|
|
} // end_NT check for SNMPTRAP service
|
|
|
|
//If we got this far, add it
|
|
lError = snmpAllocTableEntry(&TrapDescr, &nNotice);
|
|
if (lError != SNMPAPI_SUCCESS)
|
|
goto ERROR_PRECHECK;
|
|
pTrap = snmpGetTableEntry(&TrapDescr, nNotice);
|
|
|
|
// add it
|
|
pTrap->Session = hSession;
|
|
// Deliberate assignments in next three if statements
|
|
if (pTrap->ourEntity = hSrc)
|
|
//EntityTable[nSrc-1].refCount++; -- was this a bug??? nSrc is already 0 based
|
|
pEntSrc->refCount++;
|
|
if (pTrap->agentEntity = hDst)
|
|
//EntityTable[nDst-1].refCount++; -- was this a bug??? nDst is already 0 based
|
|
pEntDst->refCount++;
|
|
if (pTrap->Context = hCtx)
|
|
//ContextTable[nCtx-1].refCount++; -- was this a bug?? nCtx is already 0 based
|
|
pCtxt->refCount++;
|
|
if (notification)
|
|
{ // Reproduce the OID
|
|
pTrap->notification.ptr = NULL;
|
|
// Deliberate assignment in next statement
|
|
if (pTrap->notification.len = notification->len)
|
|
{
|
|
if (pTrap->notification.len > MAXTRAPIDS)
|
|
pTrap->notification.len = MAXTRAPIDS;
|
|
if (notification->ptr)
|
|
{
|
|
// Deliberate assignment in next statement
|
|
pTrap->notification.ptr = &(pTrap->notificationValue[0]);
|
|
CopyMemory (pTrap->notification.ptr, notification->ptr,
|
|
pTrap->notification.len * sizeof(smiUINT32));
|
|
}
|
|
}
|
|
}
|
|
if (TaskData.trapThread == NULL)
|
|
{
|
|
DWORD thrId;
|
|
TaskData.trapThread = (HANDLE)_beginthreadex (NULL, 0, thrTrap, NULL, 0, &thrId);
|
|
if (TaskData.trapThread == NULL)
|
|
{
|
|
FreeRegister(nNotice);
|
|
lError = SNMPAPI_TL_RESOURCE_ERROR;
|
|
}
|
|
}
|
|
ERROR_PRECHECK:
|
|
LeaveCriticalSection (&cs_TRAP);
|
|
if (lError == SNMPAPI_SUCCESS)
|
|
return (SNMPAPI_SUCCESS);
|
|
ERROR_OUT:
|
|
return (SaveError (lSession, lError));
|
|
} // end_SnmpRegister
|
|
|
|
void FreeMsg (DWORD nMsg)
|
|
{
|
|
LPSNMPMSG pMsg;
|
|
EnterCriticalSection (&cs_MSG);
|
|
// Decrement reference counts
|
|
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
|
|
SnmpFreeEntity (pMsg->agentEntity);
|
|
SnmpFreeEntity (pMsg->ourEntity);
|
|
SnmpFreeContext (pMsg->Context);
|
|
if (pMsg->Addr)
|
|
GlobalFree (pMsg->Addr);
|
|
snmpFreeTableEntry(&MsgDescr, nMsg);
|
|
LeaveCriticalSection (&cs_MSG);
|
|
return;
|
|
} // end_FreeMsg
|
|
|
|
SNMPAPI_STATUS SNMPAPI_CALL
|
|
SnmpListen (IN HSNMP_ENTITY hEntity,
|
|
IN smiUINT32 status)
|
|
{
|
|
smiUINT32 nAgent = 0;
|
|
DWORD thrId;
|
|
DWORD nEntity = HandleToUlong(hEntity) - 1;
|
|
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
|
|
HSNMP_SESSION lSession = 0;
|
|
LPENTITY pEntity;
|
|
LPAGENT pAgent;
|
|
|
|
if (TaskData.hTask == 0)
|
|
{
|
|
lError = SNMPAPI_NOT_INITIALIZED;
|
|
goto ERROR_OUT;
|
|
}
|
|
if (!snmpValidTableEntry(&EntsDescr, nEntity))
|
|
{
|
|
lError = SNMPAPI_ENTITY_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
pEntity = snmpGetTableEntry(&EntsDescr, nEntity);
|
|
lSession = pEntity->Session;
|
|
if (status != SNMPAPI_ON && status != SNMPAPI_OFF)
|
|
{
|
|
lError = SNMPAPI_MODE_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
EnterCriticalSection (&cs_ENTITY);
|
|
EnterCriticalSection (&cs_AGENT);
|
|
if (status)
|
|
{ // status == SNMPAPI_ON
|
|
int nProto = IPPROTO_UDP;
|
|
int nSize = sizeof(SOCKADDR_IN);
|
|
int nFamily = pEntity->addr.inet.sin_family;
|
|
if (pEntity->Agent)
|
|
{ // Entity already running as agent
|
|
lError = SNMPAPI_NOOP;
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
// Allocate a slot in AGENT table
|
|
lError = snmpAllocTableEntry(&AgentDescr, &nAgent);
|
|
if (lError != SNMPAPI_SUCCESS)
|
|
goto ERROR_PRECHECK;
|
|
pAgent = snmpGetTableEntry(&AgentDescr, nAgent);
|
|
|
|
// Agent table entry allocated...setup for agent thread
|
|
if (nFamily == AF_IPX)
|
|
{
|
|
nProto = NSPROTO_IPX;
|
|
nSize = sizeof(SOCKADDR_IPX);
|
|
}
|
|
pAgent->Socket = socket (nFamily, SOCK_DGRAM, nProto);
|
|
if (pAgent->Socket == INVALID_SOCKET)
|
|
{
|
|
snmpFreeTableEntry(&AgentDescr, nAgent);
|
|
lError = SNMPAPI_TL_RESOURCE_ERROR;
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
if (bind (pAgent->Socket,
|
|
(LPSOCKADDR)&pEntity->addr, nSize)
|
|
== SOCKET_ERROR)
|
|
{
|
|
closesocket (pAgent->Socket);
|
|
snmpFreeTableEntry(&AgentDescr, nAgent);
|
|
lError = SNMPAPI_TL_OTHER;
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
// Make Entity and Agent point to each other
|
|
pEntity->Agent = nAgent + 1;
|
|
pAgent->Entity = hEntity;
|
|
pAgent->Session = lSession;
|
|
// Create agent thread...needs error checking
|
|
pAgent->Thread = (HANDLE)_beginthreadex (NULL, 0, thrAgent, (LPVOID) ULongToPtr(nAgent), 0, &thrId);
|
|
if (pAgent->Thread == NULL)
|
|
{
|
|
closesocket(pAgent->Socket);
|
|
snmpFreeTableEntry(&AgentDescr, nAgent);
|
|
lError = SNMPAPI_TL_RESOURCE_ERROR;
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
} // end_if status == SNMPAPI_ON
|
|
else
|
|
{ // status == SNMPAPI_OFF
|
|
if (!pEntity->Agent)
|
|
{ // Entity not running as agent
|
|
lError = SNMPAPI_NOOP;
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
// Entity is running as agent
|
|
nAgent = pEntity->Agent - 1;
|
|
pAgent = snmpGetTableEntry(&AgentDescr, nAgent);
|
|
closesocket (pAgent->Socket);
|
|
WaitForSingleObject (pAgent->Thread, INFINITE);
|
|
CloseHandle (pAgent->Thread);
|
|
snmpFreeTableEntry(&AgentDescr, nAgent);
|
|
// Must terminate entity's agent status
|
|
pEntity->Agent = 0;
|
|
// Must terminate entity if nothing else was using it
|
|
if (pEntity->refCount == 0)
|
|
SnmpFreeEntity (hEntity);
|
|
} // end_else status == SNMPAPI_OFF
|
|
ERROR_PRECHECK:
|
|
LeaveCriticalSection (&cs_AGENT);
|
|
LeaveCriticalSection (&cs_ENTITY);
|
|
ERROR_OUT:
|
|
if (lError == SNMPAPI_SUCCESS)
|
|
return (SNMPAPI_SUCCESS);
|
|
else
|
|
return (SaveError (lSession, lError));
|
|
} // end_SnmpListen()
|
|
|
|
SNMPAPI_STATUS SNMPAPI_CALL
|
|
SnmpCancelMsg (HSNMP_SESSION hSession, smiINT32 nReqID)
|
|
{
|
|
DWORD nMsg = 0;
|
|
DWORD nFound = 0;
|
|
SNMPAPI_STATUS lError = SNMPAPI_SUCCESS;
|
|
HSNMP_SESSION lSession = 0;
|
|
LPSNMPMSG pMsg;
|
|
|
|
if (TaskData.hTask == 0)
|
|
{
|
|
lError = SNMPAPI_NOT_INITIALIZED;
|
|
goto ERROR_OUT;
|
|
}
|
|
if (!snmpValidTableEntry(&SessDescr, HandleToUlong(hSession)-1))
|
|
{
|
|
lError = SNMPAPI_SESSION_INVALID;
|
|
goto ERROR_OUT;
|
|
}
|
|
lSession = hSession;
|
|
EnterCriticalSection (&cs_MSG);
|
|
|
|
while (nFound < MsgDescr.Used && nMsg < MsgDescr.Allocated)
|
|
{
|
|
pMsg = snmpGetTableEntry(&MsgDescr, nMsg);
|
|
// Deliberate assignement in next conditional
|
|
if (pMsg->Session)
|
|
{
|
|
nFound++;
|
|
if (pMsg->Session == hSession)
|
|
{
|
|
if (pMsg->Status == NP_SENT &&
|
|
pMsg->appReqId == (smiUINT32)nReqID)
|
|
{
|
|
FreeMsg (nMsg);
|
|
goto ERROR_PRECHECK;
|
|
}
|
|
}
|
|
}
|
|
nMsg++;
|
|
}
|
|
// Falied to find a MSG that matched the request
|
|
lError = SNMPAPI_PDU_INVALID;
|
|
ERROR_PRECHECK:
|
|
LeaveCriticalSection (&cs_MSG);
|
|
if (lError == SNMPAPI_SUCCESS)
|
|
return (SNMPAPI_SUCCESS);
|
|
// else...failure case
|
|
ERROR_OUT:
|
|
return (SaveError (lSession, lError));
|
|
} // end_SnmpCancelMsg
|