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.

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