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.

1670 lines
49 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. api.c
  5. Abstract:
  6. Api entrypoints to WMI
  7. Author:
  8. AlanWar
  9. Environment:
  10. Kernel Mode
  11. Revision History:
  12. --*/
  13. #include "wmikmp.h"
  14. #ifndef MEMPHIS
  15. #include "evntrace.h"
  16. #include "tracep.h"
  17. #endif
  18. BOOLEAN WMIInitialize(
  19. ULONG Phase,
  20. PVOID LoaderBlock
  21. );
  22. NTSTATUS IoWMIRegistrationControl(
  23. IN PDEVICE_OBJECT DeviceObject,
  24. IN ULONG Action
  25. );
  26. NTSTATUS IoWMISuggestInstanceName(
  27. IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
  28. IN PUNICODE_STRING SymbolicLinkName OPTIONAL,
  29. IN BOOLEAN CombineNames,
  30. OUT PUNICODE_STRING SuggestedInstanceName
  31. );
  32. #ifdef ALLOC_PRAGMA
  33. #ifndef MEMPHIS
  34. #pragma alloc_text(INIT,WMIInitialize)
  35. #endif
  36. #pragma alloc_text(PAGE,IoWMIRegistrationControl)
  37. #pragma alloc_text(PAGE,IoWMIAllocateInstanceIds)
  38. #pragma alloc_text(PAGE,IoWMISuggestInstanceName)
  39. #pragma alloc_text(PAGE,IoWMIOpenBlock)
  40. #pragma alloc_text(PAGE,IoWMIQueryAllData)
  41. #pragma alloc_text(PAGE,IoWMIQueryAllDataMultiple)
  42. #pragma alloc_text(PAGE,IoWMIQuerySingleInstance)
  43. #pragma alloc_text(PAGE,IoWMIQuerySingleInstanceMultiple)
  44. #pragma alloc_text(PAGE,IoWMISetSingleInstance)
  45. #pragma alloc_text(PAGE,IoWMISetSingleItem)
  46. #pragma alloc_text(PAGE,IoWMISetNotificationCallback)
  47. #pragma alloc_text(PAGE,IoWMIExecuteMethod)
  48. #endif
  49. #ifdef MEMPHIS
  50. BOOLEAN WmipInitialized;
  51. #endif
  52. //
  53. // Mutex used to ensure single access to InstanceId chunks
  54. PINSTIDCHUNK WmipInstIdChunkHead;
  55. NTSTATUS
  56. WmipDriverEntry(
  57. IN PDRIVER_OBJECT DriverObject,
  58. IN PUNICODE_STRING RegistryPath
  59. );
  60. BOOLEAN WMIInitialize(
  61. ULONG Phase,
  62. PVOID LoaderBlockPtr
  63. )
  64. /*++
  65. Routine Description:
  66. This routine is the initialization routine for WMI and is called by IO
  67. within IoInitSystem on NT. On memphis it is called the firest time
  68. that IoWMIRegistrationControl is called. This routine asssumes that the
  69. IO system is initialized enough to call IoCreateDriver. The rest of the
  70. initialization occurs in the DriverEntry routine.
  71. Arguments:
  72. Pass specifies the pass of initalization needed
  73. Return Value:
  74. TRUE if initialization was successful
  75. --*/
  76. {
  77. #ifndef MEMPHIS
  78. //
  79. // We name the driver this so that any eventlogs fired will have the
  80. // source name WMIxWDM and thus get the eventlog messages from
  81. // ntiologc.mc
  82. //
  83. #define WMIDRIVERNAME L"\\Driver\\WMIxWDM"
  84. UNICODE_STRING DriverName;
  85. #endif
  86. NTSTATUS Status;
  87. if (Phase == 0)
  88. {
  89. WmipAssert(WmipServiceDeviceObject == NULL);
  90. WmipAssert(LoaderBlockPtr != NULL);
  91. #ifdef MEMPHIS
  92. Status = IoCreateDriver(NULL, WmipDriverEntry);
  93. WmipInitialized = TRUE;
  94. #else
  95. RtlInitUnicodeString(&DriverName, WMIDRIVERNAME);
  96. Status = IoCreateDriver(&DriverName, WmipDriverEntry);
  97. #endif
  98. #if defined(_IA64_) // EFI actually
  99. WmipGetSMBiosFromLoaderBlock(LoaderBlockPtr);
  100. #endif
  101. } else {
  102. WmipAssert(LoaderBlockPtr == NULL);
  103. WmipInitializeRegistration(Phase);
  104. Status = STATUS_SUCCESS;
  105. }
  106. #if defined(_IA64_)
  107. //
  108. // Give MCA a chance to init during phase 0 and 1
  109. //
  110. WmipRegisterMcaHandler(Phase);
  111. #endif
  112. return(NT_SUCCESS(Status));
  113. }
  114. NTSTATUS IoWMIRegistrationControl(
  115. IN PDEVICE_OBJECT DeviceObject,
  116. IN ULONG Action
  117. )
  118. /*++
  119. Routine Description:
  120. This routine informs WMI of the existence and disappearance of a device
  121. object that would support WMI.
  122. Arguments:
  123. DeviceObject - Pointer to device object or callback address
  124. Action - Registration action code
  125. WMIREG_ACTION_REGISTER - If set action is to inform WMI that the
  126. device object supports and is ready to receive WMI IRPS.
  127. WMIREG_ACTION_DEREGISTER - If set action is to inform WMI that the
  128. device object no longer supports and is not ready to receive WMI
  129. IRPS.
  130. WMIREG_ACTION_REREGISTER - If set action is to requery the device
  131. object for the guids that it supports. This has the effect of
  132. deregistering followed by registering.
  133. WMIREG_ACTION_UPDATE_GUIDS - If set action is to query for information
  134. that is used to update already registered guids.
  135. WMIREG_ACTION_BLOCK_IRPS - If set action is to block any further irps
  136. from being sent to the device. The irps are failed by WMI.
  137. If the WMIREG_FLAG_CALLBACK is set then DeviceObject actually specifies a callback
  138. address and not a DeviceObject
  139. Return Value:
  140. Returns status code
  141. --*/
  142. {
  143. #ifdef MEMPHIS
  144. //
  145. // make sure this matches with the value in io.h
  146. #define WMIREG_FLAG_CALLBACK 0x80000000
  147. #endif
  148. NTSTATUS Status;
  149. #ifdef MEMPHIS
  150. BOOLEAN IsCallback = ((Action & WMIREG_FLAG_CALLBACK) == WMIREG_FLAG_CALLBACK);
  151. #endif
  152. ULONG RegistrationFlag = 0;
  153. ULONG IsTraceProvider = FALSE;
  154. ULONG TraceClass;
  155. PREGENTRY RegEntry;
  156. PAGED_CODE();
  157. #ifdef MEMPHIS
  158. if (! WmipInitialized)
  159. {
  160. WMIInitialize();
  161. }
  162. //
  163. // Callbacks are not supported on memphis
  164. if (IsCallback)
  165. {
  166. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,
  167. "WMI: Callback registrations not supported %x\n",
  168. DeviceObject));
  169. return(STATUS_NOT_IMPLEMENTED);
  170. }
  171. #endif
  172. if (WmipIsWmiNotSetupProperly())
  173. {
  174. return(STATUS_UNSUCCESSFUL);
  175. }
  176. if (Action & WMIREG_FLAG_CALLBACK)
  177. {
  178. RegistrationFlag |= WMIREG_FLAG_CALLBACK;
  179. Action &= ~WMIREG_FLAG_CALLBACK;
  180. }
  181. #ifndef MEMPHIS
  182. if (Action & WMIREG_FLAG_TRACE_PROVIDER)
  183. {
  184. TraceClass = Action & WMIREG_FLAG_TRACE_NOTIFY_MASK;
  185. Action &= ~WMIREG_FLAG_TRACE_PROVIDER & ~WMIREG_FLAG_TRACE_NOTIFY_MASK;
  186. IsTraceProvider = TRUE;
  187. RegistrationFlag |= WMIREG_FLAG_TRACE_PROVIDER | TraceClass;
  188. }
  189. #endif
  190. switch(Action)
  191. {
  192. case WMIREG_ACTION_REGISTER:
  193. {
  194. Status = WmipRegisterDevice(
  195. DeviceObject,
  196. RegistrationFlag);
  197. #ifndef MEMPHIS
  198. if (IsTraceProvider)
  199. {
  200. WmipSetTraceNotify(DeviceObject, TraceClass, TRUE);
  201. }
  202. break;
  203. #endif
  204. }
  205. case WMIREG_ACTION_DEREGISTER:
  206. {
  207. Status = WmipDeregisterDevice(DeviceObject);
  208. break;
  209. }
  210. case WMIREG_ACTION_REREGISTER:
  211. {
  212. Status = WmipDeregisterDevice(DeviceObject);
  213. if (NT_SUCCESS(Status))
  214. {
  215. Status = WmipRegisterDevice(
  216. DeviceObject,
  217. RegistrationFlag);
  218. }
  219. break;
  220. }
  221. case WMIREG_ACTION_UPDATE_GUIDS:
  222. {
  223. Status = WmipUpdateRegistration(DeviceObject);
  224. break;
  225. }
  226. #ifndef MEMPHIS
  227. case WMIREG_ACTION_BLOCK_IRPS:
  228. {
  229. RegEntry = WmipFindRegEntryByDevice(DeviceObject, FALSE);
  230. if (RegEntry != NULL)
  231. {
  232. //
  233. // Mark the regentry as invalid so that no more irps
  234. // are sent to the device and the event will set when
  235. // the last irp completes.
  236. WmipEnterSMCritSection();
  237. RegEntry->Flags |= REGENTRY_FLAG_NOT_ACCEPTING_IRPS;
  238. WmipLeaveSMCritSection();
  239. WmipUnreferenceRegEntry(RegEntry);
  240. Status = STATUS_SUCCESS;
  241. } else {
  242. Status = STATUS_INVALID_PARAMETER;
  243. }
  244. break;
  245. }
  246. #endif
  247. default:
  248. {
  249. Status = STATUS_INVALID_PARAMETER;
  250. break;
  251. }
  252. }
  253. return(Status);
  254. }
  255. NTSTATUS IoWMIAllocateInstanceIds(
  256. IN GUID *Guid,
  257. IN ULONG InstanceCount,
  258. OUT ULONG *FirstInstanceId
  259. )
  260. /*++
  261. Routine Description:
  262. This routine allocates a range of instance ids that are unique to the
  263. guid. This routine is to be called only at PASSIVE_LEVEL.
  264. Arguments:
  265. Guid - Pointer to guid for which instance ids are needed.
  266. InstanceCount - Count of instance ids to allocate.
  267. *FirstInstanceId - Returns first instance id in the range.
  268. Return Value:
  269. Returns a status code
  270. --*/
  271. {
  272. PINSTIDCHUNK InstIdChunk, LastInstIdChunk = NULL;
  273. PINSTID InstId;
  274. ULONG i;
  275. PAGED_CODE();
  276. #ifdef MEMPHIS
  277. if (! WmipInitialized)
  278. {
  279. WMIInitialize();
  280. }
  281. #endif
  282. if (WmipIsWmiNotSetupProperly())
  283. {
  284. return(STATUS_UNSUCCESSFUL);
  285. }
  286. WmipEnterSMCritSection();
  287. //
  288. // See if the guid is already in the list
  289. InstIdChunk = WmipInstIdChunkHead;
  290. while (InstIdChunk != NULL)
  291. {
  292. for (i = 0; i < INSTIDSPERCHUNK; i++)
  293. {
  294. InstId = &InstIdChunk->InstId[i];
  295. if (InstId->BaseId == ~0)
  296. {
  297. //
  298. // Since InstIds are always filled sequentially and are
  299. // never freed, if we hit a free one then we know that
  300. // our guid is not in the list and we need to fill in a
  301. // new entry.
  302. goto FillInstId;
  303. }
  304. if (IsEqualGUID(Guid, &InstId->Guid))
  305. {
  306. //
  307. // We found an entry for our guid so use its information
  308. *FirstInstanceId = InstId->BaseId;
  309. InstId->BaseId += InstanceCount;
  310. WmipLeaveSMCritSection();
  311. return(STATUS_SUCCESS);
  312. }
  313. }
  314. LastInstIdChunk = InstIdChunk;
  315. InstIdChunk = InstIdChunk->Next;
  316. }
  317. //
  318. // We need to allocate a brand new chunk to accomodate the entry
  319. InstIdChunk = ExAllocatePoolWithTag(PagedPool,
  320. sizeof(INSTIDCHUNK),
  321. WMIIIPOOLTAG);
  322. if (InstIdChunk != NULL)
  323. {
  324. RtlFillMemory(InstIdChunk, sizeof(INSTIDCHUNK), 0xff);
  325. InstIdChunk->Next = NULL;
  326. if (LastInstIdChunk == NULL)
  327. {
  328. WmipInstIdChunkHead = InstIdChunk;
  329. } else {
  330. LastInstIdChunk->Next = InstIdChunk;
  331. }
  332. InstId = &InstIdChunk->InstId[0];
  333. } else {
  334. WmipLeaveSMCritSection();
  335. return(STATUS_INSUFFICIENT_RESOURCES);
  336. }
  337. FillInstId:
  338. RtlCopyMemory(&InstId->Guid, Guid, sizeof(GUID));
  339. InstId->BaseId = InstanceCount;
  340. WmipLeaveSMCritSection();
  341. *FirstInstanceId = 0;
  342. return(STATUS_SUCCESS);
  343. }
  344. NTSTATUS IoWMISuggestInstanceName(
  345. IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
  346. IN PUNICODE_STRING SymbolicLinkName OPTIONAL,
  347. IN BOOLEAN CombineNames,
  348. OUT PUNICODE_STRING SuggestedInstanceName
  349. )
  350. /*++
  351. Routine Description:
  352. This routine is used by a device driver to suggest a base name with which
  353. to build WMI instance names for the device. A driver is not bound to
  354. follow the instance name returned.
  355. Arguments:
  356. PhysicalDeviceObject - PDO of device for which a suggested instance name
  357. is being requested
  358. SymbolicLinkName - Symbolic link name returned from
  359. IoRegisterDeviceInterface.
  360. CombineNames - If TRUE then the suggested names arising from the
  361. PhysicalDeviceObject and the SymbolicLinkName are combined to create
  362. the resultant suggested name.
  363. SuggestedInstanceName - Supplies a pointer to an empty (i.e., Buffer
  364. field set to NULL) UNICODE_STRING structure which, upon success, will
  365. be set to a newly-allocated string buffer containing the suggested
  366. instance name. The caller is responsible for freeing
  367. SuggestedInstanceName->Buffer when it is no longer needed.
  368. Note: If CombineNames is TRUE then both PhysicalDeviceObject and
  369. SymbolicLinkName must be specified. Otherwise only one of them
  370. must be specified.
  371. Return Value:
  372. Returns a status code
  373. --*/
  374. {
  375. ULONG Status = STATUS_INVALID_PARAMETER_MIX;
  376. ULONG DeviceDescSizeRequired;
  377. ULONG DeviceDescSize;
  378. PWCHAR DeviceDescBuffer;
  379. HANDLE DeviceInstanceKey;
  380. PKEY_VALUE_FULL_INFORMATION InfoBuffer;
  381. PWCHAR SymLinkDescBuffer;
  382. ULONG InfoSizeRequired;
  383. ULONG ResultDescSize;
  384. PWCHAR ResultDescBuffer;
  385. UNICODE_STRING DefaultValue;
  386. PAGED_CODE();
  387. #ifdef MEMPHIS
  388. if (! WmipInitialized)
  389. {
  390. WMIInitialize();
  391. }
  392. #endif
  393. if (WmipIsWmiNotSetupProperly())
  394. {
  395. return(STATUS_UNSUCCESSFUL);
  396. }
  397. DeviceDescBuffer = NULL;
  398. DeviceDescSizeRequired = 0;
  399. DeviceDescSize = 0;
  400. if (PhysicalDeviceObject != NULL)
  401. {
  402. Status = IoGetDeviceProperty(PhysicalDeviceObject,
  403. DevicePropertyDeviceDescription,
  404. DeviceDescSize,
  405. DeviceDescBuffer,
  406. &DeviceDescSizeRequired);
  407. if (Status == STATUS_BUFFER_TOO_SMALL)
  408. {
  409. DeviceDescBuffer = ExAllocatePoolWithTag(PagedPool,
  410. DeviceDescSizeRequired,
  411. WMIPOOLTAG);
  412. if (DeviceDescBuffer == NULL)
  413. {
  414. return(STATUS_INSUFFICIENT_RESOURCES);
  415. }
  416. DeviceDescSize = DeviceDescSizeRequired;
  417. Status = IoGetDeviceProperty(PhysicalDeviceObject,
  418. DevicePropertyDeviceDescription,
  419. DeviceDescSize,
  420. DeviceDescBuffer,
  421. &DeviceDescSizeRequired);
  422. if (! NT_SUCCESS(Status))
  423. {
  424. ExFreePool(DeviceDescBuffer);
  425. return(Status);
  426. }
  427. } else if (! NT_SUCCESS(Status)) {
  428. return(Status);
  429. }
  430. }
  431. if (SymbolicLinkName != NULL)
  432. {
  433. Status = IoOpenDeviceInterfaceRegistryKey(SymbolicLinkName,
  434. KEY_ALL_ACCESS,
  435. &DeviceInstanceKey);
  436. if (NT_SUCCESS(Status))
  437. {
  438. //
  439. // Figure out how big the data value is so that a buffer of the
  440. // appropriate size can be allocated.
  441. DefaultValue.Length = 0;
  442. DefaultValue.MaximumLength= 0;
  443. DefaultValue.Buffer = NULL;
  444. Status = ZwQueryValueKey( DeviceInstanceKey,
  445. &DefaultValue,
  446. KeyValueFullInformation,
  447. (PVOID) NULL,
  448. 0,
  449. &InfoSizeRequired );
  450. if (Status == STATUS_BUFFER_OVERFLOW ||
  451. Status == STATUS_BUFFER_TOO_SMALL)
  452. {
  453. InfoBuffer = ExAllocatePoolWithTag(PagedPool,
  454. InfoSizeRequired,
  455. WMIPOOLTAG);
  456. if (InfoBuffer != NULL)
  457. {
  458. Status = ZwQueryValueKey(DeviceInstanceKey,
  459. &DefaultValue,
  460. KeyValueFullInformation,
  461. InfoBuffer,
  462. InfoSizeRequired,
  463. &InfoSizeRequired);
  464. if (NT_SUCCESS(Status))
  465. {
  466. SymLinkDescBuffer = (PWCHAR)((PCHAR)InfoBuffer + InfoBuffer->DataOffset);
  467. if (CombineNames)
  468. {
  469. ResultDescSize = InfoBuffer->DataLength +
  470. DeviceDescSizeRequired +
  471. sizeof(WCHAR);
  472. ResultDescBuffer = ExAllocatePoolWithTag(PagedPool,
  473. ResultDescSize,
  474. WMIPOOLTAG);
  475. if (ResultDescBuffer == NULL)
  476. {
  477. Status = STATUS_INSUFFICIENT_RESOURCES;
  478. } else {
  479. SuggestedInstanceName->Buffer = ResultDescBuffer;
  480. SuggestedInstanceName->Length = 0;
  481. SuggestedInstanceName->MaximumLength = (USHORT)ResultDescSize;
  482. RtlAppendUnicodeToString(SuggestedInstanceName,
  483. DeviceDescBuffer);
  484. RtlAppendUnicodeToString(SuggestedInstanceName,
  485. L"_");
  486. RtlAppendUnicodeToString(SuggestedInstanceName,
  487. SymLinkDescBuffer);
  488. }
  489. ExFreePool(DeviceDescBuffer);
  490. DeviceDescBuffer= NULL;
  491. } else {
  492. if (DeviceDescBuffer != NULL)
  493. {
  494. ExFreePool(DeviceDescBuffer);
  495. DeviceDescBuffer = NULL;
  496. }
  497. ResultDescBuffer = ExAllocatePoolWithTag(PagedPool,
  498. InfoBuffer->DataLength,
  499. WMIPOOLTAG);
  500. if (ResultDescBuffer == NULL)
  501. {
  502. Status = STATUS_INSUFFICIENT_RESOURCES;
  503. } else {
  504. SuggestedInstanceName->Buffer = ResultDescBuffer;
  505. SuggestedInstanceName->Length = 0;
  506. SuggestedInstanceName->MaximumLength = (USHORT)InfoBuffer->DataLength;
  507. RtlAppendUnicodeToString(SuggestedInstanceName,
  508. SymLinkDescBuffer);
  509. }
  510. }
  511. }
  512. ExFreePool(InfoBuffer);
  513. } else {
  514. Status = STATUS_INSUFFICIENT_RESOURCES;
  515. }
  516. }
  517. ZwClose(DeviceInstanceKey);
  518. }
  519. if ((DeviceDescBuffer != NULL) && (! NT_SUCCESS(Status)))
  520. {
  521. ExFreePool(DeviceDescBuffer);
  522. }
  523. } else {
  524. if (DeviceDescBuffer != NULL)
  525. {
  526. //
  527. // Only looking for device description from PDO
  528. SuggestedInstanceName->Buffer = DeviceDescBuffer;
  529. SuggestedInstanceName->Length = (USHORT)DeviceDescSizeRequired - sizeof(WCHAR);
  530. SuggestedInstanceName->MaximumLength = (USHORT)DeviceDescSize;
  531. } else {
  532. SuggestedInstanceName->Buffer = NULL;
  533. SuggestedInstanceName->Length = (USHORT)0;
  534. SuggestedInstanceName->MaximumLength = 0;
  535. }
  536. }
  537. return(Status);
  538. }
  539. NTSTATUS IoWMIWriteEvent(
  540. IN PVOID WnodeEventItem
  541. )
  542. /*++
  543. Routine Description:
  544. This routine will queue the passed WNODE_EVENT_ITEM for delivery to the
  545. WMI user mode agent. Once the event is delivered the WNODE_EVENT_ITEM
  546. buffer will be returned to the pool.
  547. This routine may be called at DPC level
  548. Arguments:
  549. WnodeEventItem - Pointer to WNODE_EVENT_ITEM that has event information.
  550. Return Value:
  551. Returns STATUS_SUCCESS or an error code
  552. --*/
  553. {
  554. NTSTATUS Status;
  555. PWNODE_HEADER WnodeHeader = (PWNODE_HEADER)WnodeEventItem;
  556. #ifndef MEMPHIS
  557. PULONG TraceMarker = (PULONG) WnodeHeader;
  558. #endif
  559. KIRQL OldIrql;
  560. PREGENTRY RegEntry;
  561. PEVENTWORKCONTEXT EventContext;
  562. if (WmipIsWmiNotSetupProperly())
  563. {
  564. return(STATUS_UNSUCCESSFUL);
  565. }
  566. #ifndef MEMPHIS
  567. //
  568. // Special mode with high order bit set
  569. //
  570. if ((*TraceMarker & 0xC0000000) == TRACE_HEADER_FLAG)
  571. {
  572. ULONG LoggerId = WmiGetLoggerId(WnodeHeader->HistoricalContext);
  573. if (LoggerId > 0 && LoggerId < MAXLOGGERS)
  574. {
  575. if (WmipLoggerContext[LoggerId] != NULL)
  576. return WmiTraceFastEvent(WnodeHeader);
  577. }
  578. #if DBG
  579. DbgPrintEx(DPFLTR_WMILIB_ID,
  580. DPFLTR_INFO_LEVEL,
  581. "IoWMIWriteEvent: Invalid loggerid %d\n",
  582. LoggerId);
  583. #endif
  584. return STATUS_WMI_INSTANCE_NOT_FOUND;
  585. }
  586. if ( (WnodeHeader->Flags & WNODE_FLAG_TRACED_GUID) ||
  587. (WnodeHeader->Flags & WNODE_FLAG_LOG_WNODE) )
  588. {
  589. ULONG LoggerId = WmiGetLoggerId(WnodeHeader->HistoricalContext);
  590. ULONG IsTrace = WnodeHeader->Flags & WNODE_FLAG_TRACED_GUID;
  591. ULONG SavedSize = WnodeHeader->BufferSize;
  592. PULONG TraceMarker = (PULONG) WnodeHeader;
  593. if (SavedSize < sizeof(WNODE_HEADER))
  594. return STATUS_BUFFER_TOO_SMALL;
  595. //
  596. // If trace header, turn higher bit on and support
  597. // only full header
  598. //
  599. if (IsTrace)
  600. {
  601. if (SavedSize > 0XFFFF) // restrict to USHORT max size
  602. return STATUS_BUFFER_OVERFLOW;
  603. *TraceMarker |= TRACE_HEADER_FLAG | TRACE_HEADER_EVENT_TRACE |
  604. (TRACE_HEADER_TYPE_FULL_HEADER << 16);
  605. }
  606. else
  607. {
  608. if (SavedSize & TRACE_HEADER_FLAG)
  609. return STATUS_BUFFER_OVERFLOW;
  610. }
  611. Status = STATUS_INVALID_HANDLE;
  612. if (LoggerId > 0 && LoggerId < MAXLOGGERS)
  613. {
  614. if (WmipLoggerContext[LoggerId] != NULL)
  615. {
  616. //
  617. // NOTE: The rule here is that IoWMIWriteEvent is always
  618. // called in kernel mode, and the buffer needs not be probed!
  619. //
  620. Status = WmiTraceEvent(WnodeHeader, KernelMode);
  621. }
  622. }
  623. // NOTE: If it is a trace, we will not go any further
  624. // Otherwise, if it is a regular WMI event, it will still
  625. // be processed by WMI.
  626. if (IsTrace)
  627. {
  628. WnodeHeader->BufferSize = SavedSize;
  629. return Status;
  630. }
  631. }
  632. #endif // MEMPHIS
  633. //
  634. // Memory for event buffers is limited so the size of any event is also
  635. // limited.
  636. #if DBG
  637. if (WnodeHeader->BufferSize > LARGEKMWNODEEVENTSIZE)
  638. {
  639. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_EVENT_INFO_LEVEL,
  640. "WMI: Large event %p fired by %x via WMI\n",
  641. WnodeEventItem,
  642. ((PWNODE_HEADER)WnodeEventItem)->ProviderId));
  643. }
  644. #endif
  645. if (WnodeHeader->BufferSize <= WmipMaxKmWnodeEventSize)
  646. {
  647. EventContext = ExAllocatePoolWithTag(NonPagedPool,
  648. sizeof(EVENTWORKCONTEXT),
  649. WMINWPOOLTAG);
  650. if (EventContext != NULL)
  651. {
  652. //
  653. // Try to take a refcount on the regentry associated with the
  654. // provider id in the event. If we are successful then we set a
  655. // flag in the wnode header saying so. When processing the
  656. // event in the work item we check the flag and if it is set
  657. // we'll go looking for the regentry on the active and zombie
  658. // lists and then use it. At that time it will give up the ref
  659. // count taken here so that if the regentry really is a zombie
  660. // then it will go away peacefully.
  661. //
  662. KeAcquireSpinLock(&WmipRegistrationSpinLock,
  663. &OldIrql);
  664. RegEntry = WmipDoFindRegEntryByProviderId(WnodeHeader->ProviderId,
  665. REGENTRY_FLAG_RUNDOWN);
  666. if (RegEntry != NULL)
  667. {
  668. WmipReferenceRegEntry(RegEntry);
  669. }
  670. KeReleaseSpinLock(&WmipRegistrationSpinLock,
  671. OldIrql);
  672. WnodeHeader->ClientContext = WnodeHeader->Version;
  673. EventContext->RegEntry = RegEntry;
  674. EventContext->Wnode = WnodeHeader;
  675. ExInterlockedInsertTailList(
  676. &WmipNPEvent,
  677. &EventContext->ListEntry,
  678. &WmipNPNotificationSpinlock);
  679. //
  680. // If the queue was empty then there was no work item outstanding
  681. // to move from non paged to paged memory. So fire up a work item
  682. // to do so.
  683. if (InterlockedIncrement(&WmipEventWorkItems) == 1)
  684. {
  685. ExQueueWorkItem( &WmipEventWorkQueueItem, DelayedWorkQueue );
  686. }
  687. Status = STATUS_SUCCESS;
  688. } else {
  689. Status = STATUS_INSUFFICIENT_RESOURCES;
  690. }
  691. } else {
  692. Status = STATUS_BUFFER_OVERFLOW;
  693. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_EVENT_INFO_LEVEL,
  694. "WMI: IoWMIWriteEvent detected an event %p fired by %x that exceeds the maximum event size\n",
  695. WnodeEventItem,
  696. ((PWNODE_HEADER)WnodeEventItem)->ProviderId));
  697. }
  698. return(Status);
  699. }
  700. // IoWMIDeviceObjectToProviderId is in register.c
  701. NTSTATUS IoWMIOpenBlock(
  702. IN GUID *Guid,
  703. IN ULONG DesiredAccess,
  704. OUT PVOID *DataBlockObject
  705. )
  706. {
  707. OBJECT_ATTRIBUTES ObjectAttributes;
  708. WCHAR ObjectName[WmiGuidObjectNameLength+1];
  709. UNICODE_STRING ObjectString;
  710. ULONG Ioctl;
  711. NTSTATUS Status;
  712. HANDLE DataBlockHandle;
  713. PAGED_CODE();
  714. //
  715. // Establish the OBJECT_ATTRIBUTES for the guid object
  716. //
  717. wcscpy(ObjectName, WmiGuidObjectDirectory);
  718. swprintf(&ObjectName[9],
  719. L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  720. Guid->Data1, Guid->Data2,
  721. Guid->Data3,
  722. Guid->Data4[0], Guid->Data4[1],
  723. Guid->Data4[2], Guid->Data4[3],
  724. Guid->Data4[4], Guid->Data4[5],
  725. Guid->Data4[6], Guid->Data4[7]);
  726. RtlInitUnicodeString(&ObjectString, ObjectName);
  727. RtlZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
  728. ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
  729. ObjectAttributes.ObjectName = &ObjectString;
  730. ObjectAttributes.Attributes = OBJ_KERNEL_HANDLE;
  731. if (DesiredAccess & WMIGUID_NOTIFICATION)
  732. {
  733. Ioctl = IOCTL_WMI_OPEN_GUID_FOR_EVENTS;
  734. } else {
  735. Ioctl = IOCTL_WMI_OPEN_GUID_FOR_QUERYSET;
  736. }
  737. Status = WmipOpenBlock(Ioctl,
  738. KernelMode,
  739. &ObjectAttributes,
  740. DesiredAccess,
  741. &DataBlockHandle);
  742. if (NT_SUCCESS(Status))
  743. {
  744. Status = ObReferenceObjectByHandle(DataBlockHandle,
  745. DesiredAccess,
  746. WmipGuidObjectType,
  747. KernelMode,
  748. DataBlockObject,
  749. NULL);
  750. ZwClose(DataBlockHandle);
  751. }
  752. return(Status);
  753. }
  754. //
  755. // Useful macro to establish a WNODE_HEADER quickly
  756. #define WmipBuildWnodeHeader(Wnode, WnodeSize, FlagsUlong, Handle) { \
  757. ((PWNODE_HEADER)(Wnode))->Flags = FlagsUlong; \
  758. ((PWNODE_HEADER)(Wnode))->KernelHandle = Handle; \
  759. ((PWNODE_HEADER)(Wnode))->BufferSize = WnodeSize; \
  760. ((PWNODE_HEADER)(Wnode))->Linkage = 0; \
  761. }
  762. NTSTATUS IoWMIQueryAllData(
  763. IN PVOID DataBlockObject,
  764. IN OUT ULONG *InOutBufferSize,
  765. OUT /* non paged */ PVOID OutBuffer
  766. )
  767. {
  768. NTSTATUS Status;
  769. WNODE_ALL_DATA WnodeAD;
  770. ULONG WnodeSize;
  771. ULONG RetSize;
  772. PWNODE_ALL_DATA Wnode;
  773. PAGED_CODE();
  774. //
  775. // See if the caller passed a buffer that is large enough
  776. //
  777. WnodeSize = *InOutBufferSize;
  778. Wnode = (PWNODE_ALL_DATA)OutBuffer;
  779. if ((Wnode == NULL) || (WnodeSize < sizeof(WNODE_ALL_DATA)))
  780. {
  781. Wnode = &WnodeAD;
  782. WnodeSize = sizeof(WnodeAD);
  783. }
  784. //
  785. // Initialize buffer for query
  786. //
  787. WmipBuildWnodeHeader(Wnode,
  788. sizeof(WNODE_HEADER),
  789. WNODE_FLAG_ALL_DATA,
  790. NULL);
  791. Status = WmipQueryAllData(DataBlockObject,
  792. NULL,
  793. KernelMode,
  794. Wnode,
  795. WnodeSize,
  796. &RetSize);
  797. //
  798. // if this was a successful query then extract the results
  799. //
  800. if (NT_SUCCESS(Status))
  801. {
  802. if (Wnode->WnodeHeader.Flags & WNODE_FLAG_INTERNAL)
  803. {
  804. //
  805. // Internal guids are not supported in KM
  806. //
  807. Status = STATUS_NOT_SUPPORTED;
  808. } else if (Wnode->WnodeHeader.Flags & WNODE_FLAG_TOO_SMALL) {
  809. //
  810. // Buffer passed was too small for provier
  811. //
  812. *InOutBufferSize = ((PWNODE_TOO_SMALL)Wnode)->SizeNeeded;
  813. Status = STATUS_BUFFER_TOO_SMALL;
  814. } else {
  815. //
  816. // Buffer was large enough for provider
  817. //
  818. *InOutBufferSize = RetSize;
  819. if (Wnode == &WnodeAD)
  820. {
  821. //
  822. // Although there was enough room for the provider,
  823. // the caller didn't pass a large enough buffer
  824. // so we need to return a buffer too small error
  825. //
  826. Status = STATUS_BUFFER_TOO_SMALL;
  827. }
  828. }
  829. }
  830. return(Status);
  831. }
  832. NTSTATUS
  833. IoWMIQueryAllDataMultiple(
  834. IN PVOID *DataBlockObjectList,
  835. IN ULONG ObjectCount,
  836. IN OUT ULONG *InOutBufferSize,
  837. OUT PVOID OutBuffer
  838. )
  839. {
  840. NTSTATUS Status;
  841. WNODE_ALL_DATA WnodeAD;
  842. PWNODE_HEADER Wnode;
  843. ULONG WnodeSize;
  844. ULONG RetSize;
  845. PAGED_CODE();
  846. //
  847. // Make sure we have an output buffer
  848. //
  849. WnodeSize = *InOutBufferSize;
  850. Wnode = (PWNODE_HEADER)OutBuffer;
  851. if ((Wnode == NULL) || (WnodeSize < sizeof(WNODE_ALL_DATA)))
  852. {
  853. Wnode = (PWNODE_HEADER)&WnodeAD;
  854. WnodeSize = sizeof(WnodeAD);
  855. }
  856. Status = WmipQueryAllDataMultiple(ObjectCount,
  857. (PWMIGUIDOBJECT *)DataBlockObjectList,
  858. NULL,
  859. KernelMode,
  860. (PUCHAR)Wnode,
  861. WnodeSize,
  862. NULL,
  863. &RetSize);
  864. //
  865. // if this was a successful query then extract the results
  866. //
  867. if (NT_SUCCESS(Status))
  868. {
  869. if (Wnode->Flags & WNODE_FLAG_TOO_SMALL)
  870. {
  871. //
  872. // Buffer passed to provider was too small
  873. //
  874. *InOutBufferSize = ((PWNODE_TOO_SMALL)Wnode)->SizeNeeded;
  875. Status = STATUS_BUFFER_TOO_SMALL;
  876. } else {
  877. //
  878. // Buffer was large enough for provider
  879. //
  880. *InOutBufferSize = RetSize;
  881. if (Wnode == (PWNODE_HEADER)&WnodeAD)
  882. {
  883. //
  884. // Although there was enough room for the provider,
  885. // the caller didn't pass a large enough buffer
  886. // so we need to return a buffer too small error
  887. //
  888. Status = STATUS_BUFFER_TOO_SMALL;
  889. }
  890. }
  891. }
  892. return(Status);
  893. }
  894. NTSTATUS
  895. IoWMIQuerySingleInstance(
  896. IN PVOID DataBlockObject,
  897. IN PUNICODE_STRING InstanceName,
  898. IN OUT ULONG *InOutBufferSize,
  899. OUT PVOID OutBuffer
  900. )
  901. {
  902. NTSTATUS Status;
  903. PWNODE_SINGLE_INSTANCE WnodeSI;
  904. ULONG WnodeSize;
  905. PWCHAR WPtr;
  906. ULONG SizeNeeded;
  907. ULONG RetSize;
  908. PAGED_CODE();
  909. //
  910. // Make sure we have an output buffer
  911. //
  912. SizeNeeded = (FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  913. VariableData) +
  914. InstanceName->Length +
  915. sizeof(USHORT) + 7) & ~7;
  916. WnodeSize = *InOutBufferSize;
  917. WnodeSI = (PWNODE_SINGLE_INSTANCE)OutBuffer;
  918. if ((WnodeSI == NULL) || (WnodeSize < SizeNeeded))
  919. {
  920. WnodeSI = (PWNODE_SINGLE_INSTANCE)WmipAllocNP(SizeNeeded);
  921. WnodeSize = SizeNeeded;
  922. }
  923. if (WnodeSI != NULL)
  924. {
  925. //
  926. // Build WNODE_SINGLE_INSTANCE appropriately and query
  927. //
  928. RtlZeroMemory(WnodeSI, FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  929. VariableData));
  930. WmipBuildWnodeHeader(WnodeSI,
  931. SizeNeeded,
  932. WNODE_FLAG_SINGLE_INSTANCE,
  933. NULL);
  934. WnodeSI->OffsetInstanceName = FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  935. VariableData);
  936. WnodeSI->DataBlockOffset = SizeNeeded;
  937. //
  938. // Copy InstanceName into the WnodeSingleInstance for the query.
  939. //
  940. WPtr = (PWCHAR)OffsetToPtr(WnodeSI, WnodeSI->OffsetInstanceName);
  941. *WPtr++ = InstanceName->Length;
  942. RtlCopyMemory(WPtr, InstanceName->Buffer, InstanceName->Length);
  943. Status = WmipQuerySetExecuteSI((PWMIGUIDOBJECT)DataBlockObject,
  944. NULL,
  945. KernelMode,
  946. IRP_MN_QUERY_SINGLE_INSTANCE,
  947. (PWNODE_HEADER)WnodeSI,
  948. WnodeSize,
  949. &RetSize);
  950. //
  951. // if this was a successful query then extract the results
  952. //
  953. if (NT_SUCCESS(Status))
  954. {
  955. if (WnodeSI->WnodeHeader.Flags & WNODE_FLAG_INTERNAL)
  956. {
  957. //
  958. // Internal guids are not supported in KM
  959. //
  960. Status = STATUS_NOT_SUPPORTED;
  961. } else if (WnodeSI->WnodeHeader.Flags & WNODE_FLAG_TOO_SMALL) {
  962. //
  963. // Our buffer was too small
  964. //
  965. *InOutBufferSize = ((PWNODE_TOO_SMALL)WnodeSI)->SizeNeeded;
  966. Status = STATUS_BUFFER_TOO_SMALL;
  967. } else {
  968. //
  969. // Buffer not too small, remember output size
  970. //
  971. *InOutBufferSize = RetSize;
  972. if (WnodeSI != OutBuffer)
  973. {
  974. //
  975. // Although there was enough room for the provider,
  976. // the caller didn't pass a large enough buffer
  977. // so we need to return a buffer too small error
  978. //
  979. Status = STATUS_BUFFER_TOO_SMALL;
  980. }
  981. }
  982. }
  983. if (WnodeSI != OutBuffer)
  984. {
  985. WmipFree(WnodeSI);
  986. }
  987. } else {
  988. Status = STATUS_INSUFFICIENT_RESOURCES;
  989. }
  990. return(Status);
  991. }
  992. NTSTATUS
  993. IoWMIQuerySingleInstanceMultiple(
  994. IN PVOID *DataBlockObjectList,
  995. IN PUNICODE_STRING InstanceNames,
  996. IN ULONG ObjectCount,
  997. IN OUT ULONG *InOutBufferSize,
  998. OUT PVOID OutBuffer
  999. )
  1000. {
  1001. NTSTATUS Status;
  1002. ULONG RetSize;
  1003. PWNODE_HEADER Wnode;
  1004. WNODE_TOO_SMALL WnodeTooSmall;
  1005. ULONG WnodeSize;
  1006. PAGED_CODE();
  1007. WnodeSize = *InOutBufferSize;
  1008. Wnode = (PWNODE_HEADER)OutBuffer;
  1009. if ((Wnode == NULL) || (WnodeSize < sizeof(WNODE_TOO_SMALL)))
  1010. {
  1011. Wnode = (PWNODE_HEADER)&WnodeTooSmall;
  1012. WnodeSize = sizeof(WNODE_TOO_SMALL);
  1013. }
  1014. Status = WmipQuerySingleMultiple(NULL,
  1015. KernelMode,
  1016. (PUCHAR)Wnode,
  1017. WnodeSize,
  1018. NULL,
  1019. ObjectCount,
  1020. (PWMIGUIDOBJECT *)DataBlockObjectList,
  1021. InstanceNames,
  1022. &RetSize);
  1023. //
  1024. // if this was a successful query then extract the results
  1025. //
  1026. if (NT_SUCCESS(Status))
  1027. {
  1028. if (Wnode->Flags & WNODE_FLAG_TOO_SMALL)
  1029. {
  1030. //
  1031. // Buffer passed to provider was too small
  1032. //
  1033. *InOutBufferSize = ((PWNODE_TOO_SMALL)Wnode)->SizeNeeded;
  1034. Status = STATUS_BUFFER_TOO_SMALL;
  1035. } else {
  1036. //
  1037. // Buffer was large enough for provider
  1038. //
  1039. *InOutBufferSize = RetSize;
  1040. if (Wnode == (PWNODE_HEADER)&WnodeTooSmall)
  1041. {
  1042. //
  1043. // Although there was enough room for the provider,
  1044. // the caller didn't pass a large enough buffer
  1045. // so we need to return a buffer too small error
  1046. //
  1047. Status = STATUS_BUFFER_TOO_SMALL;
  1048. }
  1049. }
  1050. }
  1051. return(Status);
  1052. }
  1053. NTSTATUS
  1054. IoWMISetSingleInstance(
  1055. IN PVOID DataBlockObject,
  1056. IN PUNICODE_STRING InstanceName,
  1057. IN ULONG Version,
  1058. IN ULONG ValueBufferSize,
  1059. IN PVOID ValueBuffer
  1060. )
  1061. {
  1062. NTSTATUS Status;
  1063. PWNODE_SINGLE_INSTANCE WnodeSI;
  1064. PWCHAR WPtr;
  1065. ULONG SizeNeeded;
  1066. ULONG RetSize;
  1067. ULONG InstanceOffset;
  1068. ULONG DataOffset;
  1069. PUCHAR DPtr;
  1070. PAGED_CODE();
  1071. InstanceOffset = (FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  1072. VariableData) + 1) & ~1;
  1073. DataOffset = (InstanceOffset +
  1074. InstanceName->Length + sizeof(USHORT) + 7) & ~7;
  1075. SizeNeeded = DataOffset + ValueBufferSize;
  1076. WnodeSI = (PWNODE_SINGLE_INSTANCE)WmipAllocNP(SizeNeeded);
  1077. if (WnodeSI != NULL)
  1078. {
  1079. //
  1080. // Build WNODE_SINGLE_INSTANCE appropriately and query
  1081. //
  1082. RtlZeroMemory(WnodeSI, FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  1083. VariableData));
  1084. WmipBuildWnodeHeader(WnodeSI,
  1085. SizeNeeded,
  1086. WNODE_FLAG_SINGLE_INSTANCE,
  1087. NULL);
  1088. WnodeSI->WnodeHeader.Version = Version;
  1089. //
  1090. // Copy InstanceName into the WnodeSingleInstance for the query.
  1091. //
  1092. WnodeSI->OffsetInstanceName = InstanceOffset;
  1093. WPtr = (PWCHAR)OffsetToPtr(WnodeSI, WnodeSI->OffsetInstanceName);
  1094. *WPtr++ = InstanceName->Length;
  1095. RtlCopyMemory(WPtr, InstanceName->Buffer, InstanceName->Length);
  1096. //
  1097. // Copy the new data into the WNODE
  1098. //
  1099. WnodeSI->SizeDataBlock = ValueBufferSize;
  1100. WnodeSI->DataBlockOffset = DataOffset;
  1101. DPtr = OffsetToPtr(WnodeSI, WnodeSI->DataBlockOffset);
  1102. RtlCopyMemory(DPtr, ValueBuffer, ValueBufferSize);
  1103. Status = WmipQuerySetExecuteSI(DataBlockObject,
  1104. NULL,
  1105. KernelMode,
  1106. IRP_MN_CHANGE_SINGLE_INSTANCE,
  1107. (PWNODE_HEADER)WnodeSI,
  1108. SizeNeeded,
  1109. &RetSize);
  1110. WmipFree(WnodeSI);
  1111. } else {
  1112. Status = STATUS_INSUFFICIENT_RESOURCES;
  1113. }
  1114. return(Status);
  1115. }
  1116. NTSTATUS
  1117. IoWMISetSingleItem(
  1118. IN PVOID DataBlockObject,
  1119. IN PUNICODE_STRING InstanceName,
  1120. IN ULONG DataItemId,
  1121. IN ULONG Version,
  1122. IN ULONG ValueBufferSize,
  1123. IN PVOID ValueBuffer
  1124. )
  1125. {
  1126. NTSTATUS Status;
  1127. PWNODE_SINGLE_ITEM WnodeSI;
  1128. PWCHAR WPtr;
  1129. ULONG SizeNeeded;
  1130. ULONG RetSize;
  1131. ULONG InstanceOffset;
  1132. ULONG DataOffset;
  1133. PUCHAR DPtr;
  1134. PAGED_CODE();
  1135. InstanceOffset = (FIELD_OFFSET(WNODE_SINGLE_ITEM,
  1136. VariableData) + 1) & ~1;
  1137. DataOffset = (InstanceOffset +
  1138. InstanceName->Length + sizeof(USHORT) + 7) & ~7;
  1139. SizeNeeded = DataOffset + ValueBufferSize;
  1140. WnodeSI = (PWNODE_SINGLE_ITEM)WmipAllocNP(SizeNeeded);
  1141. if (WnodeSI != NULL)
  1142. {
  1143. //
  1144. // Build WNODE_SINGLE_INSTANCE appropriately and query
  1145. //
  1146. RtlZeroMemory(WnodeSI, FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  1147. VariableData));
  1148. WmipBuildWnodeHeader(WnodeSI,
  1149. SizeNeeded,
  1150. WNODE_FLAG_SINGLE_ITEM,
  1151. NULL);
  1152. WnodeSI->WnodeHeader.Version = Version;
  1153. WnodeSI->ItemId = DataItemId;
  1154. //
  1155. // Copy InstanceName into the WnodeSingleInstance for the query.
  1156. //
  1157. WnodeSI->OffsetInstanceName = InstanceOffset;
  1158. WPtr = (PWCHAR)OffsetToPtr(WnodeSI, WnodeSI->OffsetInstanceName);
  1159. *WPtr++ = InstanceName->Length;
  1160. RtlCopyMemory(WPtr, InstanceName->Buffer, InstanceName->Length);
  1161. //
  1162. // Copy the new data into the WNODE
  1163. //
  1164. WnodeSI->SizeDataItem = ValueBufferSize;
  1165. WnodeSI->DataBlockOffset = DataOffset;
  1166. DPtr = OffsetToPtr(WnodeSI, WnodeSI->DataBlockOffset);
  1167. RtlCopyMemory(DPtr, ValueBuffer, ValueBufferSize);
  1168. Status = WmipQuerySetExecuteSI(DataBlockObject,
  1169. NULL,
  1170. KernelMode,
  1171. IRP_MN_CHANGE_SINGLE_ITEM,
  1172. (PWNODE_HEADER)WnodeSI,
  1173. SizeNeeded,
  1174. &RetSize);
  1175. WmipFree(WnodeSI);
  1176. } else {
  1177. Status = STATUS_INSUFFICIENT_RESOURCES;
  1178. }
  1179. return(Status);
  1180. }
  1181. NTSTATUS IoWMIExecuteMethod(
  1182. IN PVOID DataBlockObject,
  1183. IN PUNICODE_STRING InstanceName,
  1184. IN ULONG MethodId,
  1185. IN ULONG InBufferSize,
  1186. IN OUT PULONG OutBufferSize,
  1187. IN OUT PUCHAR InOutBuffer
  1188. )
  1189. {
  1190. NTSTATUS Status;
  1191. PWNODE_METHOD_ITEM WnodeMI;
  1192. PWCHAR WPtr;
  1193. PUCHAR DPtr;
  1194. ULONG SizeNeeded;
  1195. ULONG RetSize;
  1196. ULONG DataOffset;
  1197. PAGED_CODE();
  1198. //
  1199. // Make sure we have an output buffer
  1200. //
  1201. DataOffset = (FIELD_OFFSET(WNODE_METHOD_ITEM,
  1202. VariableData) +
  1203. InstanceName->Length +
  1204. sizeof(USHORT) +
  1205. 7) & ~7;
  1206. SizeNeeded = DataOffset +
  1207. ((InBufferSize > *OutBufferSize) ? InBufferSize :
  1208. *OutBufferSize);
  1209. WnodeMI = (PWNODE_METHOD_ITEM)WmipAllocNP(SizeNeeded);
  1210. if (WnodeMI != NULL)
  1211. {
  1212. //
  1213. // Build WNODE_SINGLE_INSTANCE appropriately and query
  1214. //
  1215. RtlZeroMemory(WnodeMI, FIELD_OFFSET(WNODE_METHOD_ITEM,
  1216. VariableData));
  1217. WmipBuildWnodeHeader(WnodeMI,
  1218. SizeNeeded,
  1219. WNODE_FLAG_METHOD_ITEM,
  1220. NULL);
  1221. WnodeMI->MethodId = MethodId;
  1222. WnodeMI->OffsetInstanceName = FIELD_OFFSET(WNODE_METHOD_ITEM,
  1223. VariableData);
  1224. WnodeMI->DataBlockOffset = DataOffset;
  1225. WnodeMI->SizeDataBlock = InBufferSize;
  1226. //
  1227. // Copy InstanceName into the WnodeMethodItem for the query.
  1228. //
  1229. WPtr = (PWCHAR)OffsetToPtr(WnodeMI, WnodeMI->OffsetInstanceName);
  1230. *WPtr++ = InstanceName->Length;
  1231. RtlCopyMemory(WPtr, InstanceName->Buffer, InstanceName->Length);
  1232. //
  1233. // Copy the input data into the WnodeMethodItem
  1234. //
  1235. DPtr = (PUCHAR)OffsetToPtr(WnodeMI, WnodeMI->DataBlockOffset);
  1236. RtlCopyMemory(DPtr, InOutBuffer, InBufferSize);
  1237. Status = WmipQuerySetExecuteSI(DataBlockObject,NULL,
  1238. KernelMode,
  1239. IRP_MN_EXECUTE_METHOD,
  1240. (PWNODE_HEADER)WnodeMI,
  1241. SizeNeeded,
  1242. &RetSize);
  1243. //
  1244. // if this was a successful query then extract the results
  1245. //
  1246. if (NT_SUCCESS(Status))
  1247. {
  1248. if (WnodeMI->WnodeHeader.Flags & WNODE_FLAG_TOO_SMALL)
  1249. {
  1250. //
  1251. // Our buffer was too small
  1252. //
  1253. *OutBufferSize = ( (((PWNODE_TOO_SMALL)WnodeMI)->SizeNeeded -
  1254. DataOffset) + 7 ) & ~7;
  1255. Status = STATUS_BUFFER_TOO_SMALL;
  1256. } else {
  1257. //
  1258. // Buffer not too small, remember output size
  1259. //
  1260. if (*OutBufferSize >= WnodeMI->SizeDataBlock)
  1261. {
  1262. *OutBufferSize = WnodeMI->SizeDataBlock;
  1263. DPtr = (PUCHAR)OffsetToPtr(WnodeMI,
  1264. WnodeMI->DataBlockOffset);
  1265. RtlCopyMemory(InOutBuffer, DPtr, WnodeMI->SizeDataBlock);
  1266. } else {
  1267. *OutBufferSize = (WnodeMI->SizeDataBlock + 7) & ~7;
  1268. Status = STATUS_BUFFER_TOO_SMALL;
  1269. }
  1270. }
  1271. }
  1272. WmipFree(WnodeMI);
  1273. } else {
  1274. Status = STATUS_INSUFFICIENT_RESOURCES;
  1275. }
  1276. return(Status);
  1277. }
  1278. NTSTATUS
  1279. IoWMISetNotificationCallback(
  1280. IN PVOID Object,
  1281. IN WMI_NOTIFICATION_CALLBACK Callback,
  1282. IN PVOID Context
  1283. )
  1284. {
  1285. NTSTATUS Status;
  1286. PWMIGUIDOBJECT GuidObject;
  1287. PAGED_CODE();
  1288. GuidObject = (PWMIGUIDOBJECT)Object;
  1289. WmipAssert(GuidObject->Flags & WMIGUID_FLAG_KERNEL_NOTIFICATION);
  1290. WmipEnterSMCritSection();
  1291. GuidObject->Callback = Callback;
  1292. GuidObject->CallbackContext = Context;
  1293. WmipLeaveSMCritSection();
  1294. return(STATUS_SUCCESS);
  1295. }
  1296. NTSTATUS IoWMIHandleToInstanceName(
  1297. IN PVOID DataBlockObject,
  1298. IN HANDLE FileHandle,
  1299. OUT PUNICODE_STRING InstanceName
  1300. )
  1301. {
  1302. NTSTATUS Status;
  1303. PAGED_CODE();
  1304. Status = WmipTranslateFileHandle(NULL,
  1305. NULL,
  1306. FileHandle,
  1307. NULL,
  1308. DataBlockObject,
  1309. InstanceName);
  1310. return(Status);
  1311. }
  1312. NTSTATUS IoWMIDeviceObjectToInstanceName(
  1313. IN PVOID DataBlockObject,
  1314. IN PDEVICE_OBJECT DeviceObject,
  1315. OUT PUNICODE_STRING InstanceName
  1316. )
  1317. {
  1318. NTSTATUS Status;
  1319. PAGED_CODE();
  1320. Status = WmipTranslateFileHandle(NULL,
  1321. NULL,
  1322. NULL,
  1323. DeviceObject,
  1324. DataBlockObject,
  1325. InstanceName);
  1326. return(Status);
  1327. }
  1328. #if 0
  1329. NTSTATUS
  1330. IoWMISetGuidSecurity(
  1331. IN PVOID Object,
  1332. IN SECURITY_INFORMATION SecurityInformation,
  1333. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  1334. )
  1335. {
  1336. NTSTATUS status;
  1337. PAGED_CODE();
  1338. DaclLength = (ULONG)sizeof(ACL) +
  1339. (1*((ULONG)sizeof(ACCESS_ALLOWED_ACE))) +
  1340. SeLengthSid( SeLocalSystemSid ) +
  1341. 8; // The 8 is just for good measure
  1342. ServiceDeviceSd = (PSECURITY_DESCRIPTOR)ExAllocatePoolWithTag(PagedPool,
  1343. DaclLength +
  1344. sizeof(SECURITY_DESCRIPTOR),
  1345. 'ZZZZ');
  1346. if (ServiceDeviceSd == NULL)
  1347. {
  1348. return(NULL);
  1349. }
  1350. ServiceDeviceDacl = (PACL)((PUCHAR)ServiceDeviceSd +
  1351. sizeof(SECURITY_DESCRIPTOR));
  1352. Status = RtlCreateAcl( ServiceDeviceDacl,
  1353. DaclLength,
  1354. ACL_REVISION2);
  1355. if (! NT_SUCCESS(Status))
  1356. {
  1357. goto Cleanup;
  1358. }
  1359. Status = RtlAddAccessAllowedAce (
  1360. ServiceDeviceDacl,
  1361. ACL_REVISION2,
  1362. FILE_ALL_ACCESS,
  1363. SeLocalSystemSid
  1364. );
  1365. if (! NT_SUCCESS(Status))
  1366. {
  1367. goto Cleanup;
  1368. }
  1369. Status = RtlCreateSecurityDescriptor(
  1370. ServiceDeviceSd,
  1371. SECURITY_DESCRIPTOR_REVISION1
  1372. );
  1373. if (! NT_SUCCESS(Status))
  1374. {
  1375. goto Cleanup;
  1376. }
  1377. Status = RtlSetDaclSecurityDescriptor(
  1378. ServiceDeviceSd,
  1379. TRUE, // DaclPresent
  1380. ServiceDeviceDacl,
  1381. FALSE // DaclDefaulted
  1382. );
  1383. if (! NT_SUCCESS(Status))
  1384. {
  1385. goto Cleanup;
  1386. }
  1387. Cleanup:
  1388. if (! NT_SUCCESS(Status))
  1389. {
  1390. ExFreePool(ServiceDeviceSd);
  1391. ServiceDeviceSd = NULL;
  1392. }
  1393. status = ObSetSecurityObjectByPointer(Object,
  1394. SecurityInformation,
  1395. SecurityDescriptor);
  1396. return(status);
  1397. }
  1398. #endif