Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1080 lines
33 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. devices.c
  5. Abstract:
  6. Plug and Play Manager routines dealing with device manipulation/registration.
  7. Author:
  8. Lonny McMichael (lonnym) 02/14/95
  9. Revision History:
  10. --*/
  11. #include "pnpmgrp.h"
  12. #pragma hdrstop
  13. typedef struct {
  14. BOOLEAN Add;
  15. } PROCESS_DRIVER_CONTEXT, *PPROCESS_DRIVER_CONTEXT;
  16. typedef NTSTATUS (*PDEVICE_SERVICE_ITERATOR_ROUTINE)(
  17. IN PUNICODE_STRING DeviceInstancePath,
  18. IN PUNICODE_STRING ServiceName,
  19. IN ULONG ServiceType,
  20. IN PVOID Context
  21. );
  22. typedef struct {
  23. PUNICODE_STRING DeviceInstancePath;
  24. PDEVICE_SERVICE_ITERATOR_ROUTINE Iterator;
  25. PVOID Context;
  26. } DEVICE_SERVICE_ITERATOR_CONTEXT, *PDEVICE_SERVICE_ITERATOR_CONTEXT;
  27. //
  28. // Prototype utility functions internal to this file.
  29. //
  30. NTSTATUS
  31. PiFindDevInstMatch(
  32. IN HANDLE ServiceEnumHandle,
  33. IN PUNICODE_STRING DeviceInstanceName,
  34. OUT PULONG InstanceCount,
  35. OUT PUNICODE_STRING MatchingValueName,
  36. OUT PULONG MatchingInstance
  37. );
  38. NTSTATUS PiProcessDriverInstance(
  39. IN PUNICODE_STRING DeviceInstancePath,
  40. IN PUNICODE_STRING ServiceName,
  41. IN ULONG ServiceType,
  42. IN PPROCESS_DRIVER_CONTEXT Context
  43. );
  44. NTSTATUS
  45. PpForEachDeviceInstanceDriver(
  46. PUNICODE_STRING DeviceInstancePath,
  47. PDEVICE_SERVICE_ITERATOR_ROUTINE IteratorRoutine,
  48. PVOID Context
  49. );
  50. NTSTATUS
  51. PiForEachDriverQueryRoutine(
  52. IN PWSTR ValueName,
  53. IN ULONG ValueType,
  54. IN PVOID ValueData,
  55. IN ULONG ValueLength,
  56. IN PDEVICE_SERVICE_ITERATOR_CONTEXT InternalContext,
  57. IN ULONG ServiceType
  58. );
  59. VOID
  60. PiRearrangeDeviceInstances(
  61. IN HANDLE ServiceEnumHandle,
  62. IN ULONG InstanceCount,
  63. IN ULONG InstanceDeleted
  64. );
  65. #ifdef ALLOC_PRAGMA
  66. #pragma alloc_text(PAGE, PpDeviceRegistration)
  67. #pragma alloc_text(PAGE, PiDeviceRegistration)
  68. #pragma alloc_text(PAGE, PiProcessDriverInstance)
  69. #pragma alloc_text(PAGE, PiFindDevInstMatch)
  70. #pragma alloc_text(PAGE, PpForEachDeviceInstanceDriver)
  71. #pragma alloc_text(PAGE, PiForEachDriverQueryRoutine)
  72. #pragma alloc_text(PAGE, PiRearrangeDeviceInstances)
  73. #endif // ALLOC_PRAGMA
  74. NTSTATUS
  75. PpDeviceRegistration(
  76. IN PUNICODE_STRING DeviceInstancePath,
  77. IN BOOLEAN Add,
  78. IN PUNICODE_STRING ServiceKeyName OPTIONAL
  79. )
  80. /*++
  81. Routine Description:
  82. If Add is set to TRUE, this Plug and Play Manager API creates (if necessary)
  83. and populates the volatile Enum subkey of a device's service list entry, based
  84. on the device instance path specified. If Add is set to FALSE, the specified
  85. device instance will be removed from the volatile Enum subkey of a device's
  86. service list entry.
  87. For example, if there is a device in the Enum tree as follows:
  88. HKLM\System\Enum\PCI
  89. \foo
  90. \0000
  91. Service = REG_SZ bar
  92. \0001
  93. Service = REG_SZ other
  94. The result of the call, PpDeviceRegistration("PCI\foo\0000", Add = TRUE), would be:
  95. HKLM\CurrentControlSet\Services
  96. \bar
  97. \Enum
  98. Count = REG_DWORD 1
  99. 0 = REG_SZ PCI\foo\0000
  100. Arguments:
  101. DeviceInstancePath - Supplies the path in the registry (relative to
  102. HKLM\CCS\System\Enum) of the device to be registered/deregistered.
  103. This path must point to an instance subkey.
  104. Add - Supplies a BOOLEAN value to indicate the operation is for addition or removal.
  105. ServiceKeyName - Optionally, supplies the address of a unicode string to
  106. receive the name of the registry key for this device
  107. instance's service (if one exists). The caller must
  108. release the space once done with it.
  109. Return Value:
  110. NTSTATUS code indicating whether or not the function was successful
  111. --*/
  112. {
  113. NTSTATUS Status;
  114. PAGED_CODE();
  115. //
  116. // Acquire PnP device-specific registry resource for exclusive (read/write) access.
  117. //
  118. PiLockPnpRegistry(TRUE);
  119. Status = PiDeviceRegistration(DeviceInstancePath,
  120. Add,
  121. ServiceKeyName);
  122. PiUnlockPnpRegistry();
  123. return Status;
  124. }
  125. NTSTATUS
  126. PiDeviceRegistration(
  127. IN PUNICODE_STRING DeviceInstancePath,
  128. IN BOOLEAN Add,
  129. IN PUNICODE_STRING ServiceKeyName OPTIONAL
  130. )
  131. /*++
  132. Routine Description:
  133. If Add is set to TRUE, this Plug and Play Manager API creates (if necessary)
  134. and populates the volatile Enum subkey of a device's service list entry, based
  135. on the device instance path specified. If Add is set to FALSE, the specified
  136. device instance will be removed from the volatile Enum subkey of a device's
  137. service list entry.
  138. For example, if there is a device in the Enum tree as follows:
  139. HKLM\System\Enum\PCI
  140. \foo
  141. \0000
  142. Service = REG_SZ bar
  143. \0001
  144. Service = REG_SZ other
  145. The result of the call, PpDeviceRegistration("PCI\foo\0000", Add = TRUE), would be:
  146. HKLM\CurrentControlSet\Services
  147. \bar
  148. \Enum
  149. Count = REG_DWORD 1
  150. 0 = REG_SZ PCI\foo\0000
  151. Arguments:
  152. DeviceInstancePath - Supplies the path in the registry (relative to
  153. HKLM\CCS\System\Enum) of the device to be registered/deregistered.
  154. This path must point to an instance subkey.
  155. Add - Supplies a BOOLEAN value to indicate the operation is for addition or removal.
  156. ServiceKeyName - Optionally, supplies the address of a unicode string to
  157. receive the name of the registry key for this device
  158. instance's service (if one exists). The caller must
  159. release the space once done with it.
  160. Return Value:
  161. NTSTATUS code indicating whether or not the function was successful
  162. --*/
  163. {
  164. NTSTATUS Status;
  165. UNICODE_STRING ServiceName;
  166. PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
  167. HANDLE TempKeyHandle;
  168. HANDLE DeviceInstanceHandle = NULL;
  169. PAGED_CODE();
  170. //
  171. // Assume successful completion.
  172. //
  173. Status = STATUS_SUCCESS;
  174. if (ServiceKeyName) {
  175. PiWstrToUnicodeString(ServiceKeyName, NULL);
  176. }
  177. //
  178. // 'Normalize' the DeviceInstancePath by stripping off a trailing
  179. // backslash (if present)
  180. //
  181. if (DeviceInstancePath->Length <= sizeof(WCHAR)) {
  182. Status = STATUS_INVALID_PARAMETER;
  183. goto PrepareForReturn1;
  184. }
  185. if (DeviceInstancePath->Buffer[CB_TO_CWC(DeviceInstancePath->Length) - 1] ==
  186. OBJ_NAME_PATH_SEPARATOR) {
  187. DeviceInstancePath->Length -= sizeof(WCHAR);
  188. }
  189. //
  190. // Open HKLM\System\CurrentControlSet\Enum
  191. //
  192. Status = IopOpenRegistryKeyEx( &TempKeyHandle,
  193. NULL,
  194. &CmRegistryMachineSystemCurrentControlSetEnumName,
  195. KEY_READ
  196. );
  197. if(!NT_SUCCESS(Status)) {
  198. goto PrepareForReturn1;
  199. }
  200. //
  201. // Open the specified device instance key under HKLM\CCS\System\Enum
  202. //
  203. Status = IopOpenRegistryKeyEx( &DeviceInstanceHandle,
  204. TempKeyHandle,
  205. DeviceInstancePath,
  206. KEY_READ
  207. );
  208. ZwClose(TempKeyHandle);
  209. if(!NT_SUCCESS(Status)) {
  210. goto PrepareForReturn1;
  211. }
  212. //
  213. // Read Service= value entry of the specified device instance key.
  214. //
  215. Status = IopGetRegistryValue(DeviceInstanceHandle,
  216. REGSTR_VALUE_SERVICE,
  217. &KeyValueInformation
  218. );
  219. ZwClose(DeviceInstanceHandle);
  220. if (NT_SUCCESS(Status)) {
  221. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  222. if (KeyValueInformation->Type == REG_SZ) {
  223. if (KeyValueInformation->DataLength > sizeof(UNICODE_NULL)) {
  224. IopRegistryDataToUnicodeString(&ServiceName,
  225. (PWSTR)KEY_VALUE_DATA(KeyValueInformation),
  226. KeyValueInformation->DataLength
  227. );
  228. Status = STATUS_SUCCESS;
  229. if (ServiceKeyName) {
  230. //
  231. // If need to return ServiceKeyName, make a copy now.
  232. //
  233. Status = PipConcatenateUnicodeStrings( ServiceKeyName,
  234. &ServiceName,
  235. NULL);
  236. }
  237. }
  238. }
  239. ExFreePool(KeyValueInformation);
  240. } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  241. //
  242. // The device instance key may have no Service value entry if the device
  243. // is raw capable.
  244. //
  245. Status = STATUS_SUCCESS;
  246. goto PrepareForReturn1;
  247. }
  248. if (NT_SUCCESS(Status)) {
  249. PROCESS_DRIVER_CONTEXT context;
  250. context.Add = Add;
  251. Status = PpForEachDeviceInstanceDriver(
  252. DeviceInstancePath,
  253. (PDEVICE_SERVICE_ITERATOR_ROUTINE) PiProcessDriverInstance,
  254. &context);
  255. if(!NT_SUCCESS(Status) && Add) {
  256. context.Add = FALSE;
  257. PpForEachDeviceInstanceDriver(DeviceInstancePath,
  258. PiProcessDriverInstance,
  259. &context);
  260. }
  261. }
  262. PrepareForReturn1:
  263. if (!NT_SUCCESS(Status)) {
  264. if (ServiceKeyName) {
  265. if (ServiceKeyName->Length != 0) {
  266. ExFreePool(ServiceKeyName->Buffer);
  267. ServiceKeyName->Buffer = NULL;
  268. ServiceKeyName->Length = ServiceKeyName->MaximumLength = 0;
  269. }
  270. }
  271. }
  272. return Status;
  273. }
  274. NTSTATUS
  275. PiProcessDriverInstance(
  276. IN PUNICODE_STRING DeviceInstancePath,
  277. IN PUNICODE_STRING ServiceName,
  278. IN ULONG ServiceType,
  279. IN PPROCESS_DRIVER_CONTEXT Context
  280. )
  281. {
  282. NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
  283. PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL;
  284. HANDLE ServiceEnumHandle;
  285. UNICODE_STRING MatchingDeviceInstance;
  286. UNICODE_STRING TempUnicodeString;
  287. CHAR UnicodeBuffer[20];
  288. BOOLEAN UpdateCount = FALSE;
  289. ULONG Count, instance;
  290. UNREFERENCED_PARAMETER( ServiceType );
  291. PAGED_CODE();
  292. ASSERT(Context != NULL);
  293. //
  294. // Next, open the service entry, and volatile Enum subkey
  295. // under HKLM\System\CurrentControlSet\Services (creating it if it
  296. // doesn't exist)
  297. //
  298. Status = PipOpenServiceEnumKeys(ServiceName,
  299. KEY_ALL_ACCESS,
  300. NULL,
  301. &ServiceEnumHandle,
  302. TRUE
  303. );
  304. if(!NT_SUCCESS(Status)) {
  305. goto PrepareForReturn2;
  306. }
  307. //
  308. // Now, search through the service's existing list of device instances, to see
  309. // if this instance has previously been registered.
  310. //
  311. Status = PiFindDevInstMatch(ServiceEnumHandle,
  312. DeviceInstancePath,
  313. &Count,
  314. &MatchingDeviceInstance,
  315. &instance
  316. );
  317. if (!NT_SUCCESS(Status)) {
  318. goto PrepareForReturn3;
  319. }
  320. if (!MatchingDeviceInstance.Buffer) {
  321. //
  322. // If we didn't find a match and caller wants to register the device, then we add
  323. // this instance to the service's Enum list.
  324. //
  325. if (Context->Add) {
  326. PWSTR instancePathBuffer;
  327. ULONG instancePathLength;
  328. PWSTR freeBuffer = NULL;
  329. //
  330. // Create the value entry and update NextInstance= for the madeup key
  331. //
  332. instancePathBuffer = DeviceInstancePath->Buffer;
  333. instancePathLength = DeviceInstancePath->Length;
  334. if (instancePathBuffer[instancePathLength / sizeof(WCHAR) - 1] !=
  335. UNICODE_NULL) {
  336. freeBuffer = (PWSTR)ExAllocatePool(PagedPool, instancePathLength + sizeof(WCHAR));
  337. if (freeBuffer) {
  338. RtlCopyMemory(freeBuffer,
  339. instancePathBuffer,
  340. instancePathLength
  341. );
  342. freeBuffer[instancePathLength / sizeof(WCHAR)] = UNICODE_NULL;
  343. instancePathBuffer = freeBuffer;
  344. instancePathLength += sizeof(WCHAR);
  345. }
  346. }
  347. PiUlongToUnicodeString(&TempUnicodeString, UnicodeBuffer, 20, Count);
  348. Status = ZwSetValueKey(
  349. ServiceEnumHandle,
  350. &TempUnicodeString,
  351. TITLE_INDEX_VALUE,
  352. REG_SZ,
  353. instancePathBuffer,
  354. instancePathLength
  355. );
  356. if (freeBuffer) {
  357. ExFreePool(freeBuffer);
  358. }
  359. Count++;
  360. UpdateCount = TRUE;
  361. }
  362. } else {
  363. //
  364. // If we did find a match and caller wants to deregister the device, then we remove
  365. // this instance from the service's Enum list.
  366. //
  367. ASSERT(instance != (ULONG)-1);
  368. if (Context->Add == FALSE) {
  369. ZwDeleteValueKey(ServiceEnumHandle, &MatchingDeviceInstance);
  370. Count--;
  371. UpdateCount = TRUE;
  372. //
  373. // Finally, if Count is not zero we need to physically reorganize the
  374. // instances under the ServiceKey\Enum key to make them contiguous. We
  375. // optimize by simply moving the last value into the empty slot. This behavior
  376. // is different for .Net Server release from previous releases but we hope
  377. // that no one depends on the ordering of values in this list. This list in a
  378. // way really represents the order in which devices (using this service) were
  379. // enumerated.
  380. //
  381. if (Count != 0) {
  382. PiRearrangeDeviceInstances(
  383. ServiceEnumHandle,
  384. Count,
  385. instance
  386. );
  387. }
  388. }
  389. }
  390. if (UpdateCount) {
  391. PiWstrToUnicodeString(&TempUnicodeString, REGSTR_VALUE_COUNT);
  392. ZwSetValueKey(
  393. ServiceEnumHandle,
  394. &TempUnicodeString,
  395. TITLE_INDEX_VALUE,
  396. REG_DWORD,
  397. &Count,
  398. sizeof(Count)
  399. );
  400. PiWstrToUnicodeString(&TempUnicodeString, REGSTR_VALUE_NEXT_INSTANCE);
  401. ZwSetValueKey(
  402. ServiceEnumHandle,
  403. &TempUnicodeString,
  404. TITLE_INDEX_VALUE,
  405. REG_DWORD,
  406. &Count,
  407. sizeof(Count)
  408. );
  409. }
  410. //
  411. // Need to release the matching device value name
  412. //
  413. if (MatchingDeviceInstance.Buffer) {
  414. RtlFreeUnicodeString(&MatchingDeviceInstance);
  415. }
  416. Status = STATUS_SUCCESS;
  417. PrepareForReturn3:
  418. ZwClose(ServiceEnumHandle);
  419. PrepareForReturn2:
  420. if (KeyValueInformation) {
  421. ExFreePool(KeyValueInformation);
  422. }
  423. return Status;
  424. }
  425. NTSTATUS
  426. PiFindDevInstMatch(
  427. IN HANDLE ServiceEnumHandle,
  428. IN PUNICODE_STRING DeviceInstanceName,
  429. OUT PULONG Count,
  430. OUT PUNICODE_STRING MatchingValueName,
  431. OUT PULONG MatchingInstance
  432. )
  433. /*++
  434. Routine Description:
  435. This routine searches through the specified Service\Enum values entries
  436. for a device instance matching the one specified by KeyInformation.
  437. If a matching is found, the MatchingValueName is returned and caller must
  438. free the unicode string when done with it.
  439. Arguments:
  440. ServiceEnumHandle - Supplies a handle to service enum key.
  441. DeviceInstanceName - Supplies a pointer to a unicode string specifying the
  442. name of the device instance key to search for.
  443. InstanceCount - Supplies a pointer to a ULONG variable to receive the device
  444. instance count under the service enum key.
  445. MatchingNameFound - Supplies a pointer to a UNICODE_STRING to receive the value
  446. name of the matched device instance.
  447. Return Value:
  448. A NTSTATUS code. if a matching is found, the MatchingValueName is the unicode
  449. string of the value name. Otherwise its length and Buffer will be set to empty.
  450. --*/
  451. {
  452. NTSTATUS status;
  453. ULONG i, instanceCount, length = 256, junk;
  454. UNICODE_STRING valueName, unicodeValue;
  455. PWCHAR unicodeBuffer;
  456. PKEY_VALUE_FULL_INFORMATION keyValueInformation = NULL;
  457. PAGED_CODE();
  458. //
  459. // Find out how many instances are referenced in the service's Enum key.
  460. //
  461. MatchingValueName->Length = 0;
  462. MatchingValueName->Buffer = NULL;
  463. *Count = instanceCount = 0;
  464. *MatchingInstance = (ULONG)-1;
  465. status = IopGetRegistryValue(ServiceEnumHandle,
  466. REGSTR_VALUE_COUNT,
  467. &keyValueInformation
  468. );
  469. if (NT_SUCCESS(status)) {
  470. if((keyValueInformation->Type == REG_DWORD) &&
  471. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  472. instanceCount = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  473. *Count = instanceCount;
  474. }
  475. ExFreePool(keyValueInformation);
  476. } else if(status != STATUS_OBJECT_NAME_NOT_FOUND) {
  477. return status;
  478. } else {
  479. //
  480. // If 'Count' value entry not found, consider this to mean there are simply
  481. // no device instance controlled by this service. Thus we don't have a match.
  482. //
  483. return STATUS_SUCCESS;
  484. }
  485. keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePool(
  486. PagedPool, length);
  487. if (!keyValueInformation) {
  488. return STATUS_INSUFFICIENT_RESOURCES;
  489. }
  490. //
  491. // Allocate heap to store value name
  492. //
  493. unicodeBuffer = (PWSTR)ExAllocatePool(PagedPool, 10 * sizeof(WCHAR));
  494. if (!unicodeBuffer) {
  495. ExFreePool(keyValueInformation);
  496. return STATUS_INSUFFICIENT_RESOURCES;
  497. }
  498. //
  499. // Next scan thru each value key to find a match
  500. //
  501. for (i = 0; i < instanceCount ; i++) {
  502. PiUlongToUnicodeString(&valueName, unicodeBuffer, 20, i);
  503. status = ZwQueryValueKey (
  504. ServiceEnumHandle,
  505. &valueName,
  506. KeyValueFullInformation,
  507. keyValueInformation,
  508. length,
  509. &junk
  510. );
  511. if (!NT_SUCCESS(status)) {
  512. if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) {
  513. ExFreePool(keyValueInformation);
  514. length = junk;
  515. keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePool(
  516. PagedPool, length);
  517. if (!keyValueInformation) {
  518. ExFreePool(unicodeBuffer);
  519. return STATUS_INSUFFICIENT_RESOURCES;
  520. }
  521. i--;
  522. }
  523. continue;
  524. }
  525. if (keyValueInformation->Type == REG_SZ) {
  526. if (keyValueInformation->DataLength > sizeof(UNICODE_NULL)) {
  527. IopRegistryDataToUnicodeString(&unicodeValue,
  528. (PWSTR)KEY_VALUE_DATA(keyValueInformation),
  529. keyValueInformation->DataLength
  530. );
  531. } else {
  532. continue;
  533. }
  534. } else {
  535. continue;
  536. }
  537. if (RtlEqualUnicodeString(&unicodeValue,
  538. DeviceInstanceName,
  539. TRUE)) {
  540. //
  541. // We found a match.
  542. //
  543. *MatchingValueName= valueName;
  544. *MatchingInstance = i;
  545. break;
  546. }
  547. }
  548. if (keyValueInformation) {
  549. ExFreePool(keyValueInformation);
  550. }
  551. if (MatchingValueName->Length == 0) {
  552. //
  553. // If we did not find a match, we need to release the buffer. Otherwise
  554. // it is caller's responsibility to release the buffer.
  555. //
  556. ExFreePool(unicodeBuffer);
  557. }
  558. return STATUS_SUCCESS;
  559. }
  560. NTSTATUS
  561. PpForEachDeviceInstanceDriver(
  562. PUNICODE_STRING DeviceInstancePath,
  563. PDEVICE_SERVICE_ITERATOR_ROUTINE IteratorRoutine,
  564. PVOID Context
  565. )
  566. /*++
  567. Routine Description:
  568. This routine will call the iterator routine once for each driver listed
  569. for this particular device instance. It will walk through any class
  570. filter drivers and device filter drivers, as well as the service, in the
  571. order they will be added to the PDO. If the iterator routine returns
  572. a failure status at any point the iteration will be terminated.
  573. Arguments:
  574. DeviceInstancePath - the registry path (relative to CCS\Enum)
  575. IteratorRoutine - the routine to be called for each service. This routine
  576. will be passed:
  577. * The device instance path
  578. * The type of driver that this is (filter, service, etc.)
  579. * the Context value passed in
  580. * The name of the service
  581. Context - an arbitrary context passed into the iterator routine
  582. Return Value:
  583. STATUS_SUCCCESS if everything was run across properly
  584. status if an error occurred opening critical keys or if the iterator
  585. routine returns an error.
  586. --*/
  587. {
  588. HANDLE enumKey,instanceKey, classKey, controlKey;
  589. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  590. DEVICE_SERVICE_ITERATOR_CONTEXT internalContext;
  591. RTL_QUERY_REGISTRY_TABLE queryTable[4];
  592. NTSTATUS status;
  593. UNICODE_STRING unicodeClassGuid;
  594. PAGED_CODE();
  595. //
  596. // Open the HKLM\System\CCS\Enum key.
  597. //
  598. status = IopOpenRegistryKeyEx( &enumKey,
  599. NULL,
  600. &CmRegistryMachineSystemCurrentControlSetEnumName,
  601. KEY_READ
  602. );
  603. if (!NT_SUCCESS(status)) {
  604. return status;
  605. }
  606. //
  607. // Open the instance key for this devnode
  608. //
  609. status = IopOpenRegistryKeyEx( &instanceKey,
  610. enumKey,
  611. DeviceInstancePath,
  612. KEY_READ
  613. );
  614. ZwClose(enumKey);
  615. if(!NT_SUCCESS(status)) {
  616. return status;
  617. }
  618. classKey = NULL;
  619. status = IopGetRegistryValue(instanceKey,
  620. REGSTR_VALUE_CLASSGUID,
  621. &keyValueInformation);
  622. if(NT_SUCCESS(status)) {
  623. if ( keyValueInformation->Type == REG_SZ &&
  624. keyValueInformation->DataLength) {
  625. IopRegistryDataToUnicodeString(
  626. &unicodeClassGuid,
  627. (PWSTR) KEY_VALUE_DATA(keyValueInformation),
  628. keyValueInformation->DataLength);
  629. //
  630. // Open the class key
  631. //
  632. status = IopOpenRegistryKeyEx( &controlKey,
  633. NULL,
  634. &CmRegistryMachineSystemCurrentControlSetControlClass,
  635. KEY_READ
  636. );
  637. if(NT_SUCCESS(status)) {
  638. status = IopOpenRegistryKeyEx( &classKey,
  639. controlKey,
  640. &unicodeClassGuid,
  641. KEY_READ
  642. );
  643. ZwClose(controlKey);
  644. }
  645. }
  646. ExFreePool(keyValueInformation);
  647. keyValueInformation = NULL;
  648. }
  649. //
  650. // For each type of filter driver we want to query for the list and
  651. // call into our callback routine. We should do this in order from
  652. // bottom to top.
  653. //
  654. internalContext.Context = Context;
  655. internalContext.DeviceInstancePath = DeviceInstancePath;
  656. internalContext.Iterator = IteratorRoutine;
  657. //
  658. // First get all the information we have to out of the instance key and
  659. // the device node.
  660. //
  661. if(classKey != NULL) {
  662. RtlZeroMemory(queryTable, sizeof(queryTable));
  663. queryTable[0].QueryRoutine =
  664. (PRTL_QUERY_REGISTRY_ROUTINE) PiForEachDriverQueryRoutine;
  665. queryTable[0].Name = REGSTR_VAL_LOWERFILTERS;
  666. queryTable[0].EntryContext = (PVOID) 0;
  667. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  668. (PWSTR) classKey,
  669. queryTable,
  670. &internalContext,
  671. NULL);
  672. if(!NT_SUCCESS(status)) {
  673. goto PrepareForReturn;
  674. }
  675. }
  676. RtlZeroMemory(queryTable, sizeof(queryTable));
  677. queryTable[0].QueryRoutine =
  678. (PRTL_QUERY_REGISTRY_ROUTINE) PiForEachDriverQueryRoutine;
  679. queryTable[0].Name = REGSTR_VAL_LOWERFILTERS;
  680. queryTable[0].EntryContext = (PVOID) 1;
  681. queryTable[1].QueryRoutine =
  682. (PRTL_QUERY_REGISTRY_ROUTINE) PiForEachDriverQueryRoutine;
  683. queryTable[1].Name = REGSTR_VAL_SERVICE;
  684. queryTable[1].EntryContext = (PVOID) 2;
  685. queryTable[2].QueryRoutine =
  686. (PRTL_QUERY_REGISTRY_ROUTINE) PiForEachDriverQueryRoutine;
  687. queryTable[2].Name = REGSTR_VAL_UPPERFILTERS;
  688. queryTable[2].EntryContext = (PVOID) 3;
  689. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  690. (PWSTR) instanceKey,
  691. queryTable,
  692. &internalContext,
  693. NULL);
  694. if(!NT_SUCCESS(status)) {
  695. goto PrepareForReturn;
  696. }
  697. if(classKey != NULL) {
  698. RtlZeroMemory(queryTable, sizeof(queryTable));
  699. queryTable[0].QueryRoutine =
  700. (PRTL_QUERY_REGISTRY_ROUTINE) PiForEachDriverQueryRoutine;
  701. queryTable[0].Name = REGSTR_VAL_UPPERFILTERS;
  702. queryTable[0].EntryContext = (PVOID) 4;
  703. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  704. (PWSTR) classKey,
  705. queryTable,
  706. &internalContext,
  707. NULL);
  708. if(!NT_SUCCESS(status)) {
  709. goto PrepareForReturn;
  710. }
  711. }
  712. PrepareForReturn:
  713. if(classKey != NULL) {
  714. ZwClose(classKey);
  715. }
  716. ZwClose(instanceKey);
  717. return status;
  718. }
  719. NTSTATUS
  720. PiForEachDriverQueryRoutine(
  721. IN PWSTR ValueName,
  722. IN ULONG ValueType,
  723. IN PVOID ValueData,
  724. IN ULONG ValueLength,
  725. IN PDEVICE_SERVICE_ITERATOR_CONTEXT InternalContext,
  726. IN ULONG ServiceType
  727. )
  728. {
  729. UNICODE_STRING ServiceName;
  730. UNREFERENCED_PARAMETER( ValueName );
  731. if (ValueType != REG_SZ) {
  732. return STATUS_SUCCESS;
  733. }
  734. //
  735. // Make sure the string is a reasonable length.
  736. // copied directly from IopCallDriverAddDeviceQueryRoutine
  737. //
  738. if (ValueLength <= sizeof(WCHAR)) {
  739. return STATUS_SUCCESS;
  740. }
  741. RtlInitUnicodeString(&ServiceName, ValueData);
  742. return InternalContext->Iterator(
  743. InternalContext->DeviceInstancePath,
  744. &ServiceName,
  745. ServiceType,
  746. InternalContext->Context);
  747. }
  748. VOID
  749. PiRearrangeDeviceInstances(
  750. IN HANDLE ServiceEnumHandle,
  751. IN ULONG InstanceCount,
  752. IN ULONG InstanceDeleted
  753. )
  754. {
  755. NTSTATUS Status;
  756. PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
  757. CHAR UnicodeBuffer[20];
  758. UNICODE_STRING TempUnicodeString;
  759. ULONG i, j, junk, maxCount;
  760. BOOLEAN PreserveOrdering;
  761. KEY_FULL_INFORMATION keyInfo;
  762. ULONG tmp;
  763. PAGED_CODE();
  764. KeyValueInformation = NULL;
  765. PreserveOrdering = TRUE;
  766. maxCount = 0x200;
  767. Status = ZwQueryKey(
  768. ServiceEnumHandle,
  769. KeyFullInformation,
  770. &keyInfo,
  771. sizeof(keyInfo),
  772. &tmp
  773. );
  774. if (NT_SUCCESS(Status) && keyInfo.Values) {
  775. maxCount = keyInfo.Values;
  776. if (maxCount > 28) {
  777. PreserveOrdering = FALSE;
  778. }
  779. }
  780. if (PreserveOrdering == FALSE) {
  781. //
  782. // Read the last value.
  783. //
  784. PiUlongToUnicodeString(&TempUnicodeString, UnicodeBuffer, 20, InstanceCount);
  785. Status = IopGetRegistryValue(ServiceEnumHandle,
  786. TempUnicodeString.Buffer,
  787. &KeyValueInformation
  788. );
  789. if (NT_SUCCESS(Status)) {
  790. //
  791. // Delete the last value.
  792. //
  793. ZwDeleteValueKey(ServiceEnumHandle, &TempUnicodeString);
  794. //
  795. // Set the new value with the instance we just deleted above..
  796. //
  797. PiUlongToUnicodeString(&TempUnicodeString, UnicodeBuffer, 20, InstanceDeleted);
  798. ZwSetValueKey (ServiceEnumHandle,
  799. &TempUnicodeString,
  800. TITLE_INDEX_VALUE,
  801. REG_SZ,
  802. (PVOID)KEY_VALUE_DATA(KeyValueInformation),
  803. KeyValueInformation->DataLength
  804. );
  805. ExFreePool(KeyValueInformation);
  806. KeyValueInformation = NULL;
  807. }
  808. } else {
  809. i = j = 0;
  810. while (j < InstanceCount && i < maxCount) {
  811. PiUlongToUnicodeString(&TempUnicodeString, UnicodeBuffer, 20, i);
  812. Status = ZwQueryValueKey(
  813. ServiceEnumHandle,
  814. &TempUnicodeString,
  815. KeyValueFullInformation,
  816. (PVOID)NULL,
  817. 0,
  818. &junk
  819. );
  820. if ((Status != STATUS_OBJECT_NAME_NOT_FOUND) && (Status != STATUS_OBJECT_PATH_NOT_FOUND)) {
  821. if (i != j) {
  822. //
  823. // Need to change the instance i to instance j
  824. //
  825. Status = IopGetRegistryValue(
  826. ServiceEnumHandle,
  827. TempUnicodeString.Buffer,
  828. &KeyValueInformation
  829. );
  830. if (NT_SUCCESS(Status)) {
  831. ZwDeleteValueKey(ServiceEnumHandle, &TempUnicodeString);
  832. PiUlongToUnicodeString(&TempUnicodeString, UnicodeBuffer, 20, j);
  833. ZwSetValueKey(
  834. ServiceEnumHandle,
  835. &TempUnicodeString,
  836. TITLE_INDEX_VALUE,
  837. REG_SZ,
  838. (PVOID)KEY_VALUE_DATA(KeyValueInformation),
  839. KeyValueInformation->DataLength
  840. );
  841. ExFreePool(KeyValueInformation);
  842. KeyValueInformation = NULL;
  843. } else {
  844. IopDbgPrint((
  845. IOP_WARNING_LEVEL,
  846. "PiRearrangeDeviceInstances: Failed to rearrange device instances %x\n",
  847. Status
  848. ));
  849. break;
  850. }
  851. }
  852. j++;
  853. }
  854. i++;
  855. }
  856. }
  857. //
  858. // Cleanup.
  859. //
  860. if (KeyValueInformation) {
  861. ExFreePool(KeyValueInformation);
  862. }
  863. }