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.

687 lines
18 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. snmpthrd.c
  5. Abstract:
  6. Contains routines for master agent network thread.
  7. Environment:
  8. User Mode - Win32
  9. Revision History:
  10. 10-Feb-1997 DonRyan
  11. Rewrote to implement SNMPv2 support.
  12. --*/
  13. ///////////////////////////////////////////////////////////////////////////////
  14. // //
  15. // Include files //
  16. // //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include <tchar.h>
  19. #include <stdio.h>
  20. #include "globals.h"
  21. #include "contexts.h"
  22. #include "regions.h"
  23. #include "snmpmgrs.h"
  24. #include "trapmgrs.h"
  25. #include "trapthrd.h"
  26. #include "network.h"
  27. #include "varbinds.h"
  28. #include "snmpmgmt.h"
  29. ///////////////////////////////////////////////////////////////////////////////
  30. // //
  31. // Global variables //
  32. // //
  33. ///////////////////////////////////////////////////////////////////////////////
  34. UINT g_nTransactionId = 0;
  35. ///////////////////////////////////////////////////////////////////////////////
  36. // //
  37. // Private definitions //
  38. // //
  39. ///////////////////////////////////////////////////////////////////////////////
  40. #define MAX_IPX_ADDR_LEN 64
  41. #define MAX_COMMUNITY_LEN 255
  42. #define ERRMSG_TRANSPORT_IP _T("IP")
  43. #define ERRMSG_TRANSPORT_IPX _T("IPX")
  44. ///////////////////////////////////////////////////////////////////////////////
  45. // //
  46. // Private procedures //
  47. // //
  48. ///////////////////////////////////////////////////////////////////////////////
  49. LPSTR
  50. AddrToString(
  51. struct sockaddr * pSockAddr
  52. )
  53. /*++
  54. Routine Description:
  55. Converts sockaddr to display string.
  56. Arguments:
  57. pSockAddr - pointer to socket address.
  58. Return Values:
  59. Returns pointer to string.
  60. --*/
  61. {
  62. static CHAR ipxAddr[MAX_IPX_ADDR_LEN];
  63. // determine family
  64. if (pSockAddr->sa_family == AF_INET) {
  65. struct sockaddr_in * pSockAddrIn;
  66. // obtain pointer to protocol specific structure
  67. pSockAddrIn = (struct sockaddr_in * )pSockAddr;
  68. // forward to winsock conversion function
  69. return inet_ntoa(pSockAddrIn->sin_addr);
  70. } else if (pSockAddr->sa_family == AF_IPX) {
  71. struct sockaddr_ipx * pSockAddrIpx;
  72. // obtain pointer to protocol specific structure
  73. pSockAddrIpx = (struct sockaddr_ipx * )pSockAddr;
  74. // transfer ipx address to static buffer
  75. sprintf(ipxAddr,
  76. "%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x",
  77. (BYTE)pSockAddrIpx->sa_netnum[0],
  78. (BYTE)pSockAddrIpx->sa_netnum[1],
  79. (BYTE)pSockAddrIpx->sa_netnum[2],
  80. (BYTE)pSockAddrIpx->sa_netnum[3],
  81. (BYTE)pSockAddrIpx->sa_nodenum[0],
  82. (BYTE)pSockAddrIpx->sa_nodenum[1],
  83. (BYTE)pSockAddrIpx->sa_nodenum[2],
  84. (BYTE)pSockAddrIpx->sa_nodenum[3],
  85. (BYTE)pSockAddrIpx->sa_nodenum[4],
  86. (BYTE)pSockAddrIpx->sa_nodenum[5]
  87. );
  88. // return addr
  89. return ipxAddr;
  90. }
  91. // failure
  92. return NULL;
  93. }
  94. LPSTR
  95. CommunityOctetsToString(
  96. AsnOctetString *pAsnCommunity,
  97. BOOL bUnicode
  98. )
  99. /*++
  100. Routine Description:
  101. Converts community octet string to display string.
  102. Arguments:
  103. pAsnCommunity - pointer to community octet string.
  104. Return Values:
  105. Returns pointer to string.
  106. --*/
  107. {
  108. static CHAR Community[MAX_COMMUNITY_LEN+1];
  109. LPSTR pCommunity = Community;
  110. // terminate string
  111. *pCommunity = '\0';
  112. // validate pointer
  113. if (pAsnCommunity != NULL)
  114. {
  115. DWORD nChars = 0;
  116. // determine number of characters to transfer
  117. nChars = min(pAsnCommunity->length, MAX_COMMUNITY_LEN);
  118. if (bUnicode)
  119. {
  120. WCHAR wCommunity[MAX_COMMUNITY_LEN+1];
  121. // tranfer memory into buffer
  122. memset(wCommunity, 0, nChars+sizeof(WCHAR));
  123. memcpy(wCommunity, pAsnCommunity->stream, nChars);
  124. SnmpUtilUnicodeToAnsi(&pCommunity, wCommunity, FALSE);
  125. }
  126. else
  127. {
  128. memcpy(Community, pAsnCommunity->stream, nChars);
  129. Community[nChars] = '\0';
  130. }
  131. }
  132. // success
  133. return pCommunity;
  134. }
  135. LPSTR
  136. StaticUnicodeToString(
  137. LPWSTR wszUnicode
  138. )
  139. /*++
  140. Routine Description:
  141. Converts null terminated UNICODE string to static LPSTR
  142. Arguments:
  143. pOctets - pointer to community octet string.
  144. Return Values:
  145. Returns pointer to string.
  146. --*/
  147. {
  148. static CHAR szString[MAX_COMMUNITY_LEN+1];
  149. LPSTR pszString = szString;
  150. // terminate string
  151. *pszString = '\0';
  152. // validate pointer
  153. if (wszUnicode != NULL)
  154. {
  155. WCHAR wcBreak;
  156. BOOL bNeedBreak;
  157. bNeedBreak = (wcslen(wszUnicode) > MAX_COMMUNITY_LEN);
  158. if (bNeedBreak)
  159. {
  160. wcBreak = wszUnicode[MAX_COMMUNITY_LEN];
  161. wszUnicode[MAX_COMMUNITY_LEN] = L'\0';
  162. }
  163. SnmpUtilUnicodeToAnsi(&pszString, wszUnicode, FALSE);
  164. if (bNeedBreak)
  165. wszUnicode[MAX_COMMUNITY_LEN] = wcBreak;
  166. }
  167. // success
  168. return pszString;
  169. }
  170. BOOL
  171. ValidateManager(
  172. PNETWORK_LIST_ENTRY pNLE
  173. )
  174. /*++
  175. Routine Description:
  176. Checks access rights of given manager.
  177. Arguments:
  178. pNLE - pointer to network list entry.
  179. Return Values:
  180. Returns true if manager allowed access.
  181. --*/
  182. {
  183. BOOL fAccessOk = FALSE;
  184. PMANAGER_LIST_ENTRY pMLE = NULL;
  185. fAccessOk = IsManagerAddrLegal((struct sockaddr_in *)&pNLE->SockAddr) &&
  186. (FindManagerByAddr(&pMLE, &pNLE->SockAddr) ||
  187. IsListEmpty(&g_PermittedManagers)
  188. );
  189. if (!fAccessOk &&
  190. snmpMgmtBase.AsnIntegerPool[IsnmpEnableAuthenTraps].asnValue.number)
  191. GenerateAuthenticationTrap();
  192. SNMPDBG((
  193. SNMP_LOG_TRACE,
  194. "SNMP: SVC: %s request from %s.\n",
  195. fAccessOk
  196. ? "accepting"
  197. : "rejecting"
  198. ,
  199. AddrToString(&pNLE->SockAddr)
  200. ));
  201. return fAccessOk;
  202. }
  203. BOOL
  204. ProcessSnmpMessage(
  205. PNETWORK_LIST_ENTRY pNLE
  206. )
  207. /*++
  208. Routine Description:
  209. Parse SNMP message and dispatch to subagents.
  210. Arguments:
  211. pNLE - pointer to network list entry.
  212. Return Values:
  213. Returns true if successful.
  214. --*/
  215. {
  216. BOOL fOk = FALSE;
  217. // decode request
  218. if (ParseMessage(pNLE))
  219. {
  220. SNMPDBG((
  221. SNMP_LOG_TRACE,
  222. "SNMP: SVC: %s request, community %s, %d variable(s).\n",
  223. PDUTYPESTRING(pNLE->Pdu.nType),
  224. CommunityOctetsToString(&(pNLE->Community), FALSE),
  225. pNLE->Pdu.Vbl.len
  226. ));
  227. if (ProcessVarBinds(pNLE))
  228. {
  229. // initialize buffer length
  230. pNLE->Buffer.len = NLEBUFLEN;
  231. // reset pdu type to response
  232. pNLE->Pdu.nType = SNMP_PDU_RESPONSE;
  233. // encode response
  234. fOk = BuildMessage(
  235. pNLE->nVersion,
  236. &pNLE->Community,
  237. &pNLE->Pdu,
  238. pNLE->Buffer.buf,
  239. &pNLE->Buffer.len
  240. );
  241. }
  242. }
  243. else
  244. {
  245. if (pNLE->fAccessOk)
  246. {
  247. // BUG# 552295
  248. // authentication succeeded or not done yet,
  249. // the error is due to BER decoding failure
  250. // register BER decoding failure into the management structures
  251. mgmtCTick(CsnmpInASNParseErrs);
  252. }
  253. }
  254. // release pdu
  255. UnloadPdu(pNLE);
  256. return fOk;
  257. }
  258. void CALLBACK
  259. RecvCompletionRoutine(
  260. IN DWORD dwStatus,
  261. IN DWORD dwBytesTransferred,
  262. IN LPWSAOVERLAPPED pOverlapped,
  263. IN DWORD dwFlags
  264. )
  265. /*++
  266. Routine Description:
  267. Callback for completing asynchronous reads.
  268. Arguments:
  269. Status - completion status for the overlapped operation.
  270. BytesTransferred - number of bytes transferred.
  271. pOverlapped - pointer to overlapped structure.
  272. Flags - receive flags.
  273. Return Values:
  274. None.
  275. --*/
  276. {
  277. PNETWORK_LIST_ENTRY pNLE;
  278. EnterCriticalSection(&g_RegCriticalSectionA);
  279. // retreive pointer to network list entry from overlapped structure
  280. pNLE = CONTAINING_RECORD(pOverlapped, NETWORK_LIST_ENTRY, Overlapped);
  281. // copy receive completion information
  282. pNLE->nTransactionId = ++g_nTransactionId;
  283. pNLE->dwBytesTransferred = dwBytesTransferred;
  284. pNLE->dwStatus = dwStatus;
  285. pNLE->dwFlags = dwFlags;
  286. SNMPDBG((
  287. SNMP_LOG_TRACE,
  288. "SNMP: SVC: --- transaction %d begin ---\n",
  289. pNLE->nTransactionId
  290. ));
  291. // validate status
  292. if (dwStatus == NOERROR) {
  293. // register incoming packet into the management structure
  294. mgmtCTick(CsnmpInPkts);
  295. SNMPDBG((
  296. SNMP_LOG_TRACE,
  297. "SNMP: SVC: received %d bytes from %s.\n",
  298. pNLE->dwBytesTransferred,
  299. AddrToString(&pNLE->SockAddr)
  300. ));
  301. // check manager address
  302. if (ValidateManager(pNLE)) {
  303. // process snmp message
  304. if (ProcessSnmpMessage(pNLE)) {
  305. // synchronous send
  306. dwStatus = WSASendTo(
  307. pNLE->Socket,
  308. &pNLE->Buffer,
  309. 1,
  310. &pNLE->dwBytesTransferred,
  311. pNLE->dwFlags,
  312. &pNLE->SockAddr,
  313. pNLE->SockAddrLenUsed,
  314. NULL,
  315. NULL
  316. );
  317. // register outgoing packet into the management structure
  318. mgmtCTick(CsnmpOutPkts);
  319. // register outgoing Response PDU
  320. mgmtCTick(CsnmpOutGetResponses);
  321. // validate return code
  322. if (dwStatus != SOCKET_ERROR) {
  323. SNMPDBG((
  324. SNMP_LOG_TRACE,
  325. "SNMP: SVC: sent %d bytes to %s.\n",
  326. pNLE->dwBytesTransferred,
  327. AddrToString(&pNLE->SockAddr)
  328. ));
  329. } else {
  330. SNMPDBG((
  331. SNMP_LOG_ERROR,
  332. "SNMP: SVC: error %d sending response.\n",
  333. WSAGetLastError()
  334. ));
  335. }
  336. }
  337. }
  338. } else {
  339. SNMPDBG((
  340. SNMP_LOG_ERROR,
  341. "SNMP: SVC: error %d receiving snmp request.\n",
  342. dwStatus
  343. ));
  344. }
  345. SNMPDBG((
  346. SNMP_LOG_TRACE,
  347. "SNMP: SVC: --- transaction %d end ---\n",
  348. pNLE->nTransactionId
  349. ));
  350. LeaveCriticalSection(&g_RegCriticalSectionA);
  351. }
  352. ///////////////////////////////////////////////////////////////////////////////
  353. // //
  354. // Public procedures //
  355. // //
  356. ///////////////////////////////////////////////////////////////////////////////
  357. DWORD
  358. ProcessSnmpMessages(
  359. PVOID pParam
  360. )
  361. /*++
  362. Routine Description:
  363. Thread procedure for processing SNMP PDUs.
  364. Arguments:
  365. pParam - unused.
  366. Return Values:
  367. Returns true if successful.
  368. --*/
  369. {
  370. DWORD dwStatus;
  371. PLIST_ENTRY pLE;
  372. PNETWORK_LIST_ENTRY pNLE;
  373. SNMPDBG((
  374. SNMP_LOG_TRACE,
  375. "SNMP: SVC: Loading Registry Parameters.\n"
  376. ));
  377. // fire cold start trap
  378. GenerateColdStartTrap();
  379. SNMPDBG((
  380. SNMP_LOG_TRACE,
  381. "SNMP: SVC: starting pdu processing thread.\n"
  382. ));
  383. ReportSnmpEvent(
  384. SNMP_EVENT_SERVICE_STARTED,
  385. 0,
  386. NULL,
  387. 0);
  388. // loop
  389. for (;;)
  390. {
  391. // obtain pointer to first transport
  392. pLE = g_IncomingTransports.Flink;
  393. // loop through incoming transports
  394. while (pLE != &g_IncomingTransports)
  395. {
  396. // retreive pointer to network list entry from link
  397. pNLE = CONTAINING_RECORD(pLE, NETWORK_LIST_ENTRY, Link);
  398. // make sure recv is not pending
  399. if (pNLE->dwStatus != WSA_IO_PENDING)
  400. {
  401. // reset completion status
  402. pNLE->dwStatus = WSA_IO_PENDING;
  403. // intialize address structure size
  404. pNLE->SockAddrLenUsed = pNLE->SockAddrLen;
  405. // initialize buffer length
  406. pNLE->Buffer.len = NLEBUFLEN;
  407. // re-initialize
  408. pNLE->dwFlags = 0;
  409. // post receive buffer
  410. dwStatus = WSARecvFrom(
  411. pNLE->Socket,
  412. &pNLE->Buffer,
  413. 1, // dwBufferCount
  414. &pNLE->dwBytesTransferred,
  415. &pNLE->dwFlags,
  416. &pNLE->SockAddr,
  417. &pNLE->SockAddrLenUsed,
  418. &pNLE->Overlapped,
  419. RecvCompletionRoutine
  420. );
  421. // handle network failures
  422. if (dwStatus == SOCKET_ERROR)
  423. {
  424. // retrieve last error
  425. dwStatus = WSAGetLastError();
  426. // if WSA_IO_PENDING everything is ok, just waiting for incoming traffic. Otherwise...
  427. if (dwStatus != WSA_IO_PENDING)
  428. {
  429. // WSAECONNRESET means the last 'WSASendTo' (the one from RecvCompletionRoutine) failed
  430. // most probably because the manager closed the socket (so we got back 'unreacheable destination port')
  431. if (dwStatus == WSAECONNRESET)
  432. {
  433. SNMPDBG((
  434. SNMP_LOG_ERROR,
  435. "SNMP: SVC: Benign error %d posting receive buffer. Retry...\n",
  436. dwStatus
  437. ));
  438. // just go one more time and setup the port. It shouldn't ever loop continuously
  439. // and hence hog the CPU..
  440. pNLE->dwStatus = ERROR_SUCCESS;
  441. continue;
  442. }
  443. else
  444. {
  445. // prepare the event log insertion string
  446. LPTSTR pMessage = (pNLE->SockAddr.sa_family == AF_INET) ?
  447. ERRMSG_TRANSPORT_IP :
  448. ERRMSG_TRANSPORT_IPX;
  449. // another error occurred. We don't know how to handle it so it is a fatal
  450. // error for this transport. Will shut it down.
  451. SNMPDBG((
  452. SNMP_LOG_ERROR,
  453. "SNMP: SVC: Fatal error %d posting receive buffer. Skip transport.\n",
  454. dwStatus
  455. ));
  456. ReportSnmpEvent(
  457. SNMP_EVNT_INCOMING_TRANSPORT_CLOSED,
  458. 1,
  459. &pMessage,
  460. dwStatus);
  461. // first step next with the pointer
  462. pLE = pLE->Flink;
  463. // delete this transport from the incoming transports list
  464. UnloadTransport(pNLE);
  465. // go on further
  466. continue;
  467. }
  468. }
  469. }
  470. }
  471. pLE = pLE->Flink;
  472. }
  473. // we might want to shut the service down if no incoming transport remains.
  474. // we might as well consider letting the service up in order to keep sending outgoing traps.
  475. // for now, keep the service up (code below commented)
  476. //if (IsListEmpty(&g_IncomingTransports))
  477. //{
  478. // ReportSnmpEvent(...);
  479. // ProcessControllerRequests(SERVICE_CONTROL_STOP);
  480. //}
  481. // wait for incoming requests or indication of process termination
  482. dwStatus = WaitForSingleObjectEx(g_hTerminationEvent, INFINITE, TRUE);
  483. // validate return code
  484. if (dwStatus == WAIT_OBJECT_0) {
  485. SNMPDBG((
  486. SNMP_LOG_TRACE,
  487. "SNMP: SVC: exiting pdu processing thread.\n"
  488. ));
  489. // success
  490. return NOERROR;
  491. } else if (dwStatus != WAIT_IO_COMPLETION) {
  492. // retrieve error
  493. dwStatus = GetLastError();
  494. SNMPDBG((
  495. SNMP_LOG_ERROR,
  496. "SNMP: SVC: error %d waiting for request.\n",
  497. dwStatus
  498. ));
  499. // failure
  500. return dwStatus;
  501. }
  502. }
  503. }