Leaked source code of windows server 2003
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.

1046 lines
38 KiB

  1. // snmptrap.c
  2. //
  3. // Original Microsoft code modified by ACE*COMM
  4. // for use with WSNMP32.DLL and other trap receiving
  5. // clients, per contract.
  6. //
  7. // Bob Natale, ACE*COMM ([email protected])
  8. // For NT v5 Beta, v970228
  9. // Additional enhancements planned.
  10. //
  11. // This version of SNMPTRAP has no dependencies
  12. // on either MGMTAPI.DLL or WSNMP32.DLL.
  13. //
  14. // WinSNMP clients use the SnmpRegister() function.
  15. //
  16. // Other clients will need to match the following
  17. // values and structures:
  18. //
  19. // SNMP_TRAP structure
  20. // SNMPTRAPPIPE name
  21. // TRAPBUFSIZE value
  22. //
  23. // Change log:
  24. // ------------------------------------------------
  25. // 4.0.1381.3 Apr 8, 1998 Bob Natale
  26. //
  27. // 1. Re-worked the trap port monitoring thread into
  28. // two threads...one for IP and one for IPX, to
  29. // comply with WinSock v2's restrictions against
  30. // multi-protocol select().
  31. //
  32. // 2. General clean-up/streamlining wrt "legacy" code
  33. // from original MS version...more to do here, esp.
  34. // wrt error handling code that does not do anything.
  35. // ------------------------------------------------
  36. // 4.0.1381.4 Apr. 10, 1998 Bob Natale
  37. //
  38. // 1. Replaced mutex calls with critical_sectin calls.
  39. //
  40. // 2. Cleaned out some dead code (removed commented out code)
  41. // ------------------------------------------------
  42. // Jan. 2, 2001 Frank Li
  43. // 1. remove TerminateThread
  44. // 2. add debug build loggings
  45. // ------------------------------------------------
  46. #include <windows.h>
  47. #include <winsock.h>
  48. #include <wsipx.h>
  49. #include <process.h>
  50. #ifdef DBG // include files for debug trace only
  51. #include <stdio.h>
  52. #include <time.h>
  53. #endif
  54. //--------------------------- PRIVATE VARIABLES -----------------------------
  55. #define SNMPMGRTRAPPIPE "\\\\.\\PIPE\\MGMTAPI"
  56. #define MAX_OUT_BUFS 16
  57. #define TRAPBUFSIZE 4096
  58. #define IP_TRAP_PORT 162
  59. #define IPX_TRAP_PORT 36880
  60. #define SNMPTRAP_WAIT_HINT 20000
  61. //
  62. // constants added to allocate trap buffer for fixing trap data of length
  63. // > 8192 bytes. Here is the buffer allocation scheme based on the common
  64. // cases that trap data sizes are less than 4-KBytes:
  65. // 1. LargeTrap
  66. // if (trap data size >= 8192 bytes), allocate MAX_UDP_SIZE sized buffer
  67. // 2. MediumTrap
  68. // if (trap data size <= 4096 bytes), allocate FOUR_K_BUF_SIZE sized buffer
  69. // 3. SmallTrap
  70. // if (4096 < trap data size < 8192), allocate just enough buffer size.
  71. // Note:
  72. // - when LargeTrap is received, the allocated buffer will stay for a time of
  73. // MAXUDPLEN_BUFFER_TIME from the last LargeTrap received.
  74. // - Once MediumTrap is received, subsequent SmallTrap will reuse the
  75. // last MediumTrap allocated buffer.
  76. //
  77. #define MAX_UDP_SIZE (65535-8) // max udp len - 8bytes udp header
  78. #define MAX_FIONREAD_UDP_SIZE 8192 // max winsock FIONREAD reported size (8kB)
  79. #define FOUR_K_BUF_SIZE 4096 // buffer of 4-KBytes in size
  80. #define MAXUDPLEN_BUFFER_TIME (2*60*1000) // max. 2 mins to keep the
  81. // last allocated large buffer.
  82. // ******** INITIALIZE A LIST HEAD ********
  83. #define ll_init(head) (head)->next = (head)->prev = (head);
  84. // ******** TEST A LIST FOR EMPTY ********
  85. #define ll_empt(head) ( ((head)->next) == (head) )
  86. // ******** Get ptr to next entry ********
  87. #define ll_next(item,head)\
  88. ( (ll_node *)(item)->next == (head) ? 0 : \
  89. (ll_node *)(item)->next )
  90. // ******** Get ptr to prev entry ********
  91. #define ll_prev(item)\
  92. ( (ll_node *)(item)->prev )
  93. // ******** ADD AN ITEM TO THE END OF A LIST ********
  94. #define ll_adde(item,head)\
  95. {\
  96. ll_node *pred = (head)->prev;\
  97. ((ll_node *)(item))->next = (head);\
  98. ((ll_node *)(item))->prev = pred;\
  99. (pred)->next = ((ll_node *)(item));\
  100. (head)->prev = ((ll_node *)(item));\
  101. }
  102. // ******** REMOVE AN ITEM FROM A LIST ********
  103. #define ll_rmv(item)\
  104. {\
  105. ll_node *pred = ((ll_node *)(item))->prev;\
  106. ll_node *succ = ((ll_node *)(item))->next;\
  107. pred->next = succ;\
  108. succ->prev = pred;\
  109. }
  110. // ******** List head/node ********
  111. typedef struct ll_s
  112. { // linked list structure
  113. struct ll_s *next; // next node
  114. struct ll_s *prev; // prev. node
  115. } ll_node; // linked list node
  116. typedef struct
  117. {// shared by server trap thread and pipe thread
  118. ll_node links;
  119. HANDLE hPipe;
  120. } svrPipeListEntry;
  121. typedef struct
  122. {
  123. SOCKADDR Addr;
  124. int AddrLen;
  125. UINT TrapBufSz;
  126. char TrapBuf[TRAPBUFSIZE]; // the size of this array should match the size of the structure
  127. // defined in wsnmp_no.c!!!
  128. } SNMP_TRAP, *PSNMP_TRAP;
  129. typedef struct
  130. {
  131. SOCKET s;
  132. OVERLAPPED ol;
  133. } TRAP_THRD_CONTEXT, *PTRAP_THRD_CONTEXT;
  134. HANDLE hExitEvent = NULL;
  135. LPCTSTR svcName = "SNMPTRAP";
  136. SERVICE_STATUS_HANDLE hService = 0;
  137. SERVICE_STATUS status =
  138. {SERVICE_WIN32, SERVICE_STOPPED, SERVICE_ACCEPT_STOP, NO_ERROR, 0, 0, 0};
  139. SOCKET ipSock = INVALID_SOCKET;
  140. SOCKET ipxSock = INVALID_SOCKET;
  141. HANDLE ipThread = NULL;
  142. HANDLE ipxThread = NULL;
  143. CRITICAL_SECTION cs_PIPELIST;
  144. ll_node *pSvrPipeListHead = NULL;
  145. // global variables added to remove the TerminateThread call
  146. OVERLAPPED g_ol; // overlapped struct for svrPipeThread
  147. TRAP_THRD_CONTEXT g_ipThreadContext; // context for ip svrTrapThread
  148. TRAP_THRD_CONTEXT g_ipxThreadContext; // context for ipx svrTrapThread
  149. ///////////////////////////////////////////////////////////////////////////////
  150. // //
  151. // SNMPTRAP Debugging Prototypes //
  152. // //
  153. ///////////////////////////////////////////////////////////////////////////////
  154. #if DBG
  155. VOID
  156. WINAPI
  157. SnmpTrapDbgPrint(
  158. IN LPSTR szFormat,
  159. IN ...
  160. );
  161. #define SNMPTRAPDBG(_x_) SnmpTrapDbgPrint _x_
  162. #else
  163. #define SNMPTRAPDBG(_x_)
  164. #endif
  165. //--------------------------- PRIVATE PROTOTYPES ----------------------------
  166. DWORD WINAPI svrTrapThread (IN OUT LPVOID threadParam);
  167. DWORD WINAPI svrPipeThread (IN LPVOID threadParam);
  168. VOID WINAPI svcHandlerFunction (IN DWORD dwControl);
  169. VOID WINAPI svcMainFunction (IN DWORD dwNumServicesArgs,
  170. IN LPSTR *lpServiceArgVectors);
  171. void FreeSvrPipeEntryList(IN ll_node* head);
  172. //--------------------------- PRIVATE PROCEDURES ----------------------------
  173. VOID WINAPI svcHandlerFunction (IN DWORD dwControl)
  174. {
  175. if (dwControl == SERVICE_CONTROL_STOP)
  176. {
  177. status.dwCurrentState = SERVICE_STOP_PENDING;
  178. status.dwCheckPoint++;
  179. status.dwWaitHint = SNMPTRAP_WAIT_HINT;
  180. if (!SetServiceStatus(hService, &status))
  181. exit(1);
  182. // set event causing trap thread to terminate
  183. if (!SetEvent(hExitEvent))
  184. {
  185. status.dwCurrentState = SERVICE_STOPPED;
  186. status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  187. status.dwServiceSpecificExitCode = 1; // OPENISSUE - svc err code
  188. status.dwCheckPoint = 0;
  189. status.dwWaitHint = 0;
  190. // We are exiting in any case, so ignore any error...
  191. SetServiceStatus (hService, &status);
  192. exit(1);
  193. }
  194. }
  195. else
  196. // dwControl == SERVICE_CONTROL_INTERROGATE
  197. // dwControl == SERVICE_CONTROL_PAUSE
  198. // dwControl == SERVICE_CONTROL_CONTINUE
  199. // dwControl == <anything else>
  200. {
  201. if (status.dwCurrentState == SERVICE_STOP_PENDING ||
  202. status.dwCurrentState == SERVICE_START_PENDING)
  203. status.dwCheckPoint++;
  204. if (!SetServiceStatus (hService, &status))
  205. exit(1);
  206. }
  207. } // end_svcHandlerFunction()
  208. VOID WINAPI svcMainFunction (IN DWORD dwNumServicesArgs,
  209. IN LPSTR *lpServiceArgVectors)
  210. {
  211. WSADATA WinSockData;
  212. HANDLE hPipeThread = NULL;
  213. DWORD dwThreadId;
  214. //---------------------------------------------------------------------
  215. hService = RegisterServiceCtrlHandler (svcName, svcHandlerFunction);
  216. if (hService == 0)
  217. {
  218. // We are exiting in any case, so ignore any error...
  219. SNMPTRAPDBG((
  220. "svcMainFunction: RegisterServiceCtrlHandler error 0x%08lx .\n",
  221. GetLastError()
  222. ));
  223. exit(1);
  224. }
  225. status.dwCurrentState = SERVICE_START_PENDING;
  226. status.dwWaitHint = SNMPTRAP_WAIT_HINT;
  227. if (!SetServiceStatus(hService, &status))
  228. exit(1);
  229. __try
  230. {
  231. InitializeCriticalSection (&cs_PIPELIST);
  232. }
  233. __except(EXCEPTION_EXECUTE_HANDLER)
  234. {
  235. exit(1);
  236. }
  237. memset(&g_ipThreadContext.ol, 0, sizeof(g_ipThreadContext.ol));
  238. memset(&g_ipxThreadContext.ol, 0, sizeof(g_ipxThreadContext.ol));
  239. if (WSAStartup ((WORD)0x0101, &WinSockData))
  240. goto CLOSE_OUT; // WinSock startup failure
  241. // allocate linked-list header for client received traps
  242. if ((pSvrPipeListHead = (ll_node *)GlobalAlloc (GPTR, sizeof(ll_node))) == NULL)
  243. goto CLOSE_OUT;
  244. ll_init(pSvrPipeListHead);
  245. if ((hPipeThread = (HANDLE)_beginthreadex
  246. (NULL, 0, svrPipeThread, NULL, 0, &dwThreadId)) == 0)
  247. goto CLOSE_OUT;
  248. //-----------------------------------------------------------------------------------
  249. //CHECK_IP:
  250. ipSock = socket (AF_INET, SOCK_DGRAM, 0);
  251. if (ipSock != INVALID_SOCKET)
  252. {
  253. struct sockaddr_in localAddress_in;
  254. struct servent *serv;
  255. ZeroMemory (&localAddress_in, sizeof(localAddress_in));
  256. localAddress_in.sin_family = AF_INET;
  257. if ((serv = getservbyname ("snmp-trap", "udp")) == NULL)
  258. localAddress_in.sin_port = htons (IP_TRAP_PORT);
  259. else
  260. localAddress_in.sin_port = (SHORT)serv->s_port;
  261. localAddress_in.sin_addr.s_addr = htonl (INADDR_ANY);
  262. if (bind (ipSock, (LPSOCKADDR)&localAddress_in, sizeof(localAddress_in)) != SOCKET_ERROR)
  263. {
  264. g_ipThreadContext.s = ipSock;
  265. // init the overlapped struct with manual reset non-signaled event
  266. g_ipThreadContext.ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  267. if (NULL == g_ipThreadContext.ol.hEvent)
  268. goto CLOSE_OUT;
  269. ipThread = (HANDLE)_beginthreadex
  270. (NULL, 0, svrTrapThread, (LPVOID)&g_ipThreadContext, 0, &dwThreadId);
  271. }
  272. }
  273. //-----------------------------------------------------------------------------------
  274. //CHECK_IPX:
  275. ipxSock = socket (AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
  276. if (ipxSock != INVALID_SOCKET)
  277. {
  278. struct sockaddr_ipx localAddress_ipx;
  279. ZeroMemory (&localAddress_ipx, sizeof(localAddress_ipx));
  280. localAddress_ipx.sa_family = AF_IPX;
  281. localAddress_ipx.sa_socket = htons (IPX_TRAP_PORT);
  282. if (bind (ipxSock, (LPSOCKADDR)&localAddress_ipx, sizeof(localAddress_ipx)) != SOCKET_ERROR)
  283. {
  284. g_ipxThreadContext.s = ipxSock;
  285. // init the overlapped struct with manual reset non-signaled event
  286. g_ipxThreadContext.ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  287. if (NULL == g_ipxThreadContext.ol.hEvent)
  288. goto CLOSE_OUT;
  289. ipxThread = (HANDLE)_beginthreadex
  290. (NULL, 0, svrTrapThread, (LPVOID)&g_ipxThreadContext, 0, &dwThreadId);
  291. }
  292. }
  293. //-----------------------------------------------------------------------------------
  294. // We are ready to listen for traps...
  295. status.dwCurrentState = SERVICE_RUNNING;
  296. status.dwCheckPoint = 0;
  297. status.dwWaitHint = 0;
  298. if (!SetServiceStatus(hService, &status))
  299. goto CLOSE_OUT;
  300. WaitForSingleObject (hExitEvent, INFINITE);
  301. //-----------------------------------------------------------------------------------
  302. CLOSE_OUT:
  303. // make sure we can bail out if we are here because of goto statements above
  304. SetEvent(hExitEvent);
  305. status.dwCurrentState = SERVICE_STOP_PENDING; // in case we need to report
  306. // reporting progress in stopping service
  307. status.dwCheckPoint++;
  308. if (!SetServiceStatus(hService, &status))
  309. {
  310. SNMPTRAPDBG((
  311. "svcMainFunction: error 0x%08lx setting service status.\n",
  312. GetLastError()
  313. ));
  314. }
  315. if (hPipeThread != NULL)
  316. {
  317. SNMPTRAPDBG(("svcMainFunction: enter SetEvent g_ol.hEvent.\n"));
  318. SetEvent(g_ol.hEvent); // signal to terminate the svrPipeThread thread
  319. WaitForSingleObject (hPipeThread, INFINITE);
  320. SNMPTRAPDBG(("svcMainFunction: WaitForSingleObject hPipeThread INFINITE done.\n"));
  321. // reporting progress in stopping service
  322. status.dwCheckPoint++;
  323. if (!SetServiceStatus(hService, &status))
  324. {
  325. SNMPTRAPDBG((
  326. "svcMainFunction: error 0x%08lx setting service status.\n",
  327. GetLastError()
  328. ));
  329. }
  330. CloseHandle (hPipeThread);
  331. }
  332. if (ipThread != NULL)
  333. {
  334. SNMPTRAPDBG(("svcMainFunction: enter SetEvent g_ipThreadContext.ol.hEvent.\n"));
  335. SetEvent(g_ipThreadContext.ol.hEvent); // signal to terminate thread
  336. WaitForSingleObject (ipThread, INFINITE);
  337. // reporting progress in stopping service
  338. status.dwCheckPoint++;
  339. if (!SetServiceStatus(hService, &status))
  340. {
  341. SNMPTRAPDBG((
  342. "svcMainFunction: error 0x%08lx setting service status.\n",
  343. GetLastError()
  344. ));
  345. }
  346. CloseHandle (ipThread);
  347. }
  348. if (ipSock != INVALID_SOCKET)
  349. closesocket (ipSock);
  350. if (g_ipThreadContext.ol.hEvent)
  351. CloseHandle(g_ipThreadContext.ol.hEvent);
  352. if (ipxThread != NULL)
  353. {
  354. SNMPTRAPDBG(("svcMainFunction: enter SetEvent g_ipxThreadContext.ol.hEvent.\n"));
  355. SetEvent(g_ipxThreadContext.ol.hEvent); // signal to terminate thread
  356. WaitForSingleObject (ipxThread, INFINITE);
  357. // reporting progress in stopping service
  358. status.dwCheckPoint++;
  359. if (!SetServiceStatus(hService, &status))
  360. {
  361. SNMPTRAPDBG((
  362. "svcMainFunction: error 0x%08lx setting service status.\n",
  363. GetLastError()
  364. ));
  365. }
  366. CloseHandle (ipxThread);
  367. }
  368. if (ipxSock != INVALID_SOCKET)
  369. closesocket (ipxSock);
  370. if (g_ipxThreadContext.ol.hEvent)
  371. CloseHandle(g_ipxThreadContext.ol.hEvent);
  372. EnterCriticalSection (&cs_PIPELIST);
  373. if (pSvrPipeListHead != NULL)
  374. {
  375. FreeSvrPipeEntryList(pSvrPipeListHead);
  376. pSvrPipeListHead = NULL;
  377. }
  378. LeaveCriticalSection (&cs_PIPELIST);
  379. DeleteCriticalSection (&cs_PIPELIST);
  380. WSACleanup();
  381. status.dwCurrentState = SERVICE_STOPPED;
  382. status.dwCheckPoint = 0;
  383. status.dwWaitHint = 0;
  384. if (!SetServiceStatus(hService, &status))
  385. exit(1);
  386. } // end_svcMainFunction()
  387. //--------------------------- PUBLIC PROCEDURES -----------------------------
  388. int __cdecl main ()
  389. {
  390. BOOL fOk;
  391. SERVICE_TABLE_ENTRY svcStartTable[2] =
  392. {
  393. {(LPTSTR)svcName, svcMainFunction},
  394. {NULL, NULL}
  395. };
  396. // create event to synchronize trap server shutdown
  397. hExitEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  398. if (NULL == hExitEvent)
  399. {
  400. exit(1);
  401. }
  402. // init the overlapped struct used by svrTrapThread
  403. // with manual reset non-signaled event
  404. memset(&g_ol, 0, sizeof(g_ol));
  405. g_ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  406. if (NULL == g_ol.hEvent)
  407. {
  408. CloseHandle(hExitEvent);
  409. exit(1);
  410. }
  411. // this call will not return until service stopped
  412. fOk = StartServiceCtrlDispatcher (svcStartTable);
  413. CloseHandle (hExitEvent);
  414. CloseHandle(g_ol.hEvent);
  415. return fOk;
  416. } // end_main()
  417. //
  418. DWORD WINAPI svrTrapThread (LPVOID threadParam)
  419. // This thread takes a SOCKET from the TRAP_THRD_CONTEXT parameter,
  420. // loops on select()
  421. // for data in-coming over that socket, writing it back
  422. // out to clients over all pipes currently on the list of
  423. // trap notification pipes shared by this thread and the
  424. // pipe thread
  425. {
  426. PSNMP_TRAP pRecvTrap = NULL;
  427. struct fd_set readfds;
  428. PTRAP_THRD_CONTEXT pThreadContext = (PTRAP_THRD_CONTEXT) threadParam;
  429. SOCKET fd = INVALID_SOCKET;
  430. int len;
  431. DWORD dwLastAllocatedUdpDataLen = 0; // the last allocated UDP data buffer size
  432. DWORD dwLastBigBufferRequestTime = 0; // the tick count that the last
  433. // LargeTrap received
  434. BOOL fTimeoutForMaxUdpLenBuffer = FALSE; // need to deallocate the big buffer
  435. struct timeval tvTimeout; // timeout for select
  436. //
  437. if (NULL == pThreadContext)
  438. return 0;
  439. fd = pThreadContext->s;
  440. dwLastBigBufferRequestTime = GetTickCount();
  441. // select with timeout so that we can response to SERVICE_CONTROL_STOP
  442. tvTimeout.tv_sec = 5; // 5 sec. timeout value
  443. tvTimeout.tv_usec = 0; // When select returns, the contents of the
  444. // tvTimeout structure are not altered.
  445. while (TRUE)
  446. {
  447. ULONG ulTrapSize = 0;
  448. DWORD dwError = 0;
  449. int nRet = 0;
  450. if (WAIT_OBJECT_0 == WaitForSingleObject (hExitEvent, 0))
  451. {
  452. SNMPTRAPDBG(("svrTrapThread: exit 0.\n"));
  453. break;
  454. }
  455. // construct readfds which gets destroyed by select()
  456. FD_ZERO(&readfds);
  457. FD_SET(fd, &readfds);
  458. nRet = select (0, &readfds, NULL, NULL, &tvTimeout);
  459. if (0 == nRet)
  460. {
  461. // timeout
  462. continue;
  463. }
  464. else if (SOCKET_ERROR == nRet)
  465. {
  466. SNMPTRAPDBG(("svrTrapThread: select failed %d.\n", WSAGetLastError()));
  467. break; // terminate thread
  468. }
  469. if (!(FD_ISSET(fd, &readfds)))
  470. continue;
  471. if (ioctlsocket(
  472. fd, // socket to query
  473. FIONREAD, // query for the size of the incoming datagram
  474. &ulTrapSize // unsigned long to store the size of the datagram
  475. ) != 0)
  476. {
  477. dwError = WSAGetLastError();
  478. SNMPTRAPDBG((
  479. "ioctlsocket FIONREAD failed: lasterror: 0x%08lx\n",
  480. dwError));
  481. continue; // continue if we could not determine the size of the
  482. // incoming datagram
  483. }
  484. if (ulTrapSize >= MAX_FIONREAD_UDP_SIZE)
  485. {
  486. dwLastBigBufferRequestTime = GetTickCount(); // update tickcount
  487. // the ulTrapSize is not accurate on reporting the size of the
  488. // next UDP datagram message. KB Q192599 and KB Q140263
  489. if ( NULL == pRecvTrap ||
  490. dwLastAllocatedUdpDataLen < MAX_UDP_SIZE )
  491. {
  492. if (pRecvTrap)
  493. {
  494. GlobalFree(pRecvTrap);
  495. pRecvTrap = NULL;
  496. dwLastAllocatedUdpDataLen = 0;
  497. }
  498. SNMPTRAPDBG((
  499. "allocate LargeTrap of size : %d\n",
  500. sizeof(SNMP_TRAP) - TRAPBUFSIZE + MAX_UDP_SIZE));
  501. // allocate for the trap header + max udp size
  502. pRecvTrap = (PSNMP_TRAP)GlobalAlloc(GPTR, (sizeof(SNMP_TRAP) -
  503. TRAPBUFSIZE + MAX_UDP_SIZE));
  504. if (NULL == pRecvTrap)
  505. {
  506. SNMPTRAPDBG(("svrTrapThread: GlobalAlloc failed.\n"));
  507. dwLastAllocatedUdpDataLen = 0;
  508. break;
  509. }
  510. dwLastAllocatedUdpDataLen = MAX_UDP_SIZE;
  511. }
  512. }
  513. else
  514. {
  515. // winsock has reported the exact amount of UDP datagram
  516. // size to be recieved as long as the next datagram is less than
  517. // 8-kbyte
  518. //
  519. // if we've allocated a big buffer before, check to see if we need
  520. // to deallocate it to save the usage of resource.
  521. //
  522. fTimeoutForMaxUdpLenBuffer = FALSE; // reset timeout flag
  523. if (MAX_UDP_SIZE == dwLastAllocatedUdpDataLen)
  524. {
  525. // we've allocated a big buffer before
  526. DWORD dwCurrTime = GetTickCount();
  527. if (dwCurrTime < dwLastBigBufferRequestTime)
  528. {
  529. // wrap around occured. we just simply assume it is time to
  530. // release the big buffer.
  531. fTimeoutForMaxUdpLenBuffer = TRUE;
  532. SNMPTRAPDBG((
  533. "Timeout to free LargeTrap buffer of size %d bytes.\n",
  534. dwLastAllocatedUdpDataLen));
  535. }
  536. else
  537. {
  538. if ( (dwCurrTime-dwLastBigBufferRequestTime) >
  539. MAXUDPLEN_BUFFER_TIME )
  540. {
  541. // after quite a long time, we don't have a large UDP
  542. // datagram received.
  543. fTimeoutForMaxUdpLenBuffer = TRUE;
  544. SNMPTRAPDBG((
  545. "Timeout to free LargeTrap buffer size of %d bytes.\n",
  546. dwLastAllocatedUdpDataLen));
  547. }
  548. }
  549. }
  550. if (pRecvTrap == NULL ||
  551. fTimeoutForMaxUdpLenBuffer ||
  552. dwLastAllocatedUdpDataLen < ulTrapSize)
  553. {
  554. // allocate/reallocate buffer
  555. if (pRecvTrap != NULL)
  556. {
  557. GlobalFree(pRecvTrap);
  558. pRecvTrap = NULL;
  559. dwLastAllocatedUdpDataLen = 0;
  560. }
  561. if (FOUR_K_BUF_SIZE >= ulTrapSize)
  562. {
  563. // allocate at least 4 KBytes buffer to avoid
  564. // re-allocations on different sizes of small trap received
  565. pRecvTrap = (PSNMP_TRAP)GlobalAlloc(GPTR, (sizeof(SNMP_TRAP) -
  566. TRAPBUFSIZE + FOUR_K_BUF_SIZE));
  567. dwLastAllocatedUdpDataLen = FOUR_K_BUF_SIZE;
  568. SNMPTRAPDBG((
  569. "allocate SmallTrap of size : %d\n",
  570. sizeof(SNMP_TRAP) - TRAPBUFSIZE + FOUR_K_BUF_SIZE));
  571. }
  572. else
  573. {
  574. // allocate what is necessary
  575. pRecvTrap = (PSNMP_TRAP)GlobalAlloc(GPTR, (sizeof(SNMP_TRAP) -
  576. TRAPBUFSIZE + ulTrapSize));
  577. dwLastAllocatedUdpDataLen = ulTrapSize;
  578. SNMPTRAPDBG((
  579. "allocate MediumTrap of size : %d\n",
  580. sizeof(SNMP_TRAP) - TRAPBUFSIZE + ulTrapSize));
  581. }
  582. if (NULL == pRecvTrap) // if there is so few memory that we can't allocate a bit ..
  583. { // bail out and stop the SNMPTRAP service (bug? - other option => 100% CPU which is worst)
  584. SNMPTRAPDBG(("svrTrapThread: GlobalAlloc failed.\n"));
  585. dwLastAllocatedUdpDataLen = 0;
  586. break;
  587. }
  588. }
  589. }
  590. pRecvTrap->TrapBufSz = dwLastAllocatedUdpDataLen; // actual buffer size
  591. pRecvTrap->AddrLen = sizeof(pRecvTrap->Addr);
  592. len = recvfrom (
  593. fd,
  594. pRecvTrap->TrapBuf,
  595. pRecvTrap->TrapBufSz,
  596. 0,
  597. &(pRecvTrap->Addr),
  598. &(pRecvTrap->AddrLen));
  599. if (len == SOCKET_ERROR)
  600. {
  601. dwError = WSAGetLastError();
  602. SNMPTRAPDBG((
  603. "recvfrom failed: ulTrapSize: %d bytes, TrapBufSz: %d bytes, lasterror: 0x%08lx\n",
  604. ulTrapSize, pRecvTrap->TrapBufSz, dwError));
  605. continue;
  606. }
  607. EnterCriticalSection (&cs_PIPELIST);
  608. pRecvTrap->TrapBufSz = len; // the acutal trap data len received
  609. // add header to length
  610. len += sizeof(SNMP_TRAP) - sizeof(pRecvTrap->TrapBuf); // - TRAPBUFSIZE
  611. if (!ll_empt(pSvrPipeListHead))
  612. {
  613. DWORD written;
  614. ll_node *item = pSvrPipeListHead;
  615. while (item = ll_next(item, pSvrPipeListHead))
  616. {
  617. if (WAIT_OBJECT_0 == WaitForSingleObject (hExitEvent, 0))
  618. {
  619. SNMPTRAPDBG(("svrTrapThread: exit 1.\n"));
  620. LeaveCriticalSection (&cs_PIPELIST);
  621. goto EXIT_TRAP_THREAD;
  622. }
  623. if (!WriteFile(
  624. ((svrPipeListEntry *)item)->hPipe,
  625. (LPBYTE)pRecvTrap,
  626. len,
  627. &written,
  628. &pThreadContext->ol))
  629. {
  630. if (ERROR_IO_PENDING == GetLastError())
  631. {
  632. SNMPTRAPDBG(("svrTrapThread: before GetOverlappedResult.\n"));
  633. GetOverlappedResult(
  634. ((svrPipeListEntry *)item)->hPipe,
  635. &pThreadContext->ol,
  636. &written,
  637. TRUE // Block
  638. );
  639. SNMPTRAPDBG(("svrTrapThread: after GetOverlappedResult.\n"));
  640. if (WAIT_OBJECT_0 == WaitForSingleObject (hExitEvent, 0))
  641. {
  642. SNMPTRAPDBG(("svrTrapThread: exit 2.\n"));
  643. LeaveCriticalSection (&cs_PIPELIST);
  644. goto EXIT_TRAP_THREAD;
  645. }
  646. // reset event to non-signaled state for next I/O
  647. ResetEvent(pThreadContext->ol.hEvent);
  648. }
  649. else
  650. {
  651. ll_node *hold;
  652. if (!DisconnectNamedPipe(((svrPipeListEntry *)item)->hPipe))
  653. {
  654. ; // Placeholder for error handling
  655. }
  656. if (!CloseHandle(((svrPipeListEntry *)item)->hPipe))
  657. {
  658. ; // Placeholder for error handling
  659. }
  660. hold = ll_prev(item);
  661. ll_rmv(item);
  662. GlobalFree(item); // check for errors?
  663. item = hold;
  664. }
  665. } // end_if !WriteFile
  666. else if (written != (DWORD)len)
  667. {
  668. SNMPTRAPDBG(("svrTrapThread: written != len\n"));
  669. ; // Placeholder for error handling
  670. }
  671. } // end_while item = ll_next
  672. } // end_if !ll_empt
  673. LeaveCriticalSection (&cs_PIPELIST);
  674. } // end while TRUE
  675. EXIT_TRAP_THREAD:
  676. if (pRecvTrap != NULL)
  677. GlobalFree(pRecvTrap);
  678. return 0;
  679. } // end svrTrapThread()
  680. PACL AllocGenericACL()
  681. {
  682. PACL pAcl;
  683. PSID pSidAdmins, pSidUsers, pSidLocalService;
  684. SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY;
  685. DWORD dwAclLength;
  686. pSidAdmins = pSidUsers = pSidLocalService = NULL;
  687. // Bug# 179644 The SNMP trap service should not run in the LocalSystem account
  688. if ( !AllocateAndInitializeSid( &Authority,
  689. 2,
  690. SECURITY_BUILTIN_DOMAIN_RID,
  691. DOMAIN_ALIAS_RID_ADMINS,
  692. 0, 0, 0, 0, 0, 0,
  693. &pSidAdmins ) ||
  694. !AllocateAndInitializeSid( &Authority,
  695. 2,
  696. SECURITY_BUILTIN_DOMAIN_RID,
  697. DOMAIN_ALIAS_RID_USERS,
  698. 0, 0, 0, 0, 0, 0,
  699. &pSidUsers ) ||
  700. !AllocateAndInitializeSid( &Authority,
  701. 1,
  702. SECURITY_LOCAL_SERVICE_RID,
  703. 0,
  704. 0, 0, 0, 0, 0, 0,
  705. &pSidLocalService ))
  706. {
  707. if (pSidAdmins)
  708. {
  709. FreeSid(pSidAdmins);
  710. }
  711. if (pSidUsers)
  712. {
  713. FreeSid(pSidUsers);
  714. }
  715. return NULL;
  716. }
  717. dwAclLength = sizeof(ACL) +
  718. sizeof(ACCESS_ALLOWED_ACE) -
  719. sizeof(ULONG) +
  720. GetLengthSid(pSidAdmins) +
  721. sizeof(ACCESS_ALLOWED_ACE) -
  722. sizeof(ULONG) +
  723. GetLengthSid(pSidUsers) +
  724. sizeof(ACCESS_ALLOWED_ACE) -
  725. sizeof(ULONG) +
  726. GetLengthSid(pSidLocalService);
  727. pAcl = GlobalAlloc (GPTR, dwAclLength);
  728. if (pAcl != NULL)
  729. {
  730. if (!InitializeAcl( pAcl, dwAclLength, ACL_REVISION) ||
  731. !AddAccessAllowedAce ( pAcl,
  732. ACL_REVISION,
  733. GENERIC_READ | GENERIC_WRITE,
  734. pSidLocalService ) ||
  735. !AddAccessAllowedAce ( pAcl,
  736. ACL_REVISION,
  737. GENERIC_READ | GENERIC_WRITE,
  738. pSidAdmins ) ||
  739. !AddAccessAllowedAce ( pAcl,
  740. ACL_REVISION,
  741. (GENERIC_READ | (FILE_GENERIC_WRITE & ~FILE_CREATE_PIPE_INSTANCE)),
  742. pSidUsers ))
  743. {
  744. GlobalFree(pAcl);
  745. pAcl = NULL;
  746. }
  747. }
  748. FreeSid(pSidAdmins);
  749. FreeSid(pSidUsers);
  750. FreeSid(pSidLocalService);
  751. return pAcl;
  752. }
  753. void FreeGenericACL( PACL pAcl)
  754. {
  755. if (pAcl != NULL)
  756. GlobalFree(pAcl);
  757. }
  758. DWORD WINAPI svrPipeThread (LPVOID threadParam)
  759. {
  760. // This thread creates a named pipe instance and
  761. // blocks waiting for a client connection. When
  762. // client connects, the pipe handle is added to the
  763. // list of trap notification pipes.
  764. // It then waits for another connection.
  765. DWORD nInBufLen = sizeof(SNMP_TRAP);
  766. DWORD nOutBufLen = sizeof(SNMP_TRAP) * MAX_OUT_BUFS;
  767. SECURITY_ATTRIBUTES S_Attrib;
  768. SECURITY_DESCRIPTOR S_Desc;
  769. PACL pAcl;
  770. DWORD dwRead;
  771. // construct security decsriptor
  772. InitializeSecurityDescriptor (&S_Desc, SECURITY_DESCRIPTOR_REVISION);
  773. if ((pAcl = AllocGenericACL()) == NULL ||
  774. !SetSecurityDescriptorDacl (&S_Desc, TRUE, pAcl, FALSE))
  775. {
  776. FreeGenericACL(pAcl);
  777. return (0);
  778. }
  779. S_Attrib.nLength = sizeof(SECURITY_ATTRIBUTES);
  780. S_Attrib.lpSecurityDescriptor = &S_Desc;
  781. S_Attrib.bInheritHandle = TRUE;
  782. while (TRUE)
  783. {
  784. HANDLE hPipe;
  785. svrPipeListEntry *item;
  786. BOOL bSuccess;
  787. // eliminate the TerminateThread call in CLOSE_OUT of svcMainFunction
  788. if (WAIT_OBJECT_0 == WaitForSingleObject (hExitEvent, 0))
  789. {
  790. SNMPTRAPDBG(("svrPipeThread: exit 0.\n"));
  791. break;
  792. }
  793. hPipe = CreateNamedPipe (SNMPMGRTRAPPIPE,
  794. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  795. (PIPE_WAIT | PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE),
  796. PIPE_UNLIMITED_INSTANCES,
  797. nOutBufLen, nInBufLen, 0, &S_Attrib);
  798. if (hPipe == INVALID_HANDLE_VALUE)
  799. {
  800. SNMPTRAPDBG(("svrPipeThread: CreateNamedPipe failed 0x%08lx.\n", GetLastError()));
  801. break;
  802. }
  803. else
  804. {
  805. bSuccess = ConnectNamedPipe(hPipe, &g_ol);
  806. if (!bSuccess && GetLastError() == ERROR_IO_PENDING)
  807. {
  808. // blocking wait until g_ol.hEvent signaled by system for a new client
  809. // connection request or by our own termination.
  810. SNMPTRAPDBG(("svrPipeThread: before GetOverlappedResult.\n"));
  811. bSuccess = GetOverlappedResult(hPipe, &g_ol, &dwRead, TRUE);
  812. SNMPTRAPDBG(("svrPipeThread: after GetOverlappedResult.\n"));
  813. if (WAIT_OBJECT_0 == WaitForSingleObject (hExitEvent, 0))
  814. {
  815. SNMPTRAPDBG(("svrPipeThread: exit 1.\n"));
  816. CloseHandle(hPipe);
  817. break;
  818. }
  819. // reset event to non-signaled state for next I/O
  820. ResetEvent(g_ol.hEvent);
  821. }
  822. // check return from either ConnectNamedPipe or GetOverlappedResult.
  823. // If a client managed to connect between the CreateNamedPipe and
  824. // ConnectNamedPipe calls, ERROR_PIPE_CONNECTED will result
  825. if (!bSuccess && GetLastError() != ERROR_PIPE_CONNECTED)
  826. {
  827. // something went wrong, close instance and try again
  828. SNMPTRAPDBG(("svrPipeThread: ConnectNamedPipe 0x%08lx.\n", GetLastError()));
  829. CloseHandle(hPipe);
  830. continue;
  831. }
  832. }
  833. if (!(item = (svrPipeListEntry *)
  834. GlobalAlloc (GPTR, sizeof(svrPipeListEntry))))
  835. {
  836. SNMPTRAPDBG(("svrPipeThread: E_OUTOFMEMORY\n"));
  837. DisconnectNamedPipe(hPipe);
  838. CloseHandle(hPipe);
  839. break;
  840. }
  841. else
  842. {
  843. ll_node *crt;
  844. item->hPipe = hPipe;
  845. SNMPTRAPDBG(("svrPipeThread: add connected client to pipe list\n"));
  846. EnterCriticalSection (&cs_PIPELIST);
  847. ll_adde(item, pSvrPipeListHead);
  848. crt = pSvrPipeListHead;
  849. // scan all the pipe instances to detect the ones that are disconnected
  850. while (crt = ll_next(crt, pSvrPipeListHead))
  851. {
  852. DWORD dwError;
  853. // subsequent ConnectNamePipe() on a handle already connected return:
  854. // - ERROR_PIPE_CONNECTED if the client is still there
  855. // - ERROR_NO_DATA if the client has disconnected
  856. ConnectNamedPipe(
  857. ((svrPipeListEntry *)crt)->hPipe,
  858. NULL);
  859. dwError = GetLastError();
  860. // For anything else but ERROR_PIPE_CONNECTED, conclude there has been
  861. // something wrong with the client/pipe so disconect and close the handle
  862. // and release the memory
  863. if (dwError != ERROR_PIPE_CONNECTED)
  864. {
  865. ll_node *hold;
  866. SNMPTRAPDBG(("svrPipeThread: disconnect client pipe handle 0x%08lx.\n", ((svrPipeListEntry *)crt)->hPipe));
  867. if (!DisconnectNamedPipe(((svrPipeListEntry *)crt)->hPipe))
  868. {
  869. ; // Placeholder for error handling
  870. }
  871. if (!CloseHandle(((svrPipeListEntry *)crt)->hPipe))
  872. {
  873. ; // Placeholder for error handling
  874. }
  875. hold = ll_prev(crt);
  876. ll_rmv(crt);
  877. GlobalFree(crt); // check for errors?
  878. crt = hold;
  879. } // end_if
  880. }
  881. LeaveCriticalSection (&cs_PIPELIST);
  882. } // end_else
  883. } // end_while TRUE
  884. FreeGenericACL(pAcl);
  885. return(0);
  886. } // end_svrPipeThread()
  887. void FreeSvrPipeEntryList(ll_node* head)
  888. {
  889. if (head)
  890. {
  891. ll_node* current;
  892. current = head;
  893. while (current = ll_next(current, head))
  894. {
  895. ll_node *hold;
  896. if (!DisconnectNamedPipe(((svrPipeListEntry *)current)->hPipe))
  897. {
  898. ; // Placeholder for error handling
  899. }
  900. if (!CloseHandle(((svrPipeListEntry *)current)->hPipe))
  901. {
  902. ; // Placeholder for error handling
  903. }
  904. hold = ll_prev(current);
  905. ll_rmv(current);
  906. GlobalFree(current); // check for errors?
  907. current = hold;
  908. }
  909. GlobalFree(head);
  910. }
  911. }
  912. #if DBG
  913. // modified from snmp\common\dll\dbg.c
  914. #define MAX_LOG_ENTRY_LEN 512
  915. VOID
  916. WINAPI
  917. SnmpTrapDbgPrint(
  918. LPSTR szFormat,
  919. ...
  920. )
  921. /*++
  922. Routine Description:
  923. Prints debug message.
  924. Arguments:
  925. szFormat - formatting string (see printf).
  926. Return Values:
  927. None.
  928. --*/
  929. {
  930. va_list arglist;
  931. // 640 octets should be enough to encode oid's of 128 sub-ids.
  932. // (one subid can be encoded on at most 5 octets; there can be at
  933. // 128 sub-ids per oid. MAX_LOG_ENTRY_LEN = 512
  934. char szLogEntry[4*MAX_LOG_ENTRY_LEN];
  935. time_t now;
  936. // initialize variable args
  937. va_start(arglist, szFormat);
  938. time(&now);
  939. strftime(szLogEntry, MAX_LOG_ENTRY_LEN, "%H:%M:%S :", localtime(&now));
  940. // transfer variable args to buffer
  941. vsprintf(szLogEntry + strlen(szLogEntry), szFormat, arglist);
  942. // output entry to debugger
  943. OutputDebugStringA(szLogEntry);
  944. }
  945. #endif