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

3684 lines
130 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Spupgcfg.c
  5. Abstract:
  6. Configuration routines for the upgrade case
  7. Author:
  8. Sunil Pai (sunilp) 18-Nov-1993
  9. Revision History:
  10. --*/
  11. #include "spprecmp.h"
  12. #include <initguid.h>
  13. #include <devguid.h>
  14. #pragma hdrstop
  15. NTSTATUS
  16. SppResetLastKnownGood(
  17. IN HANDLE hKeySystem
  18. );
  19. BOOLEAN
  20. SppEnsureHardwareProfileIsPresent(
  21. IN HANDLE hKeyCCSet
  22. );
  23. VOID
  24. SppSetGuimodeUpgradePath(
  25. IN HANDLE hKeySoftwareHive,
  26. IN HANDLE hKeyControlSet
  27. );
  28. NTSTATUS
  29. SppMigratePrinterKeys(
  30. IN HANDLE hControlSet,
  31. IN HANDLE hDestSoftwareHive
  32. );
  33. VOID
  34. SppClearMigratedInstanceValues(
  35. IN HANDLE hKeyCCSet
  36. );
  37. VOID
  38. SppClearMigratedInstanceValuesCallback(
  39. IN HANDLE SetupInstanceKeyHandle,
  40. IN HANDLE UpgradeInstanceKeyHandle OPTIONAL,
  41. IN BOOLEAN RootEnumerated,
  42. IN OUT PVOID Context
  43. );
  44. //
  45. // Callback routine for SppMigrateDeviceParentId
  46. //
  47. typedef BOOL (*PSPP_DEVICE_MIGRATION_CALLBACK_ROUTINE) (
  48. IN HANDLE InstanceKeyHandle,
  49. IN HANDLE DriverKeyHandle
  50. );
  51. VOID
  52. SppMigrateDeviceParentId(
  53. IN HANDLE hKeyCCSet,
  54. IN PWSTR DeviceId,
  55. IN PSPP_DEVICE_MIGRATION_CALLBACK_ROUTINE DeviceMigrationCallbackRoutine
  56. );
  57. VOID
  58. SppMigrateDeviceParentIdCallback(
  59. IN HANDLE SetupInstanceKeyHandle,
  60. IN HANDLE UpgradeInstanceKeyHandle OPTIONAL,
  61. IN BOOLEAN RootEnumerated,
  62. IN OUT PVOID Context
  63. );
  64. BOOL
  65. SppParallelClassCallback(
  66. IN HANDLE InstanceKeyHandle,
  67. IN HANDLE DriverKeyHandle
  68. );
  69. typedef struct _GENERIC_BUFFER_CONTEXT {
  70. PUCHAR Buffer;
  71. ULONG BufferSize;
  72. } GENERIC_BUFFER_CONTEXT, *PGENERIC_BUFFER_CONTEXT;
  73. typedef struct _DEVICE_MIGRATION_CONTEXT {
  74. PUCHAR Buffer;
  75. ULONG BufferSize;
  76. ULONG UniqueParentID;
  77. PWSTR ParentIdPrefix;
  78. HANDLE hKeyCCSet;
  79. PSPP_DEVICE_MIGRATION_CALLBACK_ROUTINE DeviceMigrationCallbackRoutine;
  80. } DEVICE_MIGRATION_CONTEXT, *PDEVICE_MIGRATION_CONTEXT;
  81. //
  82. // Device classe(s) for root device(s) that need to be deleted on upgrade
  83. //
  84. RootDevnodeSectionNamesType UpgRootDeviceClassesToDelete[] =
  85. {
  86. { L"RootDeviceClassesToDelete", RootDevnodeSectionNamesType_ALL, 0x0000, 0xffff },
  87. { L"RootDeviceClassesToDelete.NT4", RootDevnodeSectionNamesType_NTUPG, 0x0000, 0x04ff },
  88. { NULL, 0, 0, 0 }
  89. };
  90. NTSTATUS
  91. SpUpgradeNTRegistry(
  92. IN PVOID SifHandle,
  93. IN HANDLE *HiveRootKeys,
  94. IN LPCWSTR SetupSourceDevicePath,
  95. IN LPCWSTR DirectoryOnSourceDevice,
  96. IN HANDLE hKeyCCSet
  97. )
  98. /*++
  99. Routine Description:
  100. This routine does all the NT registry modifications needed on an upgrade.
  101. This includes the following:
  102. - Disabling network services
  103. - Running the addreg/delreg sections specified in txtsetup.sif
  104. - Deleting various root-enumerated devnode keys specified in txtsetup.sif
  105. Arguments:
  106. SifHandle - supplies handle to txtsetup.sif.
  107. HiveRootKeys - supplies array of handles of root keys in the hives
  108. of the system being upgraded.
  109. hKeyCCSet: Handle to the root of the control set in the system
  110. being upgraded.
  111. Return Value:
  112. Status is returned.
  113. --*/
  114. {
  115. NTSTATUS Status;
  116. OBJECT_ATTRIBUTES Obja;
  117. BOOLEAN b;
  118. //
  119. // Disable the network stuff
  120. //
  121. Status = SpDisableNetwork(SifHandle,HiveRootKeys[SetupHiveSoftware],hKeyCCSet);
  122. if(!NT_SUCCESS(Status)) {
  123. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: warning: SpDisableNetworkFailed (%lx)\n",Status));
  124. }
  125. //
  126. // Migrate the parallel class device parent id value to all parallel
  127. // devices.
  128. //
  129. SppMigrateDeviceParentId(hKeyCCSet,
  130. L"Root\\PARALLELCLASS\\0000",
  131. SppParallelClassCallback);
  132. //
  133. // Delete legacy root-enumerated devnode keys out of Enum tree.
  134. //
  135. SpDeleteRootDevnodeKeys(SifHandle,
  136. hKeyCCSet,
  137. L"RootDevicesToDelete",
  138. UpgRootDeviceClassesToDelete);
  139. //
  140. // Clean the "Migrated" values from device instance keys in the setup
  141. // and upgrade registries, as appropriate.
  142. //
  143. SppClearMigratedInstanceValues(hKeyCCSet);
  144. //
  145. // If the user doesn't have any hardware profiles defined (i.e., we're upgrading
  146. // from a pre-NT4 system), then create them one.
  147. //
  148. b = SppEnsureHardwareProfileIsPresent(hKeyCCSet);
  149. if(!b) {
  150. return STATUS_UNSUCCESSFUL;
  151. }
  152. Status = SppMigratePrinterKeys( hKeyCCSet,
  153. HiveRootKeys[SetupHiveSoftware] );
  154. if(!NT_SUCCESS(Status)) {
  155. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: warning: SppMigratePrinterKeys() failed. Status = %lx \n",Status));
  156. }
  157. //
  158. // Perform the general and wide-ranging hive upgrade.
  159. //
  160. b = SpHivesFromInfs(
  161. SifHandle,
  162. L"HiveInfs.Upgrade",
  163. SetupSourceDevicePath,
  164. DirectoryOnSourceDevice,
  165. HiveRootKeys[SetupHiveSystem],
  166. HiveRootKeys[SetupHiveSoftware],
  167. HiveRootKeys[SetupHiveDefault],
  168. HiveRootKeys[SetupHiveUserdiff]
  169. );
  170. if(!b) {
  171. return(STATUS_UNSUCCESSFUL);
  172. }
  173. SppSetGuimodeUpgradePath(HiveRootKeys[SetupHiveSystem],hKeyCCSet);
  174. //
  175. // Set 'LastKnownGood' the same as 'Current'
  176. // Ignore the error in case of failure, since this will
  177. // not affect the installation process
  178. //
  179. Status = SppResetLastKnownGood(HiveRootKeys[SetupHiveSystem]);
  180. if(!NT_SUCCESS(Status)) {
  181. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: warning: SppResetLastKnownGood() failed. Status = (%lx)\n",Status));
  182. return(Status);
  183. }
  184. return(STATUS_SUCCESS);
  185. }
  186. NTSTATUS
  187. SppDeleteKeyRecursive(
  188. HANDLE hKeyRoot,
  189. PWSTR Key,
  190. BOOLEAN ThisKeyToo
  191. )
  192. /*++
  193. Routine Description:
  194. Routine to recursively delete all subkeys under the given
  195. key, including the key given.
  196. Arguments:
  197. hKeyRoot: Handle to root relative to which the key to be deleted is
  198. specified.
  199. Key: Root relative path of the key which is to be recursively deleted.
  200. ThisKeyToo: Whether after deletion of all subkeys, this key itself is to
  201. be deleted.
  202. Return Value:
  203. Status is returned.
  204. --*/
  205. {
  206. ULONG ResultLength;
  207. PKEY_BASIC_INFORMATION KeyInfo;
  208. NTSTATUS Status;
  209. UNICODE_STRING UnicodeString;
  210. OBJECT_ATTRIBUTES Obja;
  211. PWSTR SubkeyName;
  212. HANDLE hKey;
  213. //
  214. // Initialize
  215. //
  216. KeyInfo = (PKEY_BASIC_INFORMATION)TemporaryBuffer;
  217. //
  218. // Open the key
  219. //
  220. INIT_OBJA(&Obja,&UnicodeString,Key);
  221. Obja.RootDirectory = hKeyRoot;
  222. Status = ZwOpenKey(&hKey,KEY_ALL_ACCESS,&Obja);
  223. if( !NT_SUCCESS(Status) ) {
  224. return(Status);
  225. }
  226. //
  227. // Enumerate all subkeys of the current key. if any exist they should
  228. // be deleted first. since deleting the subkey affects the subkey
  229. // index, we always enumerate on subkeyindex 0
  230. //
  231. while(1) {
  232. Status = ZwEnumerateKey(
  233. hKey,
  234. 0,
  235. KeyBasicInformation,
  236. TemporaryBuffer,
  237. sizeof(TemporaryBuffer),
  238. &ResultLength
  239. );
  240. if(!NT_SUCCESS(Status)) {
  241. break;
  242. }
  243. //
  244. // Zero-terminate the subkey name just in case.
  245. //
  246. KeyInfo->Name[KeyInfo->NameLength/sizeof(WCHAR)] = 0;
  247. //
  248. // Make a duplicate of the subkey name because the name is
  249. // in TemporaryBuffer, which might get clobbered by recursive
  250. // calls to this routine.
  251. //
  252. SubkeyName = SpDupStringW(KeyInfo->Name);
  253. Status = SppDeleteKeyRecursive( hKey, SubkeyName, TRUE);
  254. SpMemFree(SubkeyName);
  255. if(!NT_SUCCESS(Status)) {
  256. break;
  257. }
  258. }
  259. ZwClose(hKey);
  260. //
  261. // Check the status, if the status is anything other than
  262. // STATUS_NO_MORE_ENTRIES we failed in deleting some subkey,
  263. // so we cannot delete this key too
  264. //
  265. if( Status == STATUS_NO_MORE_ENTRIES) {
  266. Status = STATUS_SUCCESS;
  267. }
  268. if(!NT_SUCCESS(Status)) {
  269. return(Status);
  270. }
  271. //
  272. // else delete the current key if asked to do so
  273. //
  274. if( ThisKeyToo ) {
  275. Status = SpDeleteKey(hKeyRoot, Key);
  276. }
  277. return(Status);
  278. }
  279. NTSTATUS
  280. SppCopyKeyRecursive(
  281. HANDLE hKeyRootSrc,
  282. HANDLE hKeyRootDst,
  283. PWSTR SrcKeyPath, OPTIONAL
  284. PWSTR DstKeyPath, OPTIONAL
  285. BOOLEAN CopyAlways,
  286. BOOLEAN ApplyACLsAlways
  287. )
  288. /*++
  289. Routine Description:
  290. This routine recursively copies a src key to a destination key. Any new
  291. keys that are created will receive the same security that is present on
  292. the source key.
  293. Arguments:
  294. hKeyRootSrc: Handle to root src key
  295. hKeyRootDst: Handle to root dst key
  296. SrcKeyPath: src root key relative path to the subkey which needs to be
  297. recursively copied. if this is null hKeyRootSrc is the key
  298. from which the recursive copy is to be done.
  299. DstKeyPath: dst root key relative path to the subkey which needs to be
  300. recursively copied. if this is null hKeyRootDst is the key
  301. from which the recursive copy is to be done.
  302. CopyAlways: If FALSE, this routine doesn't copy values which are already
  303. there on the target tree.
  304. Return Value:
  305. Status is returned.
  306. --*/
  307. {
  308. NTSTATUS Status = STATUS_SUCCESS;
  309. OBJECT_ATTRIBUTES ObjaSrc, ObjaDst;
  310. UNICODE_STRING UnicodeStringSrc, UnicodeStringDst, UnicodeStringValue;
  311. HANDLE hKeySrc=NULL,hKeyDst=NULL;
  312. ULONG ResultLength, Index;
  313. PWSTR SubkeyName,ValueName;
  314. PSECURITY_DESCRIPTOR Security = NULL;
  315. PKEY_BASIC_INFORMATION KeyInfo;
  316. PKEY_VALUE_FULL_INFORMATION ValueInfo;
  317. //
  318. // Get a handle to the source key
  319. //
  320. if(SrcKeyPath == NULL) {
  321. hKeySrc = hKeyRootSrc;
  322. }
  323. else {
  324. //
  325. // Open the Src key
  326. //
  327. INIT_OBJA(&ObjaSrc,&UnicodeStringSrc,SrcKeyPath);
  328. ObjaSrc.RootDirectory = hKeyRootSrc;
  329. Status = ZwOpenKey(&hKeySrc,KEY_READ,&ObjaSrc);
  330. if(!NT_SUCCESS(Status)) {
  331. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to open key %ws in the source hive (%lx)\n",SrcKeyPath,Status));
  332. return(Status);
  333. }
  334. }
  335. //
  336. // Get a handle to the destination key
  337. //
  338. if(DstKeyPath == NULL) {
  339. hKeyDst = hKeyRootDst;
  340. } else {
  341. //
  342. // First, get the security descriptor from the source key so we can create
  343. // the destination key with the correct ACL.
  344. //
  345. Status = ZwQuerySecurityObject(hKeySrc,
  346. DACL_SECURITY_INFORMATION,
  347. NULL,
  348. 0,
  349. &ResultLength
  350. );
  351. if(Status==STATUS_BUFFER_TOO_SMALL) {
  352. Security=SpMemAlloc(ResultLength);
  353. Status = ZwQuerySecurityObject(hKeySrc,
  354. DACL_SECURITY_INFORMATION,
  355. Security,
  356. ResultLength,
  357. &ResultLength);
  358. if(!NT_SUCCESS(Status)) {
  359. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to query security for key %ws in the source hive (%lx)\n",
  360. SrcKeyPath,
  361. Status)
  362. );
  363. SpMemFree(Security);
  364. Security=NULL;
  365. }
  366. } else {
  367. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to query security size for key %ws in the source hive (%lx)\n",
  368. SrcKeyPath,
  369. Status)
  370. );
  371. Security=NULL;
  372. }
  373. //
  374. // Attempt to open (not create) the destination key first. If we can't
  375. // open the key because it doesn't exist, then we'll create it and apply
  376. // the security present on the source key.
  377. //
  378. INIT_OBJA(&ObjaDst,&UnicodeStringDst,DstKeyPath);
  379. ObjaDst.RootDirectory = hKeyRootDst;
  380. Status = ZwOpenKey(&hKeyDst,KEY_ALL_ACCESS,&ObjaDst);
  381. if(!NT_SUCCESS(Status)) {
  382. //
  383. // Assume that failure was because the key didn't exist. Now try creating
  384. // the key.
  385. ObjaDst.SecurityDescriptor = Security;
  386. Status = ZwCreateKey(
  387. &hKeyDst,
  388. KEY_ALL_ACCESS,
  389. &ObjaDst,
  390. 0,
  391. NULL,
  392. REG_OPTION_NON_VOLATILE,
  393. NULL
  394. );
  395. if(!NT_SUCCESS(Status)) {
  396. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to create key %ws(%lx)\n",DstKeyPath, Status));
  397. if(SrcKeyPath != NULL) {
  398. ZwClose(hKeySrc);
  399. }
  400. if(Security) {
  401. SpMemFree(Security);
  402. }
  403. return(Status);
  404. }
  405. } else if (ApplyACLsAlways) {
  406. Status = ZwSetSecurityObject(
  407. hKeyDst,
  408. DACL_SECURITY_INFORMATION,
  409. Security );
  410. if(!NT_SUCCESS(Status)) {
  411. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to copy ACL to existing key %ws(%lx)\n",DstKeyPath, Status));
  412. }
  413. }
  414. //
  415. // Free security descriptor buffer before checking return status from ZwCreateKey.
  416. //
  417. if(Security) {
  418. SpMemFree(Security);
  419. }
  420. }
  421. //
  422. // Enumerate all keys in the source key and recursively create
  423. // all the subkeys
  424. //
  425. KeyInfo = (PKEY_BASIC_INFORMATION)TemporaryBuffer;
  426. for( Index=0;;Index++ ) {
  427. Status = ZwEnumerateKey(
  428. hKeySrc,
  429. Index,
  430. KeyBasicInformation,
  431. TemporaryBuffer,
  432. sizeof(TemporaryBuffer),
  433. &ResultLength
  434. );
  435. if(!NT_SUCCESS(Status)) {
  436. if(Status == STATUS_NO_MORE_ENTRIES) {
  437. Status = STATUS_SUCCESS;
  438. }
  439. else {
  440. if(SrcKeyPath!=NULL) {
  441. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to enumerate subkeys in key %ws(%lx)\n",SrcKeyPath, Status));
  442. }
  443. else {
  444. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to enumerate subkeys in root key(%lx)\n", Status));
  445. }
  446. }
  447. break;
  448. }
  449. //
  450. // Zero-terminate the subkey name just in case.
  451. //
  452. KeyInfo->Name[KeyInfo->NameLength/sizeof(WCHAR)] = 0;
  453. //
  454. // Make a duplicate of the subkey name because the name is
  455. // in TemporaryBuffer, which might get clobbered by recursive
  456. // calls to this routine.
  457. //
  458. SubkeyName = SpDupStringW(KeyInfo->Name);
  459. Status = SppCopyKeyRecursive(
  460. hKeySrc,
  461. hKeyDst,
  462. SubkeyName,
  463. SubkeyName,
  464. CopyAlways,
  465. ApplyACLsAlways
  466. );
  467. SpMemFree(SubkeyName);
  468. }
  469. //
  470. // Process any errors if found
  471. //
  472. if(!NT_SUCCESS(Status)) {
  473. if(SrcKeyPath != NULL) {
  474. ZwClose(hKeySrc);
  475. }
  476. if(DstKeyPath != NULL) {
  477. ZwClose(hKeyDst);
  478. }
  479. return(Status);
  480. }
  481. //
  482. // Enumerate all values in the source key and create all the values
  483. // in the destination key
  484. //
  485. ValueInfo = (PKEY_VALUE_FULL_INFORMATION)TemporaryBuffer;
  486. for( Index=0;;Index++ ) {
  487. Status = ZwEnumerateValueKey(
  488. hKeySrc,
  489. Index,
  490. KeyValueFullInformation,
  491. TemporaryBuffer,
  492. sizeof(TemporaryBuffer),
  493. &ResultLength
  494. );
  495. if(!NT_SUCCESS(Status)) {
  496. if(Status == STATUS_NO_MORE_ENTRIES) {
  497. Status = STATUS_SUCCESS;
  498. }
  499. else {
  500. if(SrcKeyPath!=NULL) {
  501. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to enumerate values in key %ws(%lx)\n",SrcKeyPath, Status));
  502. }
  503. else {
  504. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to enumerate values in root key(%lx)\n", Status));
  505. }
  506. }
  507. break;
  508. }
  509. //
  510. // Process the value found and create the value in the destination
  511. // key
  512. //
  513. ValueName = (PWSTR)SpMemAlloc(ValueInfo->NameLength + sizeof(WCHAR));
  514. ASSERT(ValueName);
  515. wcsncpy(ValueName, ValueInfo->Name, (ValueInfo->NameLength)/sizeof(WCHAR));
  516. ValueName[(ValueInfo->NameLength)/sizeof(WCHAR)] = 0;
  517. RtlInitUnicodeString(&UnicodeStringValue,ValueName);
  518. //
  519. // If it is a conditional copy, we need to check if the value already
  520. // exists in the destination, in which case we shouldn't set the value
  521. //
  522. if( !CopyAlways ) {
  523. ULONG Length;
  524. PKEY_VALUE_BASIC_INFORMATION DestValueBasicInfo;
  525. Length = sizeof(KEY_VALUE_BASIC_INFORMATION) + ValueInfo->NameLength + sizeof(WCHAR) + MAX_PATH;
  526. DestValueBasicInfo = (PKEY_VALUE_BASIC_INFORMATION)SpMemAlloc(Length);
  527. ASSERT(DestValueBasicInfo);
  528. Status = ZwQueryValueKey(
  529. hKeyDst,
  530. &UnicodeStringValue,
  531. KeyValueBasicInformation,
  532. DestValueBasicInfo,
  533. Length,
  534. &ResultLength
  535. );
  536. SpMemFree((PVOID)DestValueBasicInfo);
  537. if(NT_SUCCESS(Status)) {
  538. //
  539. // Value exists, we shouldn't change the value
  540. //
  541. SpMemFree(ValueName);
  542. continue;
  543. }
  544. if( Status!=STATUS_OBJECT_NAME_NOT_FOUND && Status!=STATUS_OBJECT_PATH_NOT_FOUND) {
  545. if(DstKeyPath) {
  546. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to query value %ws in key %ws(%lx)\n",ValueName,DstKeyPath, Status));
  547. }
  548. else {
  549. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to query value %ws in root key(%lx)\n",ValueName, Status));
  550. }
  551. SpMemFree(ValueName);
  552. break;
  553. }
  554. }
  555. Status = ZwSetValueKey(
  556. hKeyDst,
  557. &UnicodeStringValue,
  558. ValueInfo->TitleIndex,
  559. ValueInfo->Type,
  560. (PBYTE)ValueInfo + ValueInfo->DataOffset,
  561. ValueInfo->DataLength
  562. );
  563. if(!NT_SUCCESS(Status)) {
  564. if(DstKeyPath) {
  565. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to set value %ws in key %ws(%lx)\n",ValueName,DstKeyPath, Status));
  566. }
  567. else {
  568. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to set value %ws(%lx)\n",ValueName, Status));
  569. }
  570. SpMemFree(ValueName);
  571. break;
  572. }
  573. SpMemFree(ValueName);
  574. }
  575. //
  576. // cleanup
  577. //
  578. if(SrcKeyPath != NULL) {
  579. ZwClose(hKeySrc);
  580. }
  581. if(DstKeyPath != NULL) {
  582. ZwClose(hKeyDst);
  583. }
  584. return(Status);
  585. }
  586. NTSTATUS
  587. SppResetLastKnownGood(
  588. IN HANDLE hKeySystem
  589. )
  590. {
  591. NTSTATUS Status;
  592. ULONG ResultLength;
  593. DWORD Value;
  594. //
  595. // Make the appropriate change
  596. //
  597. Status = SpGetValueKey(
  598. hKeySystem,
  599. L"Select",
  600. L"Current",
  601. sizeof(TemporaryBuffer),
  602. (PCHAR)TemporaryBuffer,
  603. &ResultLength
  604. );
  605. //
  606. // TemporaryBuffer is 32kb long, and it should be big enough
  607. // for the data.
  608. //
  609. ASSERT( Status != STATUS_BUFFER_OVERFLOW );
  610. if(!NT_SUCCESS(Status)) {
  611. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to read value from registry. KeyName = Select, ValueName = Current, Status = (%lx)\n",Status));
  612. return( Status );
  613. }
  614. Value = *(DWORD *)(((PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer)->Data);
  615. Status = SpOpenSetValueAndClose( hKeySystem,
  616. L"Select",
  617. L"LastKnownGood",
  618. REG_DWORD,
  619. &Value,
  620. sizeof( ULONG ) );
  621. if(!NT_SUCCESS(Status)) {
  622. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to write value to registry. KeyName = Select, ValueName = LastKnownGood, Status = (%lx)\n",Status));
  623. }
  624. //
  625. // We need also to reset the value 'Failed'. Otherwise, the Service Control
  626. // Manager will display a popup indicating the LastKnownGood CCSet was
  627. // used.
  628. //
  629. Value = 0;
  630. Status = SpOpenSetValueAndClose( hKeySystem,
  631. L"Select",
  632. L"Failed",
  633. REG_DWORD,
  634. &Value,
  635. sizeof( ULONG ) );
  636. if(!NT_SUCCESS(Status)) {
  637. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to write value to registry. KeyName = Select, ValueName = Failed, Status = (%lx)\n",Status));
  638. }
  639. return( Status );
  640. }
  641. VOID
  642. SpDeleteRootDevnodeKeys(
  643. IN PVOID SifHandle,
  644. IN HANDLE hKeyCCSet,
  645. IN PWSTR DevicesToDelete,
  646. IN RootDevnodeSectionNamesType *DeviceClassesToDelete
  647. )
  648. /*++
  649. Routine Description:
  650. This routine deletes some root-enumerated devnode registry keys
  651. based on criteria specified in txtsetup.sif. The following sections
  652. are processed:
  653. [RootDevicesToDelete] - this section lists device IDs under
  654. HKLM\System\CurrentControlSet\Enum\Root that
  655. should be deleted (including their subkeys).
  656. [RootDeviceClassesToDelete] - this section lists device class GUIDs
  657. whose root-enumerated members are to be
  658. deleted.
  659. For each device instance key to be deleted, we also delete the corresponding
  660. Driver key under HKLM\System\CurrentControlSet\Control\Class, if specified.
  661. We also do two additional operations to clean-up in certain cases where we
  662. may encounter junk deposited in the registry from NT4:
  663. 1. Delete any root-enumerated devnode keys that have a nonzero (or
  664. ill-formed) "Phantom" value, indicating that they're a "private
  665. phantom".
  666. 2. Delete any Control subkeys we may find--since these are supposed to
  667. always be volatile, we _should_ never see these, but we've seen
  668. cases where OEM preinstalls 'seed' the hives with device instance
  669. keys including this subkey, and the results are disastrous (i.e.,
  670. we bugcheck when we encounter a PDO address we'd squirreled away in
  671. the key on a previous boot thinking it was nonvolatile, hence would
  672. disappear upon reboot).
  673. Arguments:
  674. SifHandle: Supplies handle to txtsetup.sif.
  675. hKeyCCSet: Handle to the root of the control set in the system
  676. being upgraded.
  677. DevicesToDelete: Section name containing the root device names that need
  678. to be deleted.
  679. DeviceClassesToDelete: Specifies the classes of root devices that need to
  680. be deleted.
  681. Return Value:
  682. none.
  683. --*/
  684. {
  685. HANDLE hRootKey, hDeviceKey, hInstanceKey, hClassKey;
  686. HANDLE hSetupRootKey, hSetupDeviceKey, hSetupInstanceKey, hSetupClassKey;
  687. NTSTATUS Status;
  688. OBJECT_ATTRIBUTES Obja;
  689. UNICODE_STRING UnicodeString, guidString;
  690. ULONG LineIndex, DeviceKeyIndex, ResultLength, InstanceKeyIndex;
  691. PKEY_BASIC_INFORMATION DeviceKeyInfo, InstanceKeyInfo;
  692. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  693. PUCHAR p, q;
  694. BOOLEAN InstanceKeysEnumerated;
  695. PWSTR DeviceId, ClassGuidToDelete;
  696. PUCHAR MyScratchBuffer;
  697. ULONG MyScratchBufferSize, drvInst;
  698. BOOLEAN DeleteInstanceKey;
  699. int SectionIndex;
  700. DWORD OsFlags = 0;
  701. DWORD OsVersion = 0;
  702. DWORD MangledVersion;
  703. PWSTR Value;
  704. //
  705. // Determine OSFlags & OSVersion for going through various sections
  706. //
  707. Value = SpGetSectionKeyIndex(WinntSifHandle,
  708. SIF_DATA, WINNT_D_NTUPGRADE_W, 0);
  709. if(Value && _wcsicmp(Value, WINNT_A_YES_W)==0) {
  710. //
  711. // It's an NT upgrade
  712. //
  713. OsFlags |= RootDevnodeSectionNamesType_NTUPG;
  714. }
  715. if(!OsFlags) {
  716. Value = SpGetSectionKeyIndex(WinntSifHandle,
  717. SIF_DATA, WINNT_D_WIN95UPGRADE_W, 0);
  718. if (Value && _wcsicmp(Value, WINNT_A_YES_W)==0) {
  719. //
  720. // It's a Win9x upgrade
  721. //
  722. OsFlags |= RootDevnodeSectionNamesType_W9xUPG;
  723. }
  724. if(!OsFlags) {
  725. //
  726. // in all other cases assume clean
  727. //
  728. OsFlags = RootDevnodeSectionNamesType_CLEAN;
  729. }
  730. }
  731. Value = SpGetSectionKeyIndex(WinntSifHandle,
  732. SIF_DATA, WINNT_D_WIN32_VER_W, 0);
  733. if(Value) {
  734. //
  735. // version is bbbbllhh - build/low/high
  736. //
  737. MangledVersion = (DWORD)SpStringToLong( Value, NULL, 16 );
  738. //
  739. // NTRAID#453953 2001/08/09-JamieHun OsVersion checking is wrong
  740. // this should be RtlUshortByteSwap((USHORT)MangledVersion) & 0xffff;
  741. // Win2k -> 0005 WinXP -> 0105
  742. // so we always run ".NT4" below
  743. //
  744. OsVersion = MAKEWORD(LOBYTE(LOWORD(MangledVersion)),HIBYTE(LOWORD(MangledVersion)));
  745. } else {
  746. OsVersion = 0;
  747. }
  748. //
  749. // open CCS\Enum\Root in the registry being upgraded.
  750. //
  751. INIT_OBJA(&Obja, &UnicodeString, L"Enum\\Root");
  752. Obja.RootDirectory = hKeyCCSet;
  753. Status = ZwOpenKey(&hRootKey, KEY_ALL_ACCESS, &Obja);
  754. if(!NT_SUCCESS(Status)) {
  755. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  756. "SETUP: Unable to open upgrade Enum\\Root for devnode deletion. Status = %lx \n",
  757. Status));
  758. return;
  759. }
  760. //
  761. // Open CCS\Enum\Root in the current setup registry.
  762. //
  763. INIT_OBJA(&Obja, &UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\Root");
  764. Obja.RootDirectory = NULL;
  765. Status = ZwOpenKey(&hSetupRootKey, KEY_ALL_ACCESS, &Obja);
  766. if(!NT_SUCCESS(Status)) {
  767. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  768. "SETUP: Unable to open setup Enum\\Root for devnode deletion. Status = %lx \n",
  769. Status));
  770. ZwClose(hRootKey);
  771. return;
  772. }
  773. //
  774. // Next, open CCS\Control\Class in the registry being upgraded.
  775. //
  776. INIT_OBJA(&Obja, &UnicodeString, L"Control\\Class");
  777. Obja.RootDirectory = hKeyCCSet;
  778. Status = ZwOpenKey(&hClassKey, KEY_ALL_ACCESS, &Obja);
  779. if(!NT_SUCCESS(Status)) {
  780. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  781. "SETUP: Unable to open upgrade Control\\Class for devnode deletion. Status = %lx \n",
  782. Status));
  783. ZwClose(hSetupRootKey);
  784. ZwClose(hRootKey);
  785. return;
  786. }
  787. //
  788. // Open CCS\Control\Class in the current setup registry.
  789. //
  790. INIT_OBJA(&Obja, &UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
  791. Obja.RootDirectory = NULL;
  792. Status = ZwOpenKey(&hSetupClassKey, KEY_ALL_ACCESS, &Obja);
  793. if(!NT_SUCCESS(Status)) {
  794. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  795. "SETUP: Unable to open setup Control\\Class for devnode deletion. Status = %lx \n",
  796. Status));
  797. ZwClose(hClassKey);
  798. ZwClose(hSetupRootKey);
  799. ZwClose(hRootKey);
  800. return;
  801. }
  802. //
  803. // Allocate some scratch space to work with. The most we'll need is enough for 2
  804. // KEY_BASIC_INFORMATION structures, plus the maximum length of a device instance ID,
  805. // plus a KEY_VALUE_PARTIAL_INFORMATION structure, plus the length of a driver instance
  806. // key path [stringified GUID + '\' + 4 digit ordinal + term NULL], plus 2 large integer
  807. // structures for alignment.
  808. //
  809. MyScratchBufferSize = (2*sizeof(KEY_BASIC_INFORMATION)) + (200*sizeof(WCHAR)) +
  810. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ((GUID_STRING_LEN+5)*sizeof(WCHAR) +
  811. 2*sizeof(LARGE_INTEGER));
  812. MyScratchBuffer = SpMemAlloc(MyScratchBufferSize);
  813. if(!MyScratchBuffer) {
  814. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  815. "SETUP: Can't allocate memory for deletion of classes of root-enumerated devnodes!\n"));
  816. ZwClose(hSetupClassKey);
  817. ZwClose(hClassKey);
  818. ZwClose(hSetupRootKey);
  819. ZwClose(hRootKey);
  820. return;
  821. }
  822. //
  823. // PART 1: Process [RootDevicesToDelete]
  824. //
  825. //
  826. // Now, traverse the entries under the [RootDevicesToDelete] section, and
  827. // delete each one.
  828. //
  829. for(LineIndex = 0;
  830. DeviceId = SpGetSectionLineIndex(SifHandle, DevicesToDelete, LineIndex, 0);
  831. LineIndex++) {
  832. //
  833. // Open up the device key so we can enumerate the instances.
  834. //
  835. INIT_OBJA(&Obja, &UnicodeString, DeviceId);
  836. Obja.RootDirectory = hRootKey;
  837. Status = ZwOpenKey(&hDeviceKey, KEY_ALL_ACCESS, &Obja);
  838. if(!NT_SUCCESS(Status)) {
  839. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  840. "SETUP: Unable to open Enum\\Root\\%ws during devnode deletion. Status = %lx \n",
  841. DeviceId,
  842. Status));
  843. //
  844. // Skip this key and continue.
  845. //
  846. continue;
  847. }
  848. //
  849. // Attempt to open the device key in the setup registry.
  850. //
  851. Obja.RootDirectory = hSetupRootKey;
  852. Status = ZwOpenKey(&hSetupDeviceKey, KEY_ALL_ACCESS, &Obja);
  853. if(!NT_SUCCESS(Status)) {
  854. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  855. "SETUP: Unable to open Enum\\Root\\%ws during devnode deletion. Status = %lx \n",
  856. DeviceId,
  857. Status));
  858. //
  859. // It's ok if we don't have this device key in the setup registry.
  860. //
  861. hSetupDeviceKey = NULL;
  862. }
  863. //
  864. // Now enumerate the instance subkeys under this device key.
  865. //
  866. p = ALIGN_UP_POINTER(((PUCHAR)MyScratchBuffer), sizeof(LARGE_INTEGER));
  867. InstanceKeyInfo = (PKEY_BASIC_INFORMATION)p;
  868. InstanceKeyIndex = 0;
  869. while(TRUE) {
  870. Status = ZwEnumerateKey(hDeviceKey,
  871. InstanceKeyIndex,
  872. KeyBasicInformation,
  873. p,
  874. (ULONG)MyScratchBufferSize,
  875. &ResultLength
  876. );
  877. if(!NT_SUCCESS(Status)) {
  878. break;
  879. }
  880. //
  881. // Zero-terminate the instance key name, just in case.
  882. //
  883. InstanceKeyInfo->Name[InstanceKeyInfo->NameLength/sizeof(WCHAR)] = 0;
  884. //
  885. // Now, open up the instance key so we can check its Driver value.
  886. //
  887. INIT_OBJA(&Obja, &UnicodeString, InstanceKeyInfo->Name);
  888. Obja.RootDirectory = hDeviceKey;
  889. Status = ZwOpenKey(&hInstanceKey, KEY_ALL_ACCESS, &Obja);
  890. if(!NT_SUCCESS(Status)) {
  891. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  892. "SETUP: Unable to open Enum\\Root\\%ws\\%ws for potential devnode deletion. Status = %lx \n",
  893. DeviceId,
  894. InstanceKeyInfo->Name,
  895. Status));
  896. //
  897. // Skip this key and continue.
  898. //
  899. InstanceKeyIndex++;
  900. continue;
  901. }
  902. //
  903. // Attempt to open the same instance key in the setup registry.
  904. //
  905. hSetupInstanceKey = NULL;
  906. if (hSetupDeviceKey) {
  907. Obja.RootDirectory = hSetupDeviceKey;
  908. Status = ZwOpenKey(&hSetupInstanceKey, KEY_ALL_ACCESS, &Obja);
  909. if(!NT_SUCCESS(Status)) {
  910. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  911. "SETUP: Unable to open setup Enum\\Root\\%ws\\%ws for potential devnode deletion. Status = %lx \n",
  912. DeviceId,
  913. InstanceKeyInfo->Name,
  914. Status));
  915. }
  916. }
  917. //
  918. // Now look for some value entries under this instance key. Don't
  919. // overwrite the instance key name already in MyScratchBuffer,
  920. // since we'll need it later.
  921. //
  922. q = ALIGN_UP_POINTER(((PUCHAR)p + ResultLength), sizeof(LARGE_INTEGER));
  923. if (hSetupInstanceKey) {
  924. //
  925. // Check if the Migrated value still exists on this registry
  926. // key. If so, it was migrated, but wasn't ever used by
  927. // textmode setup and is now specified to be deleted.
  928. //
  929. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  930. RtlInitUnicodeString(&UnicodeString, L"Migrated");
  931. Status = ZwQueryValueKey(hSetupInstanceKey,
  932. &UnicodeString,
  933. KeyValuePartialInformation,
  934. q,
  935. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  936. &ResultLength);
  937. if (NT_SUCCESS(Status) &&
  938. (KeyValueInfo->Type == REG_DWORD) &&
  939. (*(PULONG)(KeyValueInfo->Data) == 1)) {
  940. DeleteInstanceKey = TRUE;
  941. } else {
  942. DeleteInstanceKey = FALSE;
  943. }
  944. }
  945. //
  946. // First check for the presence of old style "Driver" value.
  947. //
  948. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  949. RtlInitUnicodeString(&UnicodeString, REGSTR_VAL_DRIVER);
  950. Status = ZwQueryValueKey(hInstanceKey,
  951. &UnicodeString,
  952. KeyValuePartialInformation,
  953. q,
  954. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  955. &ResultLength
  956. );
  957. if (NT_SUCCESS(Status) && KeyValueInfo->Type == REG_SZ) {
  958. //
  959. // Delete the Driver key.
  960. //
  961. SppDeleteKeyRecursive(hClassKey, (PWCHAR)KeyValueInfo->Data, TRUE);
  962. //
  963. // Also attempt to delete the driver key from the setup
  964. // registry. Note that we don't need to check that it has the
  965. // same Driver value, since we explicitly migrated it to be the
  966. // same value at the start of textmode setup.
  967. //
  968. if (hSetupInstanceKey && DeleteInstanceKey) {
  969. SppDeleteKeyRecursive(hSetupClassKey, (PWCHAR)KeyValueInfo->Data, TRUE);
  970. }
  971. } else {
  972. //
  973. // Construct the driver instance as "ClassGuid\nnnn"
  974. //
  975. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  976. RtlInitUnicodeString(&UnicodeString, REGSTR_VALUE_GUID);
  977. Status = ZwQueryValueKey(hInstanceKey,
  978. &UnicodeString,
  979. KeyValuePartialInformation,
  980. q,
  981. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  982. &ResultLength
  983. );
  984. if (NT_SUCCESS(Status) && KeyValueInfo->Type == REG_BINARY) {
  985. Status = RtlStringFromGUID((REFGUID)KeyValueInfo->Data, &guidString);
  986. ASSERT(NT_SUCCESS(Status));
  987. if (NT_SUCCESS(Status)) {
  988. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  989. RtlInitUnicodeString(&UnicodeString, REGSTR_VALUE_DRVINST);
  990. Status = ZwQueryValueKey(hInstanceKey,
  991. &UnicodeString,
  992. KeyValuePartialInformation,
  993. q,
  994. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  995. &ResultLength
  996. );
  997. if (NT_SUCCESS(Status) && KeyValueInfo->Type == REG_DWORD) {
  998. drvInst = *(PULONG)KeyValueInfo->Data;
  999. swprintf((PWCHAR)&KeyValueInfo->Data[0], TEXT("%wZ\\%04u"), &guidString, drvInst);
  1000. //
  1001. // Delete the Driver key.
  1002. //
  1003. SppDeleteKeyRecursive(hClassKey, (PWCHAR)KeyValueInfo->Data, TRUE);
  1004. //
  1005. // Also attempt to delete the driver key from the setup
  1006. // registry. Note that we don't need to check that it has the
  1007. // same Driver value, since we explicitly migrated it to be the
  1008. // same value at the start of textmode setup.
  1009. //
  1010. if (hSetupInstanceKey && DeleteInstanceKey) {
  1011. SppDeleteKeyRecursive(hSetupClassKey, (PWCHAR)KeyValueInfo->Data, TRUE);
  1012. }
  1013. }
  1014. RtlFreeUnicodeString(&guidString);
  1015. }
  1016. }
  1017. }
  1018. //
  1019. // Delete the instance key from the setup registry, if we should do so.
  1020. //
  1021. if (hSetupInstanceKey && DeleteInstanceKey) {
  1022. ZwClose(hSetupInstanceKey);
  1023. SppDeleteKeyRecursive(hSetupDeviceKey, InstanceKeyInfo->Name, TRUE);
  1024. }
  1025. //
  1026. // Now close the handle, and move on to the next one.
  1027. //
  1028. ZwClose(hInstanceKey);
  1029. InstanceKeyIndex++;
  1030. }
  1031. //
  1032. // Delete the device key, and all instance subkeys.
  1033. //
  1034. ZwClose(hDeviceKey);
  1035. SppDeleteKeyRecursive(hRootKey, DeviceId, TRUE);
  1036. //
  1037. // If the device has no remaining instances in the setup registry,
  1038. // delete the device key.
  1039. //
  1040. if (hSetupDeviceKey) {
  1041. KEY_FULL_INFORMATION keyFullInfo;
  1042. Status = ZwQueryKey(hSetupDeviceKey,
  1043. KeyFullInformation,
  1044. (PVOID)&keyFullInfo,
  1045. sizeof(KEY_FULL_INFORMATION),
  1046. &ResultLength);
  1047. ZwClose(hSetupDeviceKey);
  1048. hSetupDeviceKey = NULL;
  1049. if ((NT_SUCCESS(Status) || (Status == STATUS_BUFFER_TOO_SMALL)) &&
  1050. (keyFullInfo.SubKeys == 0)) {
  1051. SppDeleteKeyRecursive(hSetupRootKey, DeviceId, TRUE);
  1052. }
  1053. }
  1054. }
  1055. //
  1056. // PART 2: Process [RootDeviceClassesToDelete]
  1057. //
  1058. //
  1059. // Now, enumerate all remaining device instances under Enum\Root, looking for
  1060. // devices whose class is one of our classes to delete.
  1061. //
  1062. DeviceKeyInfo = (PKEY_BASIC_INFORMATION)MyScratchBuffer;
  1063. DeviceKeyIndex = 0;
  1064. while(TRUE && DeviceClassesToDelete) {
  1065. Status = ZwEnumerateKey(hRootKey,
  1066. DeviceKeyIndex,
  1067. KeyBasicInformation,
  1068. MyScratchBuffer,
  1069. MyScratchBufferSize,
  1070. &ResultLength
  1071. );
  1072. if(!NT_SUCCESS(Status)) {
  1073. break;
  1074. }
  1075. //
  1076. // Reset our flag that indicates whether or not we enumerated the instance
  1077. // subkeys under this key. We use this later in determining whether the
  1078. // device key itself should be deleted.
  1079. //
  1080. InstanceKeysEnumerated = FALSE;
  1081. //
  1082. // Zero-terminate the subkey name just in case.
  1083. //
  1084. DeviceKeyInfo->Name[DeviceKeyInfo->NameLength/sizeof(WCHAR)] = 0;
  1085. //
  1086. // Go ahead and bump the used-buffer length by sizeof(WCHAR), to
  1087. // accomodate the potential growth caused by adding a terminating NULL.
  1088. //
  1089. ResultLength += sizeof(WCHAR);
  1090. //
  1091. // Now, open up the device key so we can enumerate the instances.
  1092. //
  1093. INIT_OBJA(&Obja, &UnicodeString, DeviceKeyInfo->Name);
  1094. Obja.RootDirectory = hRootKey;
  1095. Status = ZwOpenKey(&hDeviceKey, KEY_ALL_ACCESS, &Obja);
  1096. if(!NT_SUCCESS(Status)) {
  1097. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1098. "SETUP: Unable to open Enum\\Root\\%ws for potential devnode deletion. Status = %lx \n",
  1099. DeviceKeyInfo->Name,
  1100. Status));
  1101. //
  1102. // Skip this key and continue.
  1103. //
  1104. DeviceKeyIndex++;
  1105. continue;
  1106. }
  1107. //
  1108. // Attempt to open the device key in the setup registry.
  1109. //
  1110. Obja.RootDirectory = hSetupRootKey;
  1111. Status = ZwOpenKey(&hSetupDeviceKey, KEY_ALL_ACCESS, &Obja);
  1112. if(!NT_SUCCESS(Status)) {
  1113. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1114. "SETUP: Unable to open setup Enum\\Root\\%ws during devnode deletion. Status = %lx \n",
  1115. DeviceKeyInfo->Name,
  1116. Status));
  1117. //
  1118. // It's ok if we don't have this device key in the setup registry.
  1119. //
  1120. hSetupDeviceKey = NULL;
  1121. }
  1122. //
  1123. // Now enumerate the instance subkeys under this device key. Don't overwrite
  1124. // the device ID key name already in MyScratchBuffer, since we'll probably
  1125. // be needing it again in the case where all subkeys get deleted.
  1126. //
  1127. p = ALIGN_UP_POINTER(((PUCHAR)MyScratchBuffer + ResultLength), sizeof(LARGE_INTEGER));
  1128. InstanceKeyInfo = (PKEY_BASIC_INFORMATION)p;
  1129. InstanceKeyIndex = 0;
  1130. InstanceKeysEnumerated = TRUE;
  1131. while(TRUE) {
  1132. Status = ZwEnumerateKey(hDeviceKey,
  1133. InstanceKeyIndex,
  1134. KeyBasicInformation,
  1135. p,
  1136. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - p),
  1137. &ResultLength
  1138. );
  1139. if(!NT_SUCCESS(Status)) {
  1140. break;
  1141. }
  1142. //
  1143. // Zero-terminate the instance key name, just in case.
  1144. //
  1145. InstanceKeyInfo->Name[InstanceKeyInfo->NameLength/sizeof(WCHAR)] = 0;
  1146. //
  1147. // Go ahead and bump the used-buffer length by sizeof(WCHAR), to
  1148. // accomodate the potential growth caused by adding a terminating NULL.
  1149. //
  1150. ResultLength += sizeof(WCHAR);
  1151. //
  1152. // Now, open up the instance key so we can check its class.
  1153. //
  1154. INIT_OBJA(&Obja, &UnicodeString, InstanceKeyInfo->Name);
  1155. Obja.RootDirectory = hDeviceKey;
  1156. Status = ZwOpenKey(&hInstanceKey, KEY_ALL_ACCESS, &Obja);
  1157. if(!NT_SUCCESS(Status)) {
  1158. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1159. "SETUP: Unable to open Enum\\Root\\%ws\\%ws for potential devnode deletion. Status = %lx \n",
  1160. DeviceKeyInfo->Name,
  1161. InstanceKeyInfo->Name,
  1162. Status));
  1163. //
  1164. // Skip this key and continue.
  1165. //
  1166. InstanceKeyIndex++;
  1167. continue;
  1168. }
  1169. //
  1170. // Attempt to open the same instance key in the setup registry.
  1171. //
  1172. hSetupInstanceKey = NULL;
  1173. if (hSetupDeviceKey) {
  1174. Obja.RootDirectory = hSetupDeviceKey;
  1175. Status = ZwOpenKey(&hSetupInstanceKey, KEY_ALL_ACCESS, &Obja);
  1176. if(!NT_SUCCESS(Status)) {
  1177. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1178. "SETUP: Unable to open setup Enum\\Root\\%ws\\%ws for potential devnode deletion. Status = %lx \n",
  1179. DeviceId,
  1180. InstanceKeyInfo->Name,
  1181. Status));
  1182. }
  1183. }
  1184. DeleteInstanceKey = FALSE;
  1185. //
  1186. // Now look for some value entries under this instance key. Don't
  1187. // overwrite the instance key name already in MyScratchBuffer,
  1188. // since we'll need it if we discover that the instance should be
  1189. // deleted.
  1190. //
  1191. q = ALIGN_UP_POINTER(((PUCHAR)p + ResultLength), sizeof(LARGE_INTEGER));
  1192. //
  1193. // If we find a nonzero Phantom value entry, then the devnode
  1194. // should be removed.
  1195. //
  1196. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  1197. RtlInitUnicodeString(&UnicodeString, L"Phantom");
  1198. Status = ZwQueryValueKey(hInstanceKey,
  1199. &UnicodeString,
  1200. KeyValuePartialInformation,
  1201. q,
  1202. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  1203. &ResultLength
  1204. );
  1205. if(NT_SUCCESS(Status) &&
  1206. ((KeyValueInfo->Type != REG_DWORD) ||
  1207. *(PULONG)(KeyValueInfo->Data))) {
  1208. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1209. "SETUP: SpDeleteRootDevnodeKeys: Encountered a left-over phantom in Enum\\Root\\%ws\\%ws. Deleting key. \n",
  1210. DeviceKeyInfo->Name,
  1211. InstanceKeyInfo->Name));
  1212. DeleteInstanceKey = TRUE;
  1213. }
  1214. if(!DeleteInstanceKey) {
  1215. //
  1216. // Unless it is a phantom, if we find a nonzero
  1217. // FirmwareIdentified value entry, then the devnode should not
  1218. // be removed, no matter what class it is.
  1219. //
  1220. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  1221. RtlInitUnicodeString(&UnicodeString, L"FirmwareIdentified");
  1222. Status = ZwQueryValueKey(hInstanceKey,
  1223. &UnicodeString,
  1224. KeyValuePartialInformation,
  1225. q,
  1226. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  1227. &ResultLength
  1228. );
  1229. if(NT_SUCCESS(Status) &&
  1230. ((KeyValueInfo->Type != REG_DWORD) ||
  1231. *(PULONG)(KeyValueInfo->Data))) {
  1232. //
  1233. // Skip this key and continue;
  1234. //
  1235. goto CloseInstanceKeyAndContinue;
  1236. }
  1237. }
  1238. if(!DeleteInstanceKey) {
  1239. //
  1240. // Retrieve the ClassGUID value entry.
  1241. //
  1242. // First check for the old value.
  1243. //
  1244. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  1245. RtlInitUnicodeString(&UnicodeString, REGSTR_VAL_CLASSGUID);
  1246. Status = ZwQueryValueKey(hInstanceKey,
  1247. &UnicodeString,
  1248. KeyValuePartialInformation,
  1249. q,
  1250. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  1251. &ResultLength
  1252. );
  1253. if(!NT_SUCCESS(Status)) {
  1254. //
  1255. // Check the new value.
  1256. //
  1257. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  1258. RtlInitUnicodeString(&UnicodeString, REGSTR_VALUE_GUID);
  1259. Status = ZwQueryValueKey(hInstanceKey,
  1260. &UnicodeString,
  1261. KeyValuePartialInformation,
  1262. q,
  1263. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  1264. &ResultLength
  1265. );
  1266. if(NT_SUCCESS(Status) && KeyValueInfo->Type == REG_BINARY) {
  1267. GUID guid;
  1268. UNICODE_STRING guidString;
  1269. guid = *(GUID *)KeyValueInfo->Data;
  1270. Status = RtlStringFromGUID(&guid, &guidString);
  1271. ASSERT(NT_SUCCESS(Status));
  1272. if (NT_SUCCESS(Status)) {
  1273. KeyValueInfo->Type = REG_SZ;
  1274. KeyValueInfo->DataLength = guidString.MaximumLength;
  1275. RtlCopyMemory(KeyValueInfo->Data, guidString.Buffer, KeyValueInfo->DataLength);
  1276. RtlFreeUnicodeString(&guidString);
  1277. } else {
  1278. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1279. "SETUP: SpDeleteRootDevnodeKeys: Failed to convert GUID to string! \n",
  1280. DeviceKeyInfo->Name,
  1281. InstanceKeyInfo->Name));
  1282. //
  1283. // Skip this key and continue;
  1284. //
  1285. goto CloseInstanceKeyAndContinue;
  1286. }
  1287. } else {
  1288. DeleteInstanceKey = TRUE;
  1289. }
  1290. }
  1291. }
  1292. if(DeleteInstanceKey) {
  1293. //
  1294. // The instance key will be deleted. Check if the instance
  1295. // specifies a corresponding Driver key that should also be
  1296. // deleted.
  1297. //
  1298. // First read the old style "Driver" value.
  1299. //
  1300. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  1301. RtlInitUnicodeString(&UnicodeString, REGSTR_VAL_DRIVER);
  1302. Status = ZwQueryValueKey(hInstanceKey,
  1303. &UnicodeString,
  1304. KeyValuePartialInformation,
  1305. q,
  1306. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  1307. &ResultLength
  1308. );
  1309. if (NT_SUCCESS(Status) && KeyValueInfo->Type == REG_SZ) {
  1310. //
  1311. // Delete the Driver key.
  1312. //
  1313. SppDeleteKeyRecursive(hClassKey, (PWCHAR)KeyValueInfo->Data, TRUE);
  1314. //
  1315. // Also attempt to delete the driver key from the setup
  1316. // registry. Note that we don't need to check that it has the
  1317. // same Driver value, since we explicitly migrated it to be the
  1318. // same value at the start of textmode setup.
  1319. //
  1320. if (hSetupInstanceKey) {
  1321. SppDeleteKeyRecursive(hSetupClassKey, (PWCHAR)KeyValueInfo->Data, TRUE);
  1322. }
  1323. } else {
  1324. //
  1325. // Create the driver instance.
  1326. //
  1327. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  1328. RtlInitUnicodeString(&UnicodeString, REGSTR_VALUE_GUID);
  1329. Status = ZwQueryValueKey(hInstanceKey,
  1330. &UnicodeString,
  1331. KeyValuePartialInformation,
  1332. q,
  1333. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  1334. &ResultLength
  1335. );
  1336. if (NT_SUCCESS(Status) && KeyValueInfo->Type == REG_BINARY) {
  1337. Status = RtlStringFromGUID((REFGUID)KeyValueInfo->Data, &guidString);
  1338. ASSERT(NT_SUCCESS(Status));
  1339. if (NT_SUCCESS(Status)) {
  1340. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  1341. RtlInitUnicodeString(&UnicodeString, REGSTR_VALUE_DRVINST);
  1342. Status = ZwQueryValueKey(hInstanceKey,
  1343. &UnicodeString,
  1344. KeyValuePartialInformation,
  1345. q,
  1346. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  1347. &ResultLength
  1348. );
  1349. if (NT_SUCCESS(Status) && KeyValueInfo->Type == REG_DWORD) {
  1350. drvInst = *(PULONG)KeyValueInfo->Data;
  1351. swprintf((PWCHAR)&KeyValueInfo->Data[0], TEXT("%wZ\\%04u"), &guidString, drvInst);
  1352. //
  1353. // Delete the Driver key.
  1354. //
  1355. SppDeleteKeyRecursive(hClassKey, (PWCHAR)KeyValueInfo->Data, TRUE);
  1356. //
  1357. // Also attempt to delete the driver key from the setup
  1358. // registry. Note that we don't need to check that it has the
  1359. // same Driver value, since we explicitly migrated it to be the
  1360. // same value at the start of textmode setup.
  1361. //
  1362. if (hSetupInstanceKey) {
  1363. SppDeleteKeyRecursive(hSetupClassKey, (PWCHAR)KeyValueInfo->Data, TRUE);
  1364. }
  1365. }
  1366. RtlFreeUnicodeString(&guidString);
  1367. }
  1368. }
  1369. }
  1370. //
  1371. // Delete the instance key.
  1372. //
  1373. ZwClose(hInstanceKey);
  1374. SppDeleteKeyRecursive(hDeviceKey, InstanceKeyInfo->Name, TRUE);
  1375. //
  1376. // Delete the instance key from the setup registry.
  1377. //
  1378. if (hSetupInstanceKey) {
  1379. ZwClose(hSetupInstanceKey);
  1380. SppDeleteKeyRecursive(hSetupDeviceKey, InstanceKeyInfo->Name, TRUE);
  1381. }
  1382. //
  1383. // We deleted the instance key, so set the instance enumeration
  1384. // index back to zero and continue.
  1385. //
  1386. InstanceKeyIndex = 0;
  1387. continue;
  1388. }
  1389. //
  1390. // This value should be exactly the length of a stringified GUID + terminating NULL.
  1391. //
  1392. if(KeyValueInfo->DataLength != (GUID_STRING_LEN * sizeof(WCHAR))) {
  1393. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1394. "SETUP: SpDeleteRootDevnodeKeys: Enum\\Root\\%ws\\%ws has corrupted ClassGUID! \n",
  1395. DeviceKeyInfo->Name,
  1396. InstanceKeyInfo->Name));
  1397. //
  1398. // Skip this key and continue;
  1399. //
  1400. goto CloseInstanceKeyAndContinue;
  1401. }
  1402. //
  1403. // Now loop through the [RootDeviceClassesToDelete] section to see if this class is one
  1404. // of the ones whose devices we're supposed to delete.
  1405. //
  1406. // NTRAID#453953 2001/08/09-JamieHun OsVersion checking is wrong
  1407. // as this stands, we will always process all sections
  1408. //
  1409. for(SectionIndex = 0; DeviceClassesToDelete[SectionIndex].SectionName; SectionIndex++) {
  1410. if((!DeviceClassesToDelete[SectionIndex].SectionFlags & OsFlags)
  1411. || (OsVersion < DeviceClassesToDelete[SectionIndex].VerLow)
  1412. || (OsVersion > DeviceClassesToDelete[SectionIndex].VerHigh)) {
  1413. //
  1414. // not interesting
  1415. //
  1416. // NTRAID#453953 2001/08/09-JamieHun OsVersion checking is wrong
  1417. // we don't get here
  1418. //
  1419. continue;
  1420. }
  1421. for(LineIndex = 0;
  1422. ClassGuidToDelete = SpGetSectionLineIndex(SifHandle,
  1423. DeviceClassesToDelete[SectionIndex].SectionName,
  1424. LineIndex,
  1425. 0);
  1426. LineIndex++) {
  1427. //
  1428. // Compare the two GUID strings.
  1429. //
  1430. if(!_wcsicmp(ClassGuidToDelete, (PWCHAR)(KeyValueInfo->Data))) {
  1431. //
  1432. // NTRAID#257655 2001/08/09-JamieHun SMS AppCompat due to #453953
  1433. //
  1434. if((_wcsicmp(DeviceKeyInfo->Name,L"*SMS_KEYBOARD")==0) ||
  1435. (_wcsicmp(DeviceKeyInfo->Name,L"*SMS_MOUSE")==0)) {
  1436. //
  1437. // looks like an SMS mouse or keyboard
  1438. // check service name to be double-safe
  1439. //
  1440. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  1441. RtlInitUnicodeString(&UnicodeString, REGSTR_VAL_SERVICE);
  1442. Status = ZwQueryValueKey(hInstanceKey,
  1443. &UnicodeString,
  1444. KeyValuePartialInformation,
  1445. q,
  1446. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  1447. &ResultLength
  1448. );
  1449. if (NT_SUCCESS(Status) && KeyValueInfo->Type == REG_SZ) {
  1450. //
  1451. // device has a service
  1452. //
  1453. if(_wcsicmp((PWCHAR)KeyValueInfo->Data,L"kbstuff")==0) {
  1454. //
  1455. // yup, definately SMS!
  1456. // we really don't want to delete this
  1457. //
  1458. goto CloseInstanceKeyAndContinue;
  1459. }
  1460. }
  1461. }
  1462. //
  1463. // We have a match. Check if the instance specifies a
  1464. // corresponding Driver key that should also be deleted.
  1465. //
  1466. // First check the old style "Driver" value.
  1467. //
  1468. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  1469. RtlInitUnicodeString(&UnicodeString, REGSTR_VAL_DRIVER);
  1470. Status = ZwQueryValueKey(hInstanceKey,
  1471. &UnicodeString,
  1472. KeyValuePartialInformation,
  1473. q,
  1474. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  1475. &ResultLength
  1476. );
  1477. if (NT_SUCCESS(Status) && KeyValueInfo->Type == REG_SZ) {
  1478. SppDeleteKeyRecursive(hClassKey, (PWCHAR)KeyValueInfo->Data, TRUE);
  1479. } else {
  1480. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  1481. RtlInitUnicodeString(&UnicodeString, REGSTR_VALUE_GUID);
  1482. Status = ZwQueryValueKey(hInstanceKey,
  1483. &UnicodeString,
  1484. KeyValuePartialInformation,
  1485. q,
  1486. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  1487. &ResultLength
  1488. );
  1489. if (NT_SUCCESS(Status) && KeyValueInfo->Type == REG_BINARY) {
  1490. Status = RtlStringFromGUID((REFGUID)KeyValueInfo->Data, &guidString);
  1491. ASSERT(NT_SUCCESS(Status));
  1492. if (NT_SUCCESS(Status)) {
  1493. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)q;
  1494. RtlInitUnicodeString(&UnicodeString, REGSTR_VALUE_DRVINST);
  1495. Status = ZwQueryValueKey(hInstanceKey,
  1496. &UnicodeString,
  1497. KeyValuePartialInformation,
  1498. q,
  1499. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  1500. &ResultLength
  1501. );
  1502. if (NT_SUCCESS(Status) && KeyValueInfo->Type == REG_DWORD) {
  1503. drvInst = *(PULONG)KeyValueInfo->Data;
  1504. swprintf((PWCHAR)&KeyValueInfo->Data[0], TEXT("%wZ\\%04u"), &guidString, drvInst);
  1505. //
  1506. // Delete the Driver key.
  1507. //
  1508. SppDeleteKeyRecursive(hClassKey, (PWCHAR)KeyValueInfo->Data, TRUE);
  1509. }
  1510. RtlFreeUnicodeString(&guidString);
  1511. }
  1512. }
  1513. }
  1514. //
  1515. // Nuke this key and break out of the GUID comparison loop.
  1516. //
  1517. ZwClose(hInstanceKey);
  1518. SppDeleteKeyRecursive(hDeviceKey, InstanceKeyInfo->Name, TRUE);
  1519. goto DeletedKeyRecursive;
  1520. }
  1521. }
  1522. }
  1523. DeletedKeyRecursive:
  1524. if(ClassGuidToDelete) {
  1525. //
  1526. // We deleted the instance key, so set the instance enumeration index back to zero
  1527. // and continue.
  1528. //
  1529. InstanceKeyIndex = 0;
  1530. continue;
  1531. }
  1532. CloseInstanceKeyAndContinue:
  1533. //
  1534. // If we get to here, then we've decided that this instance key
  1535. // should not be deleted. Delete the Control key (if there happens
  1536. // to be one) to avoid a painful death at next boot.
  1537. //
  1538. SppDeleteKeyRecursive(hInstanceKey, L"Control", TRUE);
  1539. //
  1540. // Now close the handle, and move on to the next one.
  1541. //
  1542. ZwClose(hInstanceKey);
  1543. if (hSetupInstanceKey) {
  1544. ZwClose(hSetupInstanceKey);
  1545. }
  1546. InstanceKeyIndex++;
  1547. }
  1548. ZwClose(hDeviceKey);
  1549. //
  1550. // If we dropped out of the loop on instance subkeys, and the index is non-zero,
  1551. // then there remains at least one subkey that we didn't delete, so we can't nuke
  1552. // the parent. Otherwise, delete the device key.
  1553. //
  1554. if(InstanceKeysEnumerated && !InstanceKeyIndex) {
  1555. SppDeleteKeyRecursive(hRootKey, DeviceKeyInfo->Name, TRUE);
  1556. //
  1557. // Since we deleted a key, we must reset our enumeration index.
  1558. //
  1559. DeviceKeyIndex = 0;
  1560. } else {
  1561. //
  1562. // We didn't delete this key--move on to the next one.
  1563. //
  1564. DeviceKeyIndex++;
  1565. }
  1566. //
  1567. // If the device has no remaining instances in the setup registry,
  1568. // delete the device key.
  1569. //
  1570. if (hSetupDeviceKey) {
  1571. KEY_FULL_INFORMATION keyFullInfo;
  1572. Status = ZwQueryKey(hSetupDeviceKey,
  1573. KeyFullInformation,
  1574. (PVOID)&keyFullInfo,
  1575. sizeof(KEY_FULL_INFORMATION),
  1576. &ResultLength);
  1577. ZwClose(hSetupDeviceKey);
  1578. if ((NT_SUCCESS(Status) || (Status == STATUS_BUFFER_TOO_SMALL)) &&
  1579. (keyFullInfo.SubKeys == 0)) {
  1580. SppDeleteKeyRecursive(hSetupRootKey, DeviceKeyInfo->Name, TRUE);
  1581. }
  1582. }
  1583. }
  1584. ZwClose(hSetupClassKey);
  1585. ZwClose(hClassKey);
  1586. ZwClose(hSetupRootKey);
  1587. ZwClose(hRootKey);
  1588. SpMemFree(MyScratchBuffer);
  1589. return;
  1590. }
  1591. VOID
  1592. SppClearMigratedInstanceValues(
  1593. IN HANDLE hKeyCCSet
  1594. )
  1595. /*++
  1596. Routine Description:
  1597. This routine removes "Migrated" values from device instance keys in the
  1598. setup registry that were migrated at the start of textmode setup (from
  1599. winnt.sif, via SpMigrateDeviceInstanceData).
  1600. Arguments:
  1601. hKeyCCSet: Handle to the root of the control set in the system
  1602. being upgraded.
  1603. Return Value:
  1604. None.
  1605. Notes:
  1606. This routine is not called when performing an ASR setup (not an upgrade).
  1607. For upgrade setup, it is safe to remove "Migrated" values from all
  1608. device instance keys because these keys were migrated from the system
  1609. registry in the winnt.sif during the winnt32 portion of setup, so all the
  1610. information will be present when we boot into GUI setup after this.
  1611. Note that during ASR setup, these values are not removed during textmode
  1612. setp because the registry these instances were migrated from is not restored
  1613. until late in GUI setup.
  1614. --*/
  1615. {
  1616. GENERIC_BUFFER_CONTEXT Context;
  1617. //
  1618. // Allocate some scratch space for the callback routine to work with. The
  1619. // most it will need is enough for a KEY_VALUE_PARTIAL_INFORMATION
  1620. // structure, plus a stringified GUID, plus a large integer structure for
  1621. // alignment.
  1622. //
  1623. Context.BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
  1624. sizeof(DWORD) + sizeof(LARGE_INTEGER);
  1625. Context.Buffer = SpMemAlloc(Context.BufferSize);
  1626. if(!Context.Buffer) {
  1627. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1628. "SETUP: Can't allocate context for SppClearMigratedInstanceValuesCallback, exiting!\n"));
  1629. return;
  1630. }
  1631. //
  1632. // Apply the devnode migration processing callback to all device instance
  1633. // keys.
  1634. //
  1635. SpApplyFunctionToDeviceInstanceKeys(hKeyCCSet,
  1636. SppClearMigratedInstanceValuesCallback,
  1637. &Context);
  1638. //
  1639. // Free the allocated context buffer,
  1640. //
  1641. SpMemFree(Context.Buffer);
  1642. return;
  1643. }
  1644. VOID
  1645. SppMigrateDeviceParentId(
  1646. IN HANDLE hKeyCCSet,
  1647. IN PWSTR DeviceId,
  1648. IN PSPP_DEVICE_MIGRATION_CALLBACK_ROUTINE DeviceMigrationCallbackRoutine
  1649. )
  1650. /*++
  1651. Routine Description:
  1652. This routine migrates the ParentIdPrefix or UniqueParentID value from the
  1653. specified device instance in the registry being upgraded to any device
  1654. instances in the current registry, as dictated by the specified
  1655. InstanceKeyCallbackRoutine.
  1656. Arguments:
  1657. hKeyCCSet: Handle to the root of the control set in the system
  1658. being upgraded.
  1659. DeviceId: Device instance Id of the device in the system being upgraded
  1660. whose ParentIdPrefix (or UniqueParentID) value is to be migrated
  1661. to device instance keys in the current system registry.
  1662. InstanceKeyCallbackRoutine: Callback routine for each device instance key in
  1663. the existsing registry that should decide if the values should be
  1664. replaced.
  1665. Return Value:
  1666. None.
  1667. --*/
  1668. {
  1669. NTSTATUS Status;
  1670. OBJECT_ATTRIBUTES Obja;
  1671. UNICODE_STRING UnicodeString;
  1672. HANDLE hEnumKey, hInstanceKey;
  1673. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  1674. PUCHAR p;
  1675. ULONG ResultLength;
  1676. DEVICE_MIGRATION_CONTEXT DeviceMigrationContext;
  1677. //
  1678. // Allocate some scratch space to work with here, and in our callback
  1679. // routine. The most we'll need is enough for a
  1680. // KEY_VALUE_PARTIAL_INFORMATION structure, the length of a stringified GUID
  1681. // + '\' + 4 digit ordinal + terminating NULL, plus a large integer
  1682. // structure for alignment.
  1683. //
  1684. DeviceMigrationContext.BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
  1685. ((GUID_STRING_LEN + 5)*sizeof(WCHAR)) +
  1686. sizeof(LARGE_INTEGER);
  1687. DeviceMigrationContext.Buffer = SpMemAlloc(DeviceMigrationContext.BufferSize);
  1688. if(!DeviceMigrationContext.Buffer) {
  1689. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1690. "SETUP: Can't allocate memory for device migration processing!\n"));
  1691. return;
  1692. }
  1693. //
  1694. // Open the Enum key in the registry being upgraded.
  1695. //
  1696. INIT_OBJA(&Obja, &UnicodeString, L"Enum");
  1697. Obja.RootDirectory = hKeyCCSet;
  1698. Status = ZwOpenKey(&hEnumKey, KEY_ALL_ACCESS, &Obja);
  1699. if (!NT_SUCCESS(Status)) {
  1700. SpMemFree(DeviceMigrationContext.Buffer);
  1701. return;
  1702. }
  1703. //
  1704. // Open the specified device instance key in the registry being upgraded.
  1705. //
  1706. INIT_OBJA(&Obja, &UnicodeString, DeviceId);
  1707. Obja.RootDirectory = hEnumKey;
  1708. Status = ZwOpenKey(&hInstanceKey, KEY_ALL_ACCESS, &Obja);
  1709. ZwClose(hEnumKey);
  1710. if (!NT_SUCCESS(Status)) {
  1711. //
  1712. // Couldn't find the key to migrate, so we're done.
  1713. //
  1714. SpMemFree(DeviceMigrationContext.Buffer);
  1715. return;
  1716. }
  1717. //
  1718. // Retrieve the UniqueParentID, if one exists.
  1719. //
  1720. DeviceMigrationContext.ParentIdPrefix = NULL;
  1721. p = ALIGN_UP_POINTER(((PUCHAR)DeviceMigrationContext.Buffer), sizeof(LARGE_INTEGER));
  1722. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)p;
  1723. RtlInitUnicodeString(&UnicodeString, L"UniqueParentID");
  1724. Status = ZwQueryValueKey(hInstanceKey,
  1725. &UnicodeString,
  1726. KeyValuePartialInformation,
  1727. KeyValueInfo,
  1728. (ULONG)((DeviceMigrationContext.Buffer +
  1729. DeviceMigrationContext.BufferSize) - p),
  1730. &ResultLength);
  1731. if (NT_SUCCESS(Status)) {
  1732. ASSERT(KeyValueInfo->Type == REG_DWORD);
  1733. DeviceMigrationContext.UniqueParentID = *(PULONG)(KeyValueInfo->Data);
  1734. } else {
  1735. //
  1736. // No UniqueParentID, so look for the ParentIdPrefix.
  1737. //
  1738. RtlInitUnicodeString(&UnicodeString, L"ParentIdPrefix");
  1739. Status = ZwQueryValueKey(hInstanceKey,
  1740. &UnicodeString,
  1741. KeyValuePartialInformation,
  1742. KeyValueInfo,
  1743. (ULONG)((DeviceMigrationContext.Buffer +
  1744. DeviceMigrationContext.BufferSize) - p),
  1745. &ResultLength);
  1746. if (NT_SUCCESS(Status)) {
  1747. ASSERT(KeyValueInfo->Type == REG_SZ);
  1748. DeviceMigrationContext.ParentIdPrefix = SpDupStringW((PWSTR)KeyValueInfo->Data);
  1749. ASSERT(DeviceMigrationContext.ParentIdPrefix);
  1750. }
  1751. }
  1752. ZwClose(hInstanceKey);
  1753. if (!NT_SUCCESS(Status)) {
  1754. //
  1755. // If we couldn't find either value, there's nothing more we can do.
  1756. //
  1757. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1758. "SETUP: No Parent Id values were found for %ws for migration. Status = %lx \n",
  1759. DeviceId,
  1760. Status));
  1761. SpMemFree(DeviceMigrationContext.Buffer);
  1762. return;
  1763. }
  1764. //
  1765. // Supply the hKeyCCSet for the system being upgraded.
  1766. //
  1767. DeviceMigrationContext.hKeyCCSet = hKeyCCSet;
  1768. //
  1769. // Supply the caller specified device migration callback routine.
  1770. //
  1771. DeviceMigrationContext.DeviceMigrationCallbackRoutine = DeviceMigrationCallbackRoutine;
  1772. //
  1773. // Apply the parent id migration callback for all device instance keys.
  1774. // This will in turn, call the specified device instance callback routine to
  1775. // determine whether parent id migration should be done.
  1776. //
  1777. SpApplyFunctionToDeviceInstanceKeys(hKeyCCSet,
  1778. SppMigrateDeviceParentIdCallback,
  1779. &DeviceMigrationContext);
  1780. if (DeviceMigrationContext.ParentIdPrefix) {
  1781. SpMemFree(DeviceMigrationContext.ParentIdPrefix);
  1782. }
  1783. SpMemFree(DeviceMigrationContext.Buffer);
  1784. return;
  1785. }
  1786. VOID
  1787. SppMigrateDeviceParentIdCallback(
  1788. IN HANDLE SetupInstanceKeyHandle,
  1789. IN HANDLE UpgradeInstanceKeyHandle OPTIONAL,
  1790. IN BOOLEAN RootEnumerated,
  1791. IN OUT PVOID Context
  1792. )
  1793. /*++
  1794. Routine Description:
  1795. This routine is a callback routine for SpApplyFunctionToDeviceInstanceKeys.
  1796. Arguments:
  1797. SetupInstanceKeyHandle: Handle to the device instance key in the current
  1798. registry.
  1799. UpgradeInstanceKeyHandle: Handle to the corresponding device instance key in
  1800. the system being upgraded, if it exists.
  1801. Context: User supplied context.
  1802. Return Value:
  1803. None.
  1804. --*/
  1805. {
  1806. NTSTATUS Status;
  1807. OBJECT_ATTRIBUTES Obja;
  1808. UNICODE_STRING UnicodeString, guidString;
  1809. PDEVICE_MIGRATION_CONTEXT DeviceMigrationContext;
  1810. PUCHAR p;
  1811. ULONG ResultLength, drvInst;
  1812. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  1813. HANDLE hClassKey, hDriverKey;
  1814. BOOL CallbackResult;
  1815. UNREFERENCED_PARAMETER(SetupInstanceKeyHandle);
  1816. UNREFERENCED_PARAMETER(RootEnumerated);
  1817. //
  1818. // We only care about keys that exist in the system being upgraded.
  1819. //
  1820. if (!UpgradeInstanceKeyHandle) {
  1821. return;
  1822. }
  1823. //
  1824. // Retrieve the "Driver" value from the instance key.
  1825. //
  1826. DeviceMigrationContext = (PDEVICE_MIGRATION_CONTEXT)Context;
  1827. p = ALIGN_UP_POINTER(((PUCHAR)DeviceMigrationContext->Buffer), sizeof(LARGE_INTEGER));
  1828. //
  1829. // First check the old style "Driver" value.
  1830. //
  1831. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)p;
  1832. RtlInitUnicodeString(&UnicodeString, REGSTR_VAL_DRIVER);
  1833. Status = ZwQueryValueKey(UpgradeInstanceKeyHandle,
  1834. &UnicodeString,
  1835. KeyValuePartialInformation,
  1836. p,
  1837. (ULONG)((DeviceMigrationContext->Buffer +
  1838. DeviceMigrationContext->BufferSize) - p),
  1839. &ResultLength
  1840. );
  1841. if (!NT_SUCCESS(Status) || KeyValueInfo->Type != REG_SZ) {
  1842. //
  1843. // Try the new style "GUID" and "DrvInst" values.
  1844. //
  1845. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)p;
  1846. RtlInitUnicodeString(&UnicodeString, REGSTR_VALUE_GUID);
  1847. Status = ZwQueryValueKey(UpgradeInstanceKeyHandle,
  1848. &UnicodeString,
  1849. KeyValuePartialInformation,
  1850. p,
  1851. (ULONG)((DeviceMigrationContext->Buffer +
  1852. DeviceMigrationContext->BufferSize) - p),
  1853. &ResultLength
  1854. );
  1855. if (!NT_SUCCESS(Status) || KeyValueInfo->Type != REG_BINARY) {
  1856. return;
  1857. }
  1858. Status = RtlStringFromGUID((REFGUID)KeyValueInfo->Data, &guidString);
  1859. ASSERT(NT_SUCCESS(Status));
  1860. if (!NT_SUCCESS(Status)) {
  1861. return;
  1862. }
  1863. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)p;
  1864. RtlInitUnicodeString(&UnicodeString, REGSTR_VALUE_DRVINST);
  1865. Status = ZwQueryValueKey(UpgradeInstanceKeyHandle,
  1866. &UnicodeString,
  1867. KeyValuePartialInformation,
  1868. p,
  1869. (ULONG)((DeviceMigrationContext->Buffer +
  1870. DeviceMigrationContext->BufferSize) - p),
  1871. &ResultLength
  1872. );
  1873. if (!NT_SUCCESS(Status) || KeyValueInfo->Type != REG_DWORD) {
  1874. return;
  1875. }
  1876. drvInst = *(PULONG)KeyValueInfo->Data;
  1877. swprintf((PWCHAR)&KeyValueInfo->Data[0], TEXT("%wZ\\%04u"), &guidString, drvInst);
  1878. RtlFreeUnicodeString(&guidString);
  1879. }
  1880. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1881. "SETUP: SppMigrateDeviceParentIdCallback: Driver = %ws\n",
  1882. (PWSTR)KeyValueInfo->Data));
  1883. //
  1884. // Open the Control\Class key in the system being upgraded.
  1885. //
  1886. INIT_OBJA(&Obja, &UnicodeString, L"Control\\Class");
  1887. Obja.RootDirectory = DeviceMigrationContext->hKeyCCSet;
  1888. Status = ZwOpenKey(&hClassKey, KEY_ALL_ACCESS, &Obja);
  1889. if(!NT_SUCCESS(Status)) {
  1890. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1891. "SETUP: Unable to open Class key for device migration processing. Status = %lx \n",
  1892. Status));
  1893. return;
  1894. }
  1895. //
  1896. // Open the device's "Driver" key.
  1897. //
  1898. INIT_OBJA(&Obja, &UnicodeString, (PWSTR)KeyValueInfo->Data);
  1899. Obja.RootDirectory = hClassKey;
  1900. Status = ZwOpenKey(&hDriverKey, KEY_ALL_ACCESS, &Obja);
  1901. ZwClose(hClassKey);
  1902. if(!NT_SUCCESS(Status)) {
  1903. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1904. "SETUP: Unable to open Class\\%ws key for device migration processing. Status = %lx \n",
  1905. (PWSTR)KeyValueInfo->Data,
  1906. Status));
  1907. return;
  1908. }
  1909. //
  1910. // Call the specified device migration callback routine.
  1911. //
  1912. CallbackResult = (DeviceMigrationContext->DeviceMigrationCallbackRoutine)(
  1913. UpgradeInstanceKeyHandle,
  1914. hDriverKey);
  1915. ZwClose(hDriverKey);
  1916. if (!CallbackResult) {
  1917. return;
  1918. }
  1919. //
  1920. // Replace the UniqueParentID or ParentIdPrefix values for this device
  1921. // instance. First, remove any UniqueParentId or ParentIdPrefix values that
  1922. // already exist for this instance key.
  1923. //
  1924. RtlInitUnicodeString(&UnicodeString, L"ParentIdPrefix");
  1925. ZwDeleteValueKey(UpgradeInstanceKeyHandle, &UnicodeString);
  1926. RtlInitUnicodeString(&UnicodeString, L"UniqueParentID");
  1927. ZwDeleteValueKey(UpgradeInstanceKeyHandle, &UnicodeString);
  1928. //
  1929. // Replace the instance key's UniqueParentID or ParentIdPrefix with that
  1930. // from the device migration context.
  1931. //
  1932. if (!DeviceMigrationContext->ParentIdPrefix) {
  1933. //
  1934. // We're using the old UniqueParentID mechanism.
  1935. //
  1936. RtlInitUnicodeString(&UnicodeString, L"UniqueParentID");
  1937. Status = ZwSetValueKey(UpgradeInstanceKeyHandle,
  1938. &UnicodeString,
  1939. 0,
  1940. REG_DWORD,
  1941. &DeviceMigrationContext->UniqueParentID,
  1942. sizeof(DeviceMigrationContext->UniqueParentID));
  1943. if (!NT_SUCCESS(Status)) {
  1944. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1945. "SETUP: Unable to set %ws during device migration processing. Status = %lx \n",
  1946. UnicodeString.Buffer,
  1947. Status));
  1948. }
  1949. } else {
  1950. //
  1951. // We're using the ParentIdPrefix mechanism.
  1952. //
  1953. RtlInitUnicodeString(&UnicodeString, L"ParentIdPrefix");
  1954. Status = ZwSetValueKey(UpgradeInstanceKeyHandle,
  1955. &UnicodeString,
  1956. 0,
  1957. REG_SZ,
  1958. DeviceMigrationContext->ParentIdPrefix,
  1959. (wcslen(DeviceMigrationContext->ParentIdPrefix)+1)*sizeof(WCHAR));
  1960. if (!NT_SUCCESS(Status)) {
  1961. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1962. "SETUP: Unable to set %ws during device migration processing. Status = %lx \n",
  1963. UnicodeString.Buffer,
  1964. Status));
  1965. }
  1966. }
  1967. return;
  1968. }
  1969. BOOL
  1970. SppParallelClassCallback(
  1971. IN HANDLE InstanceKeyHandle,
  1972. IN HANDLE DriverKeyHandle
  1973. )
  1974. /*++
  1975. Routine Description:
  1976. This routine is a callback routine for SpApplyFunctionToDeviceInstanceKeys.
  1977. Arguments:
  1978. InstanceKeyHandle: Handle to the device instance key in the system being
  1979. upgraded.
  1980. DriverKeyHandle: Handle to the driver key for device instance in
  1981. the system being upgraded.
  1982. Return Value:
  1983. Returns TRUE/FALSE.
  1984. --*/
  1985. {
  1986. NTSTATUS Status;
  1987. OBJECT_ATTRIBUTES Obja;
  1988. PUCHAR MyScratchBuffer;
  1989. ULONG MyScratchBufferSize;
  1990. PUCHAR p;
  1991. ULONG ResultLength;
  1992. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  1993. HANDLE hClassKey, hDriverKey;
  1994. UNICODE_STRING UnicodeString;
  1995. GUID guid;
  1996. //
  1997. // Allocate some scratch space to work with. The most we'll need is enough
  1998. // for a KEY_VALUE_PARTIAL_INFORMATION structure, plus a stringified GUID,
  1999. // plus a large integer structure for alignment.
  2000. //
  2001. MyScratchBufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
  2002. (GUID_STRING_LEN * sizeof(WCHAR)) +
  2003. sizeof(LARGE_INTEGER);
  2004. MyScratchBuffer = SpMemAlloc(MyScratchBufferSize);
  2005. if(!MyScratchBuffer) {
  2006. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2007. "SETUP: Can't allocate memory for parallel migration processing!\n"));
  2008. return FALSE;
  2009. }
  2010. //
  2011. // Check the class of the enumerated device instance, and see if it is a
  2012. // member of the "Ports" class.
  2013. //
  2014. p = ALIGN_UP_POINTER(((PUCHAR)MyScratchBuffer), sizeof(LARGE_INTEGER));
  2015. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)p;
  2016. RtlInitUnicodeString(&UnicodeString, REGSTR_VAL_CLASSGUID);
  2017. Status = ZwQueryValueKey(InstanceKeyHandle,
  2018. &UnicodeString,
  2019. KeyValuePartialInformation,
  2020. p,
  2021. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - p),
  2022. &ResultLength);
  2023. if (NT_SUCCESS(Status)) {
  2024. if (KeyValueInfo->Type == REG_SZ) {
  2025. RtlInitUnicodeString(&UnicodeString, (PWSTR)KeyValueInfo->Data);
  2026. Status = RtlGUIDFromString(&UnicodeString, &guid);
  2027. } else {
  2028. Status = STATUS_UNSUCCESSFUL;
  2029. }
  2030. } else {
  2031. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)p;
  2032. RtlInitUnicodeString(&UnicodeString, REGSTR_VALUE_GUID);
  2033. Status = ZwQueryValueKey(InstanceKeyHandle,
  2034. &UnicodeString,
  2035. KeyValuePartialInformation,
  2036. p,
  2037. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - p),
  2038. &ResultLength);
  2039. if (NT_SUCCESS(Status)) {
  2040. if (KeyValueInfo->Type == REG_BINARY) {
  2041. guid = *(GUID *)KeyValueInfo->Data;
  2042. } else {
  2043. Status = STATUS_UNSUCCESSFUL;
  2044. }
  2045. }
  2046. }
  2047. if (NT_SUCCESS(Status)) {
  2048. if (!IsEqualGUID(&GUID_DEVCLASS_PORTS, &guid)) {
  2049. //
  2050. // Not a match.
  2051. //
  2052. Status = STATUS_UNSUCCESSFUL;
  2053. }
  2054. }
  2055. if (!NT_SUCCESS(Status)) {
  2056. return FALSE;
  2057. }
  2058. //
  2059. // Check the "PortSubClass" value from the device's driver key.
  2060. //
  2061. RtlInitUnicodeString(&UnicodeString, REGSTR_VAL_PORTSUBCLASS);
  2062. Status = ZwQueryValueKey(DriverKeyHandle,
  2063. &UnicodeString,
  2064. KeyValuePartialInformation,
  2065. p,
  2066. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - p),
  2067. &ResultLength);
  2068. if (!NT_SUCCESS(Status) ||
  2069. (KeyValueInfo->Type != REG_BINARY) ||
  2070. (KeyValueInfo->DataLength != sizeof(BYTE)) ||
  2071. (*(PBYTE)(KeyValueInfo->Data) != 0x0)) {
  2072. return FALSE;
  2073. }
  2074. //
  2075. // This device instance is a parallel port device.
  2076. //
  2077. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2078. "SETUP: \tSppParallelClassCallback: Found a parallel port!\n"));
  2079. return TRUE;
  2080. }
  2081. VOID
  2082. SppClearMigratedInstanceValuesCallback(
  2083. IN HANDLE SetupInstanceKeyHandle,
  2084. IN HANDLE UpgradeInstanceKeyHandle OPTIONAL,
  2085. IN BOOLEAN RootEnumerated,
  2086. IN OUT PVOID Context
  2087. )
  2088. /*++
  2089. Routine Description:
  2090. This routine is a callback routine for SpApplyFunctionToDeviceInstanceKeys.
  2091. Arguments:
  2092. SetupInstanceKeyHandle: Handle to the device instance key in the current
  2093. registry.
  2094. UpgradeInstanceKeyHandle: Handle to the corresponding device instance key in
  2095. the system being upgraded, if it exists.
  2096. Context: User supplied context.
  2097. Return Value:
  2098. None.
  2099. --*/
  2100. {
  2101. NTSTATUS Status;
  2102. UNICODE_STRING UnicodeString;
  2103. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  2104. PUCHAR p;
  2105. ULONG ResultLength;
  2106. PGENERIC_BUFFER_CONTEXT BufferContext;
  2107. //
  2108. // To save us the effort of allocating a buffer on every iteration of the
  2109. // callback, SppClearMigratedInstanceValues has already allocated a buffer
  2110. // for us to use, and supplied to us as our context.
  2111. //
  2112. BufferContext = (PGENERIC_BUFFER_CONTEXT)Context;
  2113. ASSERT(BufferContext->Buffer);
  2114. ASSERT(BufferContext->BufferSize > 0);
  2115. //
  2116. // Check if the Migrated value still exists on this registry key. If so, it
  2117. // was migrated, but wasn't seen by textmode setup.
  2118. //
  2119. p = ALIGN_UP_POINTER(((PUCHAR)BufferContext->Buffer), sizeof(LARGE_INTEGER));
  2120. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)p;
  2121. RtlInitUnicodeString(&UnicodeString, L"Migrated");
  2122. Status = ZwQueryValueKey(SetupInstanceKeyHandle,
  2123. &UnicodeString,
  2124. KeyValuePartialInformation,
  2125. p,
  2126. (ULONG)(BufferContext->BufferSize),
  2127. &ResultLength);
  2128. if (NT_SUCCESS(Status)) {
  2129. //
  2130. // If there is a Migrated value, it should be well-formed, but we still
  2131. // want to delete it no matter what it is.
  2132. //
  2133. ASSERT(KeyValueInfo->Type == REG_DWORD);
  2134. ASSERT(*(PULONG)(KeyValueInfo->Data) == 1);
  2135. if (UpgradeInstanceKeyHandle) {
  2136. //
  2137. // This instance key exists in the upgraded registry, so we'll
  2138. // remove the Migrated value from it in the setup registry.
  2139. //
  2140. Status = ZwDeleteValueKey(SetupInstanceKeyHandle, &UnicodeString);
  2141. ASSERT(NT_SUCCESS(Status));
  2142. //
  2143. // Remove the migrated value from the key in the upgraded registry
  2144. // only if it is root-enumerated, because those devices should
  2145. // always be enumerated, no matter what.
  2146. //
  2147. // (If the instance key is not root-enumerated, the value should
  2148. // really stay as it is - so that migrated values on ASR machines
  2149. // are preserved on upgrades.)
  2150. //
  2151. if (RootEnumerated) {
  2152. ZwDeleteValueKey(UpgradeInstanceKeyHandle, &UnicodeString);
  2153. }
  2154. }
  2155. }
  2156. return;
  2157. }
  2158. VOID
  2159. SpApplyFunctionToDeviceInstanceKeys(
  2160. IN HANDLE hKeyCCSet,
  2161. IN PSPP_INSTANCEKEY_CALLBACK_ROUTINE InstanceKeyCallbackRoutine,
  2162. IN OUT PVOID Context
  2163. )
  2164. /*++
  2165. Routine Description:
  2166. This routine enumerates device instance keys in the setup registry, and
  2167. calls the specified callback routine for each such device instance key.
  2168. Arguments:
  2169. hKeyCCSet: Handle to the root of the control set in the system
  2170. being upgraded.
  2171. InstanceKeyCallbackRoutine - Supplies a pointer to a function that will be
  2172. called for each device instance key in the setup registry.
  2173. The prototype of the function is as follows:
  2174. typedef VOID (*PSPP_INSTANCEKEY_CALLBACK_ROUTINE) (
  2175. IN HANDLE SetupInstanceKeyHandle,
  2176. IN HANDLE UpgradeInstanceKeyHandle OPTIONAL,
  2177. IN BOOLEAN RootEnumerated,
  2178. IN OUT PVOID Context
  2179. );
  2180. where SetupInstanceKeyHandle is the handle to an enumerated device
  2181. instance key in the setup registry, UpgradeInstanceKeyHandle is the
  2182. handle to the corresponding device instance key in the registry being
  2183. upgraded (if exists), and Context is a pointer to user-defined data.
  2184. Return Value:
  2185. None.
  2186. Note:
  2187. Note that a device instance key in the system being upgraded is opened only
  2188. after the corresponding device instance key was enumerated in the setup
  2189. registry.
  2190. --*/
  2191. {
  2192. NTSTATUS Status;
  2193. HANDLE hEnumKey, hEnumeratorKey, hDeviceKey, hInstanceKey;
  2194. HANDLE hUpgradeEnumKey, hUpgradeEnumeratorKey, hUpgradeDeviceKey, hUpgradeInstanceKey;
  2195. BOOLEAN RootEnumerated;
  2196. OBJECT_ATTRIBUTES Obja;
  2197. UNICODE_STRING UnicodeString;
  2198. PUCHAR MyScratchBuffer;
  2199. ULONG MyScratchBufferSize;
  2200. ULONG EnumeratorKeyIndex, DeviceKeyIndex, InstanceKeyIndex, ResultLength;
  2201. PKEY_BASIC_INFORMATION EnumeratorKeyInfo, DeviceKeyInfo, InstanceKeyInfo;
  2202. PUCHAR p, q, r;
  2203. //
  2204. // First, open CCS\Enum in the setup registry.
  2205. //
  2206. INIT_OBJA(&Obja, &UnicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum");
  2207. Obja.RootDirectory = NULL;
  2208. Status = ZwOpenKey(&hEnumKey, KEY_ALL_ACCESS, &Obja);
  2209. if(!NT_SUCCESS(Status)) {
  2210. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2211. "SETUP: Unable to open setup Enum for device migration processing. Status = %lx \n",
  2212. Status));
  2213. return;
  2214. }
  2215. //
  2216. // Next, open CCS\Enum in the registry being upgraded.
  2217. //
  2218. INIT_OBJA(&Obja, &UnicodeString, L"Enum");
  2219. Obja.RootDirectory = hKeyCCSet;
  2220. Status = ZwOpenKey(&hUpgradeEnumKey, KEY_ALL_ACCESS, &Obja);
  2221. if (!NT_SUCCESS(Status)) {
  2222. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2223. "SETUP: Unable to open upgrade Enum for device migration processing. Status = %lx \n",
  2224. Status));
  2225. //
  2226. // This is really odd, but not fatal.
  2227. //
  2228. hUpgradeEnumKey = NULL;
  2229. }
  2230. //
  2231. // Allocate some scratch space to work with. The most we'll need is enough
  2232. // for 3 KEY_BASIC_INFORMATION structures, plus the maximum length of a
  2233. // device instance ID, plus 3 large integer structures for alignment.
  2234. //
  2235. MyScratchBufferSize = (3*sizeof(KEY_BASIC_INFORMATION)) +
  2236. (200*sizeof(WCHAR)) +
  2237. (3*sizeof(LARGE_INTEGER));
  2238. MyScratchBuffer = SpMemAlloc(MyScratchBufferSize);
  2239. if(!MyScratchBuffer) {
  2240. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2241. "SETUP: Can't allocate memory for device migration processing!\n"));
  2242. ZwClose(hEnumKey);
  2243. return;
  2244. }
  2245. //
  2246. // First, enumerate the enumerator subkeys under the Enum key.
  2247. //
  2248. EnumeratorKeyInfo = (PKEY_BASIC_INFORMATION)MyScratchBuffer;
  2249. EnumeratorKeyIndex = 0;
  2250. while(TRUE) {
  2251. Status = ZwEnumerateKey(hEnumKey,
  2252. EnumeratorKeyIndex,
  2253. KeyBasicInformation,
  2254. MyScratchBuffer,
  2255. MyScratchBufferSize,
  2256. &ResultLength);
  2257. if(!NT_SUCCESS(Status)) {
  2258. break;
  2259. }
  2260. //
  2261. // Zero-terminate the subkey name just in case.
  2262. //
  2263. EnumeratorKeyInfo->Name[EnumeratorKeyInfo->NameLength/sizeof(WCHAR)] = 0;
  2264. //
  2265. // Go ahead and bump the used-buffer length by sizeof(WCHAR), to
  2266. // accomodate the potential growth caused by adding a terminating NULL.
  2267. //
  2268. ResultLength += sizeof(WCHAR);
  2269. //
  2270. // Determine if the subkey devices are root-enumerated.
  2271. //
  2272. RootEnumerated = (_wcsnicmp(EnumeratorKeyInfo->Name,
  2273. REGSTR_KEY_ROOTENUM, 4) == 0);
  2274. //
  2275. // Now, open up the enumerator key so we can enumerate the devices.
  2276. //
  2277. INIT_OBJA(&Obja, &UnicodeString, EnumeratorKeyInfo->Name);
  2278. Obja.RootDirectory = hEnumKey;
  2279. Status = ZwOpenKey(&hEnumeratorKey, KEY_ALL_ACCESS, &Obja);
  2280. if(!NT_SUCCESS(Status)) {
  2281. //
  2282. // Skip this key and continue.
  2283. //
  2284. EnumeratorKeyIndex++;
  2285. continue;
  2286. }
  2287. //
  2288. // Open the enumerator key in the registry being upgraded.
  2289. //
  2290. hUpgradeEnumeratorKey = NULL;
  2291. if (hUpgradeEnumKey) {
  2292. Obja.RootDirectory = hUpgradeEnumKey;
  2293. Status = ZwOpenKey(&hUpgradeEnumeratorKey, KEY_ALL_ACCESS, &Obja);
  2294. if(!NT_SUCCESS(Status)) {
  2295. //
  2296. // Again, this is odd, but not fatal.
  2297. //
  2298. hUpgradeEnumeratorKey = NULL;
  2299. }
  2300. }
  2301. //
  2302. // Now enumerate the device subkeys under this enumerator key. Don't
  2303. // overwrite the enumerator key name already in MyScratchBuffer.
  2304. //
  2305. p = ALIGN_UP_POINTER(((PUCHAR)MyScratchBuffer + ResultLength), sizeof(LARGE_INTEGER));
  2306. //
  2307. // Now, enumerate all devices under the enumerator.
  2308. //
  2309. DeviceKeyInfo = (PKEY_BASIC_INFORMATION)p;
  2310. DeviceKeyIndex = 0;
  2311. while(TRUE) {
  2312. Status = ZwEnumerateKey(hEnumeratorKey,
  2313. DeviceKeyIndex,
  2314. KeyBasicInformation,
  2315. p,
  2316. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - p),
  2317. &ResultLength);
  2318. if(!NT_SUCCESS(Status)) {
  2319. break;
  2320. }
  2321. //
  2322. // Zero-terminate the subkey name just in case.
  2323. //
  2324. DeviceKeyInfo->Name[DeviceKeyInfo->NameLength/sizeof(WCHAR)] = 0;
  2325. //
  2326. // Go ahead and bump the used-buffer length by sizeof(WCHAR), to
  2327. // accomodate the potential growth caused by adding a terminating NULL.
  2328. //
  2329. ResultLength += sizeof(WCHAR);
  2330. //
  2331. // Now, open up the device key so we can enumerate the instances.
  2332. //
  2333. INIT_OBJA(&Obja, &UnicodeString, DeviceKeyInfo->Name);
  2334. Obja.RootDirectory = hEnumeratorKey;
  2335. Status = ZwOpenKey(&hDeviceKey, KEY_ALL_ACCESS, &Obja);
  2336. if(!NT_SUCCESS(Status)) {
  2337. //
  2338. // Skip this key and continue.
  2339. //
  2340. DeviceKeyIndex++;
  2341. continue;
  2342. }
  2343. //
  2344. // Open the device key in the registry being upgraded.
  2345. //
  2346. hUpgradeDeviceKey = NULL;
  2347. if (hUpgradeEnumeratorKey) {
  2348. Obja.RootDirectory = hUpgradeEnumeratorKey;
  2349. Status = ZwOpenKey(&hUpgradeDeviceKey, KEY_ALL_ACCESS, &Obja);
  2350. if(!NT_SUCCESS(Status)) {
  2351. //
  2352. // Again, this is odd, but not fatal.
  2353. //
  2354. hUpgradeDeviceKey = NULL;
  2355. }
  2356. }
  2357. //
  2358. // Now enumerate the device subkeys under this enumerator key. Don't
  2359. // overwrite the enumerator key name already in MyScratchBuffer.
  2360. //
  2361. q = ALIGN_UP_POINTER(((PUCHAR)p + ResultLength), sizeof(LARGE_INTEGER));
  2362. //
  2363. // Now, enumerate all instances under the device.
  2364. //
  2365. InstanceKeyInfo = (PKEY_BASIC_INFORMATION)q;
  2366. InstanceKeyIndex = 0;
  2367. while(TRUE) {
  2368. Status = ZwEnumerateKey(hDeviceKey,
  2369. InstanceKeyIndex,
  2370. KeyBasicInformation,
  2371. q,
  2372. (ULONG)((MyScratchBuffer + MyScratchBufferSize) - q),
  2373. &ResultLength);
  2374. if(!NT_SUCCESS(Status)) {
  2375. break;
  2376. }
  2377. //
  2378. // Zero-terminate the subkey name just in case.
  2379. //
  2380. InstanceKeyInfo->Name[InstanceKeyInfo->NameLength/sizeof(WCHAR)] = 0;
  2381. //
  2382. // Go ahead and bump the used-buffer length by sizeof(WCHAR), to
  2383. // accomodate the potential growth caused by adding a terminating NULL.
  2384. //
  2385. ResultLength += sizeof(WCHAR);
  2386. //
  2387. // Now, open up the instance key.
  2388. //
  2389. INIT_OBJA(&Obja, &UnicodeString, InstanceKeyInfo->Name);
  2390. Obja.RootDirectory = hDeviceKey;
  2391. Status = ZwOpenKey(&hInstanceKey, KEY_ALL_ACCESS, &Obja);
  2392. if(!NT_SUCCESS(Status)) {
  2393. //
  2394. // Skip this key and continue.
  2395. //
  2396. InstanceKeyIndex++;
  2397. continue;
  2398. }
  2399. //
  2400. // Open the instance key in the registry being upgraded.
  2401. //
  2402. hUpgradeInstanceKey = NULL;
  2403. if (hUpgradeDeviceKey) {
  2404. Obja.RootDirectory = hUpgradeDeviceKey;
  2405. Status = ZwOpenKey(&hUpgradeInstanceKey, KEY_ALL_ACCESS, &Obja);
  2406. if(!NT_SUCCESS(Status)) {
  2407. //
  2408. // Again, this is odd, but not fatal.
  2409. //
  2410. hUpgradeInstanceKey = NULL;
  2411. }
  2412. }
  2413. //
  2414. // Call the specified callback routine for this device instance key.
  2415. //
  2416. InstanceKeyCallbackRoutine(hInstanceKey,
  2417. hUpgradeInstanceKey,
  2418. RootEnumerated,
  2419. Context);
  2420. InstanceKeyIndex++;
  2421. ZwClose(hInstanceKey);
  2422. if (hUpgradeInstanceKey) {
  2423. ZwClose(hUpgradeInstanceKey);
  2424. }
  2425. }
  2426. DeviceKeyIndex++;
  2427. ZwClose(hDeviceKey);
  2428. if (hUpgradeDeviceKey) {
  2429. ZwClose(hUpgradeDeviceKey);
  2430. }
  2431. }
  2432. EnumeratorKeyIndex++;
  2433. ZwClose(hEnumeratorKey);
  2434. if (hUpgradeEnumeratorKey) {
  2435. ZwClose(hUpgradeEnumeratorKey);
  2436. }
  2437. }
  2438. ZwClose(hEnumKey);
  2439. if (hUpgradeEnumKey) {
  2440. ZwClose(hUpgradeEnumKey);
  2441. }
  2442. SpMemFree(MyScratchBuffer);
  2443. return;
  2444. }
  2445. BOOLEAN
  2446. SppEnsureHardwareProfileIsPresent(
  2447. IN HANDLE hKeyCCSet
  2448. )
  2449. /*++
  2450. Routine Description:
  2451. This routine checks for the presence of the presence of the following keys:
  2452. HKLM\System\CurrentControlSet\Control\IDConfigDB\Hardware Profiles
  2453. HKLM\System\CurrentControlSet\Hardware Profiles
  2454. If these keys exist, it checks the profile information subkeys under
  2455. IDConfigDB for a "Pristine Profile".
  2456. If the Pristine Profile is not in the proper NT5 format, that is
  2457. under the \0000 subkey, with a PreferenceOrder == -1 and Pristine == 1,
  2458. then it is deleted, and we rely on a valid pristine profile with
  2459. these settings to be migrated from the SETUPREG.HIV. We then re-order
  2460. the PreferenceOrder values for the remaining hardware profiles, and
  2461. make sure sure each has a HwProfileGuid.
  2462. If a valid Pristine profile is found, it is not removed, and will
  2463. not be replaced during migration.
  2464. If one of either the CCS\Control\IDConfigDB\Hardware Profiles key, or
  2465. the CCS\Hardware Profiles keys is missing, then the set of hardware
  2466. profiles is invalid, and both keys will be removed and migrated from
  2467. the SETUPREG.HIV.
  2468. Arguments:
  2469. hKeyCCSet - Handle to the root of the control set in the system
  2470. being upgraded.
  2471. Return Value:
  2472. If successful, the return value is TRUE, otherwise it is FALSE.
  2473. --*/
  2474. {
  2475. OBJECT_ATTRIBUTES ObjaID, ObjaHw;
  2476. UNICODE_STRING UnicodeString, TempString, UnicodeValueName;
  2477. UNICODE_STRING UnicodeKeyName, GuidString, UnicodeLabel;
  2478. NTSTATUS Status;
  2479. HANDLE IDConfigProfiles=NULL, IDConfigEntry=NULL;
  2480. HANDLE HwProfiles=NULL, HwProfileEntry=NULL;
  2481. ULONG profileNumber;
  2482. ULONG len;
  2483. PWSTR SubkeyName;
  2484. ULONG ValueBufferSize;
  2485. BOOLEAN b = TRUE;
  2486. BOOLEAN ReOrder = FALSE, bKeyNameIs0000 = FALSE;
  2487. ULONG pristinePreferenceOrder, preferenceOrder;
  2488. ULONG enumIndex, resultLength;
  2489. ULONG nameIndex, dockState;
  2490. UUID uuid;
  2491. PKEY_BASIC_INFORMATION pKeyInfo;
  2492. PKEY_VALUE_FULL_INFORMATION pValueInfo;
  2493. //
  2494. // Initialize Object Attributes for Hardware profile specific keys
  2495. //
  2496. INIT_OBJA(&ObjaID, &UnicodeString, L"Control\\IDConfigDB\\Hardware Profiles");
  2497. ObjaID.RootDirectory = hKeyCCSet;
  2498. INIT_OBJA(&ObjaHw, &TempString, L"Hardware Profiles");
  2499. ObjaHw.RootDirectory = hKeyCCSet;
  2500. //
  2501. // Attempt to open "CCS\Control\IDConfigDB\Hardware Profiles"
  2502. // and "CCS\Hardware Profiles" keys.
  2503. // If either key is missing, this is an inconsistent state;
  2504. // make sure neither key is present and rely on the migration of these
  2505. // keys from SETUPREG.HIV to provide the basic state (pristine only).
  2506. //
  2507. if ((ZwOpenKey(&IDConfigProfiles,
  2508. KEY_READ | KEY_WRITE,
  2509. &ObjaID) != STATUS_SUCCESS) ||
  2510. (ZwOpenKey(&HwProfiles,
  2511. KEY_READ | KEY_WRITE,
  2512. &ObjaHw) != STATUS_SUCCESS)) {
  2513. SppDeleteKeyRecursive(hKeyCCSet, UnicodeString.Buffer, TRUE);
  2514. SppDeleteKeyRecursive(hKeyCCSet, TempString.Buffer, TRUE);
  2515. goto Clean;
  2516. }
  2517. //
  2518. // Look for the pristine profile.
  2519. //
  2520. enumIndex = 0;
  2521. while(TRUE) {
  2522. //
  2523. //Enumerate through each Profile Key
  2524. //
  2525. Status = ZwEnumerateKey(IDConfigProfiles,
  2526. enumIndex,
  2527. KeyBasicInformation,
  2528. TemporaryBuffer,
  2529. sizeof(TemporaryBuffer),
  2530. &resultLength);
  2531. if(!NT_SUCCESS(Status)) {
  2532. //
  2533. // couldn't enumerate subkeys
  2534. //
  2535. if(Status == STATUS_NO_MORE_ENTRIES) {
  2536. Status = STATUS_SUCCESS;
  2537. }
  2538. else {
  2539. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ** Unable to enumerate existing Hardware Profiles (%lx)\n", Status));
  2540. b = FALSE;
  2541. }
  2542. break;
  2543. }
  2544. //
  2545. // Zero-terminate the subkey name just in case.
  2546. //
  2547. pKeyInfo = (PKEY_BASIC_INFORMATION)TemporaryBuffer;
  2548. pKeyInfo->Name[pKeyInfo->NameLength/sizeof(WCHAR)] = UNICODE_NULL;
  2549. SubkeyName = SpDupStringW(pKeyInfo->Name);
  2550. RtlInitUnicodeString(&UnicodeKeyName, SubkeyName);
  2551. //
  2552. // See if this Profile is occupying the space the Pristine Profile should
  2553. // occupy. We'll check to see if it is really the Pristine Profile later.
  2554. //
  2555. Status = RtlUnicodeStringToInteger( &UnicodeKeyName, 10, &profileNumber );
  2556. if (!NT_SUCCESS(Status)) {
  2557. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Could not get integer profile number for key %ws (%lx)\n",
  2558. UnicodeKeyName.Buffer,Status));
  2559. bKeyNameIs0000 = FALSE;
  2560. } else {
  2561. bKeyNameIs0000 = (profileNumber==0);
  2562. }
  2563. //
  2564. // Open the subkey
  2565. //
  2566. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Checking Profile Key %ws (%lx)\n",UnicodeKeyName.Buffer,Status));
  2567. InitializeObjectAttributes (&ObjaID,
  2568. &UnicodeKeyName,
  2569. OBJ_CASE_INSENSITIVE,
  2570. IDConfigProfiles,
  2571. NULL);
  2572. Status = ZwOpenKey(&IDConfigEntry,
  2573. KEY_ALL_ACCESS,
  2574. &ObjaID);
  2575. if (!NT_SUCCESS(Status)) {
  2576. //
  2577. // Couldn't open this particular profile key, just log
  2578. // it and check the others, shouldn't stop Setup here.
  2579. //
  2580. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ** Unable to open enumerated Hardware Profile key %ws (%lx)\n",
  2581. UnicodeKeyName.Buffer, Status));
  2582. SpMemFree(SubkeyName);
  2583. enumIndex++;
  2584. continue;
  2585. }
  2586. //
  2587. // Look for the Pristine Entry
  2588. //
  2589. RtlInitUnicodeString(&UnicodeValueName, L"Pristine");
  2590. Status = ZwQueryValueKey(IDConfigEntry,
  2591. &UnicodeValueName,
  2592. KeyValueFullInformation,
  2593. TemporaryBuffer,
  2594. sizeof(TemporaryBuffer),
  2595. &resultLength);
  2596. pValueInfo = (PKEY_VALUE_FULL_INFORMATION)TemporaryBuffer;
  2597. if (NT_SUCCESS(Status) && (pValueInfo->Type == REG_DWORD) &&
  2598. (* (PULONG) ((PUCHAR)pValueInfo + pValueInfo->DataOffset))) {
  2599. //
  2600. // Found the Pristine Entry, now find its PreferenceOrder
  2601. //
  2602. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Found what appears to be a Pristine profile (%lx)\n",Status));
  2603. RtlInitUnicodeString(&UnicodeValueName, REGSTR_VAL_PREFERENCEORDER);
  2604. Status = ZwQueryValueKey(IDConfigEntry,
  2605. &UnicodeValueName,
  2606. KeyValueFullInformation,
  2607. TemporaryBuffer,
  2608. sizeof(TemporaryBuffer),
  2609. &resultLength);
  2610. if(NT_SUCCESS(Status) && (pValueInfo->Type == REG_DWORD)) {
  2611. //
  2612. // Found the PreferenceOrder of the Pristine;
  2613. // save it so we can fill in the gap left after we delete it.
  2614. //
  2615. pristinePreferenceOrder = (* (PULONG) ((PUCHAR)pValueInfo + pValueInfo->DataOffset));
  2616. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: PreferenceOrder of this Pristine == %u\n",
  2617. pristinePreferenceOrder));
  2618. //
  2619. // At most one Pristine Profile should ever be found and reordered,
  2620. // or else the reordering of profiles will not work properly.
  2621. //
  2622. ASSERT(!ReOrder);
  2623. if (bKeyNameIs0000 && (pristinePreferenceOrder == -1)) {
  2624. //
  2625. // This is a valid 0000 Pristine Profile Key, don't touch it.
  2626. //
  2627. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Key %ws is a valid pristine profile\n",
  2628. UnicodeKeyName.Buffer));
  2629. enumIndex++;
  2630. } else {
  2631. //
  2632. // This is an old-style Pristine Profile, delete it and the corresponding
  2633. // key under "CCS\Hardware Profiles", and rely on the Pristine Profile
  2634. // keys migrated from setupreg.hiv (as specified in txtsetup.sif)
  2635. //
  2636. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Key %ws is an invalid pristine profile, deleteing this key.\n",
  2637. UnicodeKeyName.Buffer));
  2638. ReOrder = TRUE;
  2639. ZwDeleteKey(IDConfigEntry);
  2640. SppDeleteKeyRecursive(HwProfiles,
  2641. UnicodeKeyName.Buffer,
  2642. TRUE);
  2643. }
  2644. } else {
  2645. //
  2646. // An invalid Pristine config has no PreferenceOrder,
  2647. // Just delete it, and nobody should miss it.
  2648. //
  2649. ZwDeleteKey(IDConfigEntry);
  2650. SppDeleteKeyRecursive(HwProfiles,
  2651. UnicodeKeyName.Buffer,
  2652. TRUE);
  2653. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Invalid PreferenceOrder value for key %ws, deleting this key. (%lx)\n",
  2654. UnicodeKeyName.Buffer,Status));
  2655. }
  2656. } else {
  2657. //
  2658. // Not a Pristine Profile
  2659. //
  2660. if (bKeyNameIs0000) {
  2661. //
  2662. // We need to wipe out any non-Pristine Profiles currently occupying key \0000
  2663. // to make room for the new Pristine Profile that we'll migrate over later.
  2664. // (sorry, but nobody has any business being here in the first place.)
  2665. //
  2666. ZwDeleteKey(IDConfigEntry);
  2667. SppDeleteKeyRecursive(HwProfiles,
  2668. UnicodeKeyName.Buffer,
  2669. TRUE);
  2670. } else {
  2671. //
  2672. // Check that it has a PreferenceOrder
  2673. //
  2674. RtlInitUnicodeString(&UnicodeValueName, REGSTR_VAL_PREFERENCEORDER);
  2675. Status = ZwQueryValueKey(IDConfigEntry,
  2676. &UnicodeValueName,
  2677. KeyValueFullInformation,
  2678. TemporaryBuffer,
  2679. sizeof(TemporaryBuffer),
  2680. &resultLength);
  2681. if(!NT_SUCCESS(Status) || (pValueInfo->Type != REG_DWORD)) {
  2682. //
  2683. // Invalid or missing PreferenceOrder for this profile;
  2684. // Since this profile was most likely inaccessible anyways,
  2685. // just delete it and the corresponding entry under CCS\\Hardware Profiles.
  2686. //
  2687. ZwDeleteKey(IDConfigEntry);
  2688. SppDeleteKeyRecursive(HwProfiles,
  2689. UnicodeKeyName.Buffer,
  2690. TRUE);
  2691. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Invalid PreferenceOrder value for key %ws, deleting this key. (%lx)\n",
  2692. UnicodeKeyName.Buffer,Status));
  2693. } else {
  2694. //
  2695. // Make sure all profiles have a HwProfileGuid value.
  2696. //
  2697. RtlInitUnicodeString(&UnicodeValueName, L"HwProfileGuid");
  2698. Status = ZwQueryValueKey(IDConfigEntry,
  2699. &UnicodeValueName,
  2700. KeyValueFullInformation,
  2701. TemporaryBuffer,
  2702. sizeof(TemporaryBuffer),
  2703. &resultLength);
  2704. pValueInfo = (PKEY_VALUE_FULL_INFORMATION)TemporaryBuffer;
  2705. if (!NT_SUCCESS(Status) || (pValueInfo->Type != REG_SZ)) {
  2706. //
  2707. // Profile doesn't have a HwProfileGuid; make one up.
  2708. //
  2709. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Missing or invalid HwProfileGuid for Profile %ws, creating one (%lx)\n",
  2710. UnicodeKeyName.Buffer, Status));
  2711. Status = ExUuidCreate(&uuid);
  2712. if (NT_SUCCESS(Status)) {
  2713. Status = RtlStringFromGUID(&uuid, &GuidString);
  2714. ASSERT(NT_SUCCESS(Status));
  2715. if (NT_SUCCESS(Status)) {
  2716. Status = ZwSetValueKey(IDConfigEntry,
  2717. &UnicodeValueName,
  2718. 0,
  2719. REG_SZ,
  2720. GuidString.Buffer,
  2721. GuidString.Length + sizeof(UNICODE_NULL));
  2722. RtlFreeUnicodeString(&GuidString);
  2723. if(!NT_SUCCESS(Status)) {
  2724. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ** Unable to set HwProfileGuid value for key %ws, Status = (%lx)\n",
  2725. UnicodeKeyName.Buffer,Status));
  2726. }
  2727. } else {
  2728. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ** Unable to create string from GUID (Status = %lx)\n",
  2729. Status));
  2730. }
  2731. } else {
  2732. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ** Could not create a GUID for this profile (Status = %lx)\n",
  2733. Status));
  2734. }
  2735. }
  2736. //
  2737. // only raise enumIndex when we don't delete a key.
  2738. //
  2739. enumIndex++;
  2740. }
  2741. }
  2742. }
  2743. SpMemFree(SubkeyName);
  2744. ZwClose(IDConfigEntry);
  2745. IDConfigEntry = NULL;
  2746. }
  2747. //
  2748. // If we don't need to reorder any PreferenceOrder values, we're done.
  2749. //
  2750. if (!ReOrder) {
  2751. goto Clean;
  2752. }
  2753. //
  2754. // ReOrder PreferenceOrder values after deleting one
  2755. // to make up for the gap.
  2756. //
  2757. enumIndex = 0;
  2758. while(TRUE) {
  2759. //
  2760. //Enumerate through each Profile Key again
  2761. //
  2762. Status = ZwEnumerateKey(IDConfigProfiles,
  2763. enumIndex,
  2764. KeyBasicInformation,
  2765. TemporaryBuffer,
  2766. sizeof(TemporaryBuffer),
  2767. &resultLength);
  2768. if(!NT_SUCCESS(Status)) {
  2769. if(Status == STATUS_NO_MORE_ENTRIES) {
  2770. Status = STATUS_SUCCESS;
  2771. }
  2772. else {
  2773. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ** Unable to reorder remaining Hardware Profiles (%lx)\n", Status));
  2774. b = FALSE;
  2775. }
  2776. break;
  2777. }
  2778. //
  2779. // Zero-terminate the subkey name just in case.
  2780. //
  2781. pKeyInfo = (PKEY_BASIC_INFORMATION)TemporaryBuffer;
  2782. pKeyInfo->Name[pKeyInfo->NameLength/sizeof(WCHAR)] = UNICODE_NULL;
  2783. SubkeyName = SpDupStringW(pKeyInfo->Name);
  2784. RtlInitUnicodeString(&UnicodeKeyName, SubkeyName);
  2785. InitializeObjectAttributes (&ObjaID,
  2786. &UnicodeKeyName,
  2787. OBJ_CASE_INSENSITIVE,
  2788. IDConfigProfiles,
  2789. NULL);
  2790. Status = ZwOpenKey (&IDConfigEntry,
  2791. KEY_ALL_ACCESS,
  2792. &ObjaID);
  2793. if (!NT_SUCCESS(Status)) {
  2794. //
  2795. // Couldn't open this particular profile key, just log
  2796. // it and check the others, shouldn't stop Setup here.
  2797. //
  2798. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ** Unable to open enumerated Hardware Profile key %ws (%lx)\n",
  2799. UnicodeKeyName.Buffer, Status));
  2800. SpMemFree(SubkeyName);
  2801. enumIndex++;
  2802. continue;
  2803. }
  2804. pValueInfo = (PKEY_VALUE_FULL_INFORMATION)(TemporaryBuffer + (sizeof(TemporaryBuffer) / sizeof(WCHAR) / 2));
  2805. ValueBufferSize = sizeof(TemporaryBuffer) / 2;
  2806. //
  2807. // Get the PreferenceOrder for this profile
  2808. //
  2809. RtlInitUnicodeString(&UnicodeValueName, REGSTR_VAL_PREFERENCEORDER);
  2810. Status = ZwQueryValueKey(IDConfigEntry,
  2811. &UnicodeValueName,
  2812. KeyValueFullInformation,
  2813. pValueInfo,
  2814. ValueBufferSize,
  2815. &len);
  2816. if(NT_SUCCESS(Status) && (pValueInfo->Type == REG_DWORD)) {
  2817. //
  2818. // Got the Preference Order
  2819. //
  2820. ASSERT((* (PULONG) ((PUCHAR)pValueInfo + pValueInfo->DataOffset)) != pristinePreferenceOrder);
  2821. if (((* (PULONG) ((PUCHAR)pValueInfo + pValueInfo->DataOffset)) > pristinePreferenceOrder) &&
  2822. ((* (PULONG) ((PUCHAR)pValueInfo + pValueInfo->DataOffset)) != -1)) {
  2823. //
  2824. // Re-order PreferenceOrders for profiles other than a valid pristine,
  2825. // beyond deleted pristine up one.
  2826. //
  2827. preferenceOrder = (* (PULONG) ((PUCHAR)pValueInfo + pValueInfo->DataOffset)) - 1;
  2828. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: ReOrdering Profile %ws to PreferenceOrder %u\n",
  2829. UnicodeKeyName.Buffer,preferenceOrder));
  2830. Status = ZwSetValueKey(IDConfigEntry,
  2831. &UnicodeValueName,
  2832. 0,
  2833. REG_DWORD,
  2834. &preferenceOrder,
  2835. sizeof(preferenceOrder));
  2836. if(!NT_SUCCESS(Status)) {
  2837. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to change PreferenceOrder for Profile %ws, Status = (%lx)\n",
  2838. UnicodeKeyName.Buffer,Status));
  2839. b = FALSE;
  2840. }
  2841. }
  2842. } else {
  2843. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: *** Couldn't determine PreferenceOrder of profile %ws (%lx)\n",
  2844. UnicodeKeyName.Buffer,Status));
  2845. }
  2846. enumIndex++;
  2847. SpMemFree(SubkeyName);
  2848. ZwClose(IDConfigEntry);
  2849. IDConfigEntry = NULL;
  2850. }
  2851. Clean:
  2852. if (NULL != IDConfigProfiles) {
  2853. ZwClose (IDConfigProfiles);
  2854. }
  2855. if (NULL != IDConfigEntry) {
  2856. ZwClose (IDConfigEntry);
  2857. }
  2858. if (NULL != HwProfiles) {
  2859. ZwClose (HwProfiles);
  2860. }
  2861. if (NULL != HwProfileEntry) {
  2862. ZwClose (HwProfileEntry);
  2863. }
  2864. return b;
  2865. }
  2866. VOID
  2867. SppSetGuimodeUpgradePath(
  2868. IN HANDLE hKeySoftwareHive,
  2869. IN HANDLE hKeyControlSet
  2870. )
  2871. {
  2872. PWSTR Default_Path[3] = { L"%SystemRoot%\\system32",
  2873. L"%SystemRoot%",
  2874. L"%SystemRoot%\\system32\\WBEM"};
  2875. UNICODE_STRING StringRegPath;
  2876. UNICODE_STRING StringRegOldPath, UnicodeString;
  2877. PKEY_VALUE_PARTIAL_INFORMATION pValueInfo;
  2878. ULONG len;
  2879. PWSTR CurrentPath = NULL;
  2880. PWSTR p,q,final;
  2881. OBJECT_ATTRIBUTES Obja;
  2882. HKEY hKeyEnv;
  2883. DWORD err;
  2884. BOOL Found;
  2885. int i;
  2886. INIT_OBJA( &Obja, &UnicodeString, L"Control\\Session Manager\\Environment" );
  2887. Obja.RootDirectory = hKeyControlSet;
  2888. err = ZwOpenKey( &hKeyEnv, KEY_ALL_ACCESS, &Obja );
  2889. if( NT_SUCCESS( err )){
  2890. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP:SppSetGuimodeUpgradePath - Opened the Environment key\n" ));
  2891. RtlInitUnicodeString(&StringRegPath, L"Path");
  2892. err = ZwQueryValueKey(
  2893. hKeyEnv,
  2894. &StringRegPath,
  2895. KeyValuePartialInformation,
  2896. TemporaryBuffer,
  2897. sizeof(TemporaryBuffer),
  2898. &len);
  2899. if( NT_SUCCESS(err)) {
  2900. pValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer;
  2901. if( pValueInfo->Type == REG_EXPAND_SZ || pValueInfo->Type == REG_SZ) {
  2902. CurrentPath = SpDupStringW( (PWSTR)pValueInfo->Data );
  2903. // Now we try to extract from the existing path all elements that are not part of the default
  2904. // path that we maintain during GUI Setup. We then append that to the default path. That way
  2905. // we don't end up duplicating path elements over successive upgrades. We store this in the
  2906. // 'OldPath' value and restore it at the end of GUI mode.
  2907. //
  2908. TemporaryBuffer[0]=L'\0';
  2909. for(i=0; i<ELEMENT_COUNT(Default_Path); i++){
  2910. wcscat( TemporaryBuffer, Default_Path[i] );
  2911. wcscat( TemporaryBuffer, L";");
  2912. }
  2913. TemporaryBuffer[wcslen(TemporaryBuffer)-1]=L'\0';
  2914. //Set the default path in the registry
  2915. err = ZwSetValueKey(
  2916. hKeyEnv,
  2917. &StringRegPath,
  2918. 0,
  2919. REG_EXPAND_SZ,
  2920. TemporaryBuffer,
  2921. ((wcslen(TemporaryBuffer)+1)*sizeof(WCHAR)));
  2922. if( !NT_SUCCESS( err ) )
  2923. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "\nSETUP: Error %x in saving path. Ignoring and not resetting PATH for GUI Setup\n", err));
  2924. for( p=q=CurrentPath; p && *p; ){
  2925. //Jump to the ';' delimiter
  2926. if( q = wcsstr(p, L";") )
  2927. *q=0;
  2928. // Compare with elements of our default path
  2929. Found=FALSE;
  2930. for(i=0; i<ELEMENT_COUNT(Default_Path); i++){
  2931. if (!_wcsicmp(p,Default_Path[i])) {
  2932. Found=TRUE;
  2933. break;
  2934. }
  2935. }
  2936. if(!Found){
  2937. wcscat( TemporaryBuffer, L";");
  2938. wcscat( TemporaryBuffer, p);
  2939. }
  2940. if(q)
  2941. p=q+1;
  2942. else
  2943. break;
  2944. }
  2945. RtlInitUnicodeString(&StringRegOldPath, L"OldPath");
  2946. //
  2947. // Set the Oldpath always, if it exists or not
  2948. //
  2949. err = ZwSetValueKey(
  2950. hKeyEnv,
  2951. &StringRegOldPath,
  2952. 0,
  2953. REG_EXPAND_SZ,
  2954. TemporaryBuffer,
  2955. ((wcslen(TemporaryBuffer)+1)*sizeof(WCHAR)));
  2956. if( !NT_SUCCESS( err ) )
  2957. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "\nSETUP: Error %x in saving old PATH. \n", err));
  2958. } else {
  2959. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "\nSETUP:PATH type in registry not REG_EXPAND_SZ nor REG_SZ. Resetting PATH to default\n"));
  2960. TemporaryBuffer[0]=L'\0';
  2961. for(i=0; i<ELEMENT_COUNT(Default_Path); i++){
  2962. wcscat( TemporaryBuffer, Default_Path[i] );
  2963. wcscat( TemporaryBuffer, L";");
  2964. }
  2965. TemporaryBuffer[wcslen(TemporaryBuffer)-1]=L'\0';
  2966. //Set the default path in the registry
  2967. err = ZwSetValueKey(
  2968. hKeyEnv,
  2969. &StringRegPath,
  2970. 0,
  2971. REG_EXPAND_SZ,
  2972. TemporaryBuffer,
  2973. ((wcslen(TemporaryBuffer)+1)*sizeof(WCHAR)));
  2974. if( !NT_SUCCESS( err ) )
  2975. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "\nSETUP: Error %x in saving path. Ignoring and not resetting PATH for GUI Setup\n", err));
  2976. }
  2977. }else {
  2978. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "\nSETUP:Query for PATH value failed with error %x. Ignoring and not resetting PATH for GUI Setup\n",err));
  2979. }
  2980. ZwClose( hKeyEnv );
  2981. }else
  2982. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "\nSETUP:Error %x while opening Environment key. Ignoring and not resetting PATH for GUI Setup\n",err));
  2983. if( CurrentPath )
  2984. SpMemFree( CurrentPath );
  2985. return;
  2986. }
  2987. NTSTATUS
  2988. SppMigratePrinterKeys(
  2989. IN HANDLE hControlSet,
  2990. IN HANDLE hDestSoftwareHive
  2991. )
  2992. /*++
  2993. Routine Description:
  2994. This routine migrates HKLM\SYSTEM\CurrentControlSet\Control\Print\Printers to
  2995. HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers.
  2996. Arguments:
  2997. hControlSet - Handle to CurrentControlSet key in the system hive of the system being upgraded
  2998. hDestSoftwareHive - Handle to the root of the software hive on the system
  2999. being upgraded.
  3000. Return Value:
  3001. Status value indicating outcome of operation.
  3002. --*/
  3003. {
  3004. NTSTATUS Status;
  3005. OBJECT_ATTRIBUTES Obja;
  3006. UNICODE_STRING UnicodeString;
  3007. PWSTR SrcPrinterKeyPath = L"Control\\Print\\Printers";
  3008. PWSTR DstPrinterKeyName = L"Printers";
  3009. PWSTR DstPrinterKeyPath = SpDupStringW(L"Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers");
  3010. HANDLE SrcKey;
  3011. HANDLE DstKey;
  3012. //
  3013. // Find out if the destination key exists
  3014. //
  3015. INIT_OBJA(&Obja,&UnicodeString,DstPrinterKeyPath);
  3016. Obja.RootDirectory = hDestSoftwareHive;
  3017. Status = ZwOpenKey(&DstKey,KEY_ALL_ACCESS,&Obja);
  3018. if( NT_SUCCESS( Status ) ) {
  3019. //
  3020. // If the key exists, then there is no need to do any migration.
  3021. // The migration has occurred on previous upgrades.
  3022. //
  3023. ZwClose( DstKey );
  3024. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: HKLM\\SYSTEM\\CurrentControlSet\\%ls doesn't need to be migrated. \n", DstPrinterKeyPath));
  3025. SpMemFree( DstPrinterKeyPath );
  3026. return( Status );
  3027. } else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  3028. //
  3029. // The key doesn't exist, so we need to do migration.
  3030. // First create the parent key.
  3031. //
  3032. PWSTR p;
  3033. p = wcsrchr ( DstPrinterKeyPath, L'\\' );
  3034. if (p) {
  3035. *p = L'\0';
  3036. }
  3037. INIT_OBJA(&Obja,&UnicodeString,DstPrinterKeyPath);
  3038. Obja.RootDirectory = hDestSoftwareHive;
  3039. Status = ZwCreateKey(&DstKey,
  3040. KEY_ALL_ACCESS,
  3041. &Obja,
  3042. 0,
  3043. NULL,
  3044. REG_OPTION_NON_VOLATILE,
  3045. NULL );
  3046. if( !NT_SUCCESS( Status ) ) {
  3047. //
  3048. // If unable to create the parent key, then don't do migration
  3049. //
  3050. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to create HKLM\\SOFTWARE\\%ls. Status = %lx \n", DstPrinterKeyPath, Status));
  3051. SpMemFree( DstPrinterKeyPath );
  3052. return( Status );
  3053. }
  3054. } else {
  3055. //
  3056. // We can't really determine whether or not the migration has occurred in the past, because the key is
  3057. // unaccessible. So son't attempt to do migration.
  3058. //
  3059. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open HKLM\\SOFTWARE\\%ls. Status = %lx \n", DstPrinterKeyPath, Status));
  3060. SpMemFree( DstPrinterKeyPath );
  3061. return( Status );
  3062. }
  3063. //
  3064. // At this point we now that the migration needs to be done.
  3065. // First, open the source key. Note that DstPrinterKeyPath is no longer needed.
  3066. //
  3067. SpMemFree( DstPrinterKeyPath );
  3068. INIT_OBJA(&Obja,&UnicodeString,SrcPrinterKeyPath);
  3069. Obja.RootDirectory = hControlSet;
  3070. Status = ZwOpenKey(&SrcKey,KEY_ALL_ACCESS,&Obja);
  3071. if( !NT_SUCCESS( Status ) ) {
  3072. //
  3073. // If unable to open the source key, then fail.
  3074. //
  3075. ZwClose( DstKey );
  3076. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open HKLM\\SYSTEM\\CurrentControlSet\\%ls. Status = %lx \n", SrcPrinterKeyPath, Status));
  3077. return( Status );
  3078. }
  3079. Status = SppCopyKeyRecursive( SrcKey,
  3080. DstKey,
  3081. NULL,
  3082. DstPrinterKeyName,
  3083. FALSE,
  3084. TRUE
  3085. );
  3086. if( !NT_SUCCESS( Status ) ) {
  3087. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to migrate %ls. Status = %lx\n", SrcPrinterKeyPath, Status));
  3088. }
  3089. ZwClose( SrcKey );
  3090. ZwClose( DstKey );
  3091. //
  3092. // If the key was migrated successfully, then attempt to delete the source key.
  3093. // if we are unable to delete the key, then silently fail.
  3094. //
  3095. if( NT_SUCCESS( Status ) ) {
  3096. NTSTATUS Status1;
  3097. PWSTR q, r;
  3098. //
  3099. // q will point to "Control\Print"
  3100. // r will point to "Printers"
  3101. //
  3102. q = SpDupStringW( SrcPrinterKeyPath );
  3103. r = wcsrchr ( q, L'\\' );
  3104. *r = L'\0';
  3105. r++;
  3106. INIT_OBJA(&Obja,&UnicodeString,q);
  3107. Obja.RootDirectory = hControlSet;
  3108. Status1 = ZwOpenKey(&SrcKey,KEY_ALL_ACCESS,&Obja);
  3109. if( NT_SUCCESS( Status1 ) ) {
  3110. Status1 = SppDeleteKeyRecursive(SrcKey,
  3111. r,
  3112. TRUE);
  3113. if( !NT_SUCCESS( Status1 ) ) {
  3114. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to delete %ls\\%ls. Status = %lx\n", q, r, Status1));
  3115. }
  3116. ZwClose( SrcKey );
  3117. } else {
  3118. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to delete %ls. ZwOpenKey() failed. Status = %lx\n", SrcPrinterKeyPath, Status1));
  3119. }
  3120. SpMemFree(q);
  3121. }
  3122. return( Status );
  3123. }