Source code of Windows XP (NT5)
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.

727 lines
20 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. trapthrd.c
  5. Abstract:
  6. Contains routines for trap processing 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 "globals.h"
  19. #include "trapthrd.h"
  20. #include "subagnts.h"
  21. #include "snmppdus.h"
  22. #include "trapmgrs.h"
  23. #include "snmpmgrs.h"
  24. #include "network.h"
  25. #include "snmpmgmt.h"
  26. ///////////////////////////////////////////////////////////////////////////////
  27. // //
  28. // Global variables //
  29. // //
  30. ///////////////////////////////////////////////////////////////////////////////
  31. static SnmpVarBindList g_NullVbl = { NULL, 0 };
  32. ///////////////////////////////////////////////////////////////////////////////
  33. // //
  34. // Private procedures //
  35. // //
  36. ///////////////////////////////////////////////////////////////////////////////
  37. BOOL
  38. LoadWaitObjects(
  39. DWORD * pnWaitObjects,
  40. PHANDLE * ppWaitObjects,
  41. PSUBAGENT_LIST_ENTRY ** pppNLEs
  42. )
  43. /*++
  44. Routine Description:
  45. Loads arrays with necessary wait object information.
  46. Arguments:
  47. pnWaitObjects - pointer to receive count of wait objects.
  48. ppWaitObjects - pointer to receive wait object handles.
  49. pppNLEs - pointer to receive array of associated subagents pointers.
  50. Return Values:
  51. Returns true if successful.
  52. --*/
  53. {
  54. PLIST_ENTRY pLE;
  55. PSUBAGENT_LIST_ENTRY pNLE;
  56. PSUBAGENT_LIST_ENTRY * ppNLEs = NULL;
  57. PHANDLE pWaitObjects = NULL;
  58. DWORD nWaitObjects = 2;
  59. BOOL fOk = FALSE;
  60. EnterCriticalSection(&g_RegCriticalSectionB);
  61. // point to first subagent
  62. pLE = g_Subagents.Flink;
  63. // process each subagent
  64. while (pLE != &g_Subagents) {
  65. // retreive pointer to subagent list entry from link
  66. pNLE = CONTAINING_RECORD(pLE, SUBAGENT_LIST_ENTRY, Link);
  67. // check for subagent trap event
  68. if (pNLE->hSubagentTrapEvent != NULL) {
  69. // increment
  70. nWaitObjects++;
  71. }
  72. // next entry
  73. pLE = pLE->Flink;
  74. }
  75. // attempt to allocate array of subagent pointers
  76. ppNLEs = AgentMemAlloc(nWaitObjects * sizeof(PSUBAGENT_LIST_ENTRY));
  77. // validate pointers
  78. if (ppNLEs != NULL) {
  79. // attempt to allocate array of event handles
  80. pWaitObjects = AgentMemAlloc(nWaitObjects * sizeof(HANDLE));
  81. // validate pointer
  82. if (pWaitObjects != NULL) {
  83. // success
  84. fOk = TRUE;
  85. } else {
  86. SNMPDBG((
  87. SNMP_LOG_ERROR,
  88. "SNMP: SVC: could not allocate handle array.\n"
  89. ));
  90. // release array
  91. AgentMemFree(ppNLEs);
  92. // re-init
  93. ppNLEs = NULL;
  94. }
  95. } else {
  96. SNMPDBG((
  97. SNMP_LOG_ERROR,
  98. "SNMP: SVC: could not allocate subagent pointers.\n"
  99. ));
  100. }
  101. if (fOk) {
  102. // initialize
  103. DWORD dwIndex = 0;
  104. // point to first subagent
  105. pLE = g_Subagents.Flink;
  106. // process each subagent and check for overflow
  107. while ((pLE != &g_Subagents) && (dwIndex < nWaitObjects - 1)) {
  108. // retreive pointer to subagent list entry from link
  109. pNLE = CONTAINING_RECORD(pLE, SUBAGENT_LIST_ENTRY, Link);
  110. // check for subagent trap event
  111. if (pNLE->hSubagentTrapEvent != NULL) {
  112. // copy subagent trap event handle
  113. pWaitObjects[dwIndex] = pNLE->hSubagentTrapEvent;
  114. // copy subagent pointer
  115. ppNLEs[dwIndex] = pNLE;
  116. // next
  117. dwIndex++;
  118. }
  119. // next entry
  120. pLE = pLE->Flink;
  121. }
  122. // copy registry update event into second last entry
  123. pWaitObjects[dwIndex++] = g_hRegistryEvent;
  124. // copy termination event into last entry
  125. pWaitObjects[dwIndex++] = g_hTerminationEvent;
  126. // validate number of items
  127. if (dwIndex != nWaitObjects) {
  128. SNMPDBG((
  129. SNMP_LOG_WARNING,
  130. "SNMP: SVC: updating number of events from %d to %d.\n",
  131. nWaitObjects,
  132. dwIndex
  133. ));
  134. // use latest number
  135. nWaitObjects = dwIndex;
  136. }
  137. }
  138. // transfer wait object information
  139. *pnWaitObjects = fOk ? nWaitObjects : 0;
  140. *ppWaitObjects = pWaitObjects;
  141. *pppNLEs = ppNLEs;
  142. LeaveCriticalSection(&g_RegCriticalSectionB);
  143. return fOk;
  144. }
  145. BOOL
  146. UnloadWaitObjects(
  147. PHANDLE pWaitObjects,
  148. PSUBAGENT_LIST_ENTRY * ppNLEs
  149. )
  150. /*++
  151. Routine Description:
  152. Loads arrays with necessary wait object information.
  153. Arguments:
  154. pWaitObjects - pointer to wait object handles.
  155. ppNLEs - pointer to array of associated subagents pointers.
  156. Return Values:
  157. Returns true if successful.
  158. --*/
  159. {
  160. // release array
  161. AgentMemFree(pWaitObjects);
  162. // release array
  163. AgentMemFree(ppNLEs);
  164. return TRUE;
  165. }
  166. BOOL
  167. GenerateExtensionTrap(
  168. AsnObjectIdentifier * pEnterpriseOid,
  169. AsnInteger32 nGenericTrap,
  170. AsnInteger32 nSpecificTrap,
  171. AsnTimeticks nTimeStamp,
  172. SnmpVarBindList * pVbl
  173. )
  174. /*
  175. Routine Description:
  176. Generates trap for subagent.
  177. Arguments:
  178. pEnterpriseOid - pointer to EnterpriseOid OID.
  179. nGenericTrap - generic trap identifier.
  180. nSpecificTrap - EnterpriseOid specific trap identifier.
  181. nTimeStamp - timestamp to include in trap.
  182. pVbl - pointer to optional variables.
  183. Return Values:
  184. Returns true if successful.
  185. */
  186. {
  187. SNMP_PDU Pdu;
  188. BOOL fOk = FALSE;
  189. // note this is in older format
  190. Pdu.nType = SNMP_PDU_V1TRAP;
  191. // validate pointer
  192. if (pVbl != NULL) {
  193. // copy varbinds
  194. Pdu.Vbl = *pVbl;
  195. } else {
  196. // initialize
  197. Pdu.Vbl.len = 0;
  198. Pdu.Vbl.list = NULL;
  199. }
  200. // validate enterprise oid
  201. if ((pEnterpriseOid != NULL) &&
  202. (pEnterpriseOid->ids != NULL) &&
  203. (pEnterpriseOid->idLength != 0)) {
  204. // transfer specified enterprise oid
  205. Pdu.Pdu.TrapPdu.EnterpriseOid = *pEnterpriseOid;
  206. } else {
  207. // transfer microsoft enterprise oid
  208. // Note: transfer the AsnObjectIdentifier structure as a whole, but no new memory is allocated
  209. // for the 'ids' buffer. Hence, Pdu....EnterpriseOid should not be 'SnmpUtilFreeOid'!!
  210. Pdu.Pdu.TrapPdu.EnterpriseOid = snmpMgmtBase.AsnObjectIDs[OsnmpSysObjectID].asnValue.object;
  211. }
  212. // make sure that the system uptime is consistent by overriding
  213. Pdu.Pdu.TrapPdu.nTimeticks = nTimeStamp ? SnmpSvcGetUptime() : 0;
  214. // transfer the remaining parameters
  215. Pdu.Pdu.TrapPdu.nGenericTrap = nGenericTrap;
  216. Pdu.Pdu.TrapPdu.nSpecificTrap = nSpecificTrap;
  217. // initialize agent address structure
  218. Pdu.Pdu.TrapPdu.AgentAddr.dynamic = FALSE;
  219. Pdu.Pdu.TrapPdu.AgentAddr.stream = NULL;
  220. Pdu.Pdu.TrapPdu.AgentAddr.length = 0;
  221. // send trap to managers
  222. return GenerateTrap(&Pdu);
  223. }
  224. ///////////////////////////////////////////////////////////////////////////////
  225. // //
  226. // Public procedures //
  227. // //
  228. ///////////////////////////////////////////////////////////////////////////////
  229. BOOL
  230. ProcessSubagentEvents(
  231. )
  232. /*++
  233. Routine Description:
  234. Processes subagent trap events.
  235. Arguments:
  236. None.
  237. Return Values:
  238. Returns true if successful.
  239. --*/
  240. {
  241. BOOL fOk = FALSE;
  242. PSUBAGENT_LIST_ENTRY * ppNLEs = NULL;
  243. PHANDLE pWaitObjects = NULL;
  244. DWORD nWaitObjects = 0;
  245. DWORD dwIndex;
  246. // attempt to load waitable objects into array
  247. if (LoadWaitObjects(&nWaitObjects, &pWaitObjects, &ppNLEs)) {
  248. // loop
  249. for (;;) {
  250. // subagent event or termination
  251. dwIndex = WaitForMultipleObjects(
  252. nWaitObjects,
  253. pWaitObjects,
  254. FALSE,
  255. INFINITE
  256. );
  257. // check for process termination event first
  258. // note: g_hTerminationEvent is a manual reset event
  259. if (WAIT_OBJECT_0 == WaitForSingleObject(g_hTerminationEvent, 0)) {
  260. SNMPDBG((
  261. SNMP_LOG_TRACE,
  262. "SNMP: SVC: shutting down trap thread.\n"
  263. ));
  264. break; // bail...
  265. // check for registry update event next
  266. } else if (dwIndex == (WAIT_OBJECT_0 + nWaitObjects - 2)) {
  267. SNMPDBG((
  268. SNMP_LOG_TRACE,
  269. "SNMP: SVC: recalling LoadWaitObjects.\n"
  270. ));
  271. if (!LoadWaitObjects(&nWaitObjects, &pWaitObjects, &ppNLEs))
  272. break;
  273. // check for subagent trap notification event
  274. } else if (dwIndex < (WAIT_OBJECT_0 + nWaitObjects - 1)) {
  275. AsnObjectIdentifier EnterpriseOid;
  276. AsnInteger nGenericTrap;
  277. AsnInteger nSpecificTrap;
  278. AsnInteger nTimeStamp;
  279. SnmpVarBindList Vbl;
  280. PFNSNMPEXTENSIONTRAP pfnSnmpExtensionTrap;
  281. // retrieve pointer to subagent trap entry point
  282. pfnSnmpExtensionTrap = ppNLEs[dwIndex]->pfnSnmpExtensionTrap;
  283. // validate function pointer
  284. if (pfnSnmpExtensionTrap != NULL) {
  285. __try {
  286. // loop until false is returned
  287. while ((*pfnSnmpExtensionTrap)(
  288. &EnterpriseOid,
  289. &nGenericTrap,
  290. &nSpecificTrap,
  291. &nTimeStamp,
  292. &Vbl)) {
  293. // send extension trap
  294. GenerateExtensionTrap(
  295. &EnterpriseOid,
  296. nGenericTrap,
  297. nSpecificTrap,
  298. nTimeStamp,
  299. &Vbl
  300. );
  301. SnmpUtilVarBindListFree(&Vbl);
  302. // check for process termination event while we are in this while loop
  303. if (WAIT_OBJECT_0 == WaitForSingleObject(g_hTerminationEvent, 0))
  304. {
  305. SNMPDBG((
  306. SNMP_LOG_TRACE,
  307. "SNMP: SVC: shutting down trap thread in \"while((*pfnSnmpExtensionTrap)\" loop.\n"
  308. ));
  309. break; // bail...
  310. }
  311. }
  312. } __except (EXCEPTION_EXECUTE_HANDLER) {
  313. SNMPDBG((
  314. SNMP_LOG_ERROR,
  315. "SNMP: SVC: exception 0x%08lx polling %s.\n",
  316. GetExceptionCode(),
  317. ppNLEs[dwIndex]->pPathname
  318. ));
  319. }
  320. }
  321. }
  322. }
  323. // release memory for wait objects
  324. UnloadWaitObjects(pWaitObjects, ppNLEs);
  325. }
  326. return fOk;
  327. }
  328. BOOL
  329. GenerateTrap(
  330. PSNMP_PDU pPdu
  331. )
  332. /*
  333. Routine Description:
  334. Generates trap for agent.
  335. Arguments:
  336. pPdu - pointer to initialized TRAP or TRAPv1 PDU.
  337. Return Values:
  338. Returns true if successful.
  339. */
  340. {
  341. BOOL fOk = TRUE;
  342. PLIST_ENTRY pLE1;
  343. PLIST_ENTRY pLE2;
  344. PLIST_ENTRY pLE3;
  345. PNETWORK_LIST_ENTRY pNLE;
  346. PMANAGER_LIST_ENTRY pMLE;
  347. PTRAP_DESTINATION_LIST_ENTRY pTLE;
  348. AsnOctetString CommunityOctets;
  349. DWORD dwStatus;
  350. DWORD dwIPAddr;
  351. EnterCriticalSection(&g_RegCriticalSectionC);
  352. // obtain first trap destination
  353. pLE1 = g_TrapDestinations.Flink;
  354. // process each trap destination
  355. while (pLE1 != &g_TrapDestinations) {
  356. // retrieve pointer to outgoing transport structure
  357. pTLE = CONTAINING_RECORD(pLE1, TRAP_DESTINATION_LIST_ENTRY, Link);
  358. // copy community string into octet structure
  359. CommunityOctets.length = strlen(pTLE->pCommunity);
  360. CommunityOctets.stream = pTLE->pCommunity;
  361. CommunityOctets.dynamic = FALSE;
  362. // obtain first manager
  363. pLE2 = pTLE->Managers.Flink;
  364. // process each receiving manager
  365. while (pLE2 != &pTLE->Managers) {
  366. // retrieve pointer to next manager
  367. pMLE = CONTAINING_RECORD(pLE2, MANAGER_LIST_ENTRY, Link);
  368. // refresh addr
  369. UpdateMLE(pMLE);
  370. // don't send traps to addresses that are DEAD or NULL
  371. if (pMLE->dwAge == MGRADDR_DEAD ||
  372. !IsValidSockAddr(&pMLE->SockAddr))
  373. {
  374. pLE2 = pLE2->Flink;
  375. continue;
  376. }
  377. // obtain first outgoing transport
  378. pLE3 = g_OutgoingTransports.Flink;
  379. // process each outgoing transport
  380. while (pLE3 != &g_OutgoingTransports) {
  381. // retrieve pointer to outgoing transport structure
  382. pNLE = CONTAINING_RECORD(pLE3, NETWORK_LIST_ENTRY, Link);
  383. // initialize buffer length
  384. pNLE->Buffer.len = NLEBUFLEN;
  385. // can only send on same protocol
  386. if (pNLE->SockAddr.sa_family != pMLE->SockAddr.sa_family)
  387. {
  388. pLE3 = pLE3->Flink;
  389. continue;
  390. }
  391. // modify agent address
  392. if (pNLE->SockAddr.sa_family == AF_INET)
  393. {
  394. struct sockaddr_in * pSockAddrIn;
  395. DWORD szSockToBind;
  396. // see if the trap destination address is valid and if the
  397. // card to use for sending the trap could be determined
  398. if (WSAIoctl(pNLE->Socket,
  399. SIO_ROUTING_INTERFACE_QUERY,
  400. &pMLE->SockAddr,
  401. sizeof(pMLE->SockAddr),
  402. &pNLE->SockAddr,
  403. sizeof(pNLE->SockAddr),
  404. &szSockToBind,
  405. NULL,
  406. NULL) == SOCKET_ERROR)
  407. {
  408. SNMPDBG((
  409. SNMP_LOG_ERROR,
  410. "SNMP: SVC: cannot determine interface to use for trap destination %s [err=%d].\n",
  411. inet_ntoa(((struct sockaddr_in *)&pMLE->SockAddr)->sin_addr),
  412. WSAGetLastError()
  413. ));
  414. // if we can't determine on what interface the trap will be sent from, just bail.
  415. pLE3 = pLE3->Flink;
  416. continue;
  417. }
  418. // obtain pointer to protocol specific structure
  419. pSockAddrIn = (struct sockaddr_in * )&pNLE->SockAddr;
  420. // copy agent address into temp buffer
  421. dwIPAddr = pSockAddrIn->sin_addr.s_addr;
  422. // initialize agent address structure
  423. pPdu->Pdu.TrapPdu.AgentAddr.dynamic = FALSE;
  424. pPdu->Pdu.TrapPdu.AgentAddr.stream = (LPBYTE)&dwIPAddr;
  425. pPdu->Pdu.TrapPdu.AgentAddr.length = sizeof(dwIPAddr);
  426. } else {
  427. // re-initialize agent address structure
  428. pPdu->Pdu.TrapPdu.AgentAddr.dynamic = FALSE;
  429. pPdu->Pdu.TrapPdu.AgentAddr.stream = NULL;
  430. pPdu->Pdu.TrapPdu.AgentAddr.length = 0;
  431. }
  432. // build message
  433. if (BuildMessage(
  434. SNMP_VERSION_1,
  435. &CommunityOctets,
  436. pPdu,
  437. pNLE->Buffer.buf,
  438. &pNLE->Buffer.len
  439. )) {
  440. // synchronous send
  441. dwStatus = WSASendTo(
  442. pNLE->Socket,
  443. &pNLE->Buffer,
  444. 1,
  445. &pNLE->dwBytesTransferred,
  446. pNLE->dwFlags,
  447. &pMLE->SockAddr,
  448. pMLE->SockAddrLen,
  449. NULL,
  450. NULL
  451. );
  452. // register outgoing packet into the management structure
  453. mgmtCTick(CsnmpOutPkts);
  454. // retister outgoing trap into the management structure
  455. mgmtCTick(CsnmpOutTraps);
  456. // validate return code
  457. if (dwStatus == SOCKET_ERROR) {
  458. SNMPDBG((
  459. SNMP_LOG_ERROR,
  460. "SNMP: SVC: error code %d on sending trap to %s.\n",
  461. WSAGetLastError(),
  462. pTLE->pCommunity
  463. ));
  464. }
  465. }
  466. // next entry
  467. pLE3 = pLE3->Flink;
  468. }
  469. // next entry
  470. pLE2 = pLE2->Flink;
  471. }
  472. // next entry
  473. pLE1 = pLE1->Flink;
  474. }
  475. LeaveCriticalSection(&g_RegCriticalSectionC);
  476. return fOk;
  477. }
  478. BOOL
  479. GenerateColdStartTrap(
  480. )
  481. /*
  482. Routine Description:
  483. Generates cold start trap.
  484. Arguments:
  485. None.
  486. Return Values:
  487. Returns true if successful.
  488. */
  489. {
  490. // generate cold start
  491. return GenerateExtensionTrap(
  492. NULL, // pEnterpriseOid
  493. SNMP_GENERICTRAP_COLDSTART,
  494. 0, // nSpecificTrapId
  495. 0, // nTimeStamp
  496. &g_NullVbl
  497. );
  498. }
  499. BOOL
  500. GenerateAuthenticationTrap(
  501. )
  502. /*
  503. Routine Description:
  504. Generates authentication trap.
  505. Arguments:
  506. None.
  507. Return Values:
  508. Returns true if successful.
  509. */
  510. {
  511. // generate cold start
  512. return GenerateExtensionTrap(
  513. NULL, // pEnterpriseOid
  514. SNMP_GENERICTRAP_AUTHFAILURE,
  515. 0, // nSpecificTrapId
  516. SnmpSvcGetUptime(),
  517. &g_NullVbl
  518. );
  519. }