Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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