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.

4921 lines
167 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. consumer.c
  5. Abstract:
  6. Data Consumer apis
  7. Author:
  8. AlanWar
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "wmikmp.h"
  14. #include <evntrace.h>
  15. #include <ntcsrmsg.h>
  16. #define NTOSKRNL_WMI
  17. #include <basemsg.h>
  18. #define STRSAFE_NO_DEPRECATE
  19. #include <strsafe.h>
  20. void WmipCompleteGuidIrpWithError(
  21. PWMIGUIDOBJECT GuidObject
  22. );
  23. NTSTATUS WmipCreatePumpThread(
  24. PWMIGUIDOBJECT Object
  25. );
  26. void WmipClearThreadObjectList(
  27. PWMIGUIDOBJECT MainObject
  28. );
  29. void
  30. WmipGetGuidPropertiesFromGuidEntry(
  31. PWMIGUIDPROPERTIES GuidInfo,
  32. PGUIDENTRY GuidEntry);
  33. BOOLEAN WmipIsQuerySetGuid(
  34. PBGUIDENTRY GuidEntry
  35. );
  36. NTSTATUS WmipAddProviderIdToPIList(
  37. PBINSTANCESET **PIPtrPtr,
  38. PULONG PICountPtr,
  39. PULONG PIMaxPtr,
  40. PBINSTANCESET *StaticPIPtr,
  41. PBINSTANCESET InstanceSet
  42. );
  43. NTSTATUS WmipPrepareForWnodeAD(
  44. IN PWMIGUIDOBJECT GuidObject,
  45. OUT LPGUID Guid,
  46. IN OUT ULONG *ProviderIdCount,
  47. OUT PBINSTANCESET **ProviderIdList,
  48. OUT BOOLEAN *InternalGuid
  49. );
  50. ULONG WmipStaticInstanceNameSize(
  51. PBINSTANCESET InstanceSet
  52. );
  53. void WmipInsertStaticNames(
  54. PWNODE_ALL_DATA Wnode,
  55. ULONG MaxWnodeSize,
  56. PBINSTANCESET InstanceSet
  57. );
  58. NTSTATUS WmipQueryGuidInfo(
  59. IN OUT PWMIQUERYGUIDINFO QueryGuidInfo
  60. );
  61. void WmipCopyFromEventQueues(
  62. IN POBJECT_EVENT_INFO ObjectArray,
  63. IN ULONG HandleCount,
  64. OUT PUCHAR OutBuffer,
  65. OUT ULONG *OutBufferSizeUsed,
  66. OUT PWNODE_HEADER *LastWnode,
  67. IN BOOLEAN IsHiPriority
  68. );
  69. void WmipClearIrpObjectList(
  70. PIRP Irp
  71. );
  72. NTSTATUS WmipReceiveNotifications(
  73. PWMIRECEIVENOTIFICATION ReceiveNotification,
  74. PULONG OutBufferSize,
  75. PIRP Irp
  76. );
  77. NTSTATUS WmipQueueNotification(
  78. PWMIGUIDOBJECT Object,
  79. PWMIEVENTQUEUE EventQueue,
  80. PWNODE_HEADER Wnode
  81. );
  82. PWNODE_HEADER WmipDereferenceEvent(
  83. PWNODE_HEADER Wnode
  84. );
  85. PWNODE_HEADER WmipIncludeStaticNames(
  86. PWNODE_HEADER Wnode
  87. );
  88. NTSTATUS WmipWriteWnodeToObject(
  89. PWMIGUIDOBJECT Object,
  90. PWNODE_HEADER Wnode,
  91. BOOLEAN IsHighPriority
  92. );
  93. NTSTATUS WmipProcessEvent(
  94. PWNODE_HEADER InWnode,
  95. BOOLEAN IsHighPriority,
  96. BOOLEAN FreeBuffer
  97. );
  98. NTSTATUS WmipRegisterUMGuids(
  99. IN POBJECT_ATTRIBUTES ObjectAttributes,
  100. IN ULONG Cookie,
  101. IN PWMIREGINFO RegInfo,
  102. IN ULONG RegInfoSize,
  103. OUT HANDLE *RequestHandle,
  104. OUT ULONG64 *LoggerContext
  105. );
  106. NTSTATUS WmipUnregisterGuids(
  107. PWMIUNREGGUIDS UnregGuids
  108. );
  109. NTSTATUS WmipWriteMBToObject(
  110. IN PWMIGUIDOBJECT RequestObject,
  111. IN PWMIGUIDOBJECT ReplyObject,
  112. IN PUCHAR Message,
  113. IN ULONG MessageSize
  114. );
  115. NTSTATUS WmipWriteMessageToGuid(
  116. IN PBGUIDENTRY GuidEntry,
  117. IN PWMIGUIDOBJECT ReplyObject,
  118. IN PUCHAR Message,
  119. IN ULONG MessageSize,
  120. OUT PULONG WrittenCount
  121. );
  122. NTSTATUS WmipCreateUMLogger(
  123. IN OUT PWMICREATEUMLOGGER CreateInfo
  124. );
  125. NTSTATUS WmipMBReply(
  126. IN HANDLE RequestHandle,
  127. IN ULONG ReplyIndex,
  128. IN PUCHAR Message,
  129. IN ULONG MessageSize
  130. );
  131. NTSTATUS WmipPrepareWnodeSI(
  132. IN PWMIGUIDOBJECT GuidObject,
  133. IN OUT PWNODE_SINGLE_INSTANCE WnodeSI,
  134. IN OUT ULONG *ProviderIdCount,
  135. OUT PBINSTANCESET **ProviderIdList,
  136. OUT BOOLEAN *IsDynamic,
  137. OUT BOOLEAN *InternalGuid
  138. );
  139. void WmipCreatePumpThreadRoutine(
  140. PVOID Context
  141. );
  142. #ifdef ALLOC_PRAGMA
  143. #pragma alloc_text(PAGE,WmipIsQuerySetGuid)
  144. #pragma alloc_text(PAGE,WmipOpenBlock)
  145. #pragma alloc_text(PAGE,WmipAddProviderIdToPIList)
  146. #pragma alloc_text(PAGE,WmipPrepareForWnodeAD)
  147. #pragma alloc_text(PAGE,WmipStaticInstanceNameSize)
  148. #pragma alloc_text(PAGE,WmipInsertStaticNames)
  149. #pragma alloc_text(PAGE,WmipQueryAllData)
  150. #pragma alloc_text(PAGE,WmipQueryAllDataMultiple)
  151. #pragma alloc_text(PAGE,WmipPrepareWnodeSI)
  152. #pragma alloc_text(PAGE,WmipQuerySetExecuteSI)
  153. #pragma alloc_text(PAGE,WmipQuerySingleMultiple)
  154. #pragma alloc_text(PAGE,WmipEnumerateGuids)
  155. #pragma alloc_text(PAGE,WmipQueryGuidInfo)
  156. #pragma alloc_text(PAGE,WmipClearIrpObjectList)
  157. #pragma alloc_text(PAGE,WmipReceiveNotifications)
  158. #pragma alloc_text(PAGE,WmipQueueNotification)
  159. #pragma alloc_text(PAGE,WmipDereferenceEvent)
  160. #pragma alloc_text(PAGE,WmipIncludeStaticNames)
  161. #pragma alloc_text(PAGE,WmipWriteWnodeToObject)
  162. #pragma alloc_text(PAGE,WmipProcessEvent)
  163. #pragma alloc_text(PAGE,WmipUMProviderCallback)
  164. #pragma alloc_text(PAGE,WmipRegisterUMGuids)
  165. #pragma alloc_text(PAGE,WmipUnregisterGuids)
  166. #pragma alloc_text(PAGE,WmipWriteMBToObject)
  167. #pragma alloc_text(PAGE,WmipWriteMessageToGuid)
  168. #pragma alloc_text(PAGE,WmipCreateUMLogger)
  169. #pragma alloc_text(PAGE,WmipMBReply)
  170. #pragma alloc_text(PAGE,WmipGetGuidPropertiesFromGuidEntry)
  171. #pragma alloc_text(PAGE,WmipClearThreadObjectList)
  172. #pragma alloc_text(PAGE,WmipClearObjectFromThreadList)
  173. #pragma alloc_text(PAGE,WmipCreatePumpThread)
  174. #pragma alloc_text(PAGE,WmipCopyFromEventQueues)
  175. #pragma alloc_text(PAGE,WmipCreatePumpThreadRoutine)
  176. #pragma alloc_text(PAGE,WmipMarkHandleAsClosed)
  177. #pragma alloc_text(PAGE,WmipCompleteGuidIrpWithError)
  178. #endif
  179. BOOLEAN WmipIsQuerySetGuid(
  180. PBGUIDENTRY GuidEntry
  181. )
  182. {
  183. PLIST_ENTRY InstanceSetList;
  184. PBINSTANCESET InstanceSet;
  185. PAGED_CODE();
  186. WmipAssert(GuidEntry != NULL);
  187. WmipEnterSMCritSection();
  188. InstanceSetList = GuidEntry->ISHead.Flink;
  189. while (InstanceSetList != &GuidEntry->ISHead)
  190. {
  191. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  192. INSTANCESET,
  193. GuidISList);
  194. if ( (InstanceSet->Flags &
  195. (IS_TRACED | IS_CONTROL_GUID | IS_EVENT_ONLY)) == 0 )
  196. {
  197. //
  198. // If there is at least one IS that isn't traced and isn't
  199. // an event only then it is a queryset guid
  200. //
  201. WmipLeaveSMCritSection();
  202. return (TRUE);
  203. }
  204. InstanceSetList = InstanceSetList->Flink;
  205. }
  206. WmipLeaveSMCritSection();
  207. return (FALSE);
  208. }
  209. NTSTATUS WmipOpenBlock(
  210. IN ULONG Ioctl,
  211. IN KPROCESSOR_MODE AccessMode,
  212. IN POBJECT_ATTRIBUTES CapturedObjectAttributes,
  213. IN ULONG DesiredAccess,
  214. OUT PHANDLE Handle
  215. )
  216. {
  217. PBGUIDENTRY GuidEntry;
  218. PWMIGUIDOBJECT Object;
  219. NTSTATUS Status;
  220. PAGED_CODE();
  221. //
  222. // Creates a guid handle with the desired access
  223. //
  224. Status = WmipOpenGuidObject(CapturedObjectAttributes,
  225. DesiredAccess,
  226. AccessMode,
  227. Handle,
  228. &Object);
  229. if (NT_SUCCESS(Status))
  230. {
  231. Object->Type = Ioctl;
  232. if (Ioctl != IOCTL_WMI_OPEN_GUID)
  233. {
  234. GuidEntry = WmipFindGEByGuid(&Object->Guid, FALSE);
  235. //
  236. // Establish our object on the guidentry list
  237. //
  238. WmipEnterSMCritSection();
  239. if (GuidEntry != NULL)
  240. {
  241. InsertTailList(&GuidEntry->ObjectHead,
  242. &Object->GEObjectList);
  243. }
  244. Object->GuidEntry = GuidEntry;
  245. WmipLeaveSMCritSection();
  246. switch (Ioctl)
  247. {
  248. case IOCTL_WMI_OPEN_GUID_FOR_QUERYSET:
  249. {
  250. //
  251. // Guid is being opened for query/set/method operations so
  252. // we need to insure that there is a guid entry and that
  253. // the guid entry has InstanceSets attached and it is
  254. // has at least one instance set that is not a traced
  255. // guid and is not an event only guid
  256. //
  257. if ((GuidEntry == NULL) ||
  258. (GuidEntry->ISCount == 0) ||
  259. (! WmipIsQuerySetGuid(GuidEntry)))
  260. {
  261. //
  262. // Either we could not find a guidentry or there
  263. // is no instance sets attached. We close the
  264. // original handle and fail the IOCTL
  265. //
  266. ZwClose(*Handle);
  267. Status = STATUS_WMI_GUID_NOT_FOUND;
  268. break;
  269. }
  270. //
  271. // Fall through
  272. //
  273. }
  274. case IOCTL_WMI_OPEN_GUID_FOR_EVENTS:
  275. {
  276. //
  277. // Since we can register to receive events before
  278. // the event provider has been registered we'll need
  279. // to create the guid entry if one does not exist
  280. //
  281. if (AccessMode == KernelMode)
  282. {
  283. Object->Flags |= WMIGUID_FLAG_KERNEL_NOTIFICATION;
  284. }
  285. if (GuidEntry == NULL)
  286. {
  287. WmipAssert(Ioctl == IOCTL_WMI_OPEN_GUID_FOR_EVENTS);
  288. WmipEnterSMCritSection();
  289. GuidEntry = WmipAllocGuidEntry();
  290. if (GuidEntry != NULL)
  291. {
  292. //
  293. // Initialize the new GuidEntry and place it
  294. // on the master GuidEntry list.
  295. //
  296. memcpy(&GuidEntry->Guid,
  297. &Object->Guid,
  298. sizeof(GUID));
  299. InsertHeadList(WmipGEHeadPtr, &GuidEntry->MainGEList);
  300. InsertTailList(&GuidEntry->ObjectHead,
  301. &Object->GEObjectList);
  302. Object->GuidEntry = GuidEntry;
  303. WmipLeaveSMCritSection();
  304. } else {
  305. WmipLeaveSMCritSection();
  306. ZwClose(*Handle);
  307. Status = STATUS_INSUFFICIENT_RESOURCES;
  308. break;
  309. }
  310. }
  311. //
  312. // Now we need to see if we have to enable collection
  313. // or events
  314. //
  315. Status = WmipEnableCollectOrEvent(GuidEntry,
  316. Ioctl,
  317. &Object->EnableRequestSent,
  318. 0);
  319. if (! NT_SUCCESS(Status))
  320. {
  321. //
  322. // For some reason enabling failed so just return
  323. // the error
  324. //
  325. ZwClose(*Handle);
  326. }
  327. //
  328. // Don't unref the guid entry as that ref count is
  329. // taken by the object just placed on the list
  330. //
  331. break;
  332. }
  333. default:
  334. {
  335. //
  336. // We should never get here.....
  337. //
  338. WmipAssert(FALSE);
  339. ZwClose(*Handle);
  340. Status = STATUS_ILLEGAL_FUNCTION;
  341. break;
  342. }
  343. }
  344. } else {
  345. //
  346. // Mark this as a security object
  347. //
  348. Object->Flags |= WMIGUID_FLAG_SECURITY_OBJECT;
  349. }
  350. //
  351. // remove the ref taken when the object was created
  352. //
  353. ObDereferenceObject(Object);
  354. }
  355. return(Status);
  356. }
  357. NTSTATUS WmipAddProviderIdToPIList(
  358. PBINSTANCESET **PIPtrPtr,
  359. PULONG PICountPtr,
  360. PULONG PIMaxPtr,
  361. PBINSTANCESET *StaticPIPtr,
  362. PBINSTANCESET InstanceSet
  363. )
  364. {
  365. ULONG PICount;
  366. ULONG PIMax, NewPIMax;
  367. PBINSTANCESET *PIPtr, *OldPIPtr, *NewPIPtr;
  368. NTSTATUS Status;
  369. ULONG i;
  370. PAGED_CODE();
  371. Status = STATUS_SUCCESS;
  372. PICount = *PICountPtr;
  373. PIMax = *PIMaxPtr;
  374. PIPtr = *PIPtrPtr;
  375. //
  376. // Remember dynamic providerid
  377. //
  378. if (PICount == PIMax)
  379. {
  380. //
  381. // We have overflowed the PI List so we need to
  382. // reallocate a bigger buffer
  383. //
  384. NewPIMax = PIMax * 2;
  385. NewPIPtr = (PBINSTANCESET *)WmipAlloc(NewPIMax *
  386. sizeof(PBINSTANCESET));
  387. OldPIPtr = PIPtr;
  388. if (NewPIPtr != NULL)
  389. {
  390. //
  391. // Copy provider ids from old to new buffer
  392. //
  393. memcpy(NewPIPtr, OldPIPtr, PIMax*sizeof(PBINSTANCESET));
  394. PIPtr = NewPIPtr;
  395. *PIPtrPtr = NewPIPtr;
  396. PIMax = NewPIMax;
  397. *PIMaxPtr = PIMax;
  398. } else {
  399. //
  400. // Bad break, we could not allocate more space
  401. // unref any instance sets and return an error
  402. //
  403. for (i = 0; i < PIMax; i++)
  404. {
  405. WmipUnreferenceIS(PIPtr[i]);
  406. }
  407. WmipUnreferenceIS(InstanceSet);
  408. *PIPtrPtr = NULL;
  409. Status = STATUS_INSUFFICIENT_RESOURCES;
  410. }
  411. //
  412. // if previous buffer was not static then free it
  413. //
  414. if (OldPIPtr != StaticPIPtr)
  415. {
  416. WmipFree(OldPIPtr);
  417. }
  418. }
  419. if (NT_SUCCESS(Status))
  420. {
  421. //
  422. // Remember instance set
  423. //
  424. PIPtr[PICount++] = InstanceSet;
  425. *PICountPtr = PICount;
  426. }
  427. return(Status);
  428. }
  429. NTSTATUS WmipPrepareForWnodeAD(
  430. IN PWMIGUIDOBJECT GuidObject,
  431. OUT LPGUID Guid,
  432. IN OUT ULONG *ProviderIdCount,
  433. OUT PBINSTANCESET **ProviderIdList,
  434. OUT BOOLEAN *InternalGuid
  435. )
  436. {
  437. PBINSTANCESET *PIPtr, *StaticPIPtr;
  438. ULONG PICount, PIMax;
  439. NTSTATUS Status;
  440. PBGUIDENTRY GuidEntry;
  441. PBINSTANCESET InstanceSet;
  442. PLIST_ENTRY InstanceSetList;
  443. PAGED_CODE();
  444. GuidEntry = GuidObject->GuidEntry;
  445. if ((GuidEntry != NULL) && (GuidEntry->ISCount > 0))
  446. {
  447. //
  448. // We were passed a valid guid handle, get out the guid
  449. //
  450. *Guid = GuidEntry->Guid;
  451. Status = STATUS_SUCCESS;
  452. if (GuidEntry->Flags & GE_FLAG_INTERNAL)
  453. {
  454. *InternalGuid = TRUE;
  455. } else {
  456. //
  457. // Build list of provider ids to whom the QAD will be targetted
  458. //
  459. *InternalGuid = FALSE;
  460. StaticPIPtr = *ProviderIdList;
  461. PIPtr = StaticPIPtr;
  462. PIMax = *ProviderIdCount;
  463. PICount = 0;
  464. WmipEnterSMCritSection();
  465. InstanceSetList = GuidEntry->ISHead.Flink;
  466. while ((InstanceSetList != &GuidEntry->ISHead) &&
  467. NT_SUCCESS(Status))
  468. {
  469. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  470. INSTANCESET,
  471. GuidISList);
  472. //
  473. // Take a refcount on the instance set so that it won't
  474. // go away until after we are done with our query
  475. // The refcount gets removed by the caller when it is
  476. // done with the list or in WmipAddProviderIdTOLlist if it
  477. // returns an error
  478. //
  479. if ((InstanceSet->Flags & (IS_TRACED | IS_CONTROL_GUID | IS_EVENT_ONLY)) == 0)
  480. {
  481. //
  482. // Only take those IS that are not traced or control
  483. // guids and are not event only guids
  484. //
  485. WmipReferenceIS(InstanceSet);
  486. Status = WmipAddProviderIdToPIList(&PIPtr,
  487. &PICount,
  488. &PIMax,
  489. StaticPIPtr,
  490. InstanceSet);
  491. }
  492. InstanceSetList = InstanceSetList->Flink;
  493. }
  494. WmipLeaveSMCritSection();
  495. if (PICount == 0)
  496. {
  497. Status = STATUS_WMI_GUID_DISCONNECTED;
  498. } else {
  499. *ProviderIdCount = PICount;
  500. *ProviderIdList = PIPtr;
  501. }
  502. }
  503. } else {
  504. Status = STATUS_WMI_GUID_DISCONNECTED;
  505. }
  506. return(Status);
  507. }
  508. ULONG WmipStaticInstanceNameSize(
  509. PBINSTANCESET InstanceSet
  510. )
  511. /*+++
  512. Routine Description:
  513. This routine will calculate the size needed to place instance names in
  514. a WNODE_ALL_DATA
  515. Arguments:
  516. WmiInstanceInfo describes to instance set whose instance name size
  517. is to be calculated
  518. Return Value:
  519. Size needed to place instance names in a WNODE_ALL_DATA plus 3. The
  520. extra 3 bytes are added in case the OffsetInstanceNameOffsets need to be
  521. padded since they must be on a 4 byte boundary.
  522. ---*/
  523. {
  524. SIZE_T NameSize;
  525. ULONG i;
  526. PAGED_CODE();
  527. //
  528. // If we already computed this then just return the results
  529. if (InstanceSet->WADInstanceNameSize != 0)
  530. {
  531. return(InstanceSet->WADInstanceNameSize);
  532. }
  533. //
  534. // Start with a name size of 3 in case the OffsetInstanceNameOffset will
  535. // need to be padded so that it starts on a 4 byte boundary.
  536. NameSize = 3;
  537. if (InstanceSet->Flags & IS_INSTANCE_BASENAME)
  538. {
  539. //
  540. // For static base names we assume that there will never be more than
  541. // MAXBASENAMESUFFIXVALUE instances of a guid. So the size of each instance name
  542. // would be the size of the base name plus the size of the suffix
  543. // plus a USHORT for the count (for counted string) plus a ULONG
  544. // to hold the offset to the instance name
  545. //
  546. WmipAssert((InstanceSet->IsBaseName->BaseIndex + InstanceSet->Count) < MAXBASENAMESUFFIXVALUE);
  547. NameSize += ((wcslen(InstanceSet->IsBaseName->BaseName) * sizeof(WCHAR)) +
  548. MAXBASENAMESUFFIXSIZE * sizeof(WCHAR) +
  549. sizeof(USHORT) +
  550. sizeof(ULONG)) * InstanceSet->Count;
  551. } else if (InstanceSet->Flags & IS_INSTANCE_STATICNAMES)
  552. {
  553. //
  554. // For a static name list we count up each size of
  555. // the static instance names in the list and add a ULONG and a USHORT
  556. // for the offset and count (for counted string)
  557. for (i = 0; i < InstanceSet->Count; i++)
  558. {
  559. NameSize += (wcslen(InstanceSet->IsStaticNames->StaticNamePtr[i]) + 2) * sizeof(WCHAR) + sizeof(ULONG);
  560. }
  561. }
  562. InstanceSet->WADInstanceNameSize = (ULONG)NameSize;
  563. return(ULONG)(NameSize);
  564. }
  565. void WmipInsertStaticNames(
  566. PWNODE_ALL_DATA Wnode,
  567. ULONG MaxWnodeSize,
  568. PBINSTANCESET InstanceSet
  569. )
  570. /*+++
  571. Routine Description:
  572. This routine will copy into the WNODE_ALL_DATA instance names for a
  573. static instance name set. If the Wnode_All_data is too small then it
  574. is converted to a WNODE_TOO_SMALL
  575. Arguments:
  576. Wnode points at the WNODE_ALL_DATA
  577. MaxWnodeSize is the maximum size of the Wnode
  578. WmiInstanceInfo is the Instance Info
  579. Return Value:
  580. ---*/
  581. {
  582. PWCHAR NamePtr;
  583. PULONG NameOffsetPtr;
  584. ULONG InstanceCount;
  585. ULONG i;
  586. WCHAR Index[MAXBASENAMESUFFIXSIZE+1];
  587. PWCHAR StaticName;
  588. ULONG SizeNeeded;
  589. SIZE_T NameLen;
  590. USHORT Len;
  591. ULONG PaddedBufferSize;
  592. size_t Size;
  593. HRESULT hr;
  594. PAGED_CODE();
  595. if ((InstanceSet->Flags &
  596. (IS_INSTANCE_BASENAME | IS_INSTANCE_STATICNAMES)) == 0)
  597. {
  598. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_ERROR_LEVEL,"WMI: Try to setup static names for dynamic guid\n"));
  599. return;
  600. }
  601. InstanceCount = InstanceSet->Count;
  602. //
  603. // Pad out the size of the incoming wnode to a 4 byte boundary since the
  604. // OffsetInstanceNameOffsets is being appended to the end of the
  605. // wnode and it must be on a 4 byte boundary
  606. //
  607. PaddedBufferSize = (Wnode->WnodeHeader.BufferSize + 3) & ~3;
  608. //
  609. // Compute the complete size needed to rewrite the WNODE to include
  610. // the instance names.
  611. //
  612. // Include the size that is needed to fill out
  613. Size = WmipStaticInstanceNameSize(InstanceSet);
  614. // Include the space needed for the array of offsets to the
  615. // instance names plus the size of the names plus the padded
  616. // size of the wnode
  617. SizeNeeded = (InstanceCount * sizeof(ULONG)) +
  618. (ULONG)Size +
  619. PaddedBufferSize;
  620. if (SizeNeeded > MaxWnodeSize)
  621. {
  622. //
  623. // If not enough space left in the buffer passed then build a
  624. // WNODE_TOO_SMALL as the result to indicate how much buffer
  625. // space is needed.
  626. //
  627. Wnode->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  628. Wnode->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  629. ((PWNODE_TOO_SMALL)Wnode)->SizeNeeded = SizeNeeded;
  630. return;
  631. }
  632. //
  633. // Allocate space for the array of offsets to instance names
  634. //
  635. NameOffsetPtr = (PULONG)((PUCHAR)Wnode + PaddedBufferSize);
  636. Wnode->OffsetInstanceNameOffsets = (ULONG)((PUCHAR)NameOffsetPtr - (PUCHAR)Wnode);
  637. //
  638. // Point at the beginning of the area to write the instance names
  639. //
  640. NamePtr = (PWCHAR)(NameOffsetPtr + InstanceCount);
  641. if (InstanceSet->Flags & IS_INSTANCE_BASENAME)
  642. {
  643. //
  644. // The instance name is based upon a basename with a trailing
  645. // index number to provide uniqueness
  646. //
  647. if (InstanceSet->Flags & IS_PDO_INSTANCENAME)
  648. {
  649. Wnode->WnodeHeader.Flags |= WNODE_FLAG_PDO_INSTANCE_NAMES;
  650. }
  651. for (i = 0; i < InstanceCount; i++)
  652. {
  653. //
  654. // Account for space used by length of string that follows
  655. //
  656. Size -= sizeof(USHORT);
  657. *NameOffsetPtr++ = (ULONG)((PUCHAR)NamePtr - (PUCHAR)Wnode);
  658. //
  659. // Copy over basename while accounting length used by it
  660. //
  661. hr = StringCbCopy(NamePtr+1,
  662. Size,
  663. InstanceSet->IsBaseName->BaseName);
  664. WmipAssert(hr == S_OK);
  665. //
  666. // Format unique index number
  667. //
  668. hr = StringCbPrintf(Index,
  669. sizeof(Index),
  670. BASENAMEFORMATSTRING,
  671. InstanceSet->IsBaseName->BaseIndex+i);
  672. WmipAssert(hr == S_OK);
  673. //
  674. // Append unique index number to instance name
  675. //
  676. hr = StringCbCat(NamePtr+1,
  677. Size,
  678. Index);
  679. WmipAssert(hr == S_OK);
  680. NameLen = wcslen(NamePtr+1) + 1;
  681. *NamePtr = (USHORT)NameLen * sizeof(WCHAR);
  682. NamePtr += NameLen + 1;
  683. Size -= NameLen * sizeof(WCHAR);
  684. }
  685. } else if (InstanceSet->Flags & IS_INSTANCE_STATICNAMES) {
  686. //
  687. // Instance names are from a list of static names
  688. //
  689. for (i = 0; i < InstanceCount; i++)
  690. {
  691. *NameOffsetPtr++ = (ULONG)((PUCHAR)NamePtr - (PUCHAR)Wnode);
  692. StaticName = InstanceSet->IsStaticNames->StaticNamePtr[i];
  693. Len = (USHORT)((wcslen(StaticName)+1) * sizeof(WCHAR));
  694. *NamePtr++ = Len;
  695. //
  696. // Account for space used by length of string that follows
  697. //
  698. Size -= sizeof(USHORT);
  699. //
  700. // Copy over and account for static name
  701. //
  702. hr = StringCbCopyEx(NamePtr,
  703. Size,
  704. StaticName,
  705. NULL,
  706. &Size,
  707. 0);
  708. WmipAssert(hr == S_OK);
  709. NamePtr += Len / sizeof(WCHAR);
  710. }
  711. }
  712. Wnode->WnodeHeader.BufferSize = SizeNeeded;
  713. }
  714. //
  715. // This defines how many provider ids will fit within the static block. If
  716. // we need more than this, then we'll have to allocate memory for it
  717. //
  718. #if DBG
  719. #define MANYPROVIDERIDS 1
  720. #else
  721. #define MANYPROVIDERIDS 16
  722. #endif
  723. NTSTATUS WmipQueryAllData(
  724. IN PWMIGUIDOBJECT GuidObject,
  725. IN PIRP Irp,
  726. IN KPROCESSOR_MODE AccessMode,
  727. IN PWNODE_ALL_DATA Wnode,
  728. IN ULONG OutBufferLen,
  729. OUT PULONG RetSize
  730. )
  731. {
  732. NTSTATUS Status;
  733. PBINSTANCESET StaticPIList[MANYPROVIDERIDS];
  734. PBINSTANCESET *PIList;
  735. PBINSTANCESET InstanceSet;
  736. WNODE_ALL_DATA WnodeAllData;
  737. BOOLEAN IsBufferTooSmall;
  738. PWNODE_HEADER WnodeHeader;
  739. LOGICAL UsesStaticNames;
  740. PWNODE_TOO_SMALL WnodeTooSmall = (PWNODE_TOO_SMALL)&WnodeAllData;
  741. PWNODE_ALL_DATA WnodeAD;
  742. ULONG BufferLeft;
  743. ULONG SizeNeeded;
  744. ULONG PICount;
  745. ULONG WnodeFlags, WnodeSize;
  746. PWNODE_HEADER WnodeLast;
  747. ULONG Linkage;
  748. ULONG i;
  749. GUID Guid;
  750. PUCHAR Buffer;
  751. ULONG BufferUsed;
  752. HANDLE KernelHandle;
  753. BOOLEAN InternalGuid;
  754. IO_STATUS_BLOCK Iosb;
  755. PAGED_CODE();
  756. //
  757. // Check Security
  758. //
  759. if (GuidObject != NULL)
  760. {
  761. Status = ObReferenceObjectByPointer(GuidObject,
  762. WMIGUID_QUERY,
  763. WmipGuidObjectType,
  764. AccessMode);
  765. } else {
  766. KernelHandle = Wnode->WnodeHeader.KernelHandle;
  767. Status = ObReferenceObjectByHandle(KernelHandle,
  768. WMIGUID_QUERY,
  769. WmipGuidObjectType,
  770. AccessMode,
  771. &GuidObject,
  772. NULL);
  773. }
  774. if (NT_SUCCESS(Status))
  775. {
  776. //
  777. // Get the provider id list for the guid
  778. //
  779. PIList = StaticPIList;
  780. PICount = MANYPROVIDERIDS;
  781. Status = WmipPrepareForWnodeAD(GuidObject,
  782. &Guid,
  783. &PICount,
  784. &PIList,
  785. &InternalGuid);
  786. if (NT_SUCCESS(Status))
  787. {
  788. if (InternalGuid)
  789. {
  790. //
  791. // This is an internal guid so we fill out the WNODE_ALL_DATA
  792. // and mark it to be completed by the user mode code
  793. //
  794. Wnode->WnodeHeader.Guid = Guid;
  795. Wnode->WnodeHeader.Flags |= WNODE_FLAG_INTERNAL;
  796. Wnode->WnodeHeader.Linkage = 0;
  797. *RetSize = sizeof(WNODE_HEADER);
  798. Status = STATUS_SUCCESS;
  799. } else {
  800. //
  801. // Get all of the information from the WNODE_HEADER so we can
  802. // rebuild it
  803. //
  804. WnodeFlags = Wnode->WnodeHeader.Flags;
  805. WnodeSize = Wnode->WnodeHeader.BufferSize;
  806. //
  807. // Loop over all provider ids and send each a WAD query
  808. //
  809. Buffer = (PUCHAR)Wnode;
  810. BufferLeft = OutBufferLen;
  811. IsBufferTooSmall = FALSE;
  812. SizeNeeded = 0;
  813. WnodeLast = NULL;
  814. for (i = 0; i < PICount; i++)
  815. {
  816. InstanceSet = PIList[i];
  817. if ((IsBufferTooSmall) || (BufferLeft < sizeof(WNODE_ALL_DATA)))
  818. {
  819. //
  820. // If we have already determined that the buffer is
  821. // too small then we use the static WNODE_ALL_DATA
  822. // just to get the size needed
  823. //
  824. WnodeAD = &WnodeAllData;
  825. BufferLeft = sizeof(WNODE_ALL_DATA);
  826. IsBufferTooSmall = TRUE;
  827. } else {
  828. //
  829. // Otherwise we will append to the end of the buffer
  830. //
  831. WnodeAD = (PWNODE_ALL_DATA)Buffer;
  832. }
  833. //
  834. // Build the WNODE and send it off to the driver
  835. //
  836. WnodeHeader = (PWNODE_HEADER)WnodeAD;
  837. WnodeHeader->BufferSize = sizeof(WNODE_HEADER);
  838. UsesStaticNames =((InstanceSet->Flags & IS_INSTANCE_BASENAME) ||
  839. (InstanceSet->Flags & IS_INSTANCE_STATICNAMES));
  840. WnodeHeader->Flags = WnodeFlags | (UsesStaticNames ?
  841. WNODE_FLAG_STATIC_INSTANCE_NAMES :
  842. 0);
  843. WnodeHeader->Guid = Guid;
  844. WnodeHeader->ProviderId = PIList[i]->ProviderId;
  845. WnodeHeader->Linkage = 0;
  846. if (Irp != NULL)
  847. {
  848. Status = WmipForwardWmiIrp(Irp,
  849. IRP_MN_QUERY_ALL_DATA,
  850. WnodeHeader->ProviderId,
  851. &WnodeHeader->Guid,
  852. BufferLeft,
  853. WnodeAD);
  854. } else {
  855. Status = WmipSendWmiIrp(
  856. IRP_MN_QUERY_ALL_DATA,
  857. WnodeHeader->ProviderId,
  858. &WnodeHeader->Guid,
  859. BufferLeft,
  860. WnodeAD,
  861. &Iosb);
  862. }
  863. if (NT_SUCCESS(Status))
  864. {
  865. if (WnodeHeader->Flags & WNODE_FLAG_TOO_SMALL)
  866. {
  867. //
  868. // There was not enough space to write the WNODE
  869. // so we keep track of how much was needed and then
  870. // switch to the mode where we just query for size needed
  871. //
  872. WnodeTooSmall = (PWNODE_TOO_SMALL)WnodeAD;
  873. SizeNeeded += WnodeTooSmall->SizeNeeded;
  874. if (UsesStaticNames)
  875. {
  876. SizeNeeded = (SizeNeeded + 3) &~3;
  877. SizeNeeded += WmipStaticInstanceNameSize(InstanceSet)+
  878. (InstanceSet->Count *sizeof(ULONG));
  879. }
  880. SizeNeeded = (SizeNeeded +7) & ~7;
  881. IsBufferTooSmall = TRUE;
  882. } else if (IsBufferTooSmall) {
  883. //
  884. // We passed a minimum sized buffer, but it is large
  885. // enough for the driver. Since we are just trying
  886. // to get the size needed we get the size he needs
  887. // and throw away his data
  888. //
  889. SizeNeeded += WnodeAD->WnodeHeader.BufferSize +
  890. WmipStaticInstanceNameSize(InstanceSet) +
  891. (InstanceSet->Count *sizeof(ULONG));
  892. SizeNeeded = (SizeNeeded +7) & ~7;
  893. } else {
  894. //
  895. // The driver returned a completed WNODE_ALL_DATA
  896. // so we need to link the previous WNODE_ALL_DATA to
  897. // this one, fill out any static instance names, and
  898. // then update the buffer pointer and size
  899. //
  900. if (WnodeLast != NULL)
  901. {
  902. Linkage = (ULONG) ((PCHAR)WnodeAD - (PCHAR)WnodeLast);
  903. WnodeLast->Linkage = Linkage;
  904. }
  905. WnodeLast = (PWNODE_HEADER)WnodeAD;
  906. if (UsesStaticNames)
  907. {
  908. //
  909. // We need to insert the static names
  910. //
  911. WmipInsertStaticNames(WnodeAD,
  912. BufferLeft,
  913. InstanceSet);
  914. if (WnodeAD->WnodeHeader.Flags & WNODE_FLAG_TOO_SMALL)
  915. {
  916. //
  917. // The static names caused us to run out of
  918. // buffer so we switch to mode where we
  919. // query for the sizes
  920. //
  921. WnodeTooSmall = (PWNODE_TOO_SMALL)WnodeAD;
  922. IsBufferTooSmall = TRUE;
  923. BufferUsed = WnodeTooSmall->SizeNeeded;
  924. } else {
  925. //
  926. // Static names fit so just pull out the updated
  927. // wnode size
  928. //
  929. BufferUsed = WnodeAD->WnodeHeader.BufferSize;
  930. }
  931. } else {
  932. //
  933. // Wnode has dynamic names so just add size returned
  934. // by driver
  935. //
  936. BufferUsed = WnodeAD->WnodeHeader.BufferSize;
  937. }
  938. //
  939. // Update size needed and advance to free space in
  940. // output buffer
  941. //
  942. BufferUsed = (BufferUsed + 7) & ~7;
  943. SizeNeeded += BufferUsed;
  944. //
  945. // Make sure that by adding in pad we don't run out of
  946. // room in buffer
  947. //
  948. if ((! IsBufferTooSmall) && (BufferLeft >= BufferUsed))
  949. {
  950. BufferLeft -= BufferUsed;
  951. Buffer += BufferUsed;
  952. } else {
  953. IsBufferTooSmall = TRUE;
  954. }
  955. }
  956. } else {
  957. //
  958. // The driver failed the request, but that is no biggie
  959. // as we just ignore it for now
  960. //
  961. }
  962. //
  963. // We are done with the instance set so remove our ref
  964. // on it so it can go away if need be
  965. //
  966. WmipUnreferenceIS(InstanceSet);
  967. }
  968. if (SizeNeeded == 0)
  969. {
  970. //
  971. // No devices responded to the WMI Query All Data so we
  972. // return an error
  973. //
  974. Status = STATUS_WMI_GUID_NOT_FOUND;
  975. } else if ((IsBufferTooSmall) &&
  976. (SizeNeeded > OutBufferLen)) {
  977. //
  978. // Our buffer passed was too small so return a WNODE_TOO_SMALL
  979. //
  980. WnodeTooSmall = (PWNODE_TOO_SMALL)Wnode;
  981. WnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  982. WnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  983. WnodeTooSmall->SizeNeeded = SizeNeeded;
  984. *RetSize = sizeof(WNODE_TOO_SMALL);
  985. Status = STATUS_SUCCESS;
  986. } else {
  987. *RetSize = SizeNeeded;
  988. Status = STATUS_SUCCESS;
  989. }
  990. //
  991. // Make sure any memory allocated for the PI list is freed
  992. //
  993. if ((PIList != StaticPIList) && (PIList != NULL))
  994. {
  995. WmipFree(PIList);
  996. }
  997. }
  998. }
  999. //
  1000. // And remove ref on guid object
  1001. //
  1002. ObDereferenceObject(GuidObject);
  1003. }
  1004. return(Status);
  1005. }
  1006. NTSTATUS WmipQueryAllDataMultiple(
  1007. IN ULONG ObjectCount,
  1008. IN PWMIGUIDOBJECT *ObjectList,
  1009. IN PIRP Irp,
  1010. IN KPROCESSOR_MODE AccessMode,
  1011. IN OUT PUCHAR BufferPtr,
  1012. IN ULONG BufferSize,
  1013. IN PWMIQADMULTIPLE QadMultiple,
  1014. OUT ULONG *ReturnSize
  1015. )
  1016. {
  1017. ULONG i;
  1018. HANDLE *Handles;
  1019. ULONG Count;
  1020. WNODE_ALL_DATA WnodeAD;
  1021. BOOLEAN BufferOverFlow;
  1022. ULONG SkipSize, RetSize, SizeNeeded;
  1023. ULONG WnodeSize;
  1024. NTSTATUS Status, Status2;
  1025. ULONG Linkage = 0;
  1026. PWNODE_TOO_SMALL WnodeTooSmall;
  1027. PWNODE_HEADER WnodePrev;
  1028. PUCHAR Buffer;
  1029. PWNODE_ALL_DATA Wnode;
  1030. PWMIGUIDOBJECT Object = NULL;
  1031. PAGED_CODE();
  1032. Status = STATUS_SUCCESS;
  1033. if (ObjectList == NULL)
  1034. {
  1035. //
  1036. // Copy the handle list out of the system buffer since it will
  1037. // be overwritten by the first query all data
  1038. //
  1039. Count = QadMultiple->HandleCount;
  1040. Handles = (HANDLE *)WmipAlloc(Count * sizeof(HANDLE));
  1041. if (Handles != NULL)
  1042. {
  1043. for (i = 0; i < Count; i++)
  1044. {
  1045. Handles[i] = QadMultiple->Handles[i].Handle;
  1046. }
  1047. } else {
  1048. return STATUS_INSUFFICIENT_RESOURCES;
  1049. }
  1050. } else {
  1051. Count = ObjectCount;
  1052. Handles = NULL;
  1053. }
  1054. SizeNeeded = 0;
  1055. Buffer = BufferPtr;
  1056. BufferOverFlow = FALSE;
  1057. WnodePrev = NULL;
  1058. Wnode = (PWNODE_ALL_DATA)Buffer;
  1059. WnodeSize = BufferSize;
  1060. for (i = 0; i < Count; i++)
  1061. {
  1062. if ((Wnode == &WnodeAD) || (WnodeSize < sizeof(WNODE_ALL_DATA)))
  1063. {
  1064. //
  1065. // If there is no more room, we are just querying for the
  1066. // size that will be needed.
  1067. //
  1068. Wnode = &WnodeAD;
  1069. WnodeSize = sizeof(WNODE_ALL_DATA);
  1070. WnodePrev = NULL;
  1071. } else {
  1072. Wnode = (PWNODE_ALL_DATA)Buffer;
  1073. WnodeSize = BufferSize;
  1074. }
  1075. //
  1076. // Build WNODE_ALL_DATA in order to do the query
  1077. //
  1078. RtlZeroMemory(Wnode, sizeof(WNODE_ALL_DATA));
  1079. Wnode->WnodeHeader.Flags = WNODE_FLAG_ALL_DATA;
  1080. Wnode->WnodeHeader.BufferSize = sizeof(WNODE_HEADER);
  1081. if (ObjectList == NULL)
  1082. {
  1083. Wnode->WnodeHeader.KernelHandle = Handles[i];
  1084. } else {
  1085. Object = ObjectList[i];
  1086. }
  1087. Status2 = WmipQueryAllData(Object,
  1088. Irp,
  1089. AccessMode,
  1090. Wnode,
  1091. WnodeSize,
  1092. &RetSize);
  1093. if (NT_SUCCESS(Status2))
  1094. {
  1095. if (Wnode->WnodeHeader.Flags & WNODE_FLAG_INTERNAL)
  1096. {
  1097. //
  1098. // Skip any internal guid quesries
  1099. //
  1100. } else if (Wnode->WnodeHeader.Flags & WNODE_FLAG_TOO_SMALL) {
  1101. //
  1102. // There is no enough room so just tally up
  1103. // the size that will be needed.
  1104. //
  1105. WnodeTooSmall = (PWNODE_TOO_SMALL)Wnode;
  1106. SizeNeeded += (WnodeTooSmall->SizeNeeded+7) & ~7;
  1107. Wnode = &WnodeAD;
  1108. BufferOverFlow = TRUE;
  1109. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_API_INFO_LEVEL,"WMI: %x Too Small %x needed, total %x\n",
  1110. ObjectList ? ObjectList[i] : Handles[i],
  1111. WnodeTooSmall->SizeNeeded, SizeNeeded));
  1112. } else if (Wnode == &WnodeAD) {
  1113. //
  1114. // Even though this succeeded, we still aren't going
  1115. // to be able to return any data so just count up
  1116. // how much size we need
  1117. //
  1118. SizeNeeded += (RetSize+7) & ~7;
  1119. BufferOverFlow = TRUE;
  1120. WmipDebugPrintEx((DPFLTR_WMICORE_ID,
  1121. DPFLTR_API_INFO_LEVEL,"WMI: %x Large Enough but full %x needed, total %x\n",
  1122. ObjectList ? ObjectList[i] : Handles[i],
  1123. RetSize, SizeNeeded));
  1124. } else {
  1125. //
  1126. // We successfully got data. Link the previous wnode
  1127. // to this one
  1128. //
  1129. if (WnodePrev != NULL)
  1130. {
  1131. WnodePrev->Linkage = Linkage;
  1132. }
  1133. WnodePrev = (PWNODE_HEADER)Wnode;
  1134. while (WnodePrev->Linkage != 0)
  1135. {
  1136. WnodePrev = (PWNODE_HEADER)OffsetToPtr(WnodePrev,
  1137. WnodePrev->Linkage);
  1138. }
  1139. SkipSize = (RetSize+7) &~7;
  1140. SizeNeeded += SkipSize;
  1141. BufferSize -= SkipSize;
  1142. Buffer += SkipSize;
  1143. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_API_INFO_LEVEL,"WMI: %x Large Enough %x needed, total %x\n",
  1144. ObjectList ? ObjectList[i] : Handles[i],
  1145. RetSize, SizeNeeded));
  1146. Linkage = (ULONG) ((PCHAR)Buffer - (PCHAR)WnodePrev);
  1147. }
  1148. } else {
  1149. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_API_INFO_LEVEL,"WMI: %x Failed %x, total %x\n",
  1150. ObjectList ? ObjectList[i] : Handles[i],
  1151. Status2,
  1152. SizeNeeded));
  1153. }
  1154. }
  1155. if (Handles != NULL)
  1156. {
  1157. WmipFree(Handles);
  1158. }
  1159. if (BufferOverFlow)
  1160. {
  1161. WnodeTooSmall = (PWNODE_TOO_SMALL)BufferPtr;
  1162. WnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  1163. WnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  1164. WnodeTooSmall->SizeNeeded = SizeNeeded;
  1165. *ReturnSize = sizeof(WNODE_TOO_SMALL);
  1166. } else {
  1167. *ReturnSize = SizeNeeded;
  1168. }
  1169. return(Status);
  1170. }
  1171. NTSTATUS WmipPrepareWnodeSI(
  1172. IN PWMIGUIDOBJECT GuidObject,
  1173. IN OUT PWNODE_SINGLE_INSTANCE WnodeSI,
  1174. IN OUT ULONG *ProviderIdCount,
  1175. OUT PBINSTANCESET **ProviderIdList,
  1176. OUT BOOLEAN *IsDynamic,
  1177. OUT BOOLEAN *InternalGuid
  1178. )
  1179. {
  1180. NTSTATUS Status;
  1181. PBGUIDENTRY GuidEntry;
  1182. ULONG i;
  1183. PWNODE_HEADER Wnode;
  1184. PWCHAR CInstanceName;
  1185. PWCHAR InstanceName;
  1186. PLIST_ENTRY InstanceSetList;
  1187. PBINSTANCESET InstanceSet;
  1188. PBINSTANCESET *PIPtr = NULL;
  1189. PBINSTANCESET *StaticPIPtr = NULL;
  1190. ULONG PICount = 0, PIMax;
  1191. BOOLEAN Done;
  1192. PAGED_CODE();
  1193. *IsDynamic = TRUE;
  1194. GuidEntry = GuidObject->GuidEntry;
  1195. Wnode = (PWNODE_HEADER)WnodeSI;
  1196. if ((GuidEntry != NULL) && (GuidEntry->ISCount > 0))
  1197. {
  1198. //
  1199. // We were passed a valid guid handle, fill out the guid
  1200. // in WNODE_HEADER
  1201. //
  1202. Status = STATUS_SUCCESS;
  1203. Wnode->Guid = GuidEntry->Guid;
  1204. if (GuidEntry->Flags & GE_FLAG_INTERNAL)
  1205. {
  1206. *InternalGuid = TRUE;
  1207. } else {
  1208. *InternalGuid = FALSE;
  1209. //
  1210. // Obtain instance name from WNODE
  1211. //
  1212. CInstanceName = (PWCHAR)OffsetToPtr(WnodeSI,
  1213. WnodeSI->OffsetInstanceName);
  1214. InstanceName = WmipCountedToSz(CInstanceName);
  1215. if (InstanceName != NULL)
  1216. {
  1217. //
  1218. // Remember the static provider id list and assume that the
  1219. // request is going to be dynamic
  1220. //
  1221. StaticPIPtr = *ProviderIdList;
  1222. PIPtr = StaticPIPtr;
  1223. PIMax = *ProviderIdCount;
  1224. PICount = 0;
  1225. //
  1226. // March down instance set list to see if we have a
  1227. // static name and build the list of dynamic provider ids
  1228. //
  1229. Done = FALSE;
  1230. WmipEnterSMCritSection();
  1231. if (GuidEntry->ISCount > 0)
  1232. {
  1233. InstanceSetList = GuidEntry->ISHead.Flink;
  1234. while ((InstanceSetList != &GuidEntry->ISHead) && ! Done)
  1235. {
  1236. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  1237. INSTANCESET,
  1238. GuidISList);
  1239. if ((InstanceSet->Flags & (IS_TRACED | IS_CONTROL_GUID | IS_EVENT_ONLY)) == 0)
  1240. {
  1241. //
  1242. // Only take those IS that are not traced or control
  1243. // guids and are not event only guids
  1244. //
  1245. if (InstanceSet->Flags & IS_INSTANCE_BASENAME)
  1246. {
  1247. PBISBASENAME IsBaseName;
  1248. ULONG BaseIndex;
  1249. PWCHAR BaseName;
  1250. SIZE_T BaseNameLen;
  1251. PWCHAR SuffixPtr;
  1252. ULONG Suffix;
  1253. WCHAR SuffixText[MAXBASENAMESUFFIXSIZE+1];
  1254. //
  1255. // See if the instance name is from this base name
  1256. //
  1257. IsBaseName = InstanceSet->IsBaseName;
  1258. BaseIndex = IsBaseName->BaseIndex;
  1259. BaseName = IsBaseName->BaseName;
  1260. BaseNameLen = wcslen(BaseName);
  1261. if ((wcslen(InstanceName) > BaseNameLen) &&
  1262. (_wcsnicmp(InstanceName, BaseName, BaseNameLen) == 0))
  1263. {
  1264. //
  1265. // The suffix matches the beginning of our instance
  1266. // name and our instance name is longer than the
  1267. // suffix.
  1268. //
  1269. SuffixPtr = &InstanceName[BaseNameLen];
  1270. Suffix = _wtoi(SuffixPtr);
  1271. if ((WmipIsNumber(SuffixPtr) &&
  1272. (Suffix >= BaseIndex) &&
  1273. (Suffix < (BaseIndex + InstanceSet->Count))))
  1274. {
  1275. //
  1276. // Our suffix is a number within the range for
  1277. // this instance set
  1278. //
  1279. if (Suffix < MAXBASENAMESUFFIXVALUE)
  1280. {
  1281. StringCbPrintf(SuffixText,
  1282. sizeof(SuffixText),
  1283. BASENAMEFORMATSTRING,
  1284. Suffix);
  1285. if (_wcsicmp(SuffixText, SuffixPtr) == 0)
  1286. {
  1287. //
  1288. // Our instance name is part of the
  1289. // instance set so note the provider id
  1290. // and instance index
  1291. //
  1292. Wnode->Flags |= WNODE_FLAG_STATIC_INSTANCE_NAMES;
  1293. Wnode->ProviderId = InstanceSet->ProviderId;
  1294. WnodeSI->InstanceIndex = Suffix - BaseIndex;
  1295. *IsDynamic = FALSE;
  1296. Done = TRUE;
  1297. }
  1298. }
  1299. }
  1300. }
  1301. } else if (InstanceSet->Flags & IS_INSTANCE_STATICNAMES) {
  1302. //
  1303. // See if the passed instance name matches any of the
  1304. // static names for this instnace set
  1305. //
  1306. PWCHAR *StaticNames;
  1307. StaticNames = InstanceSet->IsStaticNames->StaticNamePtr;
  1308. for (i =0; i < InstanceSet->Count; i++)
  1309. {
  1310. if (_wcsicmp(StaticNames[i], InstanceName) == 0)
  1311. {
  1312. //
  1313. // We matched our instance name with a static
  1314. // instance name. Remember provider id and
  1315. // instance index.
  1316. //
  1317. Wnode->Flags |= WNODE_FLAG_STATIC_INSTANCE_NAMES;
  1318. Wnode->ProviderId = InstanceSet->ProviderId;
  1319. WnodeSI->InstanceIndex = i;
  1320. *IsDynamic = FALSE;
  1321. Done = TRUE;
  1322. break;
  1323. }
  1324. }
  1325. } else {
  1326. //
  1327. // Remember dynamic providerid
  1328. //
  1329. WmipReferenceIS(InstanceSet);
  1330. Status = WmipAddProviderIdToPIList(&PIPtr,
  1331. &PICount,
  1332. &PIMax,
  1333. StaticPIPtr,
  1334. InstanceSet);
  1335. if (! NT_SUCCESS(Status))
  1336. {
  1337. Done = TRUE;
  1338. }
  1339. }
  1340. }
  1341. InstanceSetList = InstanceSetList->Flink;
  1342. }
  1343. } else {
  1344. //
  1345. // There are no instance sets registered for this guid
  1346. //
  1347. Status = STATUS_WMI_GUID_DISCONNECTED;
  1348. }
  1349. WmipFree(InstanceName);
  1350. WmipLeaveSMCritSection();
  1351. } else {
  1352. Status = STATUS_INSUFFICIENT_RESOURCES;
  1353. }
  1354. if (*IsDynamic)
  1355. {
  1356. //
  1357. // Dynamic instance name so return list of dynamic providers
  1358. //
  1359. *ProviderIdCount = PICount;
  1360. *ProviderIdList = PIPtr;
  1361. } else {
  1362. //
  1363. // Static instance name so unref an dynamic instance sets
  1364. //
  1365. if (PIPtr != NULL)
  1366. {
  1367. for (i = 0; i < PICount; i++)
  1368. {
  1369. WmipUnreferenceIS(PIPtr[i]);
  1370. }
  1371. if (PIPtr != StaticPIPtr)
  1372. {
  1373. WmipFree(PIPtr);
  1374. }
  1375. }
  1376. }
  1377. }
  1378. } else {
  1379. Status = STATUS_WMI_GUID_DISCONNECTED;
  1380. }
  1381. return(Status);
  1382. }
  1383. #ifdef ALLOC_DATA_PRAGMA
  1384. #pragma const_seg("PAGECONST")
  1385. #endif
  1386. const ACCESS_MASK DesiredAccessForFunction[] =
  1387. {
  1388. WMIGUID_QUERY, // IRP_MN_QUERY_ALL_DATA
  1389. WMIGUID_QUERY, // IRP_MN_QUERY_SINGLE_INSTANCE
  1390. WMIGUID_SET, // IRP_MN_CHANGE_SINGLE_INSTANCE
  1391. WMIGUID_SET, // IRP_MN_CHANGE_SINGLE_ITEM
  1392. 0, // IRP_MN_ENABLE_EVENTS
  1393. 0, // IRP_MN_DISABLE_EVENTS
  1394. 0, // IRP_MN_ENABLE_COLLECTION
  1395. 0, // IRP_MN_DISABLE_COLLECTION
  1396. 0, // IRP_MN_REGINFO
  1397. WMIGUID_EXECUTE, // IRP_MN_EXECUTE_METHOD
  1398. 0, // IRP_MN_TRACE_EVENT or IRP_MN_SET_TRACE_NOTIFY
  1399. 0 // IRP_MN_REGINFO_EX
  1400. };
  1401. NTSTATUS WmipQuerySetExecuteSI(
  1402. IN PWMIGUIDOBJECT GuidObject,
  1403. IN PIRP Irp,
  1404. IN KPROCESSOR_MODE AccessMode,
  1405. IN UCHAR MinorFunction,
  1406. IN OUT PWNODE_HEADER Wnode,
  1407. IN ULONG OutBufferSize,
  1408. OUT PULONG RetSize
  1409. )
  1410. {
  1411. NTSTATUS Status, ReturnStatus;
  1412. PBINSTANCESET StaticPIList[MANYPROVIDERIDS];
  1413. PBINSTANCESET *PIList;
  1414. HANDLE KernelHandle;
  1415. ULONG PICount;
  1416. BOOLEAN IsDynamic;
  1417. ULONG i;
  1418. BOOLEAN InternalGuid;
  1419. IO_STATUS_BLOCK Iosb;
  1420. #if DBG
  1421. BOOLEAN InstanceClaimed;
  1422. #endif
  1423. PAGED_CODE();
  1424. WmipAssert(((MinorFunction >= IRP_MN_QUERY_ALL_DATA) &&
  1425. (MinorFunction <= IRP_MN_CHANGE_SINGLE_ITEM)) ||
  1426. (MinorFunction == IRP_MN_EXECUTE_METHOD));
  1427. //
  1428. // Check Security
  1429. //
  1430. if (GuidObject != NULL)
  1431. {
  1432. Status = ObReferenceObjectByPointer(GuidObject,
  1433. DesiredAccessForFunction[MinorFunction],
  1434. WmipGuidObjectType,
  1435. AccessMode);
  1436. } else {
  1437. KernelHandle = Wnode->KernelHandle;
  1438. Status = ObReferenceObjectByHandle(KernelHandle,
  1439. DesiredAccessForFunction[MinorFunction],
  1440. WmipGuidObjectType,
  1441. AccessMode,
  1442. &GuidObject,
  1443. NULL);
  1444. }
  1445. if (NT_SUCCESS(Status))
  1446. {
  1447. PIList = StaticPIList;
  1448. PICount = MANYPROVIDERIDS;
  1449. Status = WmipPrepareWnodeSI(GuidObject,
  1450. (PWNODE_SINGLE_INSTANCE)Wnode,
  1451. &PICount,
  1452. &PIList,
  1453. &IsDynamic,
  1454. &InternalGuid);
  1455. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_API_INFO_LEVEL,
  1456. "WMI: QSI Prepare [%s - %s] %x with %x PI at %p\n",
  1457. IsDynamic ? "Dynamic" : "Static",
  1458. InternalGuid ? "Internal" : "External",
  1459. Wnode->KernelHandle, PICount, PIList));
  1460. if (NT_SUCCESS(Status))
  1461. {
  1462. if (InternalGuid)
  1463. {
  1464. //
  1465. // Internal guid query
  1466. //
  1467. Wnode->Flags |= WNODE_FLAG_INTERNAL;
  1468. Wnode->BufferSize = sizeof(WNODE_HEADER);
  1469. Irp->IoStatus.Information = sizeof(WNODE_HEADER);
  1470. } else {
  1471. if (IsDynamic)
  1472. {
  1473. //
  1474. // We need to loop over all dynamic instance names until
  1475. // one of them responds successfully and then we assume
  1476. // that they own the instance
  1477. //
  1478. #if DBG
  1479. InstanceClaimed = FALSE;
  1480. #endif
  1481. if ((MinorFunction == IRP_MN_CHANGE_SINGLE_ITEM) ||
  1482. (MinorFunction == IRP_MN_EXECUTE_METHOD))
  1483. {
  1484. Status = STATUS_WMI_ITEMID_NOT_FOUND;
  1485. } else {
  1486. Status = STATUS_WMI_INSTANCE_NOT_FOUND;
  1487. }
  1488. for (i = 0; i < PICount; i++)
  1489. {
  1490. Wnode->ProviderId = PIList[i]->ProviderId;
  1491. if (Irp != NULL)
  1492. {
  1493. ReturnStatus = WmipForwardWmiIrp(Irp,
  1494. MinorFunction,
  1495. Wnode->ProviderId,
  1496. &Wnode->Guid,
  1497. OutBufferSize,
  1498. Wnode);
  1499. if (NT_SUCCESS(ReturnStatus))
  1500. {
  1501. *RetSize = (ULONG)Irp->IoStatus.Information;
  1502. }
  1503. } else {
  1504. ReturnStatus = WmipSendWmiIrp(
  1505. MinorFunction,
  1506. Wnode->ProviderId,
  1507. &Wnode->Guid,
  1508. OutBufferSize,
  1509. Wnode,
  1510. &Iosb);
  1511. if (NT_SUCCESS(ReturnStatus))
  1512. {
  1513. *RetSize = (ULONG)Iosb.Information;
  1514. }
  1515. }
  1516. //
  1517. // One of these status codes imply that the device does
  1518. // positively claim the instance name and so we break out
  1519. // and return the results
  1520. //
  1521. if ((NT_SUCCESS(ReturnStatus)) ||
  1522. (ReturnStatus == STATUS_WMI_SET_FAILURE) ||
  1523. (ReturnStatus == STATUS_WMI_ITEMID_NOT_FOUND) ||
  1524. (ReturnStatus == STATUS_WMI_READ_ONLY))
  1525. {
  1526. Status = ReturnStatus;
  1527. break;
  1528. }
  1529. //
  1530. // If the device does not own the instance it can
  1531. // only return STATUS_WMI_INSTANCE_NOT_FOUND or
  1532. // STATUS_WMI_GUID_NOT_FOUND. Any other return code
  1533. // implies that the device owns the instance, but
  1534. // encountered an error.
  1535. //
  1536. if ( (ReturnStatus != STATUS_WMI_INSTANCE_NOT_FOUND) &&
  1537. (ReturnStatus != STATUS_WMI_GUID_NOT_FOUND))
  1538. {
  1539. WmipAssert(! InstanceClaimed);
  1540. #if DBG
  1541. InstanceClaimed = TRUE;
  1542. #endif
  1543. Status = ReturnStatus;
  1544. }
  1545. WmipUnreferenceIS(PIList[i]);
  1546. }
  1547. if ((PIList != StaticPIList) && (PIList != NULL))
  1548. {
  1549. WmipFree(PIList);
  1550. }
  1551. } else {
  1552. //
  1553. // Since we have a static instance name we can target directly
  1554. // at the device that has our instance name
  1555. //
  1556. if (Irp != NULL)
  1557. {
  1558. Status = WmipForwardWmiIrp(Irp,
  1559. MinorFunction,
  1560. Wnode->ProviderId,
  1561. &Wnode->Guid,
  1562. OutBufferSize,
  1563. Wnode);
  1564. *RetSize = (ULONG)Irp->IoStatus.Information;
  1565. } else {
  1566. Status = WmipSendWmiIrp(
  1567. MinorFunction,
  1568. Wnode->ProviderId,
  1569. &Wnode->Guid,
  1570. OutBufferSize,
  1571. Wnode,
  1572. &Iosb);
  1573. *RetSize = (ULONG)Iosb.Information;
  1574. }
  1575. }
  1576. }
  1577. }
  1578. //
  1579. // And remove ref on guid object
  1580. //
  1581. ObDereferenceObject(GuidObject);
  1582. }
  1583. return(Status);
  1584. }
  1585. NTSTATUS WmipQuerySingleMultiple(
  1586. IN PIRP Irp,
  1587. IN KPROCESSOR_MODE AccessMode,
  1588. IN OUT PUCHAR BufferPtr,
  1589. IN ULONG BufferSize,
  1590. IN PWMIQSIMULTIPLE QsiMultiple,
  1591. IN ULONG QueryCount,
  1592. IN PWMIGUIDOBJECT *ObjectList,
  1593. IN PUNICODE_STRING InstanceNames,
  1594. OUT ULONG *ReturnSize
  1595. )
  1596. {
  1597. PWMIQSIINFO QsiInfo;
  1598. UCHAR WnodeQSIStatic[sizeof(WNODE_SINGLE_INSTANCE) +
  1599. 256*sizeof(WCHAR) +
  1600. sizeof(ULONG)];
  1601. PWNODE_SINGLE_INSTANCE WnodeQSI;
  1602. ULONG WnodeQSISize;
  1603. ULONG WnodeSizeNeeded;
  1604. NTSTATUS Status, Status2;
  1605. ULONG SizeNeeded;
  1606. BOOLEAN BufferFull, BufferOverFlow;
  1607. PWNODE_HEADER WnodePrev;
  1608. PUCHAR Buffer;
  1609. ULONG i;
  1610. ULONG WnodeSize;
  1611. PWNODE_SINGLE_INSTANCE Wnode;
  1612. PWCHAR InstanceName;
  1613. ULONG RetSize;
  1614. PWNODE_TOO_SMALL WnodeTooSmall;
  1615. ULONG Linkage = 0;
  1616. ULONG SkipSize;
  1617. PWMIGUIDOBJECT Object = NULL;
  1618. UNICODE_STRING UString;
  1619. HANDLE KernelHandle;
  1620. PAGED_CODE();
  1621. //
  1622. // We are called by kernel mode and passed an object list and InstanceNames
  1623. // or we are called by user mode and passed a QsiMultiple instead
  1624. //
  1625. WmipAssert( ((AccessMode == KernelMode) &&
  1626. (QsiMultiple == NULL) &&
  1627. (ObjectList != NULL) &&
  1628. (InstanceNames != NULL)) ||
  1629. ((AccessMode == UserMode) &&
  1630. (QsiMultiple != NULL) &&
  1631. (ObjectList == NULL) &&
  1632. (InstanceNames == NULL)) );
  1633. Status = STATUS_SUCCESS;
  1634. if (ObjectList == NULL)
  1635. {
  1636. //
  1637. // if this is a user call then we need to copy out the
  1638. // QSIMULTIPLE information since it is in the system buffer and
  1639. // will get overwritten on the first query
  1640. //
  1641. QsiInfo = (PWMIQSIINFO)WmipAlloc(QueryCount * sizeof(WMIQSIINFO));
  1642. if (QsiInfo != NULL)
  1643. {
  1644. RtlCopyMemory(QsiInfo,
  1645. &QsiMultiple->QsiInfo,
  1646. QueryCount * sizeof(WMIQSIINFO));
  1647. } else {
  1648. Status = STATUS_INSUFFICIENT_RESOURCES;
  1649. }
  1650. Object = NULL;
  1651. } else {
  1652. QsiInfo = NULL;
  1653. }
  1654. if (NT_SUCCESS(Status))
  1655. {
  1656. SizeNeeded = 0;
  1657. BufferFull = FALSE;
  1658. BufferOverFlow = FALSE;
  1659. WnodePrev = NULL;
  1660. Buffer = BufferPtr;
  1661. WnodeQSI = (PWNODE_SINGLE_INSTANCE)&WnodeQSIStatic;
  1662. WnodeQSISize = sizeof(WnodeQSIStatic);
  1663. for (i = 0; i < QueryCount; i++)
  1664. {
  1665. if (ObjectList == NULL)
  1666. {
  1667. UString.Length = QsiInfo[i].InstanceName.Length;
  1668. UString.MaximumLength = QsiInfo[i].InstanceName.MaximumLength;
  1669. UString.Buffer = QsiInfo[i].InstanceName.Buffer;
  1670. KernelHandle = QsiInfo[i].Handle.Handle;
  1671. } else {
  1672. UString = InstanceNames[i];
  1673. Object = ObjectList[i];
  1674. KernelHandle = NULL;
  1675. }
  1676. WnodeSizeNeeded = (FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  1677. VariableData) +
  1678. UString.Length +
  1679. sizeof(USHORT) + 7) & ~7;
  1680. if ((BufferFull) || (BufferSize < WnodeSizeNeeded))
  1681. {
  1682. //
  1683. // If there is no more room, we are just querying for the
  1684. // size that will be needed.
  1685. //
  1686. if (WnodeSizeNeeded > WnodeQSISize)
  1687. {
  1688. //
  1689. // Our temporary buffer is too small so lets alloc a
  1690. // larger one
  1691. //
  1692. if (WnodeQSI != (PWNODE_SINGLE_INSTANCE)WnodeQSIStatic)
  1693. {
  1694. WmipFree(WnodeQSI);
  1695. }
  1696. WnodeQSI = (PWNODE_SINGLE_INSTANCE)WmipAllocNP(WnodeSizeNeeded);
  1697. if (WnodeQSI == NULL)
  1698. {
  1699. //
  1700. // We couldn't allocate a larger temporary buffer
  1701. // so we abort this call and try to exit gracefully
  1702. //
  1703. Status = STATUS_INSUFFICIENT_RESOURCES;
  1704. break;
  1705. }
  1706. WnodeQSISize = WnodeSizeNeeded;
  1707. }
  1708. Wnode = WnodeQSI;
  1709. WnodeSize = WnodeSizeNeeded;
  1710. WnodePrev = NULL;
  1711. BufferFull = TRUE;
  1712. } else {
  1713. //
  1714. // Plenty of room so build wnode directly into the output
  1715. // buffer
  1716. //
  1717. Wnode = (PWNODE_SINGLE_INSTANCE)Buffer;
  1718. WnodeSize = BufferSize;
  1719. }
  1720. //
  1721. // Build WNODE_SINGLE_INSTANCE in order to do the query
  1722. //
  1723. RtlZeroMemory(Wnode, sizeof(WNODE_SINGLE_INSTANCE));
  1724. Wnode->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE;
  1725. Wnode->WnodeHeader.BufferSize = WnodeSizeNeeded;
  1726. Wnode->WnodeHeader.KernelHandle = KernelHandle;
  1727. Wnode->OffsetInstanceName = FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  1728. VariableData);
  1729. Wnode->DataBlockOffset = WnodeSizeNeeded;
  1730. InstanceName = (PWCHAR)OffsetToPtr(Wnode,
  1731. Wnode->OffsetInstanceName);
  1732. *InstanceName++ = UString.Length;
  1733. try
  1734. {
  1735. if (AccessMode == UserMode)
  1736. {
  1737. ProbeForRead(UString.Buffer,
  1738. UString.Length,
  1739. sizeof(WCHAR));
  1740. }
  1741. RtlCopyMemory(InstanceName,
  1742. UString.Buffer,
  1743. UString.Length);
  1744. } except(EXCEPTION_EXECUTE_HANDLER) {
  1745. //
  1746. // If an error occured probing then we fail the entire call
  1747. //
  1748. Status = GetExceptionCode();
  1749. break;
  1750. }
  1751. Status2 = WmipQuerySetExecuteSI(Object,
  1752. Irp,
  1753. AccessMode,
  1754. IRP_MN_QUERY_SINGLE_INSTANCE,
  1755. (PWNODE_HEADER)Wnode,
  1756. WnodeSize,
  1757. &RetSize);
  1758. if (NT_SUCCESS(Status2))
  1759. {
  1760. if (Wnode->WnodeHeader.Flags & WNODE_FLAG_INTERNAL)
  1761. {
  1762. //
  1763. // Skip any internal guid quesries
  1764. //
  1765. } else if (Wnode->WnodeHeader.Flags & WNODE_FLAG_TOO_SMALL) {
  1766. //
  1767. // There is no enough room so just tally up
  1768. // the size that will be needed.
  1769. //
  1770. WnodeTooSmall = (PWNODE_TOO_SMALL)Wnode;
  1771. SizeNeeded += (WnodeTooSmall->SizeNeeded+7) & ~7;
  1772. BufferFull = TRUE;
  1773. BufferOverFlow = TRUE;
  1774. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_API_INFO_LEVEL,
  1775. "WMI: QSIM %ws too small %x SizeNeeded %x\n",
  1776. UString.Buffer,
  1777. (WnodeTooSmall->SizeNeeded+7) & ~7,
  1778. SizeNeeded));
  1779. } else if (BufferFull) {
  1780. //
  1781. // There was enough room, but the buffer was already
  1782. // filled so we just tally up the size needed
  1783. //
  1784. SizeNeeded += (RetSize+7) & ~7;
  1785. BufferOverFlow = TRUE;
  1786. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_API_INFO_LEVEL,
  1787. "WMI: QSIM %ws big enough but full %x SizeNeeded %x\n",
  1788. UString.Buffer,
  1789. (RetSize+7) & ~7,
  1790. SizeNeeded));
  1791. } else {
  1792. //
  1793. // We successfully got data. Link the previous wnode
  1794. // to this one
  1795. //
  1796. if (WnodePrev != NULL)
  1797. {
  1798. WnodePrev->Linkage = Linkage;
  1799. }
  1800. WnodePrev = (PWNODE_HEADER)Wnode;
  1801. while (WnodePrev->Linkage != 0)
  1802. {
  1803. WnodePrev = (PWNODE_HEADER)OffsetToPtr(WnodePrev,
  1804. WnodePrev->Linkage);
  1805. }
  1806. SkipSize = (RetSize+7) &~7;
  1807. SizeNeeded += SkipSize;
  1808. BufferSize -= SkipSize;
  1809. Buffer += SkipSize;
  1810. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_API_INFO_LEVEL,
  1811. "WMI: QSIM %ws big enough %x SizeNeeded %x\n",
  1812. UString.Buffer,
  1813. SkipSize,
  1814. SizeNeeded));
  1815. Linkage = (ULONG) ((PCHAR)Buffer - (PCHAR)WnodePrev);
  1816. }
  1817. } else {
  1818. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_API_INFO_LEVEL,
  1819. "WMI: QSIM %ws Failed SizeNeeded %x\n",
  1820. UString.Buffer,
  1821. SizeNeeded));
  1822. }
  1823. }
  1824. if (WnodeQSI != (PWNODE_SINGLE_INSTANCE)WnodeQSIStatic)
  1825. {
  1826. WmipFree(WnodeQSI);
  1827. }
  1828. if (NT_SUCCESS(Status) && (BufferFull))
  1829. {
  1830. WnodeTooSmall = (PWNODE_TOO_SMALL)BufferPtr;
  1831. WnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  1832. WnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  1833. WnodeTooSmall->SizeNeeded = SizeNeeded;
  1834. *ReturnSize = sizeof(WNODE_TOO_SMALL);
  1835. } else {
  1836. *ReturnSize = SizeNeeded;
  1837. }
  1838. if (QsiInfo != NULL)
  1839. {
  1840. WmipFree(QsiInfo);
  1841. }
  1842. }
  1843. return(Status);
  1844. }
  1845. void
  1846. WmipGetGuidPropertiesFromGuidEntry(
  1847. PWMIGUIDPROPERTIES GuidInfo,
  1848. PGUIDENTRY GuidEntry)
  1849. /*++
  1850. Routine Description:
  1851. This routine fills GuidInfo with the properties for the Guid
  1852. represented by the GuidEntry. Note that this call is made holding
  1853. the SMCritSection.
  1854. Arguments:
  1855. Return Value:
  1856. --*/
  1857. {
  1858. PLIST_ENTRY InstanceSetList;
  1859. PBINSTANCESET InstanceSet;
  1860. PAGED_CODE();
  1861. GuidInfo->GuidType = WMI_GUIDTYPE_DATA;
  1862. GuidInfo->IsEnabled = FALSE;
  1863. GuidInfo->LoggerId = 0;
  1864. GuidInfo->EnableLevel = 0;
  1865. GuidInfo->EnableFlags = 0;
  1866. InstanceSetList = GuidEntry->ISHead.Flink;
  1867. while (InstanceSetList != &GuidEntry->ISHead)
  1868. {
  1869. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  1870. INSTANCESET,
  1871. GuidISList);
  1872. if (InstanceSet->Flags & IS_EVENT_ONLY)
  1873. {
  1874. GuidInfo->GuidType = WMI_GUIDTYPE_EVENT;
  1875. }
  1876. if (((InstanceSet->Flags & IS_ENABLE_EVENT) ||
  1877. (InstanceSet->Flags & IS_ENABLE_COLLECTION)) ||
  1878. (InstanceSet->Flags & IS_COLLECTING))
  1879. {
  1880. GuidInfo->IsEnabled = TRUE;
  1881. }
  1882. if ( (InstanceSet->Flags & IS_TRACED) &&
  1883. (InstanceSet->Flags & IS_CONTROL_GUID) )
  1884. {
  1885. GuidInfo->GuidType = WMI_GUIDTYPE_TRACECONTROL;
  1886. break;
  1887. }
  1888. InstanceSetList = InstanceSetList->Flink;
  1889. }
  1890. if (GuidEntry->Flags & GE_NOTIFICATION_TRACE_FLAG)
  1891. {
  1892. if (GuidInfo->GuidType == WMI_GUIDTYPE_TRACECONTROL) {
  1893. //
  1894. // If a NotificationEntry is found for a TraceControlGuid
  1895. // it means that it is enabled.
  1896. //
  1897. ULONG64 LoggerContext = GuidEntry->LoggerContext;
  1898. GuidInfo->IsEnabled = TRUE;
  1899. GuidInfo->LoggerId = WmiGetLoggerId(LoggerContext);
  1900. GuidInfo->EnableLevel = WmiGetLoggerEnableLevel(LoggerContext);
  1901. GuidInfo->EnableFlags = WmiGetLoggerEnableFlags(LoggerContext);
  1902. }
  1903. }
  1904. }
  1905. NTSTATUS WmipEnumerateGuids(
  1906. ULONG Ioctl,
  1907. PWMIGUIDLISTINFO GuidList,
  1908. ULONG MaxBufferSize,
  1909. ULONG *OutBufferSize
  1910. )
  1911. {
  1912. ULONG TotalGuidCount;
  1913. ULONG WrittenGuidCount;
  1914. ULONG AllowedGuidCount;
  1915. PWMIGUIDPROPERTIES GuidPtr;
  1916. PBGUIDENTRY GuidEntry;
  1917. PLIST_ENTRY GuidEntryList;
  1918. PAGED_CODE();
  1919. TotalGuidCount = 0;
  1920. WrittenGuidCount = 0;
  1921. AllowedGuidCount = (MaxBufferSize - FIELD_OFFSET(WMIGUIDLISTINFO, GuidList)) / sizeof(WMIGUIDPROPERTIES);
  1922. GuidPtr = &GuidList->GuidList[0];
  1923. WmipEnterSMCritSection();
  1924. //
  1925. // Fill up structure with list of guids
  1926. //
  1927. GuidEntryList = WmipGEHeadPtr->Flink;
  1928. while (GuidEntryList != WmipGEHeadPtr)
  1929. {
  1930. GuidEntry = CONTAINING_RECORD(GuidEntryList,
  1931. GUIDENTRY,
  1932. MainGEList);
  1933. TotalGuidCount++;
  1934. if (WrittenGuidCount < AllowedGuidCount)
  1935. {
  1936. GuidPtr[WrittenGuidCount].Guid = GuidEntry->Guid;
  1937. WrittenGuidCount++;
  1938. }
  1939. GuidEntryList = GuidEntryList->Flink;
  1940. }
  1941. if (Ioctl == IOCTL_WMI_ENUMERATE_GUIDS_AND_PROPERTIES)
  1942. {
  1943. //
  1944. // If needed fill struct with guid properties
  1945. //
  1946. TotalGuidCount = 0;
  1947. WrittenGuidCount = 0;
  1948. GuidEntryList = WmipGEHeadPtr->Flink;
  1949. while (GuidEntryList != WmipGEHeadPtr)
  1950. {
  1951. GuidEntry = CONTAINING_RECORD(GuidEntryList,
  1952. GUIDENTRY,
  1953. MainGEList);
  1954. TotalGuidCount++;
  1955. if (WrittenGuidCount < AllowedGuidCount)
  1956. {
  1957. WmipGetGuidPropertiesFromGuidEntry(&GuidPtr[WrittenGuidCount],
  1958. GuidEntry);
  1959. WrittenGuidCount++;
  1960. }
  1961. GuidEntryList = GuidEntryList->Flink;
  1962. }
  1963. }
  1964. WmipLeaveSMCritSection();
  1965. GuidList->TotalGuidCount = TotalGuidCount;
  1966. GuidList->ReturnedGuidCount = WrittenGuidCount;
  1967. *OutBufferSize = FIELD_OFFSET(WMIGUIDLISTINFO, GuidList) +
  1968. WrittenGuidCount * sizeof(WMIGUIDPROPERTIES);
  1969. return(STATUS_SUCCESS);
  1970. }
  1971. NTSTATUS WmipQueryGuidInfo(
  1972. IN OUT PWMIQUERYGUIDINFO QueryGuidInfo
  1973. )
  1974. {
  1975. HANDLE Handle;
  1976. NTSTATUS Status;
  1977. PLIST_ENTRY InstanceSetList;
  1978. PBINSTANCESET InstanceSet;
  1979. PBGUIDENTRY GuidEntry;
  1980. PWMIGUIDOBJECT GuidObject;
  1981. PAGED_CODE();
  1982. Handle = QueryGuidInfo->KernelHandle.Handle;
  1983. Status = ObReferenceObjectByHandle(Handle,
  1984. WMIGUID_QUERY,
  1985. WmipGuidObjectType,
  1986. UserMode,
  1987. &GuidObject,
  1988. NULL);
  1989. if (NT_SUCCESS(Status))
  1990. {
  1991. GuidEntry = GuidObject->GuidEntry;
  1992. if (GuidEntry != NULL)
  1993. {
  1994. //
  1995. // Assume that the guid is not expensive and then loop over
  1996. // all instances to see if one of them is expensive.
  1997. //
  1998. QueryGuidInfo->IsExpensive = FALSE;
  1999. WmipEnterSMCritSection();
  2000. InstanceSetList = GuidEntry->ISHead.Flink;
  2001. while (InstanceSetList != &GuidEntry->ISHead)
  2002. {
  2003. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  2004. INSTANCESET,
  2005. GuidISList);
  2006. if (InstanceSet->Flags & IS_EXPENSIVE)
  2007. {
  2008. //
  2009. // The guid is expensive so remember that and break
  2010. // out of loop
  2011. //
  2012. QueryGuidInfo->IsExpensive = TRUE;
  2013. break;
  2014. }
  2015. InstanceSetList = InstanceSetList->Flink;
  2016. }
  2017. WmipLeaveSMCritSection();
  2018. } else {
  2019. //
  2020. // The guid object exists, but there is not a corresponding
  2021. // guidentry which is an error.
  2022. //
  2023. Status = STATUS_WMI_GUID_DISCONNECTED;
  2024. }
  2025. //
  2026. // And remove ref on guid object
  2027. //
  2028. ObDereferenceObject(GuidObject);
  2029. }
  2030. return(Status);
  2031. }
  2032. //
  2033. // The head of the list that contains the guid objects associated with
  2034. // an irp is in the DriverContext part of the irp
  2035. //
  2036. #define IRP_OBJECT_LIST_HEAD(Irp) (PLIST_ENTRY)((Irp)->Tail.Overlay.DriverContext)
  2037. void WmipClearIrpObjectList(
  2038. PIRP Irp
  2039. )
  2040. {
  2041. PLIST_ENTRY ObjectListHead;
  2042. PLIST_ENTRY ObjectList, ObjectListNext;
  2043. PWMIGUIDOBJECT Object;
  2044. PAGED_CODE();
  2045. //
  2046. // This routine assumes that the SMCritSection is being held
  2047. //
  2048. ObjectListHead = IRP_OBJECT_LIST_HEAD(Irp);
  2049. ObjectList = ObjectListHead->Flink;
  2050. //
  2051. // Loop over all objects associated with this irp and reset the
  2052. // value for its associated irp since this irp is now going away
  2053. //
  2054. while (ObjectList != ObjectListHead)
  2055. {
  2056. Object = CONTAINING_RECORD(ObjectList,
  2057. WMIGUIDOBJECT,
  2058. IrpObjectList);
  2059. WmipAssert(Object->Irp == Irp);
  2060. WmipAssert(Object->EventQueueAction == RECEIVE_ACTION_NONE);
  2061. Object->Irp = NULL;
  2062. RemoveEntryList(ObjectList);
  2063. ObjectListNext = ObjectList->Flink;
  2064. ObjectList = ObjectListNext;
  2065. }
  2066. }
  2067. void WmipClearObjectFromThreadList(
  2068. PWMIGUIDOBJECT Object
  2069. )
  2070. {
  2071. PLIST_ENTRY ThreadList;
  2072. PAGED_CODE();
  2073. ThreadList = &Object->ThreadObjectList;
  2074. if (IsListEmpty(ThreadList))
  2075. {
  2076. //
  2077. // if this is the last object on the thread list then we need
  2078. // to close the handle (in the system handle table) to the user
  2079. // mode process
  2080. //
  2081. ZwClose(Object->UserModeProcess);
  2082. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_API_INFO_LEVEL,
  2083. "WMI: Closed UserModeProcessHandle %x\n", Object->UserModeProcess));
  2084. }
  2085. Object->UserModeProcess = NULL;
  2086. Object->UserModeCallback = NULL;
  2087. Object->EventQueueAction = RECEIVE_ACTION_NONE;
  2088. RemoveEntryList(ThreadList);
  2089. InitializeListHead(ThreadList);
  2090. }
  2091. void WmipClearThreadObjectList(
  2092. PWMIGUIDOBJECT MainObject
  2093. )
  2094. {
  2095. PWMIGUIDOBJECT Object;
  2096. PLIST_ENTRY ObjectList;
  2097. #if DBG
  2098. HANDLE MyUserModeProcess;
  2099. PUSER_THREAD_START_ROUTINE MyUserModeCallback;
  2100. #endif
  2101. PAGED_CODE();
  2102. //
  2103. // This routine assumes the SMCrit Section is held
  2104. //
  2105. #if DBG
  2106. MyUserModeProcess = MainObject->UserModeProcess;
  2107. MyUserModeCallback = MainObject->UserModeCallback;
  2108. #endif
  2109. ObjectList = &MainObject->ThreadObjectList;
  2110. do
  2111. {
  2112. Object = CONTAINING_RECORD(ObjectList,
  2113. WMIGUIDOBJECT,
  2114. ThreadObjectList);
  2115. WmipAssert(Object->UserModeProcess == MyUserModeProcess);
  2116. WmipAssert(Object->UserModeCallback == MyUserModeCallback);
  2117. WmipAssert(Object->EventQueueAction == RECEIVE_ACTION_CREATE_THREAD);
  2118. ObjectList = ObjectList->Flink;
  2119. WmipClearObjectFromThreadList(Object);
  2120. } while (! IsListEmpty(ObjectList));
  2121. }
  2122. void WmipNotificationIrpCancel(
  2123. IN PDEVICE_OBJECT DeviceObject,
  2124. IN PIRP Irp
  2125. )
  2126. /*++
  2127. Routine Description:
  2128. Cancel routine for a pending read notification irp.
  2129. Arguments:
  2130. DeviceObject is the device object of the WMI service device
  2131. Irp is the pending Irp to be cancelled
  2132. Return Value:
  2133. --*/
  2134. {
  2135. UNREFERENCED_PARAMETER (DeviceObject);
  2136. IoReleaseCancelSpinLock(Irp->CancelIrql);
  2137. WmipEnterSMCritSection();
  2138. WmipClearIrpObjectList(Irp);
  2139. WmipLeaveSMCritSection();
  2140. Irp->IoStatus.Status = STATUS_CANCELLED;
  2141. Irp->IoStatus.Information = 0;
  2142. IoCompleteRequest(Irp, IO_NO_INCREMENT );
  2143. }
  2144. #define WmipHaveHiPriorityEvent(Object) \
  2145. (((Object)->HiPriority.Buffer != NULL) && \
  2146. ((Object)->HiPriority.NextOffset != 0))
  2147. #define WmipHaveLoPriorityEvent(Object) \
  2148. (((Object)->LoPriority.Buffer != NULL) && \
  2149. ((Object)->LoPriority.NextOffset != 0))
  2150. #define WmipSetHighWord(a, b) \
  2151. (a) &= ~(0xffff0000); \
  2152. (a) |= ( (USHORT)(b) << 16)
  2153. void WmipCopyFromEventQueues(
  2154. IN POBJECT_EVENT_INFO ObjectArray,
  2155. IN ULONG HandleCount,
  2156. OUT PUCHAR OutBuffer,
  2157. OUT ULONG *OutBufferSizeUsed,
  2158. OUT PWNODE_HEADER *LastWnode,
  2159. IN BOOLEAN IsHiPriority
  2160. )
  2161. {
  2162. PWMIGUIDOBJECT GuidObject;
  2163. ULONG i, Earliest;
  2164. ULONG SizeUsed, Size;
  2165. PWNODE_HEADER InWnode, OutWnode;
  2166. LARGE_INTEGER Timestamp, LastTimestamp;
  2167. PWMIEVENTQUEUE EventQueue;
  2168. //
  2169. // Consider adding extra code for perf
  2170. // 1. If only 1 object is passed
  2171. // 2. Once we find the earliest event we look ahead in that same
  2172. // event queue buffer assuming that it will be earlier than
  2173. // events in other buffers. This makes sense when only one queue
  2174. // has events left in it.
  2175. //
  2176. PAGED_CODE();
  2177. //
  2178. // This routine assumes that the output buffer has been checked and
  2179. // that it is large enough to accomodate all of the events. This
  2180. // implies that this function is called while holding the critical
  2181. // section.
  2182. //
  2183. //
  2184. // See which guid objects have events to be processed
  2185. //
  2186. for (i = 0; i < HandleCount; i++)
  2187. {
  2188. GuidObject = ObjectArray[i].GuidObject;
  2189. if (IsHiPriority)
  2190. {
  2191. if ((GuidObject->HiPriority.Buffer != NULL) &&
  2192. (GuidObject->HiPriority.NextOffset != 0))
  2193. {
  2194. ObjectArray[i].NextWnode = (PWNODE_HEADER)GuidObject->HiPriority.Buffer;
  2195. WmipSetHighWord(ObjectArray[i].NextWnode->Version,
  2196. GuidObject->HiPriority.EventsLost);
  2197. GuidObject->HiPriority.EventsLost = 0;
  2198. WmipAssert(ObjectArray[i].NextWnode != NULL);
  2199. } else {
  2200. ObjectArray[i].NextWnode = NULL;
  2201. }
  2202. } else {
  2203. if ((GuidObject->LoPriority.Buffer != 0) &&
  2204. (GuidObject->LoPriority.NextOffset != 0))
  2205. {
  2206. ObjectArray[i].NextWnode = (PWNODE_HEADER)GuidObject->LoPriority.Buffer;
  2207. WmipSetHighWord(ObjectArray[i].NextWnode->Version,
  2208. GuidObject->LoPriority.EventsLost);
  2209. GuidObject->LoPriority.EventsLost = 0;
  2210. WmipAssert(ObjectArray[i].NextWnode != NULL);
  2211. } else {
  2212. ObjectArray[i].NextWnode = NULL;
  2213. }
  2214. }
  2215. }
  2216. //
  2217. // loop until all events in all guid objects have been
  2218. // processed
  2219. //
  2220. SizeUsed = 0;
  2221. Earliest = 0;
  2222. OutWnode = NULL;
  2223. while (Earliest != 0xffffffff)
  2224. {
  2225. Timestamp.QuadPart = 0x7fffffffffffffff;
  2226. Earliest = 0xffffffff;
  2227. for (i = 0; i < HandleCount; i++)
  2228. {
  2229. InWnode = (PWNODE_HEADER)ObjectArray[i].NextWnode;
  2230. if ((InWnode != NULL) &&
  2231. (InWnode->TimeStamp.QuadPart < Timestamp.QuadPart))
  2232. {
  2233. //
  2234. // We found an event that is earlier than any previous
  2235. // one so we remember the new candidate for earliest
  2236. // event and also the previous early event
  2237. //
  2238. LastTimestamp = Timestamp;
  2239. Timestamp = InWnode->TimeStamp;
  2240. Earliest = i;
  2241. }
  2242. }
  2243. if (Earliest != 0xffffffff)
  2244. {
  2245. //
  2246. // We found the earliest event so copy it into the output
  2247. // buffer
  2248. //
  2249. InWnode = (PWNODE_HEADER)ObjectArray[Earliest].NextWnode;
  2250. Size = (InWnode->BufferSize + 7) & ~7;
  2251. OutWnode = (PWNODE_HEADER)OutBuffer;
  2252. RtlCopyMemory(OutWnode, InWnode, InWnode->BufferSize);
  2253. OutWnode->Linkage = Size;
  2254. OutBuffer += Size;
  2255. SizeUsed += Size;
  2256. if (InWnode->Linkage != 0)
  2257. {
  2258. InWnode = (PWNODE_HEADER)((PUCHAR)InWnode + InWnode->Linkage);
  2259. } else {
  2260. InWnode = NULL;
  2261. }
  2262. ObjectArray[Earliest].NextWnode = InWnode;
  2263. }
  2264. }
  2265. *LastWnode = OutWnode;
  2266. *OutBufferSizeUsed = SizeUsed;
  2267. //
  2268. // clean up event queue resources and reset the object
  2269. //
  2270. for (i = 0; i < HandleCount; i++)
  2271. {
  2272. GuidObject = ObjectArray[i].GuidObject;
  2273. if (IsHiPriority)
  2274. {
  2275. EventQueue = &GuidObject->HiPriority;
  2276. } else {
  2277. EventQueue = &GuidObject->LoPriority;
  2278. }
  2279. if (EventQueue->Buffer != NULL)
  2280. {
  2281. WmipFree(EventQueue->Buffer);
  2282. EventQueue->Buffer = NULL;
  2283. EventQueue->NextOffset = 0;
  2284. EventQueue->LastWnode = NULL;
  2285. }
  2286. KeClearEvent(&GuidObject->Event);
  2287. }
  2288. }
  2289. void WmipCompleteGuidIrpWithError(
  2290. PWMIGUIDOBJECT GuidObject
  2291. )
  2292. {
  2293. PIRP OldIrp;
  2294. PAGED_CODE();
  2295. //
  2296. // This routine assumes that the SM Critical Section is held
  2297. //
  2298. //
  2299. // If this object is already being waited on by a different
  2300. // irp then we need to fail the original irp since we only
  2301. // allow a single irp to wait on a specific object
  2302. //
  2303. WmipAssert(GuidObject->IrpObjectList.Flink != NULL);
  2304. WmipAssert(GuidObject->IrpObjectList.Blink != NULL);
  2305. OldIrp = GuidObject->Irp;
  2306. if (IoSetCancelRoutine(OldIrp, NULL))
  2307. {
  2308. //
  2309. // If there was a cancel routine then this means that
  2310. // the irp is still pending so we can go and complete it
  2311. //
  2312. WmipClearIrpObjectList(OldIrp);
  2313. WmipAssert(GuidObject->Irp == NULL);
  2314. OldIrp->IoStatus.Status = STATUS_INVALID_HANDLE;
  2315. IoCompleteRequest(OldIrp, IO_NO_INCREMENT);
  2316. }
  2317. }
  2318. NTSTATUS WmipMarkHandleAsClosed(
  2319. HANDLE Handle
  2320. )
  2321. {
  2322. NTSTATUS Status;
  2323. PWMIGUIDOBJECT GuidObject;
  2324. PAGED_CODE();
  2325. Status = ObReferenceObjectByHandle(Handle,
  2326. WMIGUID_NOTIFICATION,
  2327. WmipGuidObjectType,
  2328. UserMode,
  2329. &GuidObject,
  2330. NULL);
  2331. if (NT_SUCCESS(Status))
  2332. {
  2333. //
  2334. // Mark object as no longer able to receive events
  2335. //
  2336. WmipEnterSMCritSection();
  2337. GuidObject->Flags |= WMIGUID_FLAG_RECEIVE_NO_EVENTS;
  2338. if (GuidObject->Irp != NULL)
  2339. {
  2340. //
  2341. // If this object was is waiting in a pending irp then we
  2342. // need to complete the irp to keep the pump moving
  2343. //
  2344. WmipCompleteGuidIrpWithError(GuidObject);
  2345. }
  2346. WmipLeaveSMCritSection();
  2347. ObDereferenceObject(GuidObject);
  2348. }
  2349. return(Status);
  2350. }
  2351. NTSTATUS WmipReceiveNotifications(
  2352. PWMIRECEIVENOTIFICATION ReceiveNotification,
  2353. PULONG OutBufferSize,
  2354. PIRP Irp
  2355. )
  2356. {
  2357. #define MANY_NOTIFICATION_OBJECTS 16
  2358. ULONG i;
  2359. PWMIGUIDOBJECT GuidObject;
  2360. ULONG HandleCount;
  2361. PHANDLE3264 HandleArray;
  2362. OBJECT_EVENT_INFO *ObjectArray;
  2363. OBJECT_EVENT_INFO StaticObjects[MANY_NOTIFICATION_OBJECTS];
  2364. PUCHAR OutBuffer;
  2365. UCHAR IsLoPriorityEvent, IsHighPriorityEvent, ReplacingIrp;
  2366. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  2367. PWNODE_HEADER LastWnode;
  2368. PLIST_ENTRY IrpListHead, ThreadListHead;
  2369. ULONG MaxBufferSize, SizeUsed;
  2370. PVOID UserProcessObject;
  2371. HANDLE UserModeProcess;
  2372. ULONG SizeLeft, SizeNeeded, HiTotalSizeNeeded, LoTotalSizeNeeded;
  2373. PWNODE_TOO_SMALL WnodeTooSmall;
  2374. ULONG j, ObjectCount;
  2375. BOOLEAN DuplicateObject;
  2376. PIMAGE_NT_HEADERS NtHeaders;
  2377. SIZE_T StackSize, StackCommit;
  2378. #if defined(_WIN64)
  2379. PVOID Wow64Process;
  2380. PIMAGE_NT_HEADERS32 NtHeaders32;
  2381. #endif
  2382. PAGED_CODE();
  2383. MaxBufferSize = *OutBufferSize;
  2384. HandleCount = ReceiveNotification->HandleCount;
  2385. HandleArray = ReceiveNotification->Handles;
  2386. //
  2387. // Create space to store the object pointers so we can work with them
  2388. //
  2389. if (HandleCount > MANY_NOTIFICATION_OBJECTS)
  2390. {
  2391. ObjectArray = WmipAlloc(HandleCount * sizeof(OBJECT_EVENT_INFO));
  2392. if (ObjectArray == NULL)
  2393. {
  2394. return(STATUS_INSUFFICIENT_RESOURCES);
  2395. }
  2396. } else {
  2397. ObjectArray = StaticObjects;
  2398. }
  2399. #if DBG
  2400. RtlZeroMemory(ObjectArray, HandleCount * sizeof(OBJECT_EVENT_INFO));
  2401. #endif
  2402. //
  2403. // First check that we all handles are entitled to receive notifications
  2404. // and that the object is not already associated with an irp.
  2405. // Also check if there are any hi or lo priority events
  2406. //
  2407. WmipEnterSMCritSection();
  2408. IsLoPriorityEvent = 0;
  2409. IsHighPriorityEvent = 0;
  2410. ReplacingIrp = 0;
  2411. HiTotalSizeNeeded = 0;
  2412. LoTotalSizeNeeded = 0;
  2413. ObjectCount = 0;
  2414. for (i = 0; (i < HandleCount); i++)
  2415. {
  2416. Status = ObReferenceObjectByHandle(HandleArray[i].Handle,
  2417. WMIGUID_NOTIFICATION,
  2418. WmipGuidObjectType,
  2419. UserMode,
  2420. &GuidObject,
  2421. NULL);
  2422. if (! NT_SUCCESS(Status))
  2423. {
  2424. //
  2425. // If one handle is bad then it spoils the whole request
  2426. //
  2427. //
  2428. // Now try with Trace flags and if succeeds,
  2429. // We need to make sure the object is a trace request object.
  2430. //
  2431. Status = ObReferenceObjectByHandle(HandleArray[i].Handle,
  2432. TRACELOG_REGISTER_GUIDS,
  2433. WmipGuidObjectType,
  2434. UserMode,
  2435. &GuidObject,
  2436. NULL);
  2437. if (! NT_SUCCESS(Status))
  2438. {
  2439. goto Cleanup;
  2440. }
  2441. if (! (GuidObject->Flags & WMIGUID_FLAG_REQUEST_OBJECT) )
  2442. {
  2443. ObDereferenceObject(GuidObject);
  2444. Status = STATUS_ACCESS_DENIED;
  2445. goto Cleanup;
  2446. }
  2447. }
  2448. //
  2449. // Check that we do not have a duplicate object in the list
  2450. //
  2451. DuplicateObject = FALSE;
  2452. for (j = 0; j < ObjectCount; j++)
  2453. {
  2454. if (GuidObject == ObjectArray[j].GuidObject)
  2455. {
  2456. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_ERROR_LEVEL,
  2457. "WMI: Duplicate object %p passed to WmiReceiveNotifciations\n",
  2458. GuidObject));
  2459. ObDereferenceObject(GuidObject);
  2460. DuplicateObject = TRUE;
  2461. break;
  2462. }
  2463. }
  2464. if (! DuplicateObject)
  2465. {
  2466. //
  2467. // See if there was an irp attached to the guid object
  2468. // already. We'll need to cancel it if all guid objects
  2469. // are valid
  2470. //
  2471. if (GuidObject->Irp != NULL)
  2472. {
  2473. ReplacingIrp = 1;
  2474. }
  2475. //
  2476. // We note if there are any lo and hi priority events
  2477. //
  2478. ObjectArray[ObjectCount++].GuidObject = GuidObject;
  2479. if (WmipHaveHiPriorityEvent(GuidObject))
  2480. {
  2481. IsHighPriorityEvent = 1;
  2482. }
  2483. if (WmipHaveLoPriorityEvent(GuidObject))
  2484. {
  2485. IsLoPriorityEvent = 1;
  2486. }
  2487. //
  2488. // Clean up object in case it was part of a thread list
  2489. //
  2490. if (GuidObject->EventQueueAction == RECEIVE_ACTION_CREATE_THREAD)
  2491. {
  2492. WmipAssert(ReplacingIrp == 0);
  2493. WmipClearObjectFromThreadList(GuidObject);
  2494. }
  2495. //
  2496. // Calculate size needed to return data for this guid
  2497. //
  2498. HiTotalSizeNeeded += ((GuidObject->HiPriority.NextOffset + 7) & ~7);
  2499. LoTotalSizeNeeded += ((GuidObject->LoPriority.NextOffset + 7) & ~7);
  2500. }
  2501. }
  2502. //
  2503. // This is the total size needed to return all events
  2504. //
  2505. SizeNeeded = HiTotalSizeNeeded + LoTotalSizeNeeded;
  2506. //
  2507. // If any of the guid objects already had an irp attached then
  2508. // we need to complete that irp with an error and move on
  2509. //
  2510. if (ReplacingIrp == 1)
  2511. {
  2512. for (i = 0; i < ObjectCount; i++)
  2513. {
  2514. GuidObject = ObjectArray[i].GuidObject;
  2515. if (GuidObject->Irp != NULL)
  2516. {
  2517. WmipCompleteGuidIrpWithError(GuidObject);
  2518. }
  2519. }
  2520. }
  2521. if ( (IsHighPriorityEvent | IsLoPriorityEvent) != 0 )
  2522. {
  2523. if (SizeNeeded <= MaxBufferSize)
  2524. {
  2525. //
  2526. // There are events waiting to be recieved so pull them all
  2527. // out, high priority ones first then low priority ones. // events will show up first.
  2528. //
  2529. OutBuffer = (PUCHAR)ReceiveNotification;
  2530. LastWnode = NULL;
  2531. SizeLeft = MaxBufferSize;
  2532. SizeUsed = 0;
  2533. if (IsHighPriorityEvent != 0)
  2534. {
  2535. WmipCopyFromEventQueues(ObjectArray,
  2536. ObjectCount,
  2537. OutBuffer,
  2538. &SizeUsed,
  2539. &LastWnode,
  2540. TRUE);
  2541. WmipAssert(SizeUsed <= SizeLeft);
  2542. WmipAssert(SizeUsed = HiTotalSizeNeeded);
  2543. OutBuffer += SizeUsed;
  2544. SizeLeft -= SizeUsed;
  2545. }
  2546. if (IsLoPriorityEvent != 0)
  2547. {
  2548. WmipAssert(SizeLeft >= LoTotalSizeNeeded);
  2549. WmipCopyFromEventQueues(ObjectArray,
  2550. ObjectCount,
  2551. OutBuffer,
  2552. &SizeUsed,
  2553. &LastWnode,
  2554. FALSE);
  2555. WmipAssert(SizeUsed <= SizeLeft);
  2556. WmipAssert(SizeUsed == LoTotalSizeNeeded);
  2557. SizeLeft -= SizeUsed;
  2558. }
  2559. //
  2560. // We need to set the linkage field for the last wnode in
  2561. // the list to 0 so it can mark the end of the list
  2562. // correctly
  2563. //
  2564. if (LastWnode != NULL)
  2565. {
  2566. LastWnode->Linkage = 0;
  2567. }
  2568. //
  2569. // Compute the number of bytes used to fill the output
  2570. // buffer by subtracting the size left from the size passed
  2571. // in
  2572. //
  2573. *OutBufferSize = MaxBufferSize - SizeLeft;
  2574. } else {
  2575. //
  2576. // Not enough room to return all of the event data so we return
  2577. // a WNODE_TOO_SMALL to indicate the size needed
  2578. //
  2579. WnodeTooSmall = (PWNODE_TOO_SMALL)ReceiveNotification;
  2580. WnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  2581. WnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  2582. WnodeTooSmall->SizeNeeded = SizeNeeded;
  2583. *OutBufferSize = sizeof(WNODE_TOO_SMALL);
  2584. }
  2585. } else {
  2586. //
  2587. // There are no events waiting to be returned so we need to
  2588. // create our wait structures, pend the irp and return pending
  2589. //
  2590. if (ReceiveNotification->Action == RECEIVE_ACTION_NONE)
  2591. {
  2592. IrpListHead = IRP_OBJECT_LIST_HEAD(Irp);
  2593. InitializeListHead(IrpListHead);
  2594. for (i = 0; i < ObjectCount; i++)
  2595. {
  2596. GuidObject = ObjectArray[i].GuidObject;
  2597. GuidObject->Irp = Irp;
  2598. GuidObject->EventQueueAction = RECEIVE_ACTION_NONE;
  2599. InsertTailList(IrpListHead, &GuidObject->IrpObjectList);
  2600. }
  2601. IoSetCancelRoutine(Irp, WmipNotificationIrpCancel);
  2602. if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
  2603. {
  2604. Status = STATUS_CANCELLED;
  2605. } else {
  2606. IoMarkIrpPending(Irp);
  2607. Status = STATUS_PENDING;
  2608. }
  2609. } else if (ReceiveNotification->Action == RECEIVE_ACTION_CREATE_THREAD) {
  2610. //
  2611. // Pump has called us to tell us that it is shutting down so we
  2612. // need to establish a list linking the guid objects and
  2613. // stashing away the callback address
  2614. //
  2615. #if defined(_WIN64)
  2616. //
  2617. // For native Win64 processes, ensure that the thread start
  2618. // address is aligned properly
  2619. //
  2620. Wow64Process = _PsGetCurrentProcess()->Wow64Process;
  2621. if ((Wow64Process == NULL) &&
  2622. (((ULONG_PTR)ReceiveNotification->UserModeCallback.Handle64 & 0x7) != 0))
  2623. {
  2624. Status = STATUS_INVALID_PARAMETER;
  2625. goto Cleanup;
  2626. }
  2627. #endif
  2628. //
  2629. // Make sure that the process handle we get is valid and has
  2630. // enough permissions to create the thread
  2631. //
  2632. Status = ObReferenceObjectByHandle(ReceiveNotification->UserModeProcess.Handle,
  2633. PROCESS_CREATE_THREAD |
  2634. PROCESS_QUERY_INFORMATION |
  2635. PROCESS_VM_OPERATION |
  2636. PROCESS_VM_WRITE |
  2637. PROCESS_VM_READ ,
  2638. NULL,
  2639. UserMode,
  2640. &UserProcessObject,
  2641. NULL);
  2642. if (NT_SUCCESS(Status))
  2643. {
  2644. //
  2645. // Create a handle for the process that lives in the system
  2646. // handle table so that it will be available in any thread
  2647. // context. Note that one handle is created for each thread
  2648. // object list and the handle is closed when the last
  2649. // object is removed from the list
  2650. //
  2651. Status = ObOpenObjectByPointer(UserProcessObject,
  2652. OBJ_KERNEL_HANDLE,
  2653. NULL,
  2654. THREAD_ALL_ACCESS,
  2655. NULL,
  2656. KernelMode,
  2657. &UserModeProcess);
  2658. if (NT_SUCCESS(Status))
  2659. {
  2660. //
  2661. // Get the default stack size and commit for this
  2662. // process and store it away in the guid object so
  2663. // that the pump threads created from kernel will
  2664. // have appropriatly sized stacks
  2665. //
  2666. try {
  2667. NtHeaders = RtlImageNtHeader(_PsGetCurrentProcess()->SectionBaseAddress);
  2668. if (NtHeaders != NULL)
  2669. {
  2670. #if defined(_WIN64)
  2671. if (Wow64Process != NULL) {
  2672. NtHeaders32 = (PIMAGE_NT_HEADERS32) NtHeaders;
  2673. StackSize = NtHeaders32->OptionalHeader.SizeOfStackReserve;
  2674. StackCommit = NtHeaders32->OptionalHeader.SizeOfStackCommit;
  2675. } else {
  2676. #endif
  2677. StackSize = NtHeaders->OptionalHeader.SizeOfStackReserve;
  2678. StackCommit = NtHeaders->OptionalHeader.SizeOfStackCommit;
  2679. #if defined(_WIN64)
  2680. }
  2681. #endif
  2682. } else {
  2683. StackSize = 0;
  2684. StackCommit = 0;
  2685. }
  2686. } except (EXCEPTION_EXECUTE_HANDLER) {
  2687. StackSize = 0;
  2688. StackCommit = 0;
  2689. }
  2690. GuidObject = ObjectArray[0].GuidObject;
  2691. GuidObject->UserModeCallback = (PUSER_THREAD_START_ROUTINE)(ULONG_PTR)ReceiveNotification->UserModeCallback.Handle;
  2692. GuidObject->EventQueueAction = RECEIVE_ACTION_CREATE_THREAD;
  2693. GuidObject->UserModeProcess = UserModeProcess;
  2694. GuidObject->StackSize = StackSize;
  2695. GuidObject->StackCommit = StackCommit;
  2696. ThreadListHead = &GuidObject->ThreadObjectList;
  2697. InitializeListHead(ThreadListHead);
  2698. for (i = 1; i < ObjectCount; i++)
  2699. {
  2700. GuidObject = ObjectArray[i].GuidObject;
  2701. GuidObject->UserModeCallback = (PUSER_THREAD_START_ROUTINE)(ULONG_PTR)ReceiveNotification->UserModeCallback.Handle;
  2702. GuidObject->EventQueueAction = RECEIVE_ACTION_CREATE_THREAD;
  2703. GuidObject->UserModeProcess = UserModeProcess;
  2704. GuidObject->StackSize = StackSize;
  2705. GuidObject->StackCommit = StackCommit;
  2706. InsertTailList(ThreadListHead, &GuidObject->ThreadObjectList);
  2707. }
  2708. }
  2709. ObDereferenceObject(UserProcessObject);
  2710. }
  2711. *OutBufferSize = 0;
  2712. }
  2713. }
  2714. Cleanup:
  2715. //
  2716. // Remove any object references that we took and free memory for
  2717. // the object array
  2718. //
  2719. WmipLeaveSMCritSection();
  2720. for (i = 0; i < ObjectCount; i++)
  2721. {
  2722. ObDereferenceObject(ObjectArray[i].GuidObject);
  2723. }
  2724. if (ObjectArray != StaticObjects)
  2725. {
  2726. WmipFree(ObjectArray);
  2727. }
  2728. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_EVENT_INFO_LEVEL,
  2729. "WMI: RCV Notification call -> 0x%x\n", Status));
  2730. return(Status);
  2731. }
  2732. NTSTATUS
  2733. WmipCsrClientMessageServer(
  2734. IN PVOID CsrPort,
  2735. IN OUT PCSR_API_MSG m,
  2736. IN CSR_API_NUMBER ApiNumber,
  2737. IN ULONG ArgLength
  2738. )
  2739. /*++
  2740. Routine Description:
  2741. This function sends an API datagram to the Windows Emulation Subsystem
  2742. Server.
  2743. Arguments:
  2744. CsrPort - pointer to LPC port object that is connected to CSR on
  2745. behalf of this process
  2746. m - Pointer to the API request message to send.
  2747. ApiNumber - Small integer that is the number of the API being called.
  2748. ArgLength - Length, in bytes, of the argument portion located at the
  2749. end of the request message. Used to calculate the length of the
  2750. request message.
  2751. Return Value:
  2752. Status Code from either client or server
  2753. --*/
  2754. {
  2755. NTSTATUS Status;
  2756. //
  2757. // Initialize the header of the message.
  2758. //
  2759. if ((LONG)ArgLength < 0)
  2760. {
  2761. ArgLength = (ULONG)(-(LONG)ArgLength);
  2762. m->h.u2.s2.Type = 0;
  2763. } else {
  2764. m->h.u2.ZeroInit = 0;
  2765. }
  2766. ArgLength |= (ArgLength << 16);
  2767. ArgLength += ((sizeof( CSR_API_MSG ) - sizeof( m->u )) << 16) |
  2768. (FIELD_OFFSET( CSR_API_MSG, u ) - sizeof( m->h ));
  2769. m->h.u1.Length = ArgLength;
  2770. m->CaptureBuffer = NULL;
  2771. m->ApiNumber = ApiNumber;
  2772. Status = LpcRequestPort( CsrPort,
  2773. (PPORT_MESSAGE)m);
  2774. //
  2775. // Check for failed status and do something.
  2776. //
  2777. if (! NT_SUCCESS( Status ))
  2778. {
  2779. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_ERROR_LEVEL,
  2780. "WMI: %p.%p LpcRequestPort failed %x\n",
  2781. NtCurrentTeb()->ClientId.UniqueProcess,
  2782. NtCurrentTeb()->ClientId.UniqueThread,
  2783. Status));
  2784. WmipAssert(FALSE);
  2785. m->ReturnValue = Status;
  2786. }
  2787. //
  2788. // The value of this function is whatever the server function returned.
  2789. //
  2790. return( m->ReturnValue );
  2791. }
  2792. VOID WmipPumpThreadApc(
  2793. IN PKAPC Apc,
  2794. IN PKNORMAL_ROUTINE *NormalRoutine,
  2795. IN PVOID *NormalContext,
  2796. IN PVOID *SystemArgument1,
  2797. IN PVOID *SystemArgument2
  2798. )
  2799. /*++
  2800. Routine Description:
  2801. Kernel mode APC that will register the current thread with CSR
  2802. Arguments:
  2803. Return Value:
  2804. --*/
  2805. {
  2806. BASE_API_MSG m;
  2807. PBASE_CREATETHREAD_MSG a = &m.u.CreateThread;
  2808. PEPROCESS Process;
  2809. UNREFERENCED_PARAMETER (NormalRoutine);
  2810. UNREFERENCED_PARAMETER (NormalContext);
  2811. UNREFERENCED_PARAMETER (SystemArgument1);
  2812. UNREFERENCED_PARAMETER (SystemArgument2);
  2813. //
  2814. // Free memory used by APC
  2815. //
  2816. ExFreePool(Apc);
  2817. //
  2818. // Get the ExceptionPort from the process object. In a Win32
  2819. // process this port is set by CSR to allow it to be notified when
  2820. // an exception occurs. This code will also use it to register this
  2821. // thread with CSR. Note that if the exception port is NULL then
  2822. // the process is not a Win32 process and it doesn't matter if the
  2823. // thread doesn't get registered.
  2824. //
  2825. Process = PsGetCurrentProcess();
  2826. if (Process->ExceptionPort != NULL)
  2827. {
  2828. a->ThreadHandle = NULL;
  2829. a->ClientId = NtCurrentTeb()->ClientId;
  2830. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,
  2831. "WMI: Sending message To CSR for %p.%p\n",
  2832. NtCurrentTeb()->ClientId.UniqueProcess,
  2833. NtCurrentTeb()->ClientId.UniqueThread));
  2834. WmipCsrClientMessageServer( Process->ExceptionPort,
  2835. (PCSR_API_MSG)&m,
  2836. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  2837. BasepRegisterThread
  2838. ),
  2839. sizeof( *a )
  2840. );
  2841. } else {
  2842. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_ERROR_LEVEL,
  2843. "WMI: %p.%p Process %p has no exception port\n",
  2844. NtCurrentTeb()->ClientId.UniqueProcess,
  2845. NtCurrentTeb()->ClientId.UniqueThread,
  2846. Process));
  2847. WmipAssert(FALSE);
  2848. }
  2849. }
  2850. NTSTATUS WmipCreatePumpThread(
  2851. PWMIGUIDOBJECT Object
  2852. )
  2853. {
  2854. NTSTATUS Status = STATUS_SUCCESS;
  2855. HANDLE ThreadHandle;
  2856. PKAPC Apc;
  2857. PKTHREAD ThreadObj;
  2858. PAGED_CODE();
  2859. //
  2860. // First off we need to create the pump thread suspended so we'll
  2861. // have a chance to queue a kernel apc before the thread starts
  2862. // running
  2863. //
  2864. WmipEnterSMCritSection();
  2865. if (Object->UserModeProcess != NULL)
  2866. {
  2867. Status = RtlCreateUserThread(Object->UserModeProcess,
  2868. NULL,
  2869. TRUE,
  2870. 0,
  2871. Object->StackSize,
  2872. Object->StackCommit,
  2873. Object->UserModeCallback,
  2874. (PVOID)0x1f1f1f1f,
  2875. &ThreadHandle,
  2876. NULL);
  2877. if (NT_SUCCESS(Status))
  2878. {
  2879. //
  2880. // Queue a kernel mode apc that will call into CSR to register
  2881. // this newly created thread. Note that if the APC cannot be
  2882. // run it is not fatal as we can allow the thread to run
  2883. // without being registered with CSR. The APC is freed at the
  2884. // end of the APC routine
  2885. //
  2886. Status = ObReferenceObjectByHandle(ThreadHandle,
  2887. 0,
  2888. NULL,
  2889. KernelMode,
  2890. &ThreadObj,
  2891. NULL);
  2892. if (NT_SUCCESS(Status))
  2893. {
  2894. Apc = WmipAllocNP(sizeof(KAPC));
  2895. if (Apc != NULL)
  2896. {
  2897. KeInitializeApc(Apc,
  2898. ThreadObj,
  2899. OriginalApcEnvironment,
  2900. WmipPumpThreadApc,
  2901. NULL,
  2902. NULL,
  2903. KernelMode,
  2904. NULL);
  2905. if (! KeInsertQueueApc(Apc,
  2906. NULL,
  2907. NULL,
  2908. 0))
  2909. {
  2910. ExFreePool(Apc);
  2911. WmipAssert(FALSE);
  2912. }
  2913. }
  2914. ObDereferenceObject(ThreadObj);
  2915. } else {
  2916. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_ERROR_LEVEL,
  2917. "WMI: ObRef(ThreadObj) failed %x\n",
  2918. Status));
  2919. WmipAssert(FALSE);
  2920. //
  2921. // Status is still successful since the pump thread was
  2922. // created, just not registered with CSR
  2923. //
  2924. Status = STATUS_SUCCESS;
  2925. }
  2926. //
  2927. // If we successfully created the pump thread then mark all of
  2928. // the related objects as not needing any thread creation
  2929. // anymore
  2930. //
  2931. WmipClearThreadObjectList(Object);
  2932. WmipLeaveSMCritSection();
  2933. ZwResumeThread(ThreadHandle,
  2934. NULL);
  2935. ZwClose(ThreadHandle);
  2936. } else {
  2937. WmipLeaveSMCritSection();
  2938. }
  2939. } else {
  2940. WmipLeaveSMCritSection();
  2941. }
  2942. return(Status);
  2943. }
  2944. void WmipCreatePumpThreadRoutine(
  2945. PVOID Context
  2946. )
  2947. /*+++
  2948. Routine Description:
  2949. This routine is a worker routine that will create a user mode pump
  2950. thread so that events can be delivered.
  2951. Arguments:
  2952. Context is a pointer to a CREATETHREADWORKITEM struct. It is freed
  2953. in this routine
  2954. Return Value:
  2955. ---*/
  2956. {
  2957. PCREATETHREADWORKITEM WorkItem = (PCREATETHREADWORKITEM)Context;
  2958. NTSTATUS Status;
  2959. PAGED_CODE();
  2960. if (ObReferenceObjectSafe(WorkItem->Object))
  2961. {
  2962. //
  2963. // Only continue if the object is not being deleted
  2964. //
  2965. Status = WmipCreatePumpThread(WorkItem->Object);
  2966. if (! NT_SUCCESS(Status))
  2967. {
  2968. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_ERROR_LEVEL,
  2969. "WMI: Delayed pump thread creation failed %x\n",
  2970. Status));
  2971. }
  2972. ObDereferenceObject(WorkItem->Object);
  2973. }
  2974. //
  2975. // Release reference to object taken when work item was queued
  2976. //
  2977. ObDereferenceObject(WorkItem->Object);
  2978. ExFreePool(WorkItem);
  2979. }
  2980. #define WmipQueueEventToObject(Object, Wnode, IsHighPriority) \
  2981. WmipQueueNotification(Object, IsHighPriority ? &Object->HiPriority : \
  2982. &Object->LoPriority, \
  2983. Wnode);
  2984. NTSTATUS WmipQueueNotification(
  2985. PWMIGUIDOBJECT Object,
  2986. PWMIEVENTQUEUE EventQueue,
  2987. PWNODE_HEADER Wnode
  2988. )
  2989. {
  2990. //
  2991. // This routine assumes that the SMCritSection is held
  2992. //
  2993. PUCHAR Buffer;
  2994. ULONG InWnodeSize;
  2995. ULONG NextOffset;
  2996. PUCHAR DestPtr;
  2997. PWNODE_HEADER LastWnode;
  2998. NTSTATUS Status;
  2999. ULONG SizeNeeded;
  3000. PCREATETHREADWORKITEM WorkItem;
  3001. PAGED_CODE();
  3002. //
  3003. // If there is not a buffer allocated to store the event then
  3004. // allocate one
  3005. //
  3006. if (EventQueue->Buffer == NULL)
  3007. {
  3008. //
  3009. // If we get an event that is larger than the default max
  3010. // buffer size then we bump the buffer size up to 64K, unless
  3011. // it is larger than 64K where we bump up to the actual size of
  3012. // the event.
  3013. //
  3014. SizeNeeded = (Wnode->BufferSize + 7) & ~7;
  3015. if (SizeNeeded > EventQueue->MaxBufferSize) {
  3016. EventQueue->MaxBufferSize = (SizeNeeded >= 65536) ? SizeNeeded : 65536;
  3017. }
  3018. Buffer = WmipAlloc(EventQueue->MaxBufferSize);
  3019. if (Buffer != NULL)
  3020. {
  3021. EventQueue->Buffer = Buffer;
  3022. EventQueue->NextOffset = 0;
  3023. EventQueue->LastWnode = NULL;
  3024. } else {
  3025. EventQueue->EventsLost++;
  3026. WmipDebugPrintEx((DPFLTR_WMICORE_ID,
  3027. DPFLTR_EVENT_INFO_LEVEL,
  3028. "WMI: Event 0x%x lost for object %p since could not alloc\n",
  3029. EventQueue->EventsLost, Object));
  3030. return(STATUS_INSUFFICIENT_RESOURCES);
  3031. }
  3032. } else {
  3033. Buffer = EventQueue->Buffer;
  3034. }
  3035. //
  3036. // See if there is room to queue the WNODE
  3037. //
  3038. InWnodeSize = Wnode->BufferSize;
  3039. NextOffset = ((EventQueue->NextOffset + InWnodeSize) + 7) &~7;
  3040. if (NextOffset <= EventQueue->MaxBufferSize)
  3041. {
  3042. //
  3043. // Link the previous wnode to this one, copy in the new wnode
  3044. // and update the pointer to next free space
  3045. //
  3046. DestPtr = Buffer + EventQueue->NextOffset;
  3047. LastWnode = EventQueue->LastWnode;
  3048. if (LastWnode != NULL)
  3049. {
  3050. LastWnode->Linkage = (ULONG) ((PCHAR)DestPtr - (PCHAR)LastWnode);
  3051. }
  3052. EventQueue->LastWnode = (PWNODE_HEADER)DestPtr;
  3053. EventQueue->NextOffset = NextOffset;
  3054. memcpy(DestPtr, Wnode, InWnodeSize);
  3055. //
  3056. // Guid object gets signalled when event is placed into queue
  3057. //
  3058. KeSetEvent(&Object->Event, 0, FALSE);
  3059. //
  3060. // If consumer requested that we autostart a thread then we do
  3061. // that now
  3062. //
  3063. if (Object->EventQueueAction == RECEIVE_ACTION_CREATE_THREAD)
  3064. {
  3065. if (KeIsAttachedProcess())
  3066. {
  3067. //
  3068. // If the current thread is attached to a process then
  3069. // it is not safe to create a thread. So we queue a
  3070. // work item and let the work item create it
  3071. //
  3072. WorkItem = ExAllocatePoolWithTag(NonPagedPool,
  3073. sizeof(CREATETHREADWORKITEM),
  3074. WMIPCREATETHREADTAG);
  3075. if (WorkItem != NULL)
  3076. {
  3077. //
  3078. // Take reference on object. Reference released in
  3079. // worker routine
  3080. //
  3081. Status = ObReferenceObjectByPointer(Object,
  3082. 0,
  3083. NULL,
  3084. KernelMode);
  3085. if (NT_SUCCESS(Status))
  3086. {
  3087. WorkItem->Object = Object;
  3088. ExInitializeWorkItem(&WorkItem->WorkItem,
  3089. WmipCreatePumpThreadRoutine,
  3090. WorkItem);
  3091. ExQueueWorkItem(&WorkItem->WorkItem,
  3092. DelayedWorkQueue);
  3093. } else {
  3094. WmipDebugPrintEx((DPFLTR_WMICORE_ID,
  3095. DPFLTR_ERROR_LEVEL,
  3096. "WMI: Ref on object %p failed %x for queuing notification work item\n",
  3097. Object,
  3098. Status));
  3099. ExFreePool(WorkItem);
  3100. }
  3101. } else {
  3102. Status = STATUS_INSUFFICIENT_RESOURCES;
  3103. }
  3104. } else {
  3105. Status = WmipCreatePumpThread(Object);
  3106. }
  3107. if (! NT_SUCCESS(Status))
  3108. {
  3109. EventQueue->EventsLost++;
  3110. WmipDebugPrintEx((DPFLTR_WMICORE_ID,
  3111. DPFLTR_EVENT_INFO_LEVEL,
  3112. "WMI: Event 0x%x lost for object %p since Thread create Failed\n",
  3113. EventQueue->EventsLost, Object));
  3114. }
  3115. } else {
  3116. Status = STATUS_SUCCESS;
  3117. }
  3118. } else {
  3119. //
  3120. // Not enough space, throw away the event
  3121. //
  3122. EventQueue->EventsLost++;
  3123. WmipDebugPrintEx((DPFLTR_WMICORE_ID,
  3124. DPFLTR_EVENT_INFO_LEVEL,
  3125. "WMI: Event 0x%x lost for object %p since too large 0x%x\n",
  3126. EventQueue->EventsLost, Object, Wnode->BufferSize));
  3127. Status = STATUS_BUFFER_TOO_SMALL;
  3128. }
  3129. return(Status);
  3130. }
  3131. PWNODE_HEADER WmipDereferenceEvent(
  3132. PWNODE_HEADER Wnode
  3133. )
  3134. {
  3135. ULONG WnodeTargetSize;
  3136. ULONG IsStaticInstanceNames;
  3137. ULONG InstanceNameLen, InstanceNameLen2;
  3138. PWNODE_SINGLE_INSTANCE WnodeTarget;
  3139. PWCHAR Ptr;
  3140. PWNODE_EVENT_REFERENCE WnodeRef = (PWNODE_EVENT_REFERENCE)Wnode;
  3141. PBDATASOURCE DataSource;
  3142. NTSTATUS Status;
  3143. ULONG Retries;
  3144. PAGED_CODE();
  3145. //
  3146. // Determine if the data source is valid or not
  3147. //
  3148. DataSource = WmipFindDSByProviderId(WnodeRef->WnodeHeader.ProviderId);
  3149. if (DataSource == NULL)
  3150. {
  3151. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_EVENT_INFO_LEVEL,
  3152. "WMI: Invalid Data Source in referenced guid \n"));
  3153. return(NULL);
  3154. }
  3155. //
  3156. // Compute the size of any dynamic name that must go into the TargetWnode
  3157. //
  3158. IsStaticInstanceNames = WnodeRef->WnodeHeader.Flags &
  3159. WNODE_FLAG_STATIC_INSTANCE_NAMES;
  3160. if (IsStaticInstanceNames == 0)
  3161. {
  3162. InstanceNameLen = *WnodeRef->TargetInstanceName + sizeof(USHORT);
  3163. } else {
  3164. InstanceNameLen = 0;
  3165. }
  3166. WnodeTargetSize = WnodeRef->TargetDataBlockSize +
  3167. FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  3168. VariableData) +
  3169. InstanceNameLen +
  3170. 8;
  3171. Retries = 0;
  3172. do
  3173. {
  3174. WnodeTarget = WmipAllocNP(WnodeTargetSize);
  3175. if (WnodeTarget != NULL)
  3176. {
  3177. //
  3178. // Build WNODE_SINGLE_INSTANCE that we use to query for event data
  3179. //
  3180. memset(WnodeTarget, 0, WnodeTargetSize);
  3181. WnodeTarget->WnodeHeader.BufferSize = WnodeTargetSize;
  3182. WnodeTarget->WnodeHeader.ProviderId = WnodeRef->WnodeHeader.ProviderId;
  3183. memcpy(&WnodeTarget->WnodeHeader.Guid,
  3184. &WnodeRef->TargetGuid,
  3185. sizeof(GUID));
  3186. WnodeTarget->WnodeHeader.Version = WnodeRef->WnodeHeader.Version;
  3187. WnodeTarget->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE |
  3188. IsStaticInstanceNames;
  3189. if (IsStaticInstanceNames != 0)
  3190. {
  3191. WnodeTarget->InstanceIndex = WnodeRef->TargetInstanceIndex;
  3192. WnodeTarget->DataBlockOffset = FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  3193. VariableData);
  3194. } else {
  3195. WnodeTarget->OffsetInstanceName = FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  3196. VariableData);
  3197. Ptr = (PWCHAR)OffsetToPtr(WnodeTarget, WnodeTarget->OffsetInstanceName);
  3198. InstanceNameLen2 = InstanceNameLen - sizeof(USHORT);
  3199. *Ptr++ = (USHORT)InstanceNameLen2;
  3200. memcpy(Ptr,
  3201. &WnodeRef->TargetInstanceName[1],
  3202. InstanceNameLen2);
  3203. //
  3204. // Round data block offset to 8 byte alignment
  3205. //
  3206. WnodeTarget->DataBlockOffset = ((FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  3207. VariableData) +
  3208. InstanceNameLen2 +
  3209. sizeof(USHORT)+7) & 0xfffffff8);
  3210. }
  3211. Status = WmipDeliverWnodeToDS(IRP_MN_QUERY_SINGLE_INSTANCE,
  3212. DataSource,
  3213. (PWNODE_HEADER)WnodeTarget,
  3214. WnodeTargetSize);
  3215. if (NT_SUCCESS(Status) &&
  3216. (WnodeTarget->WnodeHeader.Flags & WNODE_FLAG_TOO_SMALL))
  3217. {
  3218. WnodeTargetSize = ((PWNODE_TOO_SMALL)WnodeTarget)->SizeNeeded;
  3219. WmipFree(WnodeTarget);
  3220. Retries++;
  3221. Status = STATUS_BUFFER_TOO_SMALL;
  3222. }
  3223. } else {
  3224. Status = STATUS_INSUFFICIENT_RESOURCES;
  3225. }
  3226. } while ((Status == STATUS_BUFFER_TOO_SMALL) && (Retries < 2));
  3227. WmipUnreferenceDS(DataSource);
  3228. if (! NT_SUCCESS(Status))
  3229. {
  3230. WmipReportEventLog(EVENT_WMI_CANT_GET_EVENT_DATA,
  3231. EVENTLOG_WARNING_TYPE,
  3232. 0,
  3233. Wnode->BufferSize,
  3234. Wnode,
  3235. 0,
  3236. NULL);
  3237. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_ERROR_LEVEL,
  3238. "WMI: Query to dereference WNODE failed %d\n",
  3239. Status));
  3240. if (WnodeTarget != NULL)
  3241. {
  3242. WmipFree(WnodeTarget);
  3243. WnodeTarget = NULL;
  3244. }
  3245. } else {
  3246. WnodeTarget->WnodeHeader.Flags |= (WnodeRef->WnodeHeader.Flags &
  3247. WNODE_FLAG_SEVERITY_MASK) |
  3248. WNODE_FLAG_EVENT_ITEM;
  3249. }
  3250. return((PWNODE_HEADER)WnodeTarget);
  3251. }
  3252. PWNODE_HEADER WmipIncludeStaticNames(
  3253. PWNODE_HEADER Wnode
  3254. )
  3255. {
  3256. PWNODE_HEADER ReturnWnode = Wnode;
  3257. PWNODE_HEADER WnodeFull;
  3258. PWNODE_ALL_DATA WnodeAllData;
  3259. PWNODE_SINGLE_INSTANCE WnodeSI;
  3260. PWCHAR InstanceName = NULL;
  3261. SIZE_T InstanceNameLen = 0;
  3262. ULONG InstanceIndex;
  3263. LPGUID EventGuid = &Wnode->Guid;
  3264. SIZE_T WnodeFullSize;
  3265. PWCHAR TargetInstanceName;
  3266. WCHAR Index[MAXBASENAMESUFFIXSIZE+1];
  3267. ULONG TargetProviderId;
  3268. BOOLEAN IsError;
  3269. PBINSTANCESET TargetInstanceSet;
  3270. PBGUIDENTRY GuidEntry;
  3271. PLIST_ENTRY InstanceSetList;
  3272. PBINSTANCESET InstanceSet;
  3273. PAGED_CODE();
  3274. IsError = TRUE;
  3275. TargetInstanceSet = NULL;
  3276. GuidEntry = WmipFindGEByGuid(EventGuid, FALSE);
  3277. if (GuidEntry != NULL)
  3278. {
  3279. //
  3280. // Loop over all instance sets to find the one that corresponds
  3281. // to our provider id
  3282. //
  3283. TargetProviderId = Wnode->ProviderId;
  3284. WmipEnterSMCritSection();
  3285. InstanceSetList = GuidEntry->ISHead.Flink;
  3286. while (InstanceSetList != &GuidEntry->ISHead)
  3287. {
  3288. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  3289. INSTANCESET,
  3290. GuidISList);
  3291. if (InstanceSet->ProviderId == TargetProviderId)
  3292. {
  3293. //
  3294. // We found the instance set corrsponding to the provider id
  3295. //
  3296. TargetInstanceSet = InstanceSet;
  3297. WmipReferenceIS(TargetInstanceSet);
  3298. break;
  3299. }
  3300. InstanceSetList = InstanceSetList->Flink;
  3301. }
  3302. WmipLeaveSMCritSection();
  3303. //
  3304. // Remove ref on the guid entry as we have refed the TargetInstanceSet
  3305. //
  3306. WmipUnreferenceGE(GuidEntry);
  3307. }
  3308. if (TargetInstanceSet != NULL)
  3309. {
  3310. if ((TargetInstanceSet->Flags &
  3311. (IS_INSTANCE_BASENAME | IS_INSTANCE_STATICNAMES)) != 0)
  3312. {
  3313. if (Wnode->Flags & WNODE_FLAG_ALL_DATA)
  3314. {
  3315. //
  3316. // Fill instance names in WNODE_ALL_DATA. Allocate a
  3317. // new buffer to hold all of the original wnode plus
  3318. // the instance names. We need to add space for padding
  3319. // the wnode to 4 bytes plus space for the array of
  3320. // offsets to instance names plus space for the instanc
  3321. // names
  3322. //
  3323. WnodeFullSize = ((Wnode->BufferSize+3) & ~3) +
  3324. (TargetInstanceSet->Count * sizeof(ULONG)) +
  3325. WmipStaticInstanceNameSize(TargetInstanceSet);
  3326. WnodeFull = WmipAlloc(WnodeFullSize);
  3327. if (WnodeFull != NULL)
  3328. {
  3329. memcpy(WnodeFull, Wnode, Wnode->BufferSize);
  3330. WnodeAllData = (PWNODE_ALL_DATA)WnodeFull;
  3331. WmipInsertStaticNames(WnodeAllData,
  3332. (ULONG)WnodeFullSize,
  3333. TargetInstanceSet);
  3334. ReturnWnode = WnodeFull;
  3335. IsError = FALSE;
  3336. }
  3337. } else if ((Wnode->Flags & WNODE_FLAG_SINGLE_INSTANCE) ||
  3338. (Wnode->Flags & WNODE_FLAG_SINGLE_ITEM)) {
  3339. //
  3340. // Fill instance names in WNODE_SINGLE_INSTANCE or
  3341. // _ITEM.
  3342. //
  3343. WnodeFull = Wnode;
  3344. WnodeSI = (PWNODE_SINGLE_INSTANCE)Wnode;
  3345. InstanceIndex = WnodeSI->InstanceIndex;
  3346. if (InstanceIndex < TargetInstanceSet->Count)
  3347. {
  3348. if (TargetInstanceSet->Flags & IS_INSTANCE_STATICNAMES)
  3349. {
  3350. InstanceName = TargetInstanceSet->IsStaticNames->StaticNamePtr[InstanceIndex];
  3351. InstanceNameLen = (wcslen(InstanceName) + 2) *
  3352. sizeof(WCHAR);
  3353. } else if (TargetInstanceSet->Flags & IS_INSTANCE_BASENAME) {
  3354. InstanceName = TargetInstanceSet->IsBaseName->BaseName;
  3355. InstanceNameLen = (wcslen(InstanceName) + 2 +
  3356. MAXBASENAMESUFFIXSIZE) * sizeof(WCHAR);
  3357. }
  3358. //
  3359. // Allocate a new Wnode and fill in the instance
  3360. // name. Include space for padding the wnode to a 2
  3361. // byte boundry and space for the instance name
  3362. //
  3363. WnodeFullSize = ((Wnode->BufferSize+1) & ~1) +
  3364. InstanceNameLen;
  3365. WnodeFull = WmipAlloc(WnodeFullSize);
  3366. if (WnodeFull != NULL)
  3367. {
  3368. memcpy(WnodeFull, Wnode, Wnode->BufferSize);
  3369. WnodeFull->BufferSize = (ULONG)WnodeFullSize;
  3370. WnodeSI = (PWNODE_SINGLE_INSTANCE)WnodeFull;
  3371. WnodeSI->OffsetInstanceName = (Wnode->BufferSize+1)& ~1;
  3372. TargetInstanceName = (PWCHAR)((PUCHAR)WnodeSI + WnodeSI->OffsetInstanceName);
  3373. if (TargetInstanceSet->Flags & IS_INSTANCE_STATICNAMES)
  3374. {
  3375. InstanceNameLen -= sizeof(WCHAR);
  3376. *TargetInstanceName++ = (USHORT)InstanceNameLen;
  3377. StringCbCopy(TargetInstanceName,
  3378. InstanceNameLen,
  3379. InstanceName);
  3380. } else {
  3381. if (TargetInstanceSet->Flags & IS_PDO_INSTANCENAME)
  3382. {
  3383. WnodeFull->Flags |= WNODE_FLAG_PDO_INSTANCE_NAMES;
  3384. }
  3385. StringCbPrintf(Index,
  3386. sizeof(Index),
  3387. BASENAMEFORMATSTRING,
  3388. TargetInstanceSet->IsBaseName->BaseIndex +
  3389. InstanceIndex);
  3390. StringCbCopy(TargetInstanceName+1,
  3391. InstanceNameLen,
  3392. InstanceName);
  3393. StringCbCat(TargetInstanceName+1,
  3394. InstanceNameLen,
  3395. Index);
  3396. InstanceNameLen = wcslen(TargetInstanceName+1);
  3397. *TargetInstanceName = ((USHORT)InstanceNameLen+1) * sizeof(WCHAR);
  3398. }
  3399. IsError = FALSE;
  3400. ReturnWnode = WnodeFull;
  3401. }
  3402. }
  3403. }
  3404. }
  3405. }
  3406. if (IsError)
  3407. {
  3408. //
  3409. // If we had an error resolving the instance name then report it
  3410. // and remove the instance name from the event.
  3411. //
  3412. WmipReportEventLog(EVENT_WMI_CANT_RESOLVE_INSTANCE,
  3413. EVENTLOG_WARNING_TYPE,
  3414. 0,
  3415. Wnode->BufferSize,
  3416. Wnode,
  3417. 0,
  3418. NULL);
  3419. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_WARNING_LEVEL,
  3420. "WMI: Static instance name in event, but error processing\n"));
  3421. if (Wnode->Flags & WNODE_FLAG_ALL_DATA)
  3422. {
  3423. WnodeAllData = (PWNODE_ALL_DATA)Wnode;
  3424. WnodeAllData->OffsetInstanceNameOffsets = 0;
  3425. } else if ((Wnode->Flags & WNODE_FLAG_SINGLE_INSTANCE) ||
  3426. (Wnode->Flags & WNODE_FLAG_SINGLE_ITEM))
  3427. {
  3428. WnodeSI = (PWNODE_SINGLE_INSTANCE)Wnode;
  3429. WnodeSI->OffsetInstanceName = 0;
  3430. }
  3431. }
  3432. if (TargetInstanceSet != NULL)
  3433. {
  3434. WmipUnreferenceIS(TargetInstanceSet);
  3435. }
  3436. return(ReturnWnode);
  3437. }
  3438. NTSTATUS WmipWriteWnodeToObject(
  3439. PWMIGUIDOBJECT Object,
  3440. PWNODE_HEADER Wnode,
  3441. BOOLEAN IsHighPriority
  3442. )
  3443. /*+++
  3444. Routine Description:
  3445. This routine will write a WNODE into the queue of events to be returned
  3446. for a guid object. If there is an irp already waiting then it will be
  3447. satisfied with the event otherwise it will be queued in the objects
  3448. buffer.
  3449. This routine assumes that the SM Critical section is held
  3450. Arguments:
  3451. Object is the object to which to send the request
  3452. Wnode is the Wnode with the event
  3453. IsHighPriority is TRUE if the event should go into the high priority
  3454. queue
  3455. Return Value:
  3456. STATUS_SUCCESS or an error code
  3457. ---*/
  3458. {
  3459. PIRP Irp;
  3460. ULONG WnodeSize;
  3461. PUCHAR OutBuffer;
  3462. ULONG OutBufferSize;
  3463. PIO_STACK_LOCATION IrpStack;
  3464. PWNODE_TOO_SMALL WnodeTooSmall;
  3465. NTSTATUS Status;
  3466. PAGED_CODE();
  3467. //
  3468. // Someone has registered to recieve this event so
  3469. // see if there is an irp waiting to be completed or
  3470. // if we should just queue it
  3471. //
  3472. Irp = Object->Irp;
  3473. if ((Irp != NULL) &&
  3474. (IoSetCancelRoutine(Irp, NULL)))
  3475. {
  3476. //
  3477. // There is an irp waiting for this event, copy out the
  3478. // event and complete the irp
  3479. //
  3480. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  3481. OutBuffer = Irp->AssociatedIrp.SystemBuffer;
  3482. OutBufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  3483. WnodeSize = Wnode->BufferSize;
  3484. if (WnodeSize > OutBufferSize)
  3485. {
  3486. //
  3487. // There is not enough room to return the event so
  3488. // we return a WNODE_TOO_SMALL with the size needed
  3489. // and then go and queue the event
  3490. //
  3491. WmipAssert(OutBufferSize >= sizeof(WNODE_TOO_SMALL));
  3492. WnodeTooSmall = (PWNODE_TOO_SMALL)OutBuffer;
  3493. WnodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
  3494. WnodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
  3495. WnodeTooSmall->SizeNeeded = WnodeSize;
  3496. WnodeSize = sizeof(WNODE_TOO_SMALL);
  3497. Status = WmipQueueEventToObject(Object,
  3498. Wnode,
  3499. IsHighPriority);
  3500. } else {
  3501. //
  3502. // Plenty of room, copy the event into the irp
  3503. // buffer and complete the irp
  3504. //
  3505. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_EVENT_INFO_LEVEL,
  3506. "WMI: Returning event to waiting irp for object %p\n", Object));
  3507. RtlCopyMemory(OutBuffer, Wnode, WnodeSize);
  3508. Status = STATUS_SUCCESS;
  3509. }
  3510. //
  3511. // Remove link from all objects associated with the irp
  3512. // since now the irp is going away.
  3513. //
  3514. WmipClearIrpObjectList(Irp);
  3515. Irp->IoStatus.Information = WnodeSize;
  3516. Irp->IoStatus.Status = STATUS_SUCCESS;
  3517. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3518. } else {
  3519. //
  3520. // There is no irp waiting to receive the event so we
  3521. // need to queue it if we can
  3522. //
  3523. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_EVENT_INFO_LEVEL,
  3524. "WMI: Queued event to object %p\n", Object));
  3525. Status = WmipQueueEventToObject(Object,
  3526. Wnode,
  3527. IsHighPriority);
  3528. }
  3529. return(Status);
  3530. }
  3531. NTSTATUS WmipProcessEvent(
  3532. PWNODE_HEADER InWnode,
  3533. BOOLEAN IsHighPriority,
  3534. BOOLEAN FreeBuffer
  3535. )
  3536. {
  3537. LPGUID Guid;
  3538. NTSTATUS Status, ReturnStatus;
  3539. PBGUIDENTRY GuidEntry;
  3540. PLIST_ENTRY ObjectList, ObjectListNext;
  3541. PWMIGUIDOBJECT Object;
  3542. LPGUID EventGuid = &InWnode->Guid;
  3543. PWNODE_HEADER Wnode, WnodeTarget;
  3544. PAGED_CODE();
  3545. //
  3546. // If the event references a guid that needs to be queried then
  3547. // go do the dereferencing here.
  3548. //
  3549. if (InWnode->Flags & WNODE_FLAG_EVENT_REFERENCE)
  3550. {
  3551. WnodeTarget = WmipDereferenceEvent(InWnode);
  3552. if (WnodeTarget == NULL)
  3553. {
  3554. // TODO: Eventlog
  3555. if (FreeBuffer)
  3556. {
  3557. ExFreePool(InWnode);
  3558. }
  3559. return(STATUS_UNSUCCESSFUL);
  3560. }
  3561. Wnode = WnodeTarget;
  3562. } else {
  3563. Wnode = InWnode;
  3564. WnodeTarget = NULL;
  3565. }
  3566. //
  3567. // Be sure to use the guid of the referenced event, not the event that
  3568. // was originally fired.
  3569. EventGuid = &Wnode->Guid;
  3570. //
  3571. // If it is Trace error notification, disable providers
  3572. //
  3573. #ifndef MEMPHIS
  3574. if (IsEqualGUID(EventGuid, & TraceErrorGuid)) {
  3575. PWMI_TRACE_EVENT WmiEvent = (PWMI_TRACE_EVENT) InWnode;
  3576. ULONG LoggerId = WmiGetLoggerId(InWnode->HistoricalContext);
  3577. if ( InWnode->BufferSize >= sizeof(WMI_TRACE_EVENT) ) {
  3578. //
  3579. // Logger thread terminating will result in DisableTrace
  3580. // through StopTrace. No need to call twice.
  3581. //
  3582. if (WmiEvent->TraceErrorFlag == STATUS_SEVERITY_ERROR) {
  3583. WmipDisableTraceProviders(LoggerId);
  3584. }
  3585. }
  3586. }
  3587. #endif
  3588. //
  3589. // See if this event has a static name and if so fill it in
  3590. if (Wnode->Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES)
  3591. {
  3592. Wnode = WmipIncludeStaticNames(Wnode);
  3593. }
  3594. //
  3595. // See if any data provider has registered this event
  3596. //
  3597. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_EVENT_INFO_LEVEL,
  3598. "WMI: Received event\n"));
  3599. Guid = &Wnode->Guid;
  3600. GuidEntry = WmipFindGEByGuid(Guid, TRUE);
  3601. if (GuidEntry != NULL)
  3602. {
  3603. //
  3604. // Yup, so check if there are any open objects to the guid and
  3605. // if anyone is interested in receiving events from them
  3606. //
  3607. ReturnStatus = STATUS_SUCCESS;
  3608. WmipEnterSMCritSection();
  3609. ObjectList = GuidEntry->ObjectHead.Flink;
  3610. while (ObjectList != &GuidEntry->ObjectHead)
  3611. {
  3612. Object = CONTAINING_RECORD(ObjectList,
  3613. WMIGUIDOBJECT,
  3614. GEObjectList);
  3615. //
  3616. // ObRefSafe so that we can be sure that the object is not
  3617. // in the process of being deleted. If this function
  3618. // returns FALSE then the object is being deleted and so we
  3619. // don't want to use it. If TRUE then it is safe to use the
  3620. // object
  3621. //
  3622. ObjectListNext = ObjectList->Flink;
  3623. if (ObReferenceObjectSafe(Object))
  3624. {
  3625. //
  3626. // Make sure the object has not been marked as one that
  3627. // should not receive any events since it is
  3628. // transitioning to a closed state
  3629. //
  3630. if ((Object->Flags & WMIGUID_FLAG_RECEIVE_NO_EVENTS) == 0)
  3631. {
  3632. if (Object->Flags & WMIGUID_FLAG_KERNEL_NOTIFICATION)
  3633. {
  3634. //
  3635. // KM clients get a direct callback
  3636. //
  3637. WMI_NOTIFICATION_CALLBACK Callback;
  3638. PVOID Context;
  3639. Callback = Object->Callback;
  3640. Context = Object->CallbackContext;
  3641. if (Callback != NULL)
  3642. {
  3643. (*Callback)(Wnode, Context);
  3644. }
  3645. } else {
  3646. //
  3647. // UM clients get event written into IRP or queued up
  3648. //
  3649. Status = WmipWriteWnodeToObject(Object,
  3650. Wnode,
  3651. IsHighPriority);
  3652. if (! NT_SUCCESS(Status))
  3653. {
  3654. //
  3655. // If any attempts to queue the event fail then we return
  3656. // an error
  3657. //
  3658. ReturnStatus = STATUS_UNSUCCESSFUL;
  3659. }
  3660. }
  3661. }
  3662. ObDereferenceObject(Object);
  3663. //
  3664. // Note that we cannot touch the object anymore
  3665. //
  3666. }
  3667. ObjectList = ObjectListNext;
  3668. }
  3669. WmipLeaveSMCritSection();
  3670. WmipUnreferenceGE(GuidEntry);
  3671. } else {
  3672. ReturnStatus = STATUS_WMI_GUID_NOT_FOUND;
  3673. }
  3674. if (FreeBuffer)
  3675. {
  3676. //
  3677. // Free buffer passed by driver containing event
  3678. //
  3679. ExFreePool(InWnode);
  3680. }
  3681. if ((Wnode != InWnode) && (Wnode != WnodeTarget))
  3682. {
  3683. //
  3684. // If we inserted static names then free it
  3685. //
  3686. WmipFree(Wnode);
  3687. }
  3688. if (WnodeTarget != NULL)
  3689. {
  3690. //
  3691. // if we dereferenced then free it
  3692. //
  3693. WmipFree(WnodeTarget);
  3694. }
  3695. return(ReturnStatus);
  3696. }
  3697. NTSTATUS WmipUMProviderCallback(
  3698. IN WMIACTIONCODE ActionCode,
  3699. IN PVOID DataPath,
  3700. IN ULONG BufferSize,
  3701. IN OUT PVOID Buffer
  3702. )
  3703. {
  3704. PAGED_CODE();
  3705. UNREFERENCED_PARAMETER (ActionCode);
  3706. UNREFERENCED_PARAMETER (DataPath);
  3707. UNREFERENCED_PARAMETER (BufferSize);
  3708. UNREFERENCED_PARAMETER (Buffer);
  3709. ASSERT(FALSE);
  3710. return(STATUS_UNSUCCESSFUL);
  3711. }
  3712. NTSTATUS WmipRegisterUMGuids(
  3713. IN POBJECT_ATTRIBUTES ObjectAttributes,
  3714. IN ULONG Cookie,
  3715. IN PWMIREGINFO RegInfo,
  3716. IN ULONG RegInfoSize,
  3717. OUT HANDLE *RequestHandle,
  3718. OUT ULONG64 *LoggerContext
  3719. )
  3720. /*+++
  3721. Routine Description:
  3722. This routine will register a set of user mode guids with WMI for use
  3723. by tracelog. The following steps will occur:
  3724. * A request object is created using the passed object attributes.
  3725. Although the object created is unnamed, the object name passed
  3726. is used to lookup a security descriptor to associate with the
  3727. object.
  3728. * The guids are registered in the system.
  3729. Arguments:
  3730. ObjectAttribtes is a pointer to the passed object attributes used to
  3731. create the request object
  3732. Cookie is a unique id to associate with the request object so that
  3733. when a request is delivered the UM code can understand the context
  3734. via the cookie.
  3735. RegInfo is the registration information passed
  3736. RegInfoSize is the number of bytes of registration information passed
  3737. *RequestHandle returns with a handle to the request object. UM logger
  3738. creation and tracelog enabled/disable requests are delivered to
  3739. the object as WMI events.
  3740. *LoggerContext returns with the logger context
  3741. Return Value:
  3742. STATUS_SUCCESS or an error code
  3743. ---*/
  3744. {
  3745. NTSTATUS Status;
  3746. PDEVICE_OBJECT Callback;
  3747. PWMIGUIDOBJECT RequestObject;
  3748. PREGENTRY RegEntry;
  3749. PBGUIDENTRY GuidEntry;
  3750. PWMIREGGUID RegGuid;
  3751. PBDATASOURCE DataSource;
  3752. PBINSTANCESET InstanceSet;
  3753. OBJECT_ATTRIBUTES CapturedObjectAttributes;
  3754. UNICODE_STRING CapturedGuidString;
  3755. WCHAR CapturedGuidBuffer[WmiGuidObjectNameLength + 1];
  3756. PAGED_CODE();
  3757. Status = WmipProbeAndCaptureGuidObjectAttributes(&CapturedObjectAttributes,
  3758. &CapturedGuidString,
  3759. CapturedGuidBuffer,
  3760. ObjectAttributes);
  3761. if (NT_SUCCESS(Status))
  3762. {
  3763. Callback = (PDEVICE_OBJECT)(ULONG_PTR) WmipUMProviderCallback;
  3764. //
  3765. // Establish a regentry for the data provider
  3766. //
  3767. WmipEnterSMCritSection();
  3768. RegEntry = WmipAllocRegEntry(Callback,
  3769. WMIREG_FLAG_CALLBACK |
  3770. REGENTRY_FLAG_TRACED |
  3771. REGENTRY_FLAG_NEWREGINFO |
  3772. REGENTRY_FLAG_INUSE |
  3773. REGENTRY_FLAG_REG_IN_PROGRESS);
  3774. WmipLeaveSMCritSection();
  3775. if (RegEntry != NULL)
  3776. {
  3777. //
  3778. // Build a request object for this data source so that any
  3779. // enable requests can be posted to it while processing the
  3780. // WmiRegInfo
  3781. //
  3782. Status = WmipOpenGuidObject(&CapturedObjectAttributes,
  3783. TRACELOG_REGISTER_GUIDS,
  3784. UserMode,
  3785. RequestHandle,
  3786. &RequestObject);
  3787. if (NT_SUCCESS(Status))
  3788. {
  3789. Status = WmipProcessWmiRegInfo(RegEntry,
  3790. RegInfo,
  3791. RegInfoSize,
  3792. RequestObject,
  3793. FALSE,
  3794. TRUE);
  3795. if (NT_SUCCESS(Status))
  3796. {
  3797. //
  3798. // Initialize/Update InstanceSet
  3799. //
  3800. DataSource = RegEntry->DataSource;
  3801. RegGuid = &RegInfo->WmiRegGuid[0];
  3802. InstanceSet = WmipFindISByGuid( DataSource,
  3803. &RegGuid->Guid );
  3804. if (InstanceSet == NULL)
  3805. {
  3806. Status = STATUS_WMI_GUID_NOT_FOUND;
  3807. }
  3808. else {
  3809. WmipUnreferenceIS(InstanceSet);
  3810. }
  3811. //
  3812. // Find out if this Guid is currently Enabled. If so find
  3813. // its LoggerContext
  3814. //
  3815. *LoggerContext = 0;
  3816. GuidEntry = WmipFindGEByGuid(&RegInfo->WmiRegGuid->Guid,
  3817. FALSE);
  3818. if (GuidEntry != NULL)
  3819. {
  3820. if (GuidEntry->Flags & GE_NOTIFICATION_TRACE_FLAG)
  3821. {
  3822. *LoggerContext = GuidEntry->LoggerContext;
  3823. }
  3824. WmipUnreferenceGE(GuidEntry);
  3825. }
  3826. RequestObject->Flags |= WMIGUID_FLAG_REQUEST_OBJECT;
  3827. RequestObject->RegEntry = RegEntry;
  3828. RequestObject->Cookie = Cookie;
  3829. }
  3830. else
  3831. {
  3832. //
  3833. // If an error registering guids then clean up regentry
  3834. //
  3835. RegEntry->Flags |= (REGENTRY_FLAG_RUNDOWN |
  3836. REGENTRY_FLAG_NOT_ACCEPTING_IRPS);
  3837. WmipUnreferenceRegEntry(RegEntry);
  3838. ZwClose(*RequestHandle);
  3839. }
  3840. //
  3841. // remove the ref from when the object was created
  3842. //
  3843. ObDereferenceObject(RequestObject);
  3844. }
  3845. else {
  3846. RegEntry->Flags |= (REGENTRY_FLAG_RUNDOWN |
  3847. REGENTRY_FLAG_NOT_ACCEPTING_IRPS);
  3848. WmipUnreferenceRegEntry(RegEntry);
  3849. }
  3850. } else {
  3851. Status = STATUS_INSUFFICIENT_RESOURCES;
  3852. }
  3853. }
  3854. return(Status);
  3855. }
  3856. NTSTATUS WmipUnregisterGuids(
  3857. PWMIUNREGGUIDS UnregGuids
  3858. )
  3859. {
  3860. PBGUIDENTRY GuidEntry;
  3861. PAGED_CODE();
  3862. //
  3863. // Check to see if this GUID got disabled in the middle
  3864. // of Unregister Call. If so, send the LoggerContext back
  3865. //
  3866. GuidEntry = WmipFindGEByGuid(&UnregGuids->Guid, FALSE);
  3867. if (GuidEntry != NULL)
  3868. {
  3869. if ((GuidEntry->Flags & GE_NOTIFICATION_TRACE_FLAG) != 0)
  3870. {
  3871. UnregGuids->LoggerContext = GuidEntry->LoggerContext;
  3872. }
  3873. WmipUnreferenceGE(GuidEntry);
  3874. return (STATUS_SUCCESS);
  3875. }
  3876. else {
  3877. return (STATUS_WMI_INSTANCE_NOT_FOUND);
  3878. }
  3879. }
  3880. NTSTATUS WmipWriteMBToObject(
  3881. IN PWMIGUIDOBJECT RequestObject,
  3882. IN PWMIGUIDOBJECT ReplyObject,
  3883. IN PUCHAR Message,
  3884. IN ULONG MessageSize
  3885. )
  3886. /*+++
  3887. Routine Description:
  3888. This routine will build a WNODE out of a message and then write it
  3889. into the Request object. If a reply object is specified then the reply
  3890. object is linked into the request object so when the reply is written
  3891. to the request object it can be routed to the reply object correctly,.
  3892. This routine assumes that the SM Critical section is held
  3893. Arguments:
  3894. RequestObject is the object to which to send the request
  3895. ReplyObject is the object to which the request object shoudl reply.
  3896. This may be NULL in the case that no reply is needed.
  3897. Message is the message to be sent
  3898. MessageSize is the size of the message in bytes
  3899. Return Value:
  3900. STATUS_SUCCESS or an error code
  3901. ---*/
  3902. {
  3903. PWNODE_HEADER Wnode;
  3904. ULONG WnodeSize;
  3905. PUCHAR Payload;
  3906. ULONG i;
  3907. PMBREQUESTS MBRequest;
  3908. NTSTATUS Status;
  3909. PAGED_CODE();
  3910. //
  3911. // Allocate space to build a wnode out of the data passed
  3912. //
  3913. WnodeSize = sizeof(WNODE_HEADER) + MessageSize;
  3914. Wnode = WmipAlloc(WnodeSize);
  3915. if (Wnode != NULL)
  3916. {
  3917. //
  3918. // Create an internal wnode with the message as the payload
  3919. //
  3920. RtlZeroMemory(Wnode, sizeof(WNODE_HEADER));
  3921. Wnode->BufferSize = WnodeSize;
  3922. Wnode->Flags = WNODE_FLAG_INTERNAL;
  3923. Wnode->Guid = RequestObject->Guid;
  3924. Wnode->ProviderId = WmiMBRequest;
  3925. Payload = (PUCHAR)Wnode + sizeof(WNODE_HEADER);
  3926. RtlCopyMemory(Payload, Message, MessageSize);
  3927. //
  3928. // if this request requires a reply then update the lists for the
  3929. // request and reply objects
  3930. //
  3931. if (ReplyObject != NULL)
  3932. {
  3933. //
  3934. // Find a free spot in the request object to link
  3935. // in the reply.
  3936. //
  3937. Status = STATUS_INSUFFICIENT_RESOURCES;
  3938. for (i = 0; i < MAXREQREPLYSLOTS; i++)
  3939. {
  3940. MBRequest = &RequestObject->MBRequests[i];
  3941. if (MBRequest->ReplyObject == NULL)
  3942. {
  3943. //
  3944. // We have a free slot so link request and reply
  3945. // objects together and send off the request.
  3946. // The request object takes a ref count on the reply
  3947. // object since it maintains a pointer to it. The
  3948. // refcount is released when the request object writes
  3949. // the reply back to the reply object.
  3950. //
  3951. Status = ObReferenceObjectByPointer(ReplyObject,
  3952. 0,
  3953. WmipGuidObjectType,
  3954. KernelMode);
  3955. if (NT_SUCCESS(Status))
  3956. {
  3957. MBRequest->ReplyObject = ReplyObject;
  3958. InsertTailList(&ReplyObject->RequestListHead,
  3959. &MBRequest->RequestListEntry);
  3960. Wnode->Version = i;
  3961. Status = WmipWriteWnodeToObject(RequestObject,
  3962. Wnode,
  3963. TRUE);
  3964. if (! NT_SUCCESS(Status))
  3965. {
  3966. //
  3967. // If writing request failed, we need to cleanup
  3968. //
  3969. ObDereferenceObject(ReplyObject);
  3970. MBRequest->ReplyObject = NULL;
  3971. RemoveEntryList(&MBRequest->RequestListEntry);
  3972. }
  3973. }
  3974. break;
  3975. }
  3976. }
  3977. } else {
  3978. //
  3979. // No reply required so we just write the message to the
  3980. // object and continue with our business
  3981. //
  3982. Status = WmipWriteWnodeToObject(RequestObject,
  3983. Wnode,
  3984. TRUE);
  3985. }
  3986. WmipFree(Wnode);
  3987. } else {
  3988. Status = STATUS_INSUFFICIENT_RESOURCES;
  3989. }
  3990. return(Status);
  3991. }
  3992. NTSTATUS WmipWriteMessageToGuid(
  3993. IN PBGUIDENTRY GuidEntry,
  3994. IN PWMIGUIDOBJECT ReplyObject,
  3995. IN PUCHAR Message,
  3996. IN ULONG MessageSize,
  3997. OUT PULONG WrittenCount
  3998. )
  3999. /*+++
  4000. Routine Description:
  4001. This routine will loop over all instance sets attached to a guid entry
  4002. and if the data source for it is a user mode data source then it will
  4003. get a request messsage sent to it.
  4004. Note that if there are more than one providers to which a message is
  4005. sent, then success is returned as long as writing to one of them is
  4006. successful.
  4007. Arguments:
  4008. GuidEntry is the guid entry for the control guid
  4009. ReplyObject is the object to which the request object shoudl reply.
  4010. This may be NULL in the case that no reply is needed.
  4011. Message is the message to be sent
  4012. MessageSize is the size of the message in bytes
  4013. Return Value:
  4014. STATUS_SUCCESS or an error code
  4015. ---*/
  4016. {
  4017. NTSTATUS Status, Status2;
  4018. PLIST_ENTRY InstanceSetList;
  4019. PBINSTANCESET InstanceSet;
  4020. PBDATASOURCE DataSource;
  4021. PAGED_CODE();
  4022. Status = STATUS_UNSUCCESSFUL;
  4023. *WrittenCount = 0;
  4024. WmipEnterSMCritSection();
  4025. //
  4026. // Loop over all instances and send create logger
  4027. // request to all user mode data providers
  4028. //
  4029. InstanceSetList = GuidEntry->ISHead.Flink;
  4030. while (InstanceSetList != &GuidEntry->ISHead)
  4031. {
  4032. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  4033. INSTANCESET,
  4034. GuidISList);
  4035. DataSource = InstanceSet->DataSource;
  4036. if (DataSource->Flags & DS_USER_MODE)
  4037. {
  4038. //
  4039. // User mode guy, so send the request to him
  4040. //
  4041. ASSERT(DataSource->RequestObject != NULL);
  4042. Status2 = WmipWriteMBToObject(DataSource->RequestObject,
  4043. ReplyObject,
  4044. Message,
  4045. MessageSize);
  4046. if (NT_SUCCESS(Status2))
  4047. {
  4048. Status = STATUS_SUCCESS;
  4049. (*WrittenCount)++;
  4050. }
  4051. }
  4052. InstanceSetList = InstanceSetList->Flink;
  4053. }
  4054. WmipLeaveSMCritSection();
  4055. return(Status);
  4056. }
  4057. NTSTATUS WmipCreateUMLogger(
  4058. IN OUT PWMICREATEUMLOGGER CreateInfo
  4059. )
  4060. /*+++
  4061. Routine Description:
  4062. This routine will send a request to create a UM logger. First it will
  4063. find the providers associated with the control guid and then create a
  4064. reply object which the providers will reply to when the UM logger is
  4065. created. Note that the reply object is created as an unnamed object,
  4066. but that the guid passed in the object name is used to look up the
  4067. security descriptor for the reply object.
  4068. Note that if there are more than one providers to which a message is
  4069. sent, then success is returned as long as writing to one of them is
  4070. successful.
  4071. Arguments:
  4072. CreateInfo has the information needed to create the UM logger.
  4073. Return Value:
  4074. STATUS_SUCCESS or an error code
  4075. ---*/
  4076. {
  4077. NTSTATUS Status;
  4078. PBGUIDENTRY GuidEntry;
  4079. HANDLE ReplyHandle;
  4080. PWMIGUIDOBJECT ReplyObject;
  4081. ULONG MessageSize = 1;
  4082. PWNODE_HEADER Wnode;
  4083. ULONG ReplyCount;
  4084. OBJECT_ATTRIBUTES CapturedObjectAttributes;
  4085. UNICODE_STRING CapturedGuidString;
  4086. WCHAR CapturedGuidBuffer[WmiGuidObjectNameLength + 1];
  4087. PAGED_CODE();
  4088. Status = WmipProbeAndCaptureGuidObjectAttributes(&CapturedObjectAttributes,
  4089. &CapturedGuidString,
  4090. CapturedGuidBuffer,
  4091. CreateInfo->ObjectAttributes);
  4092. if (NT_SUCCESS(Status))
  4093. {
  4094. GuidEntry = WmipFindGEByGuid(&CreateInfo->ControlGuid, FALSE);
  4095. if (GuidEntry != NULL)
  4096. {
  4097. //
  4098. // Control guid is registered so create a reply object that the
  4099. // provider will write to.
  4100. //
  4101. if (WmipIsControlGuid(GuidEntry))
  4102. {
  4103. //
  4104. // Create the reply object
  4105. //
  4106. Status = WmipOpenGuidObject(&CapturedObjectAttributes,
  4107. TRACELOG_CREATE_INPROC |
  4108. TRACELOG_GUID_ENABLE |
  4109. WMIGUID_NOTIFICATION,
  4110. UserMode,
  4111. &ReplyHandle,
  4112. &ReplyObject);
  4113. if (NT_SUCCESS(Status))
  4114. {
  4115. //
  4116. // Send request to all providers who registered for control
  4117. // guid
  4118. //
  4119. ReplyObject->Flags |= WMIGUID_FLAG_REPLY_OBJECT;
  4120. InitializeListHead(&ReplyObject->RequestListHead);
  4121. Wnode = (PWNODE_HEADER) ((PUCHAR) CreateInfo+ sizeof(WMICREATEUMLOGGER));
  4122. MessageSize = Wnode->BufferSize;
  4123. Status = WmipWriteMessageToGuid(GuidEntry,
  4124. ReplyObject,
  4125. (PUCHAR)Wnode,
  4126. MessageSize,
  4127. &ReplyCount
  4128. );
  4129. if (NT_SUCCESS(Status))
  4130. {
  4131. //
  4132. // Create logger requests delivered ok so return handle
  4133. // to object that will receive the replies.
  4134. //
  4135. CreateInfo->ReplyHandle.Handle = ReplyHandle;
  4136. CreateInfo->ReplyCount = ReplyCount;
  4137. } else {
  4138. //
  4139. // We were not able to deliver the requests so we do not
  4140. // need to keep the reply object open
  4141. //
  4142. ZwClose(ReplyHandle);
  4143. }
  4144. //
  4145. // remove the ref taken when the object was created
  4146. //
  4147. ObDereferenceObject(ReplyObject);
  4148. }
  4149. }
  4150. WmipUnreferenceGE(GuidEntry);
  4151. } else {
  4152. //
  4153. // Control guid is not registered so return an error
  4154. //
  4155. Status = STATUS_WMI_INSTANCE_NOT_FOUND;
  4156. }
  4157. }
  4158. return(Status);
  4159. }
  4160. NTSTATUS WmipMBReply(
  4161. IN HANDLE RequestHandle,
  4162. IN ULONG ReplyIndex,
  4163. IN PUCHAR Message,
  4164. IN ULONG MessageSize
  4165. )
  4166. /*+++
  4167. Routine Description:
  4168. This routine will write a MB reply message to the appropriate
  4169. reply object and unlink the reply object from the request object;
  4170. Arguments:
  4171. RequestHandle is the handle to the request object
  4172. ReplyIndex is the index to the MBRequest entry for the reply object
  4173. Message is the reply message
  4174. MessageSize is the size of the reply message
  4175. Return Value:
  4176. STATUS_SUCCESS or an error code
  4177. ---*/
  4178. {
  4179. NTSTATUS Status;
  4180. PWMIGUIDOBJECT RequestObject, ReplyObject;
  4181. PMBREQUESTS MBRequest;
  4182. PAGED_CODE();
  4183. Status = ObReferenceObjectByHandle(RequestHandle,
  4184. TRACELOG_REGISTER_GUIDS,
  4185. WmipGuidObjectType,
  4186. UserMode,
  4187. &RequestObject,
  4188. NULL);
  4189. if (NT_SUCCESS(Status))
  4190. {
  4191. if (ReplyIndex < MAXREQREPLYSLOTS)
  4192. {
  4193. //
  4194. // Is the ReplyIndex passed valid ??
  4195. //
  4196. WmipEnterSMCritSection();
  4197. MBRequest = &RequestObject->MBRequests[ReplyIndex];
  4198. ReplyObject = MBRequest->ReplyObject;
  4199. if (ReplyObject != NULL)
  4200. {
  4201. //
  4202. // We have figured out who we need to reply to so
  4203. // clear out the link between the reply object
  4204. // and this request object
  4205. //
  4206. RemoveEntryList(&MBRequest->RequestListEntry);
  4207. MBRequest->ReplyObject = NULL;
  4208. ObDereferenceObject(ReplyObject);
  4209. Status = WmipWriteMBToObject(ReplyObject,
  4210. NULL,
  4211. Message,
  4212. MessageSize);
  4213. if (! NT_SUCCESS(Status))
  4214. {
  4215. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_ERROR_LEVEL,
  4216. "WMI: WmipWriteMBToObject(%p) failed %x\n",
  4217. ReplyObject,
  4218. Status));
  4219. }
  4220. } else {
  4221. Status = STATUS_INVALID_PARAMETER;
  4222. }
  4223. WmipLeaveSMCritSection();
  4224. } else {
  4225. Status = STATUS_INVALID_PARAMETER;
  4226. }
  4227. ObDereferenceObject(RequestObject);
  4228. }
  4229. return(Status);
  4230. }
  4231. #ifdef ALLOC_DATA_PRAGMA
  4232. #pragma const_seg()
  4233. #endif