// wsnmp_cf.c // // WinSNMP Communications Functions and helpers // Copyright 1995-1998 ACE*COMM Corp // Rleased to Microsoft under Contract // // Bob Natale (bnatale@acecomm.com) // // 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