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.

3431 lines
104 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. ppcddb.c
  5. Abstract:
  6. This module implements the Plug and Play Critical Device Database (CDDB)
  7. and related "features".
  8. Author:
  9. James G. Cavalaris (jamesca) 01-Nov-2001
  10. Environment:
  11. Kernel mode.
  12. Revision History:
  13. 29-Jul-1997 Jim Cavalaris (t-jcaval)
  14. Creation and initial implementation.
  15. 01-Nov-2001 Jim Cavalaris (jamesca)
  16. Added routines for device pre-installation setup.
  17. --*/
  18. #include "pnpmgrp.h"
  19. #pragma hdrstop
  20. #include <wdmguid.h>
  21. #include "picddb.h"
  22. #ifdef POOL_TAGGING
  23. #undef ExAllocatePool
  24. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'dcpP')
  25. #endif
  26. #ifdef ALLOC_DATA_PRAGMA
  27. #pragma data_seg("PAGEDATA")
  28. #pragma const_seg("PAGECONST")
  29. #endif // ALLOC_DATA_PRAGMA
  30. #ifdef ALLOC_PRAGMA
  31. #pragma alloc_text(PAGE, PpCriticalProcessCriticalDevice)
  32. #pragma alloc_text(PAGE, PpCriticalGetDeviceLocationStrings)
  33. #pragma alloc_text(PAGE, PiCriticalOpenCriticalDeviceKey)
  34. #pragma alloc_text(PAGE, PiCriticalCopyCriticalDeviceProperties)
  35. #pragma alloc_text(PAGE, PiCriticalPreInstallDevice)
  36. #pragma alloc_text(PAGE, PiCriticalOpenDevicePreInstallKey)
  37. #pragma alloc_text(PAGE, PiCriticalOpenFirstMatchingSubKey)
  38. #pragma alloc_text(PAGE, PiCriticalCallbackVerifyCriticalEntry)
  39. #pragma alloc_text(PAGE, PiQueryInterface)
  40. #pragma alloc_text(PAGE, PiCopyKeyRecursive)
  41. #pragma alloc_text(PAGE, PiCriticalQueryRegistryValueCallback)
  42. #endif // ALLOC_PRAGMA
  43. typedef struct _PI_CRITICAL_QUERY_CONTEXT {
  44. PVOID Buffer;
  45. ULONG Size;
  46. }PI_CRITICAL_QUERY_CONTEXT, *PPI_CRITICAL_QUERY_CONTEXT;
  47. //
  48. // Critical Device Database data
  49. //
  50. //
  51. // Specifies whether the critical device database functionality is enabled.
  52. // (currently always TRUE).
  53. //
  54. BOOLEAN PiCriticalDeviceDatabaseEnabled = TRUE;
  55. //
  56. // Critical Device Database routines
  57. //
  58. NTSTATUS
  59. PiCriticalOpenCriticalDeviceKey(
  60. IN PDEVICE_NODE DeviceNode,
  61. IN HANDLE CriticalDeviceDatabaseRootHandle OPTIONAL,
  62. OUT PHANDLE CriticalDeviceEntryHandle
  63. )
  64. /*++
  65. Routine Description:
  66. This routine retrieves the registry key containing the critical device
  67. settings for the specified device.
  68. Arguments:
  69. DeviceNode -
  70. Specifies the device whose critical settings are to be retrieved.
  71. CriticalDeviceDatabaseRootHandle -
  72. Optionally, specifies a handle to the key that should be considered the
  73. root of the critical device database to be searched for this device.
  74. If no handle is supplied, the default critical device database is used:
  75. System\\CurrentControlSet\\Control\\CriticalDeviceDatabase
  76. CriticalDeviceEntryHandle -
  77. Returns a handle to the registry key containing critical device settings
  78. for the specified device.
  79. Return Value:
  80. NTSTATUS code.
  81. --*/
  82. {
  83. NTSTATUS Status, tmpStatus;
  84. UNICODE_STRING UnicodeString;
  85. HANDLE DeviceInstanceHandle;
  86. PWSTR SearchIds[2];
  87. ULONG SearchIdsIndex;
  88. PKEY_VALUE_FULL_INFORMATION keyValueInfo;
  89. PWCHAR DeviceIds;
  90. HANDLE DatabaseRootHandle;
  91. PAGED_CODE();
  92. //
  93. // Validate parameters.
  94. //
  95. if ((!ARGUMENT_PRESENT(DeviceNode)) ||
  96. (!ARGUMENT_PRESENT(CriticalDeviceEntryHandle))) {
  97. return STATUS_INVALID_PARAMETER;
  98. }
  99. //
  100. // Initialize output parameter.
  101. //
  102. *CriticalDeviceEntryHandle = NULL;
  103. if (CriticalDeviceDatabaseRootHandle != NULL) {
  104. //
  105. // We were given a root database to be searched.
  106. //
  107. DatabaseRootHandle = CriticalDeviceDatabaseRootHandle;
  108. } else {
  109. //
  110. // No root database handle supplied, so we open a key to the default
  111. // global critical device database root.
  112. //
  113. PiWstrToUnicodeString(
  114. &UnicodeString,
  115. CM_REGISTRY_MACHINE(REGSTR_PATH_CRITICALDEVICEDATABASE));
  116. Status =
  117. IopOpenRegistryKeyEx(
  118. &DatabaseRootHandle,
  119. NULL,
  120. &UnicodeString,
  121. KEY_READ);
  122. if (!NT_SUCCESS(Status)) {
  123. return Status;
  124. }
  125. }
  126. ASSERT(DatabaseRootHandle != NULL);
  127. //
  128. // Open the device instance registry key.
  129. //
  130. DeviceInstanceHandle = NULL;
  131. Status =
  132. IopDeviceObjectToDeviceInstance(
  133. DeviceNode->PhysicalDeviceObject,
  134. &DeviceInstanceHandle,
  135. KEY_READ);
  136. if (!NT_SUCCESS(Status)) {
  137. ASSERT(DeviceInstanceHandle == NULL);
  138. goto Clean0;
  139. }
  140. ASSERT(DeviceInstanceHandle != NULL);
  141. //
  142. // Search for a match for this device in the critical device database first
  143. // by HardwareId, then by CompatibleId.
  144. //
  145. SearchIds[0] = REGSTR_VALUE_HARDWAREID;
  146. SearchIds[1] = REGSTR_VALUE_COMPATIBLEIDS;
  147. for (SearchIdsIndex = 0;
  148. SearchIdsIndex < RTL_NUMBER_OF(SearchIds);
  149. SearchIdsIndex++) {
  150. //
  151. // Retrieve the SearchIds for the device.
  152. //
  153. // NOTE - we currently retrieve these hardware and compatible ids from
  154. // the device instance registry key, so they need to have been written
  155. // there by now, during enumeration. If a critical device database
  156. // match for a device is expected to be found prior to that, these
  157. // properties should be queried directly form the device instead.
  158. //
  159. keyValueInfo = NULL;
  160. Status =
  161. IopGetRegistryValue(
  162. DeviceInstanceHandle,
  163. SearchIds[SearchIdsIndex],
  164. &keyValueInfo
  165. );
  166. if (!NT_SUCCESS(Status)) {
  167. ASSERT(keyValueInfo == NULL);
  168. continue;
  169. }
  170. ASSERT(keyValueInfo != NULL);
  171. //
  172. // Make sure the returned registry value is a multi-sz.
  173. //
  174. if (keyValueInfo->Type != REG_MULTI_SZ) {
  175. Status = STATUS_UNSUCCESSFUL;
  176. ExFreePool(keyValueInfo);
  177. continue;
  178. }
  179. //
  180. // Munge all search ids in the multi-sz list.
  181. //
  182. DeviceIds = (PWCHAR)KEY_VALUE_DATA(keyValueInfo);
  183. UnicodeString.Buffer = DeviceIds;
  184. UnicodeString.Length = (USHORT)keyValueInfo->DataLength;
  185. UnicodeString.MaximumLength = UnicodeString.Length;
  186. tmpStatus =
  187. IopReplaceSeperatorWithPound(
  188. &UnicodeString,
  189. &UnicodeString
  190. );
  191. ASSERT(NT_SUCCESS(tmpStatus));
  192. //
  193. // Check each munged device id for a match in the
  194. // CriticalDeviceDatabase, by attempting to open the first matching
  195. // subkey.
  196. //
  197. // Use PiCriticalCallbackVerifyCriticalEntry to determine if a matching
  198. // subkey satisfies additional match requirements.
  199. //
  200. // NOTE: 01-Dec-2001 : Jim Cavalaris (jamesca)
  201. //
  202. // We do this because the previous implementation of the Critical Device
  203. // Database match code would search all matching subkeys until it found
  204. // one with a valid Service. This may be because matches may not have
  205. // been found in the most appropriate order of hw-id/compat-ids, by
  206. // decreasing relevance. Now that we do so, we should hopefully not
  207. // need to resort to a less-relevant database match with a service, over
  208. // a more specific one. A match with no service should mean none is
  209. // required. That however, would involve allowing devices to go through
  210. // the critical device database, and receive no Service match when we
  211. // might possibly find one - something we may not have done before.
  212. //
  213. // Until all these issues are sorted out, we'll just use a verification
  214. // callback routine to implement the logic that has always been there -
  215. // check for Service and ClassGUID entry values before declaring an
  216. // entry a match. If we want to change the behavior of what is
  217. // considered a match, just change the callback routine - OR - provide
  218. // no callback routine to simply declare the the first matching subkey
  219. // name as a match.
  220. //
  221. Status =
  222. PiCriticalOpenFirstMatchingSubKey(
  223. DeviceIds,
  224. DatabaseRootHandle,
  225. KEY_READ,
  226. (PCRITICAL_MATCH_CALLBACK)PiCriticalCallbackVerifyCriticalEntry,
  227. CriticalDeviceEntryHandle
  228. );
  229. ExFreePool(keyValueInfo);
  230. //
  231. // Stop if we found a match in this list of device ids.
  232. //
  233. if (NT_SUCCESS(Status)) {
  234. ASSERT(*CriticalDeviceEntryHandle != NULL);
  235. break;
  236. }
  237. }
  238. //
  239. // Close the device instance registry key handle.
  240. //
  241. ZwClose(DeviceInstanceHandle);
  242. Clean0:
  243. //
  244. // If we opened our own key to the database root, close it now.
  245. //
  246. if ((CriticalDeviceDatabaseRootHandle == NULL) &&
  247. (DatabaseRootHandle != NULL)) {
  248. ZwClose(DatabaseRootHandle);
  249. }
  250. return Status;
  251. } // PiCriticalOpenCriticalDeviceKey
  252. NTSTATUS
  253. PiCriticalCopyCriticalDeviceProperties(
  254. IN HANDLE DeviceInstanceHandle,
  255. IN HANDLE CriticalDeviceEntryHandle
  256. )
  257. /*++
  258. Routine Description:
  259. This routine will copy the Service, ClassGUID, LowerFilters and UpperFilters
  260. device registry properties from the matching database entry to the device
  261. instance registry key.
  262. Arguments:
  263. DeviceInstanceHandle -
  264. Specifies a handle to the device instance key that is to be populated
  265. with critical entries from the critical device database.
  266. CriticalDeviceEntryHandle -
  267. Specifies a handle to the matching critical device database entry that
  268. contains critical device instance registry values to populate.
  269. Return Value:
  270. NTSTATUS code.
  271. Notes:
  272. ** Values places in a given critical device database entry must be
  273. applicable to ALL INSTANCES OF A MATCHING DEVICE ID.
  274. ** Specifically, you MUST NOT write/copy values that are SPECIFIC TO A
  275. SINGLE INSTANCE OF A DEVICE to/from a critical device database entry.
  276. The "hands-off" list includes (but is not restricted to)
  277. instance-specific values such as:
  278. REGSTR_VALUE_DRIVER ("Driver")
  279. REGSTR_VAL_LOCATION_INFORMATION ("LocationInformation")
  280. REGSTR_VALUE_PARENT_ID_PREFIX ("ParentIdPrefix")
  281. REGSTR_VALUE_UNIQUE_PARENT_ID ("UniqueParentID")
  282. --*/
  283. {
  284. NTSTATUS Status, tmpStatus;
  285. RTL_QUERY_REGISTRY_TABLE QueryParameters[9];
  286. UNICODE_STRING Service, ClassGuid, LowerFilters, UpperFilters;
  287. UNICODE_STRING UnicodeValueName;
  288. PKEY_VALUE_FULL_INFORMATION keyValueFullInfo;
  289. ULONG DeviceType, Characteristics, Exclusive, dummy;
  290. PI_CRITICAL_QUERY_CONTEXT SecurityContext;
  291. PAGED_CODE();
  292. //
  293. // Validate parameters.
  294. //
  295. if ((DeviceInstanceHandle == NULL) ||
  296. (CriticalDeviceEntryHandle == NULL)) {
  297. return STATUS_INVALID_PARAMETER;
  298. }
  299. //
  300. // Query registry values from the matching critical device database entry.
  301. //
  302. // Initialize unicode strings with NULL Buffers.
  303. // RTL_QUERY_REGISTRY_DIRECT will allocate buffers as necessary.
  304. //
  305. PiWstrToUnicodeString(&Service, NULL);
  306. PiWstrToUnicodeString(&ClassGuid, NULL);
  307. PiWstrToUnicodeString(&LowerFilters, NULL);
  308. PiWstrToUnicodeString(&UpperFilters, NULL);
  309. DeviceType = 0;
  310. Exclusive = 0;
  311. Characteristics = 0;
  312. dummy = 0;
  313. SecurityContext.Buffer = NULL;
  314. SecurityContext.Size = 0;
  315. //
  316. // RTL_QUERY_REGISTRY_DIRECT uses system provided QueryRoutine.
  317. // Look at the DDK documentation for more details on this flag.
  318. //
  319. RtlZeroMemory(
  320. QueryParameters,
  321. sizeof(QueryParameters)
  322. );
  323. QueryParameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  324. QueryParameters[0].Name = REGSTR_VALUE_SERVICE;
  325. QueryParameters[0].EntryContext = &Service;
  326. QueryParameters[0].DefaultType = REG_SZ;
  327. QueryParameters[0].DefaultData = L"";
  328. QueryParameters[0].DefaultLength = 0;
  329. QueryParameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  330. QueryParameters[1].Name = REGSTR_VALUE_CLASSGUID;
  331. QueryParameters[1].EntryContext = &ClassGuid;
  332. QueryParameters[1].DefaultType = REG_SZ;
  333. QueryParameters[1].DefaultData = L"";
  334. QueryParameters[1].DefaultLength = 0;
  335. QueryParameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;
  336. QueryParameters[2].Name = REGSTR_VALUE_LOWERFILTERS;
  337. QueryParameters[2].EntryContext = &LowerFilters;
  338. QueryParameters[2].DefaultType = REG_MULTI_SZ;
  339. QueryParameters[2].DefaultData = L"";
  340. QueryParameters[2].DefaultLength = 0;
  341. QueryParameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;
  342. QueryParameters[3].Name = REGSTR_VALUE_UPPERFILTERS;
  343. QueryParameters[3].EntryContext = &UpperFilters;
  344. QueryParameters[3].DefaultType = REG_MULTI_SZ;
  345. QueryParameters[3].DefaultData = L"";
  346. QueryParameters[3].DefaultLength = 0;
  347. QueryParameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
  348. QueryParameters[4].Name = REGSTR_VAL_DEVICE_TYPE;
  349. QueryParameters[4].EntryContext = &DeviceType;
  350. QueryParameters[4].DefaultType = REG_DWORD;
  351. QueryParameters[4].DefaultData = &dummy;
  352. QueryParameters[4].DefaultLength = sizeof(DeviceType);
  353. QueryParameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
  354. QueryParameters[5].Name = REGSTR_VAL_DEVICE_EXCLUSIVE;
  355. QueryParameters[5].EntryContext = &Exclusive;
  356. QueryParameters[5].DefaultType = REG_DWORD;
  357. QueryParameters[5].DefaultData = &dummy;
  358. QueryParameters[5].DefaultLength = sizeof(Exclusive);
  359. QueryParameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
  360. QueryParameters[6].Name = REGSTR_VAL_DEVICE_CHARACTERISTICS;
  361. QueryParameters[6].EntryContext = &Characteristics;
  362. QueryParameters[6].DefaultType = REG_DWORD;
  363. QueryParameters[6].DefaultData = &dummy;
  364. QueryParameters[6].DefaultLength = sizeof(Characteristics);
  365. QueryParameters[7].QueryRoutine = PiCriticalQueryRegistryValueCallback;
  366. QueryParameters[7].Name = REGSTR_VAL_DEVICE_SECURITY_DESCRIPTOR;
  367. QueryParameters[7].EntryContext = &SecurityContext;
  368. QueryParameters[7].DefaultType = REG_BINARY;
  369. QueryParameters[7].DefaultData = NULL;
  370. QueryParameters[7].DefaultLength = 0;
  371. Status =
  372. RtlQueryRegistryValues(
  373. RTL_REGISTRY_HANDLE | RTL_REGISTRY_OPTIONAL,
  374. (PWSTR)CriticalDeviceEntryHandle,
  375. QueryParameters,
  376. NULL,
  377. NULL
  378. );
  379. if (!NT_SUCCESS(Status)) {
  380. goto Clean0;
  381. }
  382. //
  383. // If successful so far, fix up some values, as needed.
  384. //
  385. if ((Service.Length == 0) &&
  386. (Service.Buffer != NULL)) {
  387. //
  388. // Don't write an empty Service string.
  389. //
  390. RtlFreeUnicodeString(&Service);
  391. PiWstrToUnicodeString(&Service, NULL);
  392. }
  393. if ((ClassGuid.Length == 0) &&
  394. (ClassGuid.Buffer != NULL)) {
  395. //
  396. // Don't write an empty ClassGUID string.
  397. //
  398. RtlFreeUnicodeString(&ClassGuid);
  399. PiWstrToUnicodeString(&ClassGuid, NULL);
  400. }
  401. if ((UpperFilters.Length <= sizeof(UNICODE_NULL)) &&
  402. (UpperFilters.Buffer != NULL)) {
  403. //
  404. // Don't write empty UpperFilter multi-sz values.
  405. //
  406. RtlFreeUnicodeString(&UpperFilters);
  407. PiWstrToUnicodeString(&UpperFilters, NULL);
  408. }
  409. if ((LowerFilters.Length <= sizeof(UNICODE_NULL)) &&
  410. (LowerFilters.Buffer != NULL)) {
  411. //
  412. // Don't write empty LowerFilter multi-sz values.
  413. //
  414. RtlFreeUnicodeString(&LowerFilters);
  415. PiWstrToUnicodeString(&LowerFilters, NULL);
  416. }
  417. //
  418. // Set the critical device registry property values only if we have a
  419. // Service value to set for the device.
  420. //
  421. IopDbgPrint((IOP_ENUMERATION_WARNING_LEVEL,
  422. "PiCriticalCopyCriticalDeviceProperties: "
  423. "Setting up critical service\n"));
  424. //
  425. // NOTE: The PiCriticalCallbackVerifyCriticalEntry critical database entry
  426. // verification callback should never validate a critical device database
  427. // entry with no REGSTR_VALUE_SERVICE value.
  428. //
  429. if (Service.Buffer != NULL) {
  430. //
  431. // Set the "Service" device registry property.
  432. //
  433. PiWstrToUnicodeString(&UnicodeValueName, REGSTR_VALUE_SERVICE);
  434. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  435. "PiCriticalCopyCriticalDeviceProperties: "
  436. "%wZ: %wZ\n",
  437. &UnicodeValueName,
  438. &Service));
  439. ASSERT(DeviceInstanceHandle != NULL);
  440. //
  441. // Use the status from attempting to set the Service value as the
  442. // final status of the critical settings copy operation.
  443. //
  444. Status =
  445. ZwSetValueKey(
  446. DeviceInstanceHandle,
  447. &UnicodeValueName,
  448. TITLE_INDEX_VALUE,
  449. REG_SZ,
  450. Service.Buffer,
  451. Service.Length + sizeof(UNICODE_NULL)
  452. );
  453. if (!NT_SUCCESS(Status)) {
  454. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  455. "PiCriticalCopyCriticalDeviceProperties: "
  456. "Error setting %wZ, (Status = %#08lx)\n",
  457. &UnicodeValueName, Status));
  458. }
  459. } else {
  460. //
  461. // No Service value to set is considered a failure of the entire
  462. // critical settings copy operation.
  463. //
  464. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  465. "PiCriticalCopyCriticalDeviceProperties: "
  466. "No Service for critical entry!\n"));
  467. //
  468. // NOTE: We should never encounter this situation because the
  469. // PiCriticalCallbackVerifyCriticalEntry critical database entry
  470. // verification callback should never validate a critical device
  471. // database entry with no Service value, hence the ASSERT.
  472. //
  473. ASSERT(Service.Buffer != NULL);
  474. Status = STATUS_UNSUCCESSFUL;
  475. }
  476. //
  477. // If not successful setting up the service for this device, do not set the
  478. // other critical settings.
  479. //
  480. if (!NT_SUCCESS(Status)) {
  481. goto Clean0;
  482. }
  483. //
  484. // Set the "ClassGUID" device registry property.
  485. //
  486. if (ClassGuid.Buffer != NULL) {
  487. PiWstrToUnicodeString(&UnicodeValueName, REGSTR_VALUE_CLASSGUID);
  488. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  489. "PiCriticalCopyCriticalDeviceProperties: "
  490. "%wZ: %wZ\n",
  491. &UnicodeValueName,
  492. &ClassGuid));
  493. ZwSetValueKey(
  494. DeviceInstanceHandle,
  495. &UnicodeValueName,
  496. TITLE_INDEX_VALUE,
  497. REG_SZ,
  498. ClassGuid.Buffer,
  499. ClassGuid.Length + sizeof(UNICODE_NULL)
  500. );
  501. }
  502. //
  503. // Set the "LowerFilters" device registry property.
  504. //
  505. if (LowerFilters.Buffer != NULL) {
  506. PiWstrToUnicodeString(&UnicodeValueName, REGSTR_VALUE_LOWERFILTERS);
  507. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  508. "PiCriticalCopyCriticalDeviceProperties: "
  509. "%wZ:\n",
  510. &UnicodeValueName));
  511. ZwSetValueKey(
  512. DeviceInstanceHandle,
  513. &UnicodeValueName,
  514. TITLE_INDEX_VALUE,
  515. REG_MULTI_SZ,
  516. LowerFilters.Buffer,
  517. LowerFilters.Length
  518. );
  519. }
  520. //
  521. // Set the "UpperFilters" device registry property.
  522. //
  523. if (UpperFilters.Buffer != NULL) {
  524. PiWstrToUnicodeString(&UnicodeValueName, REGSTR_VALUE_UPPERFILTERS);
  525. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  526. "PiCriticalCopyCriticalDeviceProperties: "
  527. "%wZ:\n",
  528. &UnicodeValueName));
  529. ZwSetValueKey(
  530. DeviceInstanceHandle,
  531. &UnicodeValueName,
  532. TITLE_INDEX_VALUE,
  533. REG_MULTI_SZ,
  534. UpperFilters.Buffer,
  535. UpperFilters.Length
  536. );
  537. }
  538. //
  539. // Set "DeviceType" device registry property.
  540. //
  541. if (DeviceType) {
  542. //
  543. // Set the "DeviceType" device registry property.
  544. //
  545. PiWstrToUnicodeString(&UnicodeValueName, REGSTR_VAL_DEVICE_TYPE);
  546. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  547. "PiCriticalCopyCriticalDeviceProperties: "
  548. "%wZ: %X\n",
  549. &UnicodeValueName,
  550. DeviceType));
  551. //
  552. // Use the status from attempting to set the DeviceType value as the
  553. // final status of the critical settings copy operation.
  554. //
  555. Status =
  556. ZwSetValueKey(
  557. DeviceInstanceHandle,
  558. &UnicodeValueName,
  559. TITLE_INDEX_VALUE,
  560. REG_DWORD,
  561. &DeviceType,
  562. sizeof(DeviceType)
  563. );
  564. if (!NT_SUCCESS(Status)) {
  565. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  566. "PiCriticalCopyCriticalDeviceProperties: "
  567. "Error setting %wZ, (Status = %#08lx)\n",
  568. &UnicodeValueName, Status));
  569. }
  570. }
  571. //
  572. // If not successful setting up the DeviceType for this device, do not set the
  573. // other critical settings.
  574. //
  575. if (!NT_SUCCESS(Status)) {
  576. goto Clean0;
  577. }
  578. //
  579. // Set "Exclusive" device registry property.
  580. //
  581. if (Exclusive) {
  582. //
  583. // Set the "Exclusive" device registry property.
  584. //
  585. PiWstrToUnicodeString(&UnicodeValueName, REGSTR_VAL_DEVICE_EXCLUSIVE);
  586. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  587. "PiCriticalCopyCriticalDeviceProperties: "
  588. "%wZ: %X\n",
  589. &UnicodeValueName,
  590. Exclusive));
  591. //
  592. // Use the status from attempting to set the Exclusive value as the
  593. // final status of the critical settings copy operation.
  594. //
  595. Status =
  596. ZwSetValueKey(
  597. DeviceInstanceHandle,
  598. &UnicodeValueName,
  599. TITLE_INDEX_VALUE,
  600. REG_DWORD,
  601. &Exclusive,
  602. sizeof(Exclusive)
  603. );
  604. if (!NT_SUCCESS(Status)) {
  605. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  606. "PiCriticalCopyCriticalDeviceProperties: "
  607. "Error setting %wZ, (Status = %#08lx)\n",
  608. &UnicodeValueName, Status));
  609. }
  610. }
  611. //
  612. // If not successful setting up the Exclusive for this device, do not set
  613. // the other critical settings.
  614. //
  615. if (!NT_SUCCESS(Status)) {
  616. goto Clean0;
  617. }
  618. //
  619. // Set "Characteristics" device registry property.
  620. //
  621. if (Characteristics) {
  622. //
  623. // Set the "Characteristics" device registry property.
  624. //
  625. PiWstrToUnicodeString(&UnicodeValueName, REGSTR_VAL_DEVICE_CHARACTERISTICS);
  626. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  627. "PiCriticalCopyCriticalDeviceProperties: "
  628. "%wZ: %X\n",
  629. &UnicodeValueName,
  630. Characteristics));
  631. //
  632. // Use the status from attempting to set the Characteristics value as the
  633. // final status of the critical settings copy operation.
  634. //
  635. Status =
  636. ZwSetValueKey(
  637. DeviceInstanceHandle,
  638. &UnicodeValueName,
  639. TITLE_INDEX_VALUE,
  640. REG_DWORD,
  641. &Characteristics,
  642. sizeof(Characteristics)
  643. );
  644. if (!NT_SUCCESS(Status)) {
  645. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  646. "PiCriticalCopyCriticalDeviceProperties: "
  647. "Error setting %wZ, (Status = %#08lx)\n",
  648. &UnicodeValueName, Status));
  649. }
  650. }
  651. //
  652. // If not successful setting up the Characteristics for this device, do not
  653. // set the other critical settings.
  654. //
  655. if (!NT_SUCCESS(Status)) {
  656. goto Clean0;
  657. }
  658. if (SecurityContext.Buffer) {
  659. //
  660. // Set the "Security" device registry property.
  661. //
  662. PiWstrToUnicodeString(&UnicodeValueName, REGSTR_VAL_DEVICE_SECURITY_DESCRIPTOR);
  663. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  664. "PiCriticalCopyCriticalDeviceProperties: "
  665. "%wZ\n",
  666. &UnicodeValueName));
  667. //
  668. // Use the status from attempting to set the Security value as the
  669. // final status of the critical settings copy operation.
  670. //
  671. Status =
  672. ZwSetValueKey(
  673. DeviceInstanceHandle,
  674. &UnicodeValueName,
  675. TITLE_INDEX_VALUE,
  676. REG_DWORD,
  677. SecurityContext.Buffer,
  678. SecurityContext.Size
  679. );
  680. if (!NT_SUCCESS(Status)) {
  681. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  682. "PiCriticalCopyCriticalDeviceProperties: "
  683. "Error setting %wZ, (Status = %#08lx)\n",
  684. &UnicodeValueName, Status));
  685. }
  686. }
  687. //
  688. // If not successful setting up the Characteristics for this device, do not
  689. // set the other critical settings.
  690. //
  691. if (!NT_SUCCESS(Status)) {
  692. goto Clean0;
  693. }
  694. //
  695. // Now, check the critical device entry registry key for the flag that
  696. // indicates that the device settings are complete, and should be respected
  697. // by user-mode device installation. If it exists, set that value on the
  698. // device instance registry key for the device whose critical settings we
  699. // are copying.
  700. //
  701. keyValueFullInfo = NULL;
  702. tmpStatus =
  703. IopGetRegistryValue(
  704. CriticalDeviceEntryHandle,
  705. REGSTR_VAL_PRESERVE_PREINSTALL,
  706. &keyValueFullInfo);
  707. if (NT_SUCCESS(tmpStatus)) {
  708. ASSERT(keyValueFullInfo != NULL);
  709. ASSERT(keyValueFullInfo->Type == REG_DWORD);
  710. ASSERT(keyValueFullInfo->DataLength == sizeof(ULONG));
  711. if ((keyValueFullInfo->Type == REG_DWORD) &&
  712. (keyValueFullInfo->DataLength == sizeof(ULONG))) {
  713. //
  714. // Write the value to the device instance registry key.
  715. //
  716. PiWstrToUnicodeString(
  717. &UnicodeValueName,
  718. REGSTR_VAL_PRESERVE_PREINSTALL);
  719. tmpStatus =
  720. ZwSetValueKey(
  721. DeviceInstanceHandle,
  722. &UnicodeValueName,
  723. keyValueFullInfo->TitleIndex,
  724. keyValueFullInfo->Type,
  725. (PVOID)((PUCHAR)keyValueFullInfo + keyValueFullInfo->DataOffset),
  726. keyValueFullInfo->DataLength);
  727. if (!NT_SUCCESS(tmpStatus)) {
  728. IopDbgPrint((IOP_ENUMERATION_VERBOSE_LEVEL,
  729. "PiCriticalCopyCriticalDeviceProperties: "
  730. "Unable to set %wZ value to instance key.\n",
  731. &UnicodeValueName));
  732. }
  733. }
  734. ExFreePool(keyValueFullInfo);
  735. }
  736. Clean0:
  737. //
  738. // Free any allocated unicode strings.
  739. // (RtlFreeUnicodeString can handle NULL strings)
  740. //
  741. RtlFreeUnicodeString(&Service);
  742. RtlFreeUnicodeString(&ClassGuid);
  743. RtlFreeUnicodeString(&LowerFilters);
  744. RtlFreeUnicodeString(&UpperFilters);
  745. if (SecurityContext.Buffer) {
  746. ExFreePool(SecurityContext.Buffer);
  747. }
  748. return Status;
  749. } // PiCriticalCopyCriticalDeviceProperties
  750. NTSTATUS
  751. PpCriticalProcessCriticalDevice(
  752. IN PDEVICE_NODE DeviceNode
  753. )
  754. /*++
  755. Routine Description:
  756. This routine checks the critical device database for a match against one of
  757. the device's hardware or compatible ids. If a device is found, then it will
  758. be assigned a Service, ClassGUID, and potentiall LowerFilters and
  759. UpperFilters, and based on the contents of the matching database entry.
  760. Arguments:
  761. DeviceNode -
  762. Specifies the device node to be processed via the critical device
  763. database.
  764. Return Value:
  765. NTSTATUS code.
  766. --*/
  767. {
  768. NTSTATUS Status, tmpStatus;
  769. HANDLE CriticalDeviceEntryHandle, DeviceInstanceHandle;
  770. PKEY_VALUE_FULL_INFORMATION keyValueFullInfo;
  771. UNICODE_STRING UnicodeValueName;
  772. ULONG ConfigFlags;
  773. PAGED_CODE();
  774. //
  775. // First, make sure that the critical device database is currently enabled.
  776. //
  777. if (!PiCriticalDeviceDatabaseEnabled) {
  778. return STATUS_NOT_SUPPORTED;
  779. }
  780. //
  781. // Validate parameters
  782. //
  783. if (!ARGUMENT_PRESENT(DeviceNode)) {
  784. return STATUS_INVALID_PARAMETER;
  785. }
  786. CriticalDeviceEntryHandle = NULL;
  787. DeviceInstanceHandle = NULL;
  788. //
  789. // Attempt to open the matching critical device entry key.
  790. //
  791. Status =
  792. PiCriticalOpenCriticalDeviceKey(
  793. DeviceNode,
  794. NULL, // use default CriticalDeviceDatabase root key
  795. &CriticalDeviceEntryHandle
  796. );
  797. if (!NT_SUCCESS(Status)) {
  798. ASSERT(CriticalDeviceEntryHandle == NULL);
  799. goto Clean0;
  800. }
  801. ASSERT(CriticalDeviceEntryHandle != NULL);
  802. //
  803. // Open the device instance registry key.
  804. //
  805. Status =
  806. IopDeviceObjectToDeviceInstance(
  807. DeviceNode->PhysicalDeviceObject,
  808. &DeviceInstanceHandle,
  809. KEY_ALL_ACCESS
  810. );
  811. if (!NT_SUCCESS(Status)) {
  812. ASSERT(DeviceInstanceHandle == NULL);
  813. goto Clean0;
  814. }
  815. ASSERT(DeviceInstanceHandle != NULL);
  816. //
  817. // Copy critical device entries for this device. The return status
  818. // indicates that a Service was successfully set up for this device. Only
  819. // in that case should we clear the device of any problems it may have.
  820. //
  821. Status =
  822. PiCriticalCopyCriticalDeviceProperties(
  823. DeviceInstanceHandle,
  824. CriticalDeviceEntryHandle
  825. );
  826. //
  827. // NOTE: The Status returned by this routine indicates whether the Service
  828. // value was successfully copied to the device instance key. Only f we
  829. // successfully processed this device as a critical device should we:
  830. //
  831. // - attempt pre-installation of settings (should not preinstall a device
  832. // that could not be critically installed).
  833. //
  834. // - clear the reinstall and failed install config flags, and set the
  835. // finish-install configflag (should not attempt to start the device
  836. // otherwise).
  837. //
  838. if (NT_SUCCESS(Status)) {
  839. //
  840. // First, attempt pre-installation of settings for devices matching an
  841. // entry in the critical device database.
  842. //
  843. //
  844. // Use the matching critical device database entry key for this device
  845. // as the root of the preinstall database.
  846. //
  847. // i.e. <CriticalDeviceDatabaseRoot>\\<CriticalDeviceEntry>
  848. //
  849. // This allows pre-install settings settings to be applied to a device
  850. // at a specific location, only if it matches some device id.
  851. //
  852. tmpStatus =
  853. PiCriticalPreInstallDevice(
  854. DeviceNode,
  855. CriticalDeviceEntryHandle
  856. );
  857. if (NT_SUCCESS(tmpStatus)) {
  858. IopDbgPrint((IOP_ENUMERATION_VERBOSE_LEVEL,
  859. "PpCriticalProcessCriticalDevice: "
  860. "Pre-installation successfully completed for devnode %#08lx\n",
  861. DeviceNode));
  862. }
  863. //
  864. // Next, set the ConfigFlags appropriately.
  865. //
  866. //
  867. // Initialize the ConfigFlags to 0, in case none exist yet.
  868. //
  869. ConfigFlags = 0;
  870. //
  871. // Retrieve the existing ConfigFlags for the device.
  872. //
  873. keyValueFullInfo = NULL;
  874. tmpStatus =
  875. IopGetRegistryValue(
  876. DeviceInstanceHandle,
  877. REGSTR_VALUE_CONFIG_FLAGS,
  878. &keyValueFullInfo
  879. );
  880. //
  881. // If ConfigFlags were successfully retrieved, use them instead.
  882. //
  883. if (NT_SUCCESS(tmpStatus)) {
  884. ASSERT(keyValueFullInfo != NULL);
  885. if (keyValueFullInfo->Type == REG_DWORD && keyValueFullInfo->DataLength == sizeof(ULONG)) {
  886. ConfigFlags = *(PULONG)KEY_VALUE_DATA(keyValueFullInfo);
  887. }
  888. ExFreePool(keyValueFullInfo);
  889. }
  890. //
  891. // Clear the "needs re-install" and "failed install" ConfigFlags.
  892. //
  893. ConfigFlags &= ~(CONFIGFLAG_REINSTALL | CONFIGFLAG_FAILEDINSTALL);
  894. //
  895. // Installation is not considered complete, so set
  896. // CONFIGFLAG_FINISH_INSTALL so we will still get a new hw found popup
  897. // and go through the class installer.
  898. //
  899. ConfigFlags |= CONFIGFLAG_FINISH_INSTALL;
  900. PiWstrToUnicodeString(&UnicodeValueName, REGSTR_VALUE_CONFIG_FLAGS);
  901. ZwSetValueKey(
  902. DeviceInstanceHandle,
  903. &UnicodeValueName,
  904. TITLE_INDEX_VALUE,
  905. REG_DWORD,
  906. &ConfigFlags,
  907. sizeof(ULONG)
  908. );
  909. //
  910. // Make sure the device does not have any problems relating to
  911. // either being not configured or not installed.
  912. //
  913. ASSERT(!PipDoesDevNodeHaveProblem(DeviceNode) ||
  914. PipIsDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED) ||
  915. PipIsDevNodeProblem(DeviceNode, CM_PROB_FAILED_INSTALL) ||
  916. PipIsDevNodeProblem(DeviceNode, CM_PROB_REINSTALL));
  917. PipClearDevNodeProblem(DeviceNode);
  918. }
  919. Clean0:
  920. if (CriticalDeviceEntryHandle != NULL) {
  921. ZwClose(CriticalDeviceEntryHandle);
  922. }
  923. if (DeviceInstanceHandle != NULL) {
  924. ZwClose(DeviceInstanceHandle);
  925. }
  926. return Status;
  927. } // PpCriticalProcessCriticalDevice
  928. //
  929. // Critical Device Database routines related to device pre-installation.
  930. //
  931. NTSTATUS
  932. PiCriticalPreInstallDevice(
  933. IN PDEVICE_NODE DeviceNode,
  934. IN HANDLE PreInstallDatabaseRootHandle OPTIONAL
  935. )
  936. /*++
  937. Routine Description:
  938. This routine attempts to pre-install instance-specific settings for
  939. non-configured devices that will be started based on information in
  940. the Plug and Play Critical Device Database (CDDB).
  941. It is intended to complement the CriticalDeviceDatabase by applying
  942. instance-specific settings to a device, rather than the hardware-id /
  943. compatible-id specific settings applied by the CriticalDeviceDatabase.
  944. Matches for a specific device-instance are made by comparing device location
  945. information returned by the device and its ancestors with pre-seeded
  946. database entries of the same format.
  947. Arguments:
  948. DeviceNode -
  949. Specifies the device whose settings are to be pre-installed.
  950. PreInstallDatabaseRootHandle -
  951. Optionally, specifies a handle to the key that should be considered the
  952. root of the pre-install database to be searched for this device.
  953. This may be a handle to the key for the CriticalDeviceDatabase entry
  954. that matched this device - OR - may be the root of a single database
  955. that contains pre-install settings for all devices in the system.
  956. If no handle is supplied, the default global pre-install database is
  957. used:
  958. System\\CurrentControlSet\\Control\\CriticalPreInstallDatabase
  959. Return Value:
  960. NTSTATUS code.
  961. --*/
  962. {
  963. NTSTATUS Status, tmpStatus;
  964. HANDLE PreInstallHandle, DeviceInstanceHandle;
  965. HANDLE DeviceHardwareKeyHandle, DeviceSoftwareKeyHandle;
  966. HANDLE PreInstallHardwareKeyHandle, PreInstallSoftwareKeyHandle;
  967. UNICODE_STRING UnicodeString;
  968. PKEY_VALUE_FULL_INFORMATION keyValueFullInfo;
  969. PAGED_CODE();
  970. //
  971. // Validate parameters
  972. //
  973. if (!ARGUMENT_PRESENT(DeviceNode)) {
  974. return STATUS_INVALID_PARAMETER;
  975. }
  976. //
  977. // Open the device pre-install settings root key.
  978. //
  979. PreInstallHandle = NULL;
  980. Status =
  981. PiCriticalOpenDevicePreInstallKey(
  982. DeviceNode,
  983. PreInstallDatabaseRootHandle,
  984. &PreInstallHandle
  985. );
  986. if (!NT_SUCCESS(Status)) {
  987. IopDbgPrint((IOP_ENUMERATION_VERBOSE_LEVEL,
  988. "PiCriticalPreInstallDevice: "
  989. "No pre-install settings found for devnode %#08lx\n",
  990. DeviceNode));
  991. ASSERT(PreInstallHandle == NULL);
  992. goto Clean0;
  993. }
  994. ASSERT(PreInstallHandle != NULL);
  995. //
  996. // Open the pre-install settings Hardware subkey.
  997. //
  998. PiWstrToUnicodeString(&UnicodeString, _REGSTR_KEY_PREINSTALL_HARDWARE);
  999. PreInstallHardwareKeyHandle = NULL;
  1000. Status =
  1001. IopOpenRegistryKeyEx(
  1002. &PreInstallHardwareKeyHandle,
  1003. PreInstallHandle,
  1004. &UnicodeString,
  1005. KEY_READ
  1006. );
  1007. if (NT_SUCCESS(Status)) {
  1008. ASSERT(PreInstallHardwareKeyHandle != NULL);
  1009. //
  1010. // We have hardware settings to pre-install for this device, so open
  1011. // the device's hardware key.
  1012. //
  1013. DeviceHardwareKeyHandle = NULL;
  1014. Status =
  1015. IoOpenDeviceRegistryKey(
  1016. DeviceNode->PhysicalDeviceObject,
  1017. PLUGPLAY_REGKEY_DEVICE,
  1018. KEY_ALL_ACCESS,
  1019. &DeviceHardwareKeyHandle);
  1020. if (NT_SUCCESS(Status)) {
  1021. IopDbgPrint((IOP_ENUMERATION_VERBOSE_LEVEL,
  1022. "PiCriticalPreInstallDevice: "
  1023. "DeviceHardwareKeyHandle (%#08lx) successfully opened for devnode %#08lx\n",
  1024. DeviceHardwareKeyHandle, DeviceNode));
  1025. ASSERT(DeviceHardwareKeyHandle != NULL);
  1026. //
  1027. // Copy the pre-install hardware settings to the device's
  1028. // hardware key.
  1029. //
  1030. // NOTE that we specify that existing hardware settings for the
  1031. // device should NOT be replaced with values from the pre-install
  1032. // database. This is because:
  1033. //
  1034. // - If the device is truly being installed from scratch, then it
  1035. // will have no pre-existing values in this key, and all values
  1036. // will be copied from the pre-install database anyways.
  1037. //
  1038. // - If the device does happen to have pre-existing settings, but
  1039. // happened to get processed by the CDDB for some wacky reason
  1040. // like it was just missing ConfigFlags, we don't want to
  1041. // override them, just add to them.
  1042. //
  1043. Status =
  1044. PiCopyKeyRecursive(
  1045. PreInstallHardwareKeyHandle, // SourceKey
  1046. DeviceHardwareKeyHandle, // TargetKey
  1047. NULL,
  1048. NULL,
  1049. FALSE, // CopyAlways
  1050. FALSE // ApplyACLsAlways
  1051. );
  1052. ZwClose(DeviceHardwareKeyHandle);
  1053. } else {
  1054. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  1055. "PiCriticalPreInstallDevice: "
  1056. "DeviceHardwareKeyHandle was NOT successfully opened for devnode %#08lx\n",
  1057. DeviceNode));
  1058. ASSERT(DeviceHardwareKeyHandle == NULL);
  1059. }
  1060. ZwClose(PreInstallHardwareKeyHandle);
  1061. } else {
  1062. IopDbgPrint((IOP_ENUMERATION_VERBOSE_LEVEL,
  1063. "PiCriticalPreInstallDevice: "
  1064. "No hardware pre-install settings found for devnode %#08lx\n",
  1065. DeviceNode));
  1066. ASSERT(PreInstallHardwareKeyHandle == NULL);
  1067. }
  1068. //
  1069. // Open the pre-install settings Software subkey.
  1070. //
  1071. PiWstrToUnicodeString(&UnicodeString, _REGSTR_KEY_PREINSTALL_SOFTWARE);
  1072. PreInstallSoftwareKeyHandle = NULL;
  1073. Status =
  1074. IopOpenRegistryKeyEx(
  1075. &PreInstallSoftwareKeyHandle,
  1076. PreInstallHandle,
  1077. &UnicodeString,
  1078. KEY_READ
  1079. );
  1080. if (NT_SUCCESS(Status)) {
  1081. ASSERT(PreInstallSoftwareKeyHandle != NULL);
  1082. //
  1083. // We have software settings to pre-install for this device, so
  1084. // open/create the device's software key.
  1085. //
  1086. DeviceSoftwareKeyHandle = NULL;
  1087. Status =
  1088. IopOpenOrCreateDeviceRegistryKey(
  1089. DeviceNode->PhysicalDeviceObject,
  1090. PLUGPLAY_REGKEY_DRIVER,
  1091. KEY_ALL_ACCESS,
  1092. TRUE,
  1093. &DeviceSoftwareKeyHandle);
  1094. if (NT_SUCCESS(Status)) {
  1095. IopDbgPrint((IOP_ENUMERATION_VERBOSE_LEVEL,
  1096. "PiCriticalPreInstallDevice: "
  1097. "DeviceSoftwareKeyHandle (%#08lx) successfully opened for devnode %#08lx\n",
  1098. DeviceSoftwareKeyHandle, DeviceNode));
  1099. ASSERT(DeviceSoftwareKeyHandle != NULL);
  1100. //
  1101. // Copy the pre-install software settings to the device's
  1102. // software key.
  1103. //
  1104. // NOTE that we specify that existing software settings for the
  1105. // device should NOT be replaced with values from the pre-install
  1106. // database. This is because:
  1107. //
  1108. // - If the device is truly being installed from scratch, then it
  1109. // will have no pre-existing values in this key, and all values
  1110. // will be copied from the pre-install database anyways.
  1111. //
  1112. // - If the device does happen to have pre-existing settings, but
  1113. // happened to get processed by the CDDB for some wacky reason
  1114. // like it was just missing ConfigFlags, we don't want to
  1115. // override them, just add to them.
  1116. //
  1117. Status =
  1118. PiCopyKeyRecursive(
  1119. PreInstallSoftwareKeyHandle, // SourceKey
  1120. DeviceSoftwareKeyHandle, // TargetKey
  1121. NULL,
  1122. NULL,
  1123. FALSE, // CopyAlways
  1124. FALSE // ApplyACLsAlways,
  1125. );
  1126. ZwClose(DeviceSoftwareKeyHandle);
  1127. } else {
  1128. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  1129. "PiCriticalPreInstallDevice: "
  1130. "DeviceSoftwareKeyHandle was NOT successfully opened for devnode %#08lx\n",
  1131. DeviceNode));
  1132. ASSERT(DeviceSoftwareKeyHandle == NULL);
  1133. }
  1134. ZwClose(PreInstallSoftwareKeyHandle);
  1135. } else {
  1136. IopDbgPrint((IOP_ENUMERATION_VERBOSE_LEVEL,
  1137. "PiCriticalPreInstallDevice: "
  1138. "No software pre-install settings found for devnode %#08lx\n",
  1139. DeviceNode));
  1140. ASSERT(PreInstallSoftwareKeyHandle == NULL);
  1141. }
  1142. //
  1143. // Now, check the device pre-install registry key for the flag that
  1144. // indicates that the pre-install settings are complete, and should be
  1145. // respected by user-mode device installation.
  1146. //
  1147. keyValueFullInfo = NULL;
  1148. tmpStatus =
  1149. IopGetRegistryValue(
  1150. PreInstallHandle,
  1151. REGSTR_VAL_PRESERVE_PREINSTALL,
  1152. &keyValueFullInfo);
  1153. if (NT_SUCCESS(tmpStatus)) {
  1154. ASSERT(keyValueFullInfo != NULL);
  1155. //
  1156. // Open the device instance registry key.
  1157. //
  1158. DeviceInstanceHandle = NULL;
  1159. tmpStatus =
  1160. IopDeviceObjectToDeviceInstance(
  1161. DeviceNode->PhysicalDeviceObject,
  1162. &DeviceInstanceHandle,
  1163. KEY_ALL_ACCESS);
  1164. if (NT_SUCCESS(tmpStatus)) {
  1165. ASSERT(DeviceInstanceHandle != NULL);
  1166. //
  1167. // Write the value to the device instance registry key.
  1168. //
  1169. PiWstrToUnicodeString(
  1170. &UnicodeString,
  1171. REGSTR_VAL_PRESERVE_PREINSTALL);
  1172. tmpStatus =
  1173. ZwSetValueKey(
  1174. DeviceInstanceHandle,
  1175. &UnicodeString,
  1176. keyValueFullInfo->TitleIndex,
  1177. keyValueFullInfo->Type,
  1178. (PVOID)((PUCHAR)keyValueFullInfo + keyValueFullInfo->DataOffset),
  1179. keyValueFullInfo->DataLength);
  1180. if (!NT_SUCCESS(tmpStatus)) {
  1181. IopDbgPrint((IOP_ENUMERATION_VERBOSE_LEVEL,
  1182. "PiCriticalPreInstallDevice: "
  1183. "Unable to set %wZ value in instance key for devnode %#08lx\n",
  1184. &UnicodeString, DeviceNode));
  1185. }
  1186. ZwClose(DeviceInstanceHandle);
  1187. } else {
  1188. IopDbgPrint((IOP_ENUMERATION_VERBOSE_LEVEL,
  1189. "PiCriticalPreInstallDevice: "
  1190. "Unable to open device instance key for devnode %#08lx\n",
  1191. DeviceNode));
  1192. ASSERT(DeviceInstanceHandle == NULL);
  1193. }
  1194. ExFreePool(keyValueFullInfo);
  1195. }
  1196. ZwClose(PreInstallHandle);
  1197. Clean0:
  1198. return Status;
  1199. } // PiCriticalPreInstallDevice
  1200. NTSTATUS
  1201. PiCriticalOpenDevicePreInstallKey(
  1202. IN PDEVICE_NODE DeviceNode,
  1203. IN HANDLE PreInstallDatabaseRootHandle OPTIONAL,
  1204. OUT PHANDLE PreInstallHandle
  1205. )
  1206. /*++
  1207. Routine Description:
  1208. This routine retrieves the registry key containing the pre-install settings
  1209. for the specified device.
  1210. Arguments:
  1211. DeviceNode -
  1212. Specifies the device whose pre-install settings are to be retrieved.
  1213. PreInstallDatabaseRootHandle -
  1214. Optionally, specifies a handle to the key that should be considered the
  1215. root of the pre-install database to be searched for this device.
  1216. This may be a handle to the key for the CriticalDeviceDatabase entry
  1217. that matched this device - OR - may be the root of a single database
  1218. that contains pre-install settings for all devices in the system.
  1219. PreInstallHandle -
  1220. Returns a handle to the registry key containing the pre-install settings
  1221. for the specified device.
  1222. Return Value:
  1223. NTSTATUS code.
  1224. --*/
  1225. {
  1226. NTSTATUS Status = STATUS_SUCCESS;
  1227. UNICODE_STRING UnicodeString;
  1228. HANDLE DatabaseRootHandle = NULL, DevicePathsHandle;
  1229. PWCHAR DeviceLocationStrings = NULL;
  1230. PAGED_CODE();
  1231. //
  1232. // Validate parameters.
  1233. //
  1234. if ((!ARGUMENT_PRESENT(DeviceNode)) ||
  1235. (!ARGUMENT_PRESENT(PreInstallHandle))) {
  1236. return STATUS_INVALID_PARAMETER;
  1237. }
  1238. //
  1239. // Initialize output parameter.
  1240. //
  1241. *PreInstallHandle = NULL;
  1242. if (PreInstallDatabaseRootHandle != NULL) {
  1243. //
  1244. // We were given a root database to be searched.
  1245. //
  1246. DatabaseRootHandle = PreInstallDatabaseRootHandle;
  1247. } else {
  1248. //
  1249. // No root database handle supplied, so we open a key to the default
  1250. // global device pre-install database root.
  1251. //
  1252. PiWstrToUnicodeString(
  1253. &UnicodeString,
  1254. CM_REGISTRY_MACHINE(_REGSTR_PATH_DEFAULT_PREINSTALL_DATABASE_ROOT));
  1255. Status =
  1256. IopOpenRegistryKeyEx(
  1257. &DatabaseRootHandle,
  1258. NULL,
  1259. &UnicodeString,
  1260. KEY_READ);
  1261. if (!NT_SUCCESS(Status)) {
  1262. return Status;
  1263. }
  1264. }
  1265. ASSERT(DatabaseRootHandle != NULL);
  1266. //
  1267. // Open the DevicePaths subkey of the pre-install database root.
  1268. //
  1269. // This key contains subkeys which are device location paths for devices
  1270. // that may potentially be present on the system. These are devices whose
  1271. // settings we would like to pre-install, so that they may be used the very
  1272. // first time the device is started, rather than requiring the plug and play
  1273. // config manager, and/or user intervention.
  1274. //
  1275. PiWstrToUnicodeString(&UnicodeString, _REGSTR_KEY_DEVICEPATHS);
  1276. DevicePathsHandle = NULL;
  1277. Status =
  1278. IopOpenRegistryKeyEx(
  1279. &DevicePathsHandle,
  1280. DatabaseRootHandle,
  1281. &UnicodeString,
  1282. KEY_READ);
  1283. //
  1284. // If we opened our own key to the database root, close it now.
  1285. //
  1286. if ((PreInstallDatabaseRootHandle == NULL) &&
  1287. (DatabaseRootHandle != NULL)) {
  1288. ZwClose(DatabaseRootHandle);
  1289. }
  1290. //
  1291. // If unsuccessful opening the DevicePaths key, we're done.
  1292. //
  1293. if (!NT_SUCCESS(Status)) {
  1294. ASSERT(DevicePathsHandle == NULL);
  1295. goto Clean0;
  1296. }
  1297. ASSERT(DevicePathsHandle != NULL);
  1298. //
  1299. // Retrieve the multi-sz list of device location string paths for this
  1300. // device.
  1301. //
  1302. Status =
  1303. PpCriticalGetDeviceLocationStrings(
  1304. DeviceNode,
  1305. &DeviceLocationStrings
  1306. );
  1307. if (!NT_SUCCESS(Status)) {
  1308. ASSERT(DeviceLocationStrings == NULL);
  1309. ZwClose(DevicePathsHandle);
  1310. goto Clean0;
  1311. }
  1312. ASSERT(DeviceLocationStrings != NULL);
  1313. //
  1314. // Open the first matching subkey.
  1315. // No verification callback needed, the first match will do.
  1316. //
  1317. Status =
  1318. PiCriticalOpenFirstMatchingSubKey(
  1319. DeviceLocationStrings,
  1320. DevicePathsHandle,
  1321. KEY_READ,
  1322. (PCRITICAL_MATCH_CALLBACK)NULL,
  1323. PreInstallHandle
  1324. );
  1325. //
  1326. // Close the DevicePaths key.
  1327. //
  1328. ZwClose(DevicePathsHandle);
  1329. Clean0:
  1330. //
  1331. // Free the list of device location path strings, if we received one.
  1332. //
  1333. if (DeviceLocationStrings != NULL) {
  1334. ExFreePool(DeviceLocationStrings);
  1335. }
  1336. return Status;
  1337. } // PiCriticalOpenDevicePreInstallKey
  1338. NTSTATUS
  1339. PiCriticalOpenFirstMatchingSubKey(
  1340. IN PWCHAR MultiSzKeyNames,
  1341. IN HANDLE RootHandle,
  1342. IN ACCESS_MASK DesiredAccess,
  1343. IN PCRITICAL_MATCH_CALLBACK MatchingSubkeyCallback OPTIONAL,
  1344. OUT PHANDLE MatchingKeyHandle
  1345. )
  1346. /*++
  1347. Routine Description:
  1348. This routine retrieves the first subkey of the supplied root that matched a
  1349. string in the multi-sz list.
  1350. Arguments:
  1351. MultiSzKeyNames -
  1352. Supplies a multi-sz list of possible matching subkey names.
  1353. RootHandle -
  1354. Specifies a handle to the root key that should be searched for a
  1355. matching subkey.
  1356. DesiredAccess -
  1357. Specifies the desired access the matching subkey should be opened with,
  1358. if found.
  1359. MatchingSubkeyCallback -
  1360. Optionally, specifies a callback routine to be called with matching
  1361. subkeys to perform additional verification of potential subkey matches.
  1362. If the callback routine returns FALSE for a potential match, the subkey
  1363. is then considered NOT to be a match, and the search will continue.
  1364. MatchingKeyHandle -
  1365. Specifies the address of a variable to retrieve the open handle to the
  1366. first matching subkey.
  1367. Return Value:
  1368. NTSTATUS code.
  1369. --*/
  1370. {
  1371. NTSTATUS Status;
  1372. PWSTR p;
  1373. UNICODE_STRING UnicodeString;
  1374. PAGED_CODE();
  1375. //
  1376. // Validate parameters.
  1377. //
  1378. if ((!ARGUMENT_PRESENT(MultiSzKeyNames)) ||
  1379. (RootHandle == NULL) ||
  1380. (!ARGUMENT_PRESENT(MatchingKeyHandle))) {
  1381. return STATUS_INVALID_PARAMETER;
  1382. }
  1383. //
  1384. // Initialize output parameter.
  1385. //
  1386. *MatchingKeyHandle = NULL;
  1387. //
  1388. // Start with no match found yet, in case the multi-sz is empty.
  1389. //
  1390. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1391. //
  1392. // Check each string in the multi-sz list.
  1393. //
  1394. for (p = MultiSzKeyNames; *p != UNICODE_NULL; p += wcslen(p)+1) {
  1395. //
  1396. // Attempt to open a corresponding subkey of the root.
  1397. //
  1398. RtlInitUnicodeString(&UnicodeString, p);
  1399. Status =
  1400. IopOpenRegistryKeyEx(
  1401. MatchingKeyHandle,
  1402. RootHandle,
  1403. &UnicodeString,
  1404. DesiredAccess);
  1405. if (NT_SUCCESS(Status)) {
  1406. ASSERT(*MatchingKeyHandle != NULL);
  1407. //
  1408. // We have a conditional match - check the MatchingSubkeyCallback
  1409. // for verification, if we have one.
  1410. //
  1411. if ((ARGUMENT_PRESENT(MatchingSubkeyCallback)) &&
  1412. (!(MatchingSubkeyCallback(*MatchingKeyHandle)))) {
  1413. //
  1414. // Not a match.
  1415. //
  1416. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1417. //
  1418. // Close the key and continue.
  1419. //
  1420. ZwClose(*MatchingKeyHandle);
  1421. *MatchingKeyHandle = NULL;
  1422. continue;
  1423. }
  1424. //
  1425. // Match!
  1426. //
  1427. break;
  1428. }
  1429. ASSERT(*MatchingKeyHandle == NULL);
  1430. *MatchingKeyHandle = NULL;
  1431. }
  1432. if (NT_SUCCESS(Status)) {
  1433. ASSERT(*MatchingKeyHandle != NULL);
  1434. } else {
  1435. ASSERT(*MatchingKeyHandle == NULL);
  1436. }
  1437. return Status;
  1438. } // PiCriticalOpenFirstMatchingSubKey
  1439. BOOLEAN
  1440. PiCriticalCallbackVerifyCriticalEntry(
  1441. IN HANDLE CriticalDeviceEntryHandle
  1442. )
  1443. /*++
  1444. Routine Description:
  1445. This routine is a callback routine to verify that the specified critical
  1446. device database entry key can be used to supply critical device settings.
  1447. Arguments:
  1448. CriticalDeviceEntryHandle -
  1449. Specifies a handle to the registry key containing critical device
  1450. settings for the specified device.
  1451. Return Value:
  1452. Returns TRUE if the key conatins valid settings for a matching critical
  1453. device database entry, FALSE otherwise.
  1454. --*/
  1455. {
  1456. NTSTATUS Status;
  1457. PKEY_VALUE_FULL_INFORMATION keyValueFullInfo;
  1458. ULONG DataType, DataLength;
  1459. PAGED_CODE();
  1460. //
  1461. // Validate parameters.
  1462. //
  1463. if (CriticalDeviceEntryHandle == NULL) {
  1464. return FALSE;
  1465. }
  1466. //
  1467. // For critical device database entries, a match is only a match if it
  1468. // contains a "Service" value.
  1469. //
  1470. keyValueFullInfo = NULL;
  1471. Status =
  1472. IopGetRegistryValue(CriticalDeviceEntryHandle,
  1473. REGSTR_VALUE_SERVICE,
  1474. &keyValueFullInfo);
  1475. if (!NT_SUCCESS(Status)) {
  1476. ASSERT(keyValueFullInfo == NULL);
  1477. goto Clean0;
  1478. }
  1479. ASSERT(keyValueFullInfo != NULL);
  1480. DataType = keyValueFullInfo->Type;
  1481. DataLength = keyValueFullInfo->DataLength;
  1482. ExFreePool(keyValueFullInfo);
  1483. //
  1484. // Make sure the returned registry value is a non-null reg sz.
  1485. //
  1486. if ((DataType != REG_SZ) || (DataLength <= sizeof(UNICODE_NULL))) {
  1487. Status = STATUS_UNSUCCESSFUL;
  1488. goto Clean0;
  1489. }
  1490. //
  1491. // so far, so good...
  1492. //
  1493. //
  1494. // For critical device database entries, a match is only a match if it
  1495. // contains a valid "ClassGUID" value - or none at all.
  1496. //
  1497. keyValueFullInfo = NULL;
  1498. Status =
  1499. IopGetRegistryValue(
  1500. CriticalDeviceEntryHandle,
  1501. REGSTR_VALUE_CLASSGUID,
  1502. &keyValueFullInfo
  1503. );
  1504. if (!NT_SUCCESS(Status)) {
  1505. ASSERT(keyValueFullInfo == NULL);
  1506. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1507. //
  1508. // No ClassGUID entry is considered a valid match.
  1509. //
  1510. Status = STATUS_SUCCESS;
  1511. }
  1512. goto Clean0;
  1513. }
  1514. ASSERT(keyValueFullInfo != NULL);
  1515. DataType = keyValueFullInfo->Type;
  1516. DataLength = keyValueFullInfo->DataLength;
  1517. ExFreePool(keyValueFullInfo);
  1518. //
  1519. // Make sure the returned registry value is a reg-sz of the right size. The
  1520. // data must be at least as the length of the data for a stringified-GUID.
  1521. // No ClassGUID value is also valid, so a null reg-sz ClassGUID entry is
  1522. // also considered a valid match. Anything else is invalid, and shouldn't
  1523. // be used.
  1524. //
  1525. // NOTE: 01-Dec-2001 : Jim Cavalaris (jamesca)
  1526. //
  1527. // A ClassGUID value with Data that is too long for a stringified GUID
  1528. // will actually still be considered valid. We should fix this to
  1529. // consider only valid stringified GUIDs, but this is way this was done
  1530. // previously, so we won't change it for this release. Something to
  1531. // consider in the future.
  1532. //
  1533. if ((DataType != REG_SZ) ||
  1534. ((DataLength < (GUID_STRING_LEN*sizeof(WCHAR)-sizeof(UNICODE_NULL))) &&
  1535. (DataLength > sizeof(UNICODE_NULL)))) {
  1536. Status = STATUS_UNSUCCESSFUL;
  1537. goto Clean0;
  1538. }
  1539. Clean0:
  1540. return ((BOOLEAN)NT_SUCCESS(Status));
  1541. } // PiCriticalCallbackVerifyCriticalEntry
  1542. NTSTATUS
  1543. PpCriticalGetDeviceLocationStrings(
  1544. IN PDEVICE_NODE DeviceNode,
  1545. OUT PWCHAR *DeviceLocationStrings
  1546. )
  1547. /*++
  1548. Routine Description:
  1549. This routine retrieves the device location string for a device node.
  1550. Arguments:
  1551. DeviceNode -
  1552. Specifies the device whose location strings are to be retrieved.
  1553. DeviceLocationStrings -
  1554. Returns a multi-sz string of the device location path strings, composed
  1555. from the set of location strings returned from each device in the
  1556. anscestry of the specified device.
  1557. Return Value:
  1558. NTSTATUS code.
  1559. --*/
  1560. {
  1561. NTSTATUS Status = STATUS_SUCCESS;
  1562. PDEVICE_NODE deviceNode;
  1563. ULONG QueriedLocationStringsArraySize;
  1564. PWSTR *QueriedLocationStrings = NULL;
  1565. PULONG QueriedLocationStringsCount = NULL;
  1566. PNP_LOCATION_INTERFACE LocationInterface;
  1567. PWSTR TempMultiSz;
  1568. ULONG TempMultiSzLength;
  1569. PWSTR p, pdlp;
  1570. ULONG LongestStringLengthAtLevel;
  1571. ULONG FinalStringLevel, i;
  1572. ULONG DeviceLocationPathMultiSzStringCount;
  1573. ULONG DeviceLocationPathMultiSzLength;
  1574. PWCHAR DeviceLocationPathMultiSz = NULL;
  1575. ULONG CombinationsRemaining, CombinationEnumIndex;
  1576. ULONG MultiSzIndex, MultiSzLookupIndex, StringLength;
  1577. PAGED_CODE();
  1578. //
  1579. // Validate parameters.
  1580. //
  1581. if ((!ARGUMENT_PRESENT(DeviceNode)) ||
  1582. (!ARGUMENT_PRESENT(DeviceLocationStrings))) {
  1583. return STATUS_INVALID_PARAMETER;
  1584. }
  1585. //
  1586. // Initialize out parameters.
  1587. //
  1588. *DeviceLocationStrings = NULL;
  1589. //
  1590. // We should NEVER have to query for the location of the root devnode.
  1591. //
  1592. if (DeviceNode == IopRootDeviceNode) {
  1593. return STATUS_NO_SUCH_DEVICE;
  1594. }
  1595. //
  1596. // Count the number of devnodes in the ancestry of the device to find out
  1597. // the max number of location string sets we may have to query for.
  1598. //
  1599. QueriedLocationStringsArraySize = 0;
  1600. for (deviceNode = DeviceNode;
  1601. deviceNode != IopRootDeviceNode;
  1602. deviceNode = deviceNode->Parent) {
  1603. QueriedLocationStringsArraySize++;
  1604. }
  1605. ASSERT(QueriedLocationStringsArraySize > 0);
  1606. //
  1607. // Allocate and initialize an array of string buffer pointers for all
  1608. // devices in the ancestry, and a corresponding array for the number of
  1609. // strings retrieved for each device.
  1610. //
  1611. QueriedLocationStrings =
  1612. (PWSTR*)ExAllocatePool(PagedPool,
  1613. QueriedLocationStringsArraySize*sizeof(PWSTR));
  1614. if (QueriedLocationStrings == NULL) {
  1615. Status = STATUS_INSUFFICIENT_RESOURCES;
  1616. goto Clean0;
  1617. }
  1618. RtlZeroMemory(QueriedLocationStrings,
  1619. QueriedLocationStringsArraySize*sizeof(PWSTR));
  1620. QueriedLocationStringsCount =
  1621. (ULONG*)ExAllocatePool(PagedPool,
  1622. QueriedLocationStringsArraySize*sizeof(ULONG));
  1623. if (QueriedLocationStringsCount == NULL) {
  1624. Status = STATUS_INSUFFICIENT_RESOURCES;
  1625. goto Clean0;
  1626. }
  1627. RtlZeroMemory(QueriedLocationStringsCount,
  1628. QueriedLocationStringsArraySize*sizeof(ULONG));
  1629. //
  1630. // Starting at the target device, walk up the devnode tree, retrieving the
  1631. // set of location strings for all ancestors up to (but not including) the
  1632. // root devnode. We'll stop when we've reached the top of the tree, or when
  1633. // some intermediate device has explicitly declared that the translation is
  1634. // complete.
  1635. //
  1636. i = 0;
  1637. //
  1638. // Along the way, we count the total number of string combinations that can
  1639. // be formed by taking a single string from the multi-sz list at each level.
  1640. // This is simply the product of the number of string elements in the
  1641. // multi-sz list at each level.
  1642. //
  1643. DeviceLocationPathMultiSzStringCount = 1;
  1644. //
  1645. // Also along the way, calculate the length (in chars) of the longest device
  1646. // location path that can be generated from all combinations. This is just
  1647. // the sum of the longest string at each level (LongestStringLengthAtLevel
  1648. // below), plus the necessary path component separator strings and NULL
  1649. // terminating character.
  1650. //
  1651. //
  1652. // WARNING!! EXCESSIVELY VERBOSE COMMENT AHEAD!!
  1653. //
  1654. // NOTE: 27-Nov-2001 : Jim Cavalaris (jamesca)
  1655. //
  1656. // We use this length to calculate the length of the buffer required to
  1657. // hold the entire multi-sz list of device location paths ASSUMING ALL
  1658. // GENERATED STRINGS ARE EQUALLY AS LONG. This is an UPPER-BOUND, so we
  1659. // may end up allocating more memory than we actually need.
  1660. //
  1661. // This should be ok, since in the ideal (and assumed to be most-common)
  1662. // case, only one location string will ever be returned per device - in
  1663. // which case this calculation will be exactly the size required.
  1664. //
  1665. // In the event that multiple strings are returned per device, we should
  1666. // expect these strings to all be relatively short, and equal (or similar)
  1667. // in length. In that case, this calculation will be exactly the size
  1668. // required (or similar).
  1669. //
  1670. // We also currently do not expect to have to query many devices in the
  1671. // ancestry to complete the translation, so we shouldn't event expect too
  1672. // many combinations.
  1673. //
  1674. // These are our assumptions, so consider yourself warned! If any of
  1675. // these change such that we would need to allocate an excessive amount of
  1676. // memory, you will want to either run through the same algorithm the
  1677. // device location path generation code runs through just to calculate the
  1678. // exact size, or find some way to enumerate the device location path
  1679. // combinations incrementally.
  1680. //
  1681. DeviceLocationPathMultiSzLength = 0;
  1682. for (deviceNode = DeviceNode;
  1683. deviceNode != IopRootDeviceNode;
  1684. deviceNode = deviceNode->Parent) {
  1685. //
  1686. // Query the device for the location interface.
  1687. //
  1688. Status = PiQueryInterface(deviceNode->PhysicalDeviceObject,
  1689. &GUID_PNP_LOCATION_INTERFACE,
  1690. PNP_LOCATION_INTERFACE_VERSION,
  1691. sizeof(PNP_LOCATION_INTERFACE),
  1692. (PINTERFACE)&LocationInterface);
  1693. if (!NT_SUCCESS(Status)) {
  1694. //
  1695. // If the location interface was not available for some device
  1696. // before translation is complete, the entire operation is
  1697. // unsuccessful.
  1698. //
  1699. ASSERT((Status == STATUS_NOT_SUPPORTED) || (Status == STATUS_INSUFFICIENT_RESOURCES));
  1700. goto Clean0;
  1701. }
  1702. //
  1703. // If the location interface is supported, the required interface
  1704. // routines must be supplied.
  1705. //
  1706. ASSERT(LocationInterface.InterfaceReference != NULL);
  1707. ASSERT(LocationInterface.InterfaceDereference != NULL);
  1708. ASSERT(LocationInterface.GetLocationString != NULL);
  1709. if (LocationInterface.GetLocationString != NULL) {
  1710. //
  1711. // Initialize the location string.
  1712. //
  1713. TempMultiSz = NULL;
  1714. //
  1715. // Get the set of location strings for this device.
  1716. //
  1717. Status = LocationInterface.GetLocationString(
  1718. LocationInterface.Context,
  1719. &TempMultiSz);
  1720. if (NT_SUCCESS(Status)) {
  1721. //
  1722. // If successful, the caller must have supplied us with a
  1723. // buffer.
  1724. //
  1725. ASSERT(TempMultiSz != NULL);
  1726. //
  1727. // If not, the call was not really successful.
  1728. //
  1729. if (TempMultiSz == NULL) {
  1730. Status = STATUS_NOT_SUPPORTED;
  1731. }
  1732. }
  1733. if (NT_SUCCESS(Status)) {
  1734. //
  1735. // If a multi-sz list of device location strings was returned,
  1736. // inspect it, and keep note of a few things. Specifically, the
  1737. // number of strings in the multi-sz list, the length of the
  1738. // multi-sz list, and the length of the longest string in the
  1739. // list.
  1740. //
  1741. QueriedLocationStringsCount[i] = 0;
  1742. TempMultiSzLength = 0;
  1743. LongestStringLengthAtLevel = 0;
  1744. for (p = TempMultiSz; *p != UNICODE_NULL; p += wcslen(p)+1) {
  1745. //
  1746. // Count the number of strings at this level (in this
  1747. // multi-sz list).
  1748. //
  1749. QueriedLocationStringsCount[i]++;
  1750. //
  1751. // Determine the length (in chars) of the multi-sz list so
  1752. // we can allocate our own buffer, and copy it.
  1753. //
  1754. TempMultiSzLength += (ULONG)(wcslen(p) + 1);
  1755. //
  1756. // Also determine the length of the longest string of all
  1757. // strings in this multi-sz list so we can estimate the
  1758. // length required for all device location path
  1759. // combinations.
  1760. //
  1761. StringLength = (ULONG)wcslen(p);
  1762. if (StringLength > LongestStringLengthAtLevel) {
  1763. LongestStringLengthAtLevel = StringLength;
  1764. }
  1765. }
  1766. ASSERT(QueriedLocationStringsCount[i] > 0);
  1767. ASSERT(TempMultiSzLength > 0);
  1768. ASSERT(LongestStringLengthAtLevel > 0);
  1769. //
  1770. // Include the length of the double NULL-terminating character.
  1771. //
  1772. TempMultiSzLength += 1;
  1773. //
  1774. // After analyzing the device location strings at each level,
  1775. // update the number of device path combinations possible by
  1776. // simply multiplying the combinations possible so far by the
  1777. // number of strings retrieved for this level (in this multi-sz list).
  1778. //
  1779. DeviceLocationPathMultiSzStringCount *= QueriedLocationStringsCount[i];
  1780. //
  1781. // Also, update the length of the longest device location path
  1782. // possible by adding the length of the longest string available
  1783. // at this level.
  1784. //
  1785. DeviceLocationPathMultiSzLength += LongestStringLengthAtLevel;
  1786. //
  1787. // Make our own copy of the caller supplied multi-sz list of
  1788. // device location strings.
  1789. //
  1790. QueriedLocationStrings[i] =
  1791. (PWSTR)ExAllocatePool(PagedPool,
  1792. TempMultiSzLength*sizeof(WCHAR));
  1793. if (QueriedLocationStrings[i] != NULL) {
  1794. //
  1795. // Note on array element ordering - since we start at the
  1796. // target devnode and walk up the chain of parents, we don't
  1797. // yet know just how high up the translation will go. We
  1798. // add children towards the front of the array, so if
  1799. // translation is complete before every ancestor is queried,
  1800. // we'll just end up with some empty entries at the end.
  1801. //
  1802. RtlCopyMemory(QueriedLocationStrings[i],
  1803. TempMultiSz,
  1804. TempMultiSzLength*sizeof(WCHAR));
  1805. i++;
  1806. } else {
  1807. //
  1808. // Unable to allocate a buffer for our own list of pointers.
  1809. //
  1810. Status = STATUS_INSUFFICIENT_RESOURCES;
  1811. }
  1812. //
  1813. // Free the callee-allocated buffer.
  1814. //
  1815. ExFreePool(TempMultiSz);
  1816. TempMultiSz = NULL;
  1817. } else {
  1818. //
  1819. // If unsuccessful, make sure no location string was returned by
  1820. // the interface routine.
  1821. //
  1822. ASSERT(TempMultiSz == NULL);
  1823. //
  1824. // If the driver failed the call, but still allocated memory for
  1825. // us anyways, we'll clean up after it.
  1826. //
  1827. if (TempMultiSz != NULL) {
  1828. ExFreePool(TempMultiSz);
  1829. TempMultiSz = NULL;
  1830. }
  1831. }
  1832. } else {
  1833. //
  1834. // If a GetLocationString location interface routine was not
  1835. // supplied with the interface for some device before translation is
  1836. // complete, the entire operation is unsuccessful.
  1837. //
  1838. // Fall through to dereference the interface below, then exit.
  1839. //
  1840. Status = STATUS_UNSUCCESSFUL;
  1841. }
  1842. //
  1843. // Dereference the Location Interface.
  1844. //
  1845. if (LocationInterface.InterfaceDereference != NULL) {
  1846. LocationInterface.InterfaceDereference(LocationInterface.Context);
  1847. }
  1848. if (!NT_SUCCESS(Status)) {
  1849. //
  1850. // If unsuccessful while requesting location information for some
  1851. // device before translation was complete, the entire operation is
  1852. // unsuccessful.
  1853. //
  1854. goto Clean0;
  1855. } else if ((Status == STATUS_TRANSLATION_COMPLETE) ||
  1856. (i == QueriedLocationStringsArraySize)) {
  1857. //
  1858. // If successful, and the last device queried specifically indicated
  1859. // the end of the translation - OR - this is the last device in the
  1860. // ancestry, and therefore translation is explicitly complete, note
  1861. // translation is complete.
  1862. //
  1863. Status = STATUS_TRANSLATION_COMPLETE;
  1864. //
  1865. // Account for the length of the NULL-terminating character in our
  1866. // longest-length single string component estimate.
  1867. //
  1868. DeviceLocationPathMultiSzLength += 1;
  1869. //
  1870. // Stop walking up the device tree.
  1871. //
  1872. break;
  1873. }
  1874. //
  1875. // Success so far, but we still need to query more devices for
  1876. // location strings.
  1877. //
  1878. ASSERT(i < QueriedLocationStringsArraySize);
  1879. //
  1880. // Account for the length of a location path separator after every
  1881. // path component but the last.
  1882. //
  1883. DeviceLocationPathMultiSzLength +=
  1884. IopConstStringLength(_CRITICAL_DEVICE_LOCATION_PATH_SEPARATOR_STRING);
  1885. }
  1886. //
  1887. // The location information of every device in the ancestry has been queried
  1888. // successfully.
  1889. //
  1890. ASSERT(Status == STATUS_TRANSLATION_COMPLETE);
  1891. if (NT_SUCCESS(Status)) {
  1892. Status = STATUS_SUCCESS;
  1893. } else {
  1894. goto Clean0;
  1895. }
  1896. //
  1897. // Make sure we queried at least one device.
  1898. //
  1899. ASSERT(i > 0);
  1900. //
  1901. // Allocate a buffer large enough to assume that all device location path
  1902. // string combinations are as long as the longest device location path
  1903. // string formed. Also account for the double NULL-terminating character.
  1904. //
  1905. DeviceLocationPathMultiSzLength *= DeviceLocationPathMultiSzStringCount;
  1906. DeviceLocationPathMultiSzLength += 1;
  1907. DeviceLocationPathMultiSz =
  1908. (PWCHAR)ExAllocatePool(PagedPool,
  1909. DeviceLocationPathMultiSzLength*sizeof(WCHAR));
  1910. if (DeviceLocationPathMultiSz == NULL) {
  1911. Status = STATUS_INSUFFICIENT_RESOURCES;
  1912. goto Clean0;
  1913. }
  1914. RtlZeroMemory(DeviceLocationPathMultiSz,
  1915. DeviceLocationPathMultiSzLength*sizeof(WCHAR));
  1916. //
  1917. // We should now have an array of multi-sz strings returned by the location
  1918. // string interface routine for a set of devices in the ancestry of the
  1919. // specified device. From these multi-sz strings, we now need to build all
  1920. // possible device paths.
  1921. //
  1922. //
  1923. // First, determine where the first string in the device path is stored.
  1924. // Since we stored these in the array in order, starting with the child
  1925. // device, the last non-NULL string placed in the array (i - 1) is the most
  1926. // significant location string.
  1927. //
  1928. FinalStringLevel = i-1;
  1929. ASSERT(QueriedLocationStrings[FinalStringLevel] != NULL);
  1930. ASSERT(QueriedLocationStringsCount[FinalStringLevel] > 0);
  1931. //
  1932. // Build all string combinations by enumerating the total number of possible
  1933. // combinations, and picking the appropriate string element from each
  1934. // multi-sz list on each iteration.
  1935. //
  1936. pdlp = DeviceLocationPathMultiSz;
  1937. for (CombinationEnumIndex = 0;
  1938. CombinationEnumIndex < DeviceLocationPathMultiSzStringCount;
  1939. CombinationEnumIndex++) {
  1940. //
  1941. // Start with the multi-sz list at the FinalStringLevel, and work down
  1942. // to level 0.
  1943. //
  1944. i = FinalStringLevel;
  1945. //
  1946. // When starting from level 0, the number of combinations remaining is
  1947. // simply the total number of combinations that can be formed from all
  1948. // levels. The number of combination remaining will be adjusted after
  1949. // selecting a string from each subsequent level, by discounting the
  1950. // combinations that the level contributed.
  1951. //
  1952. CombinationsRemaining = DeviceLocationPathMultiSzStringCount;
  1953. for ( ; ; ) {
  1954. ASSERT(CombinationsRemaining != 0);
  1955. //
  1956. // Calculate the index of the string in the multi-sz list at this
  1957. // level that is needed by this enumeration.
  1958. //
  1959. if (CombinationEnumIndex == 0) {
  1960. //
  1961. // On the first enumeration, just pick the first element from
  1962. // every level.
  1963. //
  1964. MultiSzLookupIndex = 0;
  1965. } else {
  1966. //
  1967. // NOTE: 27-Nov-2001 : Jim Cavalaris (jamesca)
  1968. //
  1969. // For subsequent enumerations, the element to pick at each
  1970. // level to generate this enumeration's device location path is
  1971. // calculated based on:
  1972. //
  1973. // - the enumeration element we require,
  1974. // - the number of combinations remaining to be generated,
  1975. // - the number of elements to choose from at this level.
  1976. //
  1977. // This will will build all possible combinations of device
  1978. // location paths, enumerating elements from the least
  1979. // significant device (the target device) to the most
  1980. // significant device (tranlstaion complete), considering the
  1981. // the order of the strings at a particular level have been
  1982. // placed in the multi-sz list in order of decreasing relevance
  1983. // (i.e. most relevant location string for a device first).
  1984. //
  1985. //
  1986. // - CombinationsRemaining is the number of complete elements
  1987. // that must be built from the selections available from all
  1988. // levels above the current level.
  1989. //
  1990. // - (CombinationsRemaining / QueriedLocationStringsCount[i])
  1991. // describes the number of iterations through each element at
  1992. // the current level that are required before selecting the next
  1993. // element.
  1994. //
  1995. // - dividing that number into the index of the current
  1996. // enumeration gives the absolute index of the element in the
  1997. // expanded version of the selections at that level.
  1998. //
  1999. // - mod by the number of elements actually at this level to
  2000. // indicate which one to select.
  2001. //
  2002. MultiSzLookupIndex =
  2003. (CombinationEnumIndex /
  2004. (CombinationsRemaining / QueriedLocationStringsCount[i])) %
  2005. QueriedLocationStringsCount[i];
  2006. //
  2007. // (you may just want to trust me on this one.)
  2008. //
  2009. }
  2010. //
  2011. // Find the calculated string.
  2012. //
  2013. MultiSzIndex = 0;
  2014. for (p = QueriedLocationStrings[i]; MultiSzIndex < MultiSzLookupIndex; p += wcslen(p)+1) {
  2015. MultiSzIndex++;
  2016. ASSERT(*p != UNICODE_NULL);
  2017. ASSERT(MultiSzIndex < QueriedLocationStringsCount[i]);
  2018. }
  2019. //
  2020. // Append the string to the buffer.
  2021. //
  2022. RtlCopyMemory(pdlp, p, wcslen(p)*sizeof(WCHAR));
  2023. pdlp += wcslen(p);
  2024. if (i == 0) {
  2025. //
  2026. // This is the last level. NULL terminate this device location
  2027. // path combination string just formed.
  2028. //
  2029. *pdlp = UNICODE_NULL;
  2030. pdlp += 1;
  2031. break;
  2032. }
  2033. //
  2034. // If there are still more levels to process, append the device
  2035. // location path separator string.
  2036. //
  2037. RtlCopyMemory(pdlp,
  2038. _CRITICAL_DEVICE_LOCATION_PATH_SEPARATOR_STRING,
  2039. IopConstStringSize(_CRITICAL_DEVICE_LOCATION_PATH_SEPARATOR_STRING));
  2040. pdlp += IopConstStringLength(_CRITICAL_DEVICE_LOCATION_PATH_SEPARATOR_STRING);
  2041. //
  2042. // Adjust the total remaining number of string combinations that are
  2043. // possible to form from the string lists at the remaining levels.
  2044. //
  2045. CombinationsRemaining /= QueriedLocationStringsCount[i];
  2046. //
  2047. // Process the next level down.
  2048. //
  2049. i--;
  2050. }
  2051. }
  2052. //
  2053. // Double-NULL terminate the entire device location path multi-sz list.
  2054. //
  2055. *pdlp = UNICODE_NULL;
  2056. //
  2057. // The multi-sz list of device location paths for this device has been built
  2058. // successfully.
  2059. //
  2060. *DeviceLocationStrings = DeviceLocationPathMultiSz;
  2061. Clean0:
  2062. //
  2063. // Free any memory we may have allocated along the way.
  2064. //
  2065. if (QueriedLocationStrings != NULL) {
  2066. ASSERT(QueriedLocationStringsArraySize > 0);
  2067. for (i = 0; i < QueriedLocationStringsArraySize; i++) {
  2068. if (QueriedLocationStrings[i] != NULL) {
  2069. ExFreePool(QueriedLocationStrings[i]);
  2070. }
  2071. }
  2072. ExFreePool(QueriedLocationStrings);
  2073. }
  2074. if (QueriedLocationStringsCount != NULL) {
  2075. ASSERT(QueriedLocationStringsArraySize > 0);
  2076. ExFreePool(QueriedLocationStringsCount);
  2077. }
  2078. //
  2079. // If unsuccesful, make sure we don't return a buffer to the caller.
  2080. //
  2081. if (!NT_SUCCESS(Status)) {
  2082. ASSERT(*DeviceLocationStrings == NULL);
  2083. ASSERT(DeviceLocationPathMultiSz == NULL);
  2084. if (DeviceLocationPathMultiSz != NULL) {
  2085. ExFreePool(DeviceLocationPathMultiSz);
  2086. }
  2087. } else {
  2088. ASSERT(*DeviceLocationStrings != NULL);
  2089. }
  2090. return Status;
  2091. } // PpCriticalGetDeviceLocationStrings
  2092. //
  2093. // Generic synchronous query interface routine
  2094. // (may be moved from this as a public utility routine as needed)
  2095. //
  2096. NTSTATUS
  2097. PiQueryInterface(
  2098. IN PDEVICE_OBJECT DeviceObject,
  2099. IN CONST GUID * InterfaceGuid,
  2100. IN USHORT InterfaceVersion,
  2101. IN USHORT InterfaceSize,
  2102. OUT PINTERFACE Interface
  2103. )
  2104. /*++
  2105. Routine Description:
  2106. Queries the specified device for the requested interface.
  2107. Arguments:
  2108. DeviceObject -
  2109. Specifies a device object in the stack to query.
  2110. The query-interface irp will be sent to the top of the stack.
  2111. InterfaceGuid -
  2112. The GUID of the interface requested.
  2113. InterfaceVersion -
  2114. The version of the interface requested.
  2115. InterfaceSize -
  2116. The size of the interface requested.
  2117. Interface -
  2118. The place in which to return the interface.
  2119. Return Value:
  2120. Returns STATUS_SUCCESS if the interface was retrieved, else an error.
  2121. --*/
  2122. {
  2123. NTSTATUS Status;
  2124. KEVENT Event;
  2125. PDEVICE_OBJECT deviceObject;
  2126. IO_STATUS_BLOCK IoStatusBlock;
  2127. PIRP Irp;
  2128. PIO_STACK_LOCATION IrpStackNext;
  2129. PAGED_CODE();
  2130. //
  2131. // There is no file object associated with this Irp, so the event may be located
  2132. // on the stack as a non-object manager object.
  2133. //
  2134. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  2135. //
  2136. // Get a pointer to the topmost device object in the stack of devices.
  2137. //
  2138. deviceObject = IoGetAttachedDeviceReference(DeviceObject);
  2139. Irp = IoBuildSynchronousFsdRequest(
  2140. IRP_MJ_PNP,
  2141. deviceObject,
  2142. NULL,
  2143. 0,
  2144. NULL,
  2145. &Event,
  2146. &IoStatusBlock);
  2147. if (Irp) {
  2148. Irp->RequestorMode = KernelMode;
  2149. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  2150. IrpStackNext = IoGetNextIrpStackLocation(Irp);
  2151. //
  2152. // Create an interface query out of the Irp.
  2153. //
  2154. IrpStackNext->MinorFunction = IRP_MN_QUERY_INTERFACE;
  2155. IrpStackNext->Parameters.QueryInterface.InterfaceType = (GUID*)InterfaceGuid;
  2156. IrpStackNext->Parameters.QueryInterface.Size = InterfaceSize;
  2157. IrpStackNext->Parameters.QueryInterface.Version = InterfaceVersion;
  2158. IrpStackNext->Parameters.QueryInterface.Interface = (PINTERFACE)Interface;
  2159. IrpStackNext->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  2160. Status = IoCallDriver(deviceObject, Irp);
  2161. if (Status == STATUS_PENDING) {
  2162. //
  2163. // This waits using KernelMode, so that the stack, and therefore the
  2164. // event on that stack, is not paged out.
  2165. //
  2166. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  2167. Status = IoStatusBlock.Status;
  2168. }
  2169. } else {
  2170. Status = STATUS_INSUFFICIENT_RESOURCES;
  2171. }
  2172. ObDereferenceObject(deviceObject);
  2173. return Status;
  2174. } // PpQueryInterface
  2175. //
  2176. // Recursive registry key/value copy utility routine.
  2177. // (may be moved from this as a public utility routine as needed)
  2178. //
  2179. NTSTATUS
  2180. PiCopyKeyRecursive(
  2181. IN HANDLE SourceKeyRootHandle,
  2182. IN HANDLE TargetKeyRootHandle,
  2183. IN PWSTR SourceKeyPath OPTIONAL,
  2184. IN PWSTR TargetKeyPath OPTIONAL,
  2185. IN BOOLEAN CopyValuesAlways,
  2186. IN BOOLEAN ApplyACLsAlways
  2187. )
  2188. /*++
  2189. Routine Description:
  2190. This routine recursively copies a source key to a target key. Any new keys
  2191. that are created will receive the same security that is present on the
  2192. source key.
  2193. Arguments:
  2194. SourceKeyRootHandle -
  2195. Handle to root source key
  2196. TargetKeyRootHandle -
  2197. Handle to root target key
  2198. SourceKeyPath -
  2199. Source key relative path to the subkey which needs to be recursively
  2200. copied. If this is NULL, SourceKeyRootHandle is the key from which the
  2201. recursive copy is to be done.
  2202. TargetKeyPath -
  2203. Target root key relative path to the subkey which needs to be
  2204. recursively copied. if this is NULL, TargetKeyRootHandle is the key from
  2205. which the recursive copy is to be done.
  2206. CopyValuesAlways -
  2207. If FALSE, this routine doesn't copy values which are already there on
  2208. the target tree.
  2209. ApplyACLsAlways -
  2210. If TRUE, attempts to copy ACLs to existing registry keys. Otherwise,
  2211. the ACL of the source keys are only applied to new registry keys.
  2212. Return Value:
  2213. NTSTATUS code.
  2214. Notes:
  2215. Partially based on the recursive key copy routine implemented for text-mode
  2216. setup, setupdd!SppCopyKeyRecursive.
  2217. --*/
  2218. {
  2219. NTSTATUS Status = STATUS_SUCCESS;
  2220. HANDLE SourceKeyHandle = NULL, TargetKeyHandle = NULL;
  2221. OBJECT_ATTRIBUTES ObjaSource, ObjaTarget;
  2222. UNICODE_STRING UnicodeStringSource, UnicodeStringTarget, UnicodeStringValue;
  2223. NTSTATUS TempStatus;
  2224. ULONG ResultLength, Index;
  2225. PSECURITY_DESCRIPTOR Security = NULL;
  2226. PKEY_FULL_INFORMATION KeyFullInfoBuffer;
  2227. ULONG MaxNameLen, MaxValueNameLen;
  2228. PKEY_VALUE_FULL_INFORMATION ValueFullInfoBuffer;
  2229. PVOID KeyInfoBuffer;
  2230. PKEY_BASIC_INFORMATION KeyBasicInfo;
  2231. PVOID ValueInfoBuffer;
  2232. PKEY_VALUE_BASIC_INFORMATION ValueBasicInfo;
  2233. PAGED_CODE();
  2234. //
  2235. // Get a handle to the source key.
  2236. //
  2237. if (!ARGUMENT_PRESENT(SourceKeyPath)) {
  2238. //
  2239. // No path supplied; make sure that we at least have a source root key.
  2240. //
  2241. ASSERT(SourceKeyRootHandle != NULL);
  2242. if (SourceKeyRootHandle == NULL) {
  2243. Status = STATUS_INVALID_PARAMETER;
  2244. goto Clean0;
  2245. }
  2246. //
  2247. // Use source root as the source key.
  2248. //
  2249. SourceKeyHandle = SourceKeyRootHandle;
  2250. } else {
  2251. //
  2252. // Open the specified source key path off the root.
  2253. // SourceKeyRootHandle may be NULL if SourceKeyPath is a fully qualified
  2254. // registry path.
  2255. //
  2256. RtlInitUnicodeString(
  2257. &UnicodeStringSource,
  2258. SourceKeyPath);
  2259. InitializeObjectAttributes(
  2260. &ObjaSource,
  2261. &UnicodeStringSource,
  2262. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  2263. SourceKeyRootHandle,
  2264. (PSECURITY_DESCRIPTOR)NULL);
  2265. Status =
  2266. ZwOpenKey(
  2267. &SourceKeyHandle,
  2268. KEY_READ,
  2269. &ObjaSource);
  2270. if (!NT_SUCCESS(Status)) {
  2271. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2272. "PiCopyKeyRecursive: unable to open key %ws in the source hive (%lx)\n",
  2273. SourceKeyPath, Status));
  2274. goto Clean0;
  2275. }
  2276. }
  2277. //
  2278. // Should have source key now.
  2279. //
  2280. ASSERT(SourceKeyHandle != NULL);
  2281. //
  2282. // Next, get the security descriptor from the source key so we can create
  2283. // the target key with the correct ACL.
  2284. //
  2285. TempStatus =
  2286. ZwQuerySecurityObject(
  2287. SourceKeyHandle,
  2288. DACL_SECURITY_INFORMATION,
  2289. NULL,
  2290. 0,
  2291. &ResultLength);
  2292. if (TempStatus == STATUS_BUFFER_TOO_SMALL) {
  2293. Security =
  2294. (PSECURITY_DESCRIPTOR)ExAllocatePool(PagedPool,
  2295. ResultLength);
  2296. if (Security != NULL) {
  2297. TempStatus =
  2298. ZwQuerySecurityObject(
  2299. SourceKeyHandle,
  2300. DACL_SECURITY_INFORMATION,
  2301. Security,
  2302. ResultLength,
  2303. &ResultLength);
  2304. if (!NT_SUCCESS(TempStatus)) {
  2305. ExFreePool(Security);
  2306. Security = NULL;
  2307. }
  2308. }
  2309. }
  2310. if (Security == NULL) {
  2311. //
  2312. // We'll continue the copy, but won't be able to apply the source ACL to
  2313. // the target.
  2314. //
  2315. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2316. "PiCopyKeyRecursive: unable to query security for key %ws in the source hive (%lx)\n",
  2317. SourceKeyPath, TempStatus));
  2318. }
  2319. //
  2320. // Get a handle to the target key.
  2321. //
  2322. if (!ARGUMENT_PRESENT(TargetKeyPath)) {
  2323. //
  2324. // No path supplied; make sure that we at least have a target root key.
  2325. //
  2326. ASSERT(TargetKeyRootHandle != NULL);
  2327. if (TargetKeyRootHandle == NULL) {
  2328. Status = STATUS_INVALID_PARAMETER;
  2329. goto Clean0;
  2330. }
  2331. //
  2332. // No path supplied; use target root as the target key.
  2333. //
  2334. TargetKeyHandle = TargetKeyRootHandle;
  2335. } else {
  2336. //
  2337. // Attempt to open (not create) the target key first.
  2338. // TargetKeyRootHandle may be NULL if TargetKeyPath is a fully qualified
  2339. // registry path.
  2340. //
  2341. RtlInitUnicodeString(
  2342. &UnicodeStringTarget,
  2343. TargetKeyPath);
  2344. InitializeObjectAttributes(
  2345. &ObjaTarget,
  2346. &UnicodeStringTarget,
  2347. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  2348. TargetKeyRootHandle,
  2349. (PSECURITY_DESCRIPTOR)NULL);
  2350. Status =
  2351. ZwOpenKey(
  2352. &TargetKeyHandle,
  2353. KEY_ALL_ACCESS,
  2354. &ObjaTarget);
  2355. if (!NT_SUCCESS(Status)) {
  2356. //
  2357. // Assume that failure was because the key didn't exist.
  2358. //
  2359. ASSERT(Status == STATUS_OBJECT_NAME_NOT_FOUND);
  2360. //
  2361. // If we can't open the key because it doesn't exist, then we'll
  2362. // create it and apply the security present on the source key (if
  2363. // available).
  2364. //
  2365. // NOTE: 01-Dec-2001 : Jim Cavalaris (jamesca)
  2366. //
  2367. // Security attributes of the source key are always applied to the
  2368. // newly created target key root, rather than inherited from the
  2369. // target key root handle - irespective of the ApplyACLsAlways
  2370. // parameter. This may not be desired in all cases!
  2371. //
  2372. ObjaTarget.SecurityDescriptor = Security;
  2373. Status =
  2374. ZwCreateKey(
  2375. &TargetKeyHandle,
  2376. KEY_ALL_ACCESS,
  2377. &ObjaTarget,
  2378. 0,
  2379. NULL,
  2380. REG_OPTION_NON_VOLATILE,
  2381. NULL);
  2382. if (!NT_SUCCESS(Status)) {
  2383. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2384. "PiCopyKeyRecursive: unable to create target key %ws(%lx)\n",
  2385. TargetKeyPath, Status));
  2386. goto Clean0;
  2387. }
  2388. } else if (ApplyACLsAlways) {
  2389. //
  2390. // Key already exists - apply the source ACL to the target.
  2391. //
  2392. TempStatus =
  2393. ZwSetSecurityObject(
  2394. TargetKeyHandle,
  2395. DACL_SECURITY_INFORMATION,
  2396. Security);
  2397. if (!NT_SUCCESS(TempStatus)) {
  2398. //
  2399. // Unable to apply source ACL to target.
  2400. //
  2401. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2402. "PiCopyKeyRecursive: unable to copy ACL to existing key %ws(%lx)\n",
  2403. TargetKeyPath, TempStatus));
  2404. }
  2405. }
  2406. }
  2407. //
  2408. // Should have target key now.
  2409. //
  2410. ASSERT(TargetKeyHandle != NULL);
  2411. //
  2412. // Query the source key to determine the size of the buffer required to
  2413. // enumerated the longest key and value names. If successful, we are
  2414. // responsible for freeing the returned buffer.
  2415. //
  2416. KeyFullInfoBuffer = NULL;
  2417. Status =
  2418. IopGetRegistryKeyInformation(
  2419. SourceKeyHandle,
  2420. &KeyFullInfoBuffer);
  2421. if (!NT_SUCCESS(Status)) {
  2422. ASSERT(KeyFullInfoBuffer == NULL);
  2423. goto Clean0;
  2424. }
  2425. ASSERT(KeyFullInfoBuffer != NULL);
  2426. //
  2427. // Note the longest subkey name and value name length for the source key.
  2428. //
  2429. MaxNameLen = KeyFullInfoBuffer->MaxNameLen + 1;
  2430. MaxValueNameLen = KeyFullInfoBuffer->MaxValueNameLen + 1;
  2431. ExFreePool(KeyFullInfoBuffer);
  2432. //
  2433. // Allocate a key info buffer large enough to hold the basic information for
  2434. // the enumerated key with the longest name.
  2435. //
  2436. KeyInfoBuffer =
  2437. (PVOID)ExAllocatePool(PagedPool,
  2438. sizeof(KEY_BASIC_INFORMATION) +
  2439. (MaxNameLen*sizeof(WCHAR)));
  2440. if (KeyInfoBuffer == NULL) {
  2441. Status = STATUS_INSUFFICIENT_RESOURCES;
  2442. goto Clean0;
  2443. }
  2444. KeyBasicInfo = (PKEY_BASIC_INFORMATION)KeyInfoBuffer;
  2445. for (Index = 0; ; Index++) {
  2446. //
  2447. // Enumerate source subkeys.
  2448. //
  2449. Status =
  2450. ZwEnumerateKey(
  2451. SourceKeyHandle,
  2452. Index,
  2453. KeyBasicInformation,
  2454. KeyBasicInfo,
  2455. sizeof(KEY_BASIC_INFORMATION)+(MaxNameLen*sizeof(WCHAR)),
  2456. &ResultLength);
  2457. if (!NT_SUCCESS(Status)) {
  2458. //
  2459. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  2460. // was not enough room for even the fixed portions of the structure.
  2461. // Since we queried the key for the MaxNameLength prior to
  2462. // allocating, we shouldn't get STATUS_BUFFER_OVERFLOW either.
  2463. //
  2464. ASSERT(Status != STATUS_BUFFER_TOO_SMALL);
  2465. ASSERT(Status != STATUS_BUFFER_OVERFLOW);
  2466. if (Status == STATUS_NO_MORE_ENTRIES) {
  2467. //
  2468. // Finished enumerating keys.
  2469. //
  2470. Status = STATUS_SUCCESS;
  2471. } else {
  2472. //
  2473. // Some other error while enumerating keys.
  2474. //
  2475. if (ARGUMENT_PRESENT(SourceKeyPath)) {
  2476. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2477. "PiCopyKeyRecursive: unable to enumerate subkeys in key %ws(%lx)\n",
  2478. SourceKeyPath, Status));
  2479. } else {
  2480. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2481. "PiCopyKeyRecursive: unable to enumerate subkeys in root key(%lx)\n",
  2482. Status));
  2483. }
  2484. }
  2485. break;
  2486. }
  2487. //
  2488. // NULL-terminate the subkey name just in case.
  2489. //
  2490. KeyBasicInfo->Name[KeyBasicInfo->NameLength/sizeof(WCHAR)] = UNICODE_NULL;
  2491. //
  2492. // Recursively create the subkey in the target key.
  2493. //
  2494. Status =
  2495. PiCopyKeyRecursive(
  2496. SourceKeyHandle,
  2497. TargetKeyHandle,
  2498. KeyBasicInfo->Name,
  2499. KeyBasicInfo->Name,
  2500. CopyValuesAlways,
  2501. ApplyACLsAlways);
  2502. if (!NT_SUCCESS(Status)) {
  2503. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2504. "PiCopyKeyRecursive: unable to copy subkey recursively in key %ws(%lx)\n",
  2505. KeyBasicInfo->Name, Status));
  2506. break;
  2507. }
  2508. }
  2509. //
  2510. // Free the key info buffer.
  2511. //
  2512. ASSERT(KeyInfoBuffer);
  2513. ExFreePool(KeyInfoBuffer);
  2514. KeyInfoBuffer = NULL;
  2515. //
  2516. // Stop copying if we encountered some error along the way.
  2517. //
  2518. if (!NT_SUCCESS(Status)) {
  2519. goto Clean0;
  2520. }
  2521. //
  2522. // Allocate a value name info buffer large enough to hold the basic value
  2523. // information for the enumerated value with the longest name.
  2524. //
  2525. ValueInfoBuffer =
  2526. (PVOID)ExAllocatePool(PagedPool,
  2527. sizeof(KEY_VALUE_FULL_INFORMATION) +
  2528. (MaxValueNameLen*sizeof(WCHAR)));
  2529. if (ValueInfoBuffer == NULL) {
  2530. Status = STATUS_INSUFFICIENT_RESOURCES;
  2531. goto Clean0;
  2532. }
  2533. ValueBasicInfo = (PKEY_VALUE_BASIC_INFORMATION)ValueInfoBuffer;
  2534. for (Index = 0; ; Index++) {
  2535. //
  2536. // Enumerate source key values.
  2537. //
  2538. Status =
  2539. ZwEnumerateValueKey(
  2540. SourceKeyHandle,
  2541. Index,
  2542. KeyValueBasicInformation,
  2543. ValueBasicInfo,
  2544. sizeof(KEY_VALUE_FULL_INFORMATION) + (MaxValueNameLen*sizeof(WCHAR)),
  2545. &ResultLength);
  2546. if (!NT_SUCCESS(Status)) {
  2547. //
  2548. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  2549. // was not enough room for even the fixed portions of the structure.
  2550. // Since we queried the key for the MaxValueNameLength prior to
  2551. // allocating, we shouldn't get STATUS_BUFFER_OVERFLOW either.
  2552. //
  2553. ASSERT(Status != STATUS_BUFFER_TOO_SMALL);
  2554. ASSERT(Status != STATUS_BUFFER_OVERFLOW);
  2555. if (Status == STATUS_NO_MORE_ENTRIES) {
  2556. //
  2557. // Finished enumerating values.
  2558. //
  2559. Status = STATUS_SUCCESS;
  2560. } else {
  2561. //
  2562. // Some other error while enumerating values.
  2563. //
  2564. if (ARGUMENT_PRESENT(SourceKeyPath)) {
  2565. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2566. "PiCopyKeyRecursive: unable to enumerate values in key %ws(%lx)\n",
  2567. SourceKeyPath, Status));
  2568. } else {
  2569. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2570. "PiCopyKeyRecursive: unable to enumerate values in root key(%lx)\n",
  2571. Status));
  2572. }
  2573. }
  2574. break;
  2575. }
  2576. //
  2577. // NULL-terminate the value name just in case.
  2578. //
  2579. ValueBasicInfo->Name[ValueBasicInfo->NameLength/sizeof(WCHAR)] = UNICODE_NULL;
  2580. UnicodeStringValue.Buffer = ValueBasicInfo->Name;
  2581. UnicodeStringValue.Length = (USHORT)ValueBasicInfo->NameLength;
  2582. UnicodeStringValue.MaximumLength = UnicodeStringValue.Length;
  2583. //
  2584. // If it is a conditional copy, we need to check if the value already
  2585. // exists in the target, in which case we shouldn't set the value.
  2586. //
  2587. if (!CopyValuesAlways) {
  2588. KEY_VALUE_BASIC_INFORMATION TempValueBasicInfo;
  2589. //
  2590. // To see if the value exists, we attempt to get basic information
  2591. // on the key value and pass in a buffer that's large enough only
  2592. // for the fixed part of the basic info structure. If this is
  2593. // successful or reports buffer overflow, then the key
  2594. // exists. Otherwise it doesn't exist.
  2595. //
  2596. Status =
  2597. ZwQueryValueKey(
  2598. TargetKeyHandle,
  2599. &UnicodeStringValue,
  2600. KeyValueBasicInformation,
  2601. &TempValueBasicInfo,
  2602. sizeof(TempValueBasicInfo),
  2603. &ResultLength);
  2604. //
  2605. // STATUS_BUFFER_TOO_SMALL would mean that there was not enough room
  2606. // for even the fixed portions of the structure.
  2607. //
  2608. ASSERT(Status != STATUS_BUFFER_TOO_SMALL);
  2609. if ((NT_SUCCESS(Status)) ||
  2610. (Status == STATUS_BUFFER_OVERFLOW)) {
  2611. //
  2612. // Value exists, and we shouldn't change it.
  2613. //
  2614. Status = STATUS_SUCCESS;
  2615. continue;
  2616. }
  2617. }
  2618. //
  2619. // Retrieve the full source value information.
  2620. //
  2621. ValueFullInfoBuffer = NULL;
  2622. Status =
  2623. IopGetRegistryValue(
  2624. SourceKeyHandle,
  2625. UnicodeStringValue.Buffer,
  2626. &ValueFullInfoBuffer);
  2627. if (NT_SUCCESS(Status)) {
  2628. ASSERT(ValueFullInfoBuffer != NULL);
  2629. //
  2630. // If successful, write it to the target key.
  2631. //
  2632. Status =
  2633. ZwSetValueKey(
  2634. TargetKeyHandle,
  2635. &UnicodeStringValue,
  2636. ValueFullInfoBuffer->TitleIndex,
  2637. ValueFullInfoBuffer->Type,
  2638. (PVOID)((PUCHAR)ValueFullInfoBuffer + ValueFullInfoBuffer->DataOffset),
  2639. ValueFullInfoBuffer->DataLength);
  2640. ExFreePool(ValueFullInfoBuffer);
  2641. }
  2642. if (!NT_SUCCESS(Status)) {
  2643. if (ARGUMENT_PRESENT(TargetKeyPath)) {
  2644. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2645. "PiCopyKeyRecursive: unable to set value %ws in key %ws(%lx)\n",
  2646. UnicodeStringValue.Buffer, TargetKeyPath, Status));
  2647. } else {
  2648. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2649. "PiCopyKeyRecursive: unable to set value %ws(%lx)\n",
  2650. UnicodeStringValue.Buffer, Status));
  2651. }
  2652. break;
  2653. }
  2654. }
  2655. //
  2656. // Free the value info buffer.
  2657. //
  2658. ASSERT(ValueInfoBuffer);
  2659. ExFreePool(ValueInfoBuffer);
  2660. Clean0:
  2661. if (Security != NULL) {
  2662. ExFreePool(Security);
  2663. }
  2664. //
  2665. // Close handles only if explicitly opened by this routine.
  2666. //
  2667. if ((ARGUMENT_PRESENT(SourceKeyPath)) &&
  2668. (SourceKeyHandle != NULL)) {
  2669. ASSERT(SourceKeyHandle != SourceKeyRootHandle);
  2670. ZwClose(SourceKeyHandle);
  2671. }
  2672. if ((ARGUMENT_PRESENT(TargetKeyPath)) &&
  2673. (TargetKeyHandle != NULL)) {
  2674. ASSERT(TargetKeyHandle != TargetKeyRootHandle);
  2675. ZwClose(TargetKeyHandle);
  2676. }
  2677. return Status;
  2678. } // PiCopyKeyRecursive
  2679. NTSTATUS
  2680. PiCriticalQueryRegistryValueCallback(
  2681. IN PWSTR ValueName,
  2682. IN ULONG ValueType,
  2683. IN PVOID ValueData,
  2684. IN ULONG ValueLength,
  2685. IN PVOID Context,
  2686. IN PVOID EntryContext
  2687. )
  2688. {
  2689. PPI_CRITICAL_QUERY_CONTEXT context = (PPI_CRITICAL_QUERY_CONTEXT)EntryContext;
  2690. UNREFERENCED_PARAMETER(Context);
  2691. UNREFERENCED_PARAMETER(ValueName);
  2692. if (ValueType == REG_BINARY && ValueLength && ValueData) {
  2693. context->Buffer = ExAllocatePool(PagedPool, ValueLength);
  2694. if (context->Buffer) {
  2695. RtlCopyMemory(context->Buffer, ValueData, ValueLength);
  2696. context->Size = ValueLength;
  2697. }
  2698. }
  2699. return STATUS_SUCCESS;
  2700. }