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.

2455 lines
73 KiB

  1. /*++
  2. Copyright (c) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. migrate.c
  5. Abstract:
  6. This module contains the code necessary for Plug and Play to prepare the
  7. necessary state during a winnt32.exe upgrade or an ASR (Automated System
  8. Recovery) backup operation. Typically, these aspects of the Plug and Play
  9. registry are saved in a sif for later use, during the text-mode setup
  10. portion of an upgrade or ASR recovery operation.
  11. Author:
  12. Jim Cavalaris (jamesca) 07-Mar-2000
  13. Environment:
  14. User-mode only.
  15. Revision History:
  16. 07-March-2000 jamesca
  17. Creation and initial implementation.
  18. --*/
  19. //
  20. // includes
  21. //
  22. #include "precomp.h"
  23. #include "debug.h"
  24. #include "util.h"
  25. #include <aclapi.h>
  26. #include <regstr.h>
  27. #include <pnpmgr.h>
  28. #include <cfgmgr32.h>
  29. //
  30. // definitions
  31. //
  32. // do the lock/unlock Enum security thing? (as taken from PNPREG)
  33. #define DO_LOCK_UNLOCK 0
  34. //
  35. // memory allocation macros
  36. // (always use LocalAlloc/LocalReAlloc so that the caller can LocalFree the
  37. // returned buffer.)
  38. //
  39. #define MyMalloc(size) LocalAlloc(0, size);
  40. #define MyFree(entry) LocalFree(entry);
  41. #define MyRealloc(entry,size) LocalReAlloc(entry, size, LMEM_MOVEABLE | LMEM_ZEROINIT);
  42. //
  43. // globals for the Enum branch lock/unlock and security routines - taken from PNPREG
  44. // (we only need these if we're doing the Enum lock/unlock thing)
  45. //
  46. #if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
  47. PSID g_pAdminSid;
  48. PSID g_pSystemSid;
  49. PSID g_pWorldSid;
  50. SECURITY_DESCRIPTOR g_DeviceParametersSD;
  51. PACL g_pDeviceParametersDacl;
  52. SECURITY_DESCRIPTOR g_LockedPrivateKeysSD;
  53. PACL g_pLockedPrivateKeysDacl;
  54. #if 0 //#if DBG // DBG
  55. TCHAR g_szCurrentKeyName[4096];
  56. DWORD g_dwCurrentKeyNameLength = 0;
  57. #endif // DBG
  58. #endif // DO_LOCK_UNLOCK
  59. //
  60. // public prototypes
  61. //
  62. BOOL
  63. MigrateDeviceInstanceData(
  64. OUT LPTSTR *Buffer
  65. );
  66. BOOL
  67. MigrateClassKeys(
  68. OUT LPTSTR *Buffer
  69. );
  70. BOOL
  71. MigrateHashValues(
  72. OUT LPTSTR *Buffer
  73. );
  74. //
  75. // private prototypes
  76. //
  77. BOOL
  78. EnumerateDeviceKeys(
  79. IN HKEY CCSEnumKey,
  80. IN LPTSTR Enumerator,
  81. IN OUT LPTSTR *pszDeviceInstanceSection,
  82. IN OUT LPTSTR *pszDeviceInstanceCurrent,
  83. IN OUT DWORD *dwDeviceInstanceSectionLength,
  84. IN OUT DWORD *dwDeviceInstanceSectionRemaining
  85. );
  86. BOOL
  87. EnumerateInstanceKeys(
  88. IN HKEY EnumeratorKey,
  89. IN LPTSTR Enumerator,
  90. IN LPTSTR Device,
  91. IN OUT LPTSTR *pszDeviceInstanceSection,
  92. IN OUT LPTSTR *pszDeviceInstanceCurrent,
  93. IN OUT DWORD *dwDeviceInstanceSectionLength,
  94. IN OUT DWORD *dwDeviceInstanceSectionRemaining
  95. );
  96. BOOL
  97. EnumerateClassSubkeys(
  98. IN HKEY ClassKey,
  99. IN LPTSTR ClassKeyName,
  100. IN OUT LPTSTR *pszClassKeySection,
  101. IN OUT LPTSTR *pszClassKeyCurrent,
  102. IN OUT DWORD *dwClassKeySectionLength,
  103. IN OUT DWORD *dwClassKeySectionRemaining
  104. );
  105. BOOL
  106. CanStringBeMigrated(
  107. IN LPTSTR pszBuffer
  108. );
  109. // we only need these if we're doing the Enum lock/unlock thing
  110. #if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
  111. VOID
  112. LockUnlockEnumTree(
  113. IN BOOL bLock
  114. );
  115. VOID
  116. EnumKeysAndApplyDacls(
  117. IN HKEY hParentKey,
  118. IN LPTSTR pszKeyName,
  119. IN DWORD dwLevel,
  120. IN BOOL bInDeviceParameters,
  121. IN BOOL bApplyTopDown,
  122. IN PSECURITY_DESCRIPTOR pPrivateKeySD,
  123. IN PSECURITY_DESCRIPTOR pDeviceParametersSD
  124. );
  125. BOOL
  126. CreateSecurityDescriptors(
  127. VOID
  128. );
  129. VOID
  130. FreeSecurityDescriptors(
  131. VOID
  132. );
  133. #endif // DO_LOCK_UNLOCK
  134. //
  135. // Device instance enumeration routines
  136. //
  137. BOOL
  138. MigrateDeviceInstanceData(
  139. OUT LPTSTR *Buffer
  140. )
  141. /*++
  142. Routine Description:
  143. This routine walks the Plug and Play Enum tree in the registry, and collects
  144. the data that is relevant to restoring this state during textmode setup.
  145. Specifically, a multi-sz string will be returned to the caller that contains
  146. migration data for the UniqueParentID, ParentIdPrefix, and Driver registry
  147. values for all device instances in the Enum tree.
  148. Arguments:
  149. Buffer - Supplies the address of a character pointer, that on success will
  150. contain a multi-sz list of device instances and relevant values to
  151. migrate.
  152. The caller is responsible for freeing the memory via LocalFree.
  153. Return Value:
  154. TRUE if successful, FALSE otherwise. Upon failure, additional information
  155. can be retrieved by calling GetLastError().
  156. --*/
  157. {
  158. LONG result = ERROR_SUCCESS;
  159. HKEY hEnumKey = NULL;
  160. DWORD dwSubkeyCount, dwMaxSubKeyLength, i;
  161. LPTSTR pszEnumerator = NULL;
  162. LPTSTR pszDeviceInstanceSection = NULL;
  163. LPTSTR pszDeviceInstanceCurrent = NULL;
  164. DWORD dwDeviceInstanceSectionLength = 0;
  165. DWORD dwDeviceInstanceSectionRemaining = 0;
  166. //
  167. // Initialize the output parameter.
  168. //
  169. *Buffer = NULL;
  170. #if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
  171. //
  172. // Unlock the Enum key.
  173. //
  174. LockUnlockEnumTree(FALSE);
  175. #endif // DO_LOCK_UNLOCK
  176. //
  177. // Allocate storage and initialize variables for the device instance
  178. // migration section.
  179. //
  180. if (pszDeviceInstanceSection == NULL) {
  181. dwDeviceInstanceSectionLength = dwDeviceInstanceSectionRemaining = 256;
  182. pszDeviceInstanceSection = MyMalloc(dwDeviceInstanceSectionLength * sizeof(TCHAR));
  183. if (!pszDeviceInstanceSection) {
  184. DBGTRACE( DBGF_ERRORS,
  185. (TEXT("MigrateDeviceInstanceData: initial ALLOC for ClassKeySection failed!!\n") ));
  186. result = ERROR_NOT_ENOUGH_MEMORY;
  187. goto Clean0;
  188. }
  189. pszDeviceInstanceCurrent = pszDeviceInstanceSection;
  190. }
  191. //
  192. // Open a handle to the HKLM\SYSTEM\CCS\Enum key.
  193. //
  194. result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  195. REGSTR_PATH_SYSTEMENUM,
  196. 0,
  197. KEY_READ,
  198. &hEnumKey);
  199. if (result != ERROR_SUCCESS) {
  200. DBGTRACE( DBGF_ERRORS,
  201. (TEXT("MigrateDeviceInstanceData: failed to open %s, error=0x%08lx\n"),
  202. REGSTR_PATH_SYSTEMENUM, result));
  203. goto Clean0;
  204. }
  205. //
  206. // Query the Enum key for enumerator subkey information.
  207. //
  208. result = RegQueryInfoKey(hEnumKey,
  209. NULL,
  210. NULL,
  211. NULL,
  212. &dwSubkeyCount,
  213. &dwMaxSubKeyLength,
  214. NULL,
  215. NULL,
  216. NULL,
  217. NULL,
  218. NULL,
  219. NULL);
  220. if (result != ERROR_SUCCESS) {
  221. DBGTRACE( DBGF_ERRORS,
  222. (TEXT("MigrateDeviceInstanceData: failed to query %s key, error=0x%08lx\n"),
  223. REGSTR_PATH_SYSTEMENUM, result));
  224. goto Clean0;
  225. }
  226. //
  227. // Allocate a buffer to hold the largest enumerator key name.
  228. //
  229. dwMaxSubKeyLength++;
  230. pszEnumerator = MyMalloc(dwMaxSubKeyLength * sizeof(TCHAR));
  231. if (!pszEnumerator) {
  232. DBGTRACE( DBGF_ERRORS,
  233. (TEXT("MigrateDeviceInstanceData: failed to allocate buffer for Enum subkeys\n") ));
  234. result = ERROR_NOT_ENOUGH_MEMORY;
  235. goto Clean0;
  236. }
  237. //
  238. // Enumerate the enumerator subkeys.
  239. //
  240. for (i = 0; i < dwSubkeyCount; i++) {
  241. DWORD dwEnumeratorLength = dwMaxSubKeyLength;
  242. result = RegEnumKeyEx(hEnumKey,
  243. i,
  244. pszEnumerator,
  245. &dwEnumeratorLength,
  246. 0,
  247. NULL,
  248. NULL,
  249. NULL);
  250. if (result != ERROR_SUCCESS) {
  251. //
  252. // If there was some error enumerating this key, skip it.
  253. //
  254. MYASSERT(result != ERROR_NO_MORE_ITEMS);
  255. DBGTRACE( DBGF_WARNINGS,
  256. (TEXT("MigrateDeviceInstanceData: failed to enumerate an enumerator subkey, error=0x%08lx\n"),
  257. result));
  258. result = ERROR_SUCCESS;
  259. continue;
  260. }
  261. //
  262. // Enumerate the devices and device instances for this enumerator, and
  263. // append the migration data for each to the section buffer.
  264. //
  265. if (!EnumerateDeviceKeys(hEnumKey,
  266. pszEnumerator,
  267. &pszDeviceInstanceSection,
  268. &pszDeviceInstanceCurrent,
  269. &dwDeviceInstanceSectionLength,
  270. &dwDeviceInstanceSectionRemaining)) {
  271. DBGTRACE( DBGF_ERRORS,
  272. (TEXT("MigrateDeviceInstanceData: EnumerateDeviceKeys failed, error=0x%08lx\n"),
  273. GetLastError()));
  274. }
  275. }
  276. //
  277. // Once we've enumerated all device instances, add the final NULL terminator
  278. // to the multi-sz buffer. There must be enough space for the final NULL
  279. // terminator because the buffer is always reallocated unless there is room.
  280. //
  281. MYASSERT(dwDeviceInstanceSectionRemaining > 0);
  282. MYASSERT(pszDeviceInstanceCurrent);
  283. *pszDeviceInstanceCurrent = TEXT('\0');
  284. dwDeviceInstanceSectionRemaining -= 1;
  285. Clean0:
  286. //
  287. // Do some cleanup.
  288. //
  289. if (pszEnumerator) {
  290. MyFree(pszEnumerator);
  291. }
  292. if (hEnumKey) {
  293. RegCloseKey(hEnumKey);
  294. }
  295. #if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
  296. //
  297. // Lock the Enum tree.
  298. //
  299. LockUnlockEnumTree(TRUE);
  300. #endif // DO_LOCK_UNLOCK
  301. //
  302. // Return the buffer to the caller only if successful.
  303. //
  304. if (result == ERROR_SUCCESS) {
  305. *Buffer = pszDeviceInstanceSection;
  306. } else {
  307. SetLastError(result);
  308. if (pszDeviceInstanceSection) {
  309. MyFree(pszDeviceInstanceSection);
  310. }
  311. }
  312. return (result == ERROR_SUCCESS);
  313. } // MigrateDeviceInstanceData()
  314. BOOL
  315. EnumerateDeviceKeys(
  316. IN HKEY CCSEnumKey,
  317. IN LPTSTR Enumerator,
  318. IN OUT LPTSTR *pszDeviceInstanceSection,
  319. IN OUT LPTSTR *pszDeviceInstanceCurrent,
  320. IN OUT DWORD *dwDeviceInstanceSectionLength,
  321. IN OUT DWORD *dwDeviceInstanceSectionRemaining
  322. )
  323. /*++
  324. Routine Description:
  325. Enumerates device keys of an enumerator.
  326. Worker routine for MigrateDeviceInstanceData.
  327. Return Value:
  328. TRUE if successful, FALSE otherwise. Upon failure, additional information
  329. can be retrieved by calling GetLastError().
  330. --*/
  331. {
  332. LONG result;
  333. HKEY hEnumeratorKey = NULL;
  334. LPTSTR pszDeviceName = NULL;
  335. DWORD dwSubkeyCount, dwMaxSubKeyLength, dwDeviceLength, i;
  336. //
  337. // Open the enumerator key, under HKLM\SYSTEM\CCS\Enum.
  338. //
  339. result = RegOpenKeyEx(CCSEnumKey,
  340. Enumerator,
  341. 0,
  342. KEY_READ,
  343. &hEnumeratorKey);
  344. if (result != ERROR_SUCCESS) {
  345. //
  346. // If we failed to open the Enumerator key, there's nothing we can do.
  347. //
  348. DBGTRACE( DBGF_ERRORS,
  349. (TEXT("EnumerateDeviceKeys: failed to open '%s' enumerator key, error=0x%08lx\n"),
  350. Enumerator, result));
  351. goto Clean0;
  352. }
  353. //
  354. // Query the enumerator key for device subkey information.
  355. //
  356. result = RegQueryInfoKey(hEnumeratorKey,
  357. NULL,
  358. NULL,
  359. NULL,
  360. &dwSubkeyCount,
  361. &dwMaxSubKeyLength,
  362. NULL,
  363. NULL,
  364. NULL,
  365. NULL,
  366. NULL,
  367. NULL);
  368. if (result != ERROR_SUCCESS) {
  369. DBGTRACE( DBGF_ERRORS,
  370. (TEXT("EnumerateDeviceKeys: failed to query '%s' enumerator key, error=0x%08lx\n"),
  371. Enumerator, result));
  372. goto Clean0;
  373. }
  374. //
  375. // Allocate a buffer to hold the largest device subkey name.
  376. //
  377. dwMaxSubKeyLength++;
  378. pszDeviceName = MyMalloc(dwMaxSubKeyLength * sizeof(TCHAR));
  379. if (!pszDeviceName) {
  380. DBGTRACE( DBGF_ERRORS,
  381. (TEXT("EnumerateDeviceKeys: failed to allocate buffer for device subkeys of '%s'\n"),
  382. Enumerator));
  383. result = ERROR_NOT_ENOUGH_MEMORY;
  384. goto Clean0;
  385. }
  386. //
  387. // Enumerate the enumerator's devices.
  388. //
  389. for (i = 0; i < dwSubkeyCount; i++) {
  390. dwDeviceLength = dwMaxSubKeyLength;
  391. result = RegEnumKeyEx(hEnumeratorKey,
  392. i,
  393. pszDeviceName,
  394. &dwDeviceLength,
  395. 0,
  396. NULL,
  397. NULL,
  398. NULL);
  399. if (result != ERROR_SUCCESS) {
  400. //
  401. // If there was some error enumerating this device key, skip it.
  402. //
  403. MYASSERT(result != ERROR_NO_MORE_ITEMS);
  404. DBGTRACE( DBGF_WARNINGS,
  405. (TEXT("EnumerateDeviceKeys: failed to enumerate device subkey for '%s', error=0x%08lx\n"),
  406. Enumerator, result));
  407. result = ERROR_SUCCESS;
  408. continue;
  409. }
  410. //
  411. // Enumerate the device instances, and append the migration data for
  412. // each to the section buffer.
  413. //
  414. if (!EnumerateInstanceKeys(hEnumeratorKey,
  415. Enumerator,
  416. pszDeviceName,
  417. pszDeviceInstanceSection,
  418. pszDeviceInstanceCurrent,
  419. dwDeviceInstanceSectionLength,
  420. dwDeviceInstanceSectionRemaining)) {
  421. DBGTRACE( DBGF_ERRORS,
  422. (TEXT("EnumerateDeviceKeys: EnumerateInstanceKeys failed for %s\\%s, error=0x%08lx\n"),
  423. Enumerator, pszDeviceName, GetLastError()));
  424. }
  425. }
  426. Clean0:
  427. //
  428. // Do some cleanup
  429. //
  430. if (pszDeviceName) {
  431. MyFree(pszDeviceName);
  432. }
  433. if (hEnumeratorKey) {
  434. RegCloseKey(hEnumeratorKey);
  435. }
  436. if (result != ERROR_SUCCESS) {
  437. SetLastError(result);
  438. }
  439. return (result == ERROR_SUCCESS);
  440. } // EnumerateDeviceKeys()
  441. BOOL
  442. EnumerateInstanceKeys(
  443. IN HKEY EnumeratorKey,
  444. IN LPTSTR Enumerator,
  445. IN LPTSTR Device,
  446. IN OUT LPTSTR *pszDeviceInstanceSection,
  447. IN OUT LPTSTR *pszDeviceInstanceCurrent,
  448. IN OUT DWORD *dwDeviceInstanceSectionLength,
  449. IN OUT DWORD *dwDeviceInstanceSectionRemaining
  450. )
  451. /*++
  452. Routine Description:
  453. Enumerates instance keys of a device.
  454. Worker routine for EnumerateDeviceKeys,MigrateDeviceInstanceData.
  455. Return Value:
  456. TRUE if successful, FALSE otherwise. Upon failure, additional information
  457. can be retrieved by calling GetLastError().
  458. --*/
  459. {
  460. LONG result = ERROR_SUCCESS;
  461. HKEY hDeviceKey = NULL;
  462. LPTSTR pszDeviceInstanceId = NULL;
  463. DWORD dwSubkeyCount, dwMaxSubKeyLength, dwSpaceNeeded, dwSpaceConsumed, i;
  464. BOOL bIsDeviceRootEnumerated;
  465. //
  466. // Keep track of whether this is a ROOT enumerated device.
  467. //
  468. bIsDeviceRootEnumerated = (lstrcmpi(Enumerator, REGSTR_KEY_ROOTENUM) == 0);
  469. //
  470. // If this is a LEGACY_ ROOT enumerated device, don't bother migrating it
  471. // for textmode setup to see.
  472. //
  473. if (bIsDeviceRootEnumerated) {
  474. if (wcsncmp(Device,
  475. TEXT("LEGACY_"),
  476. lstrlen(TEXT("LEGACY_"))) == 0) {
  477. return TRUE;
  478. }
  479. }
  480. //
  481. // Open the device key, under the enumerator key.
  482. //
  483. result = RegOpenKeyEx(EnumeratorKey,
  484. Device,
  485. 0,
  486. KEY_READ,
  487. &hDeviceKey);
  488. if (result != ERROR_SUCCESS) {
  489. DBGTRACE( DBGF_ERRORS,
  490. (TEXT("EnumerateInstanceKeys: failed to open '%s\\%s' device key, error=0x%08lx\n"),
  491. Enumerator, Device, result));
  492. goto Clean0;
  493. }
  494. //
  495. // Query the device key for instance subkey information.
  496. //
  497. result = RegQueryInfoKey(hDeviceKey,
  498. NULL,
  499. NULL,
  500. NULL,
  501. &dwSubkeyCount,
  502. &dwMaxSubKeyLength,
  503. NULL,
  504. NULL,
  505. NULL,
  506. NULL,
  507. NULL,
  508. NULL);
  509. if (result != ERROR_SUCCESS) {
  510. DBGTRACE( DBGF_ERRORS,
  511. (TEXT("EnumerateInstanceKeys: failed to query '%s\\%s' device key, error=0x%08lx\n"),
  512. Enumerator, Device, result));
  513. goto Clean0;
  514. }
  515. //
  516. // Allocate a buffer to hold the largest device instance subkey name.
  517. //
  518. dwMaxSubKeyLength++;
  519. pszDeviceInstanceId = MyMalloc(dwMaxSubKeyLength * sizeof(TCHAR));
  520. if (!pszDeviceInstanceId) {
  521. DBGTRACE( DBGF_ERRORS,
  522. (TEXT("EnumerateInstanceKeys: failed to allocate buffer for instance subkeys of '%s\\%s'\n"),
  523. Enumerator, Device));
  524. result = ERROR_NOT_ENOUGH_MEMORY;
  525. goto Clean0;
  526. }
  527. //
  528. // Enumerate the device's instances.
  529. //
  530. for (i = 0; i < dwSubkeyCount; i++) {
  531. DWORD dwInstanceLength, dwType, dwBufferSize;
  532. DWORD dwUniqueParentID, dwFirmwareIdentified;
  533. TCHAR szParentIdPrefix[MAX_PATH];
  534. TCHAR szUniqueParentID[11], szFirmwareIdentified[11];
  535. TCHAR szDriver[2*MAX_PATH + 1];
  536. GUID classGuid;
  537. DWORD dwDrvInst;
  538. HKEY hInstanceKey = NULL, hLogConfKey = NULL;
  539. TCHAR szService[MAX_PATH];
  540. PBYTE pBootConfig = NULL;
  541. LPTSTR pszBootConfig = NULL;
  542. DWORD dwBootConfigSize = 0;
  543. dwInstanceLength = dwMaxSubKeyLength;
  544. result = RegEnumKeyEx(hDeviceKey,
  545. i,
  546. pszDeviceInstanceId,
  547. &dwInstanceLength,
  548. 0,
  549. NULL,
  550. NULL,
  551. NULL);
  552. if (result != ERROR_SUCCESS) {
  553. //
  554. // If there was some error enumerating this key, skip it.
  555. //
  556. MYASSERT(result != ERROR_NO_MORE_ITEMS);
  557. DBGTRACE( DBGF_WARNINGS,
  558. (TEXT("EnumerateInstanceKeys: failed to enumerate instance subkey of '%s\\%s', error=0x&08lx\n"),
  559. Enumerator, Device, result));
  560. result = ERROR_SUCCESS;
  561. continue;
  562. }
  563. result = RegOpenKeyEx(hDeviceKey,
  564. pszDeviceInstanceId,
  565. 0,
  566. KEY_READ,
  567. &hInstanceKey);
  568. if (result != ERROR_SUCCESS) {
  569. DBGTRACE( DBGF_WARNINGS,
  570. (TEXT("EnumerateInstanceKeys: failed to open '%s\\%s\\%s', error=0x%08lx\n"),
  571. Enumerator, Device, pszDeviceInstanceId, result));
  572. result = ERROR_SUCCESS;
  573. continue;
  574. }
  575. //
  576. // Check for the "UniqueParentID" value
  577. //
  578. dwBufferSize = sizeof(dwUniqueParentID);
  579. result = RegQueryValueEx(hInstanceKey,
  580. REGSTR_VALUE_UNIQUE_PARENT_ID,
  581. 0,
  582. &dwType,
  583. (LPBYTE)&dwUniqueParentID,
  584. &dwBufferSize);
  585. if ((result == ERROR_SUCCESS) &&
  586. (dwType == REG_DWORD)){
  587. //
  588. // Write the UniqueParentID value to the sif as a base 16 value.
  589. // (see admin\ntsetup\textmode\kernel\spsetup.c)
  590. //
  591. wsprintf(szUniqueParentID,
  592. TEXT("%X"), // base 16
  593. dwUniqueParentID);
  594. } else {
  595. //
  596. // No "UniqueParentID" value to migrate.
  597. //
  598. *szUniqueParentID = TEXT('\0');
  599. }
  600. //
  601. // Check for the "ParentIdPrefix" value
  602. //
  603. dwBufferSize = sizeof(szParentIdPrefix);
  604. result = RegQueryValueEx(hInstanceKey,
  605. REGSTR_VALUE_PARENT_ID_PREFIX,
  606. 0,
  607. &dwType,
  608. (LPBYTE)szParentIdPrefix,
  609. &dwBufferSize);
  610. if ((result != ERROR_SUCCESS) ||
  611. (dwType != REG_SZ)) {
  612. //
  613. // No "ParentIdPrefix" value to migrate.
  614. //
  615. *szParentIdPrefix = TEXT('\0');
  616. result = ERROR_SUCCESS;
  617. }
  618. //
  619. // Build the device's Driver key name by checking for the GUID and
  620. // DrvInst values.
  621. //
  622. *szDriver = TEXT('\0');
  623. dwBufferSize = sizeof(classGuid);
  624. result = RegQueryValueEx(hInstanceKey,
  625. TEXT("GUID"),
  626. 0,
  627. &dwType,
  628. (LPBYTE)&classGuid,
  629. &dwBufferSize);
  630. if ((result == ERROR_SUCCESS) &&
  631. (dwType == REG_BINARY)) {
  632. //
  633. // Get the DrvInst value for the driver key
  634. //
  635. dwBufferSize = sizeof(dwDrvInst);
  636. result = RegQueryValueEx(hInstanceKey,
  637. TEXT("DrvInst"),
  638. 0,
  639. &dwType,
  640. (LPBYTE)&dwDrvInst,
  641. &dwBufferSize);
  642. if ((result == ERROR_SUCCESS) &&
  643. (dwType == REG_DWORD)) {
  644. if (pSifUtilStringFromGuid(&classGuid,
  645. szDriver,
  646. sizeof(szDriver)/sizeof(TCHAR))) {
  647. //
  648. // Build the driver key
  649. //
  650. wsprintf((LPWSTR)szDriver, TEXT("%s\\%04u"), szDriver, dwDrvInst);
  651. } else {
  652. result = GetLastError();
  653. }
  654. } else {
  655. //
  656. // Generic error value so we try to find the driver value using
  657. // the old scheme.
  658. //
  659. result = ERROR_INVALID_PARAMETER;
  660. }
  661. } else {
  662. //
  663. // Generic error value so we try to find the driver value using
  664. // the old scheme.
  665. //
  666. result = ERROR_INVALID_PARAMETER;
  667. }
  668. //
  669. // If this device instance key is not using the new GUID\DrvInst
  670. // scheme, check for the "Driver" value
  671. //
  672. if (result != ERROR_SUCCESS) {
  673. dwBufferSize = sizeof(szDriver);
  674. result = RegQueryValueEx(hInstanceKey,
  675. REGSTR_VAL_DRIVER,
  676. 0,
  677. &dwType,
  678. (LPBYTE)szDriver,
  679. &dwBufferSize);
  680. if ((result != ERROR_SUCCESS) ||
  681. (dwType != REG_SZ)) {
  682. //
  683. // No "Driver" value to migrate.
  684. //
  685. *szDriver = TEXT('\0');
  686. result = ERROR_SUCCESS;
  687. }
  688. }
  689. //
  690. // If this is a ROOT enumerated device, check for Service, BootConfig
  691. // and FirmwareIdentified values.
  692. //
  693. if (bIsDeviceRootEnumerated) {
  694. //
  695. // Check for the "Service" value.
  696. //
  697. dwBufferSize = sizeof(szService);
  698. result = RegQueryValueEx(hInstanceKey,
  699. REGSTR_VAL_SERVICE,
  700. 0,
  701. &dwType,
  702. (LPBYTE)szService,
  703. &dwBufferSize);
  704. if ((result != ERROR_SUCCESS) ||
  705. (dwType != REG_SZ)) {
  706. //
  707. // No "Service" value to migrate.
  708. //
  709. *szService = TEXT('\0');
  710. result = ERROR_SUCCESS;
  711. }
  712. //
  713. // Check for the "LogConf\BootConfig" value.
  714. //
  715. result = RegOpenKeyEx(hInstanceKey,
  716. REGSTR_KEY_LOGCONF,
  717. 0,
  718. KEY_READ,
  719. &hLogConfKey);
  720. if (result == ERROR_SUCCESS) {
  721. result = RegQueryValueEx(hLogConfKey,
  722. REGSTR_VAL_BOOTCONFIG,
  723. 0,
  724. &dwType,
  725. (LPBYTE)NULL,
  726. &dwBootConfigSize);
  727. if ((result == ERROR_SUCCESS) &&
  728. (dwType == REG_RESOURCE_LIST)) {
  729. pBootConfig = MyMalloc(dwBootConfigSize);
  730. if (pBootConfig) {
  731. result = RegQueryValueEx(hLogConfKey,
  732. REGSTR_VAL_BOOTCONFIG,
  733. 0,
  734. &dwType,
  735. (LPBYTE)pBootConfig,
  736. &dwBootConfigSize);
  737. if ((result == ERROR_SUCCESS) &&
  738. (dwType == REG_RESOURCE_LIST)) {
  739. //
  740. // Allocate a string buffer large enough to store
  741. // each nibble of the BootConfig data as a separate
  742. // character.
  743. //
  744. pszBootConfig = MyMalloc((dwBootConfigSize*2 + 1)*sizeof(TCHAR));
  745. if (pszBootConfig) {
  746. DWORD b;
  747. //
  748. // Convert the binary BootConfig data to a string
  749. // format that we can throw into the sif.
  750. //
  751. for (b = 0; b < dwBootConfigSize; b++) {
  752. // first write the high-order nibble,
  753. wsprintf((PTCHAR)&pszBootConfig[2*b],
  754. TEXT("%X"),
  755. pBootConfig[b] / (0x10));
  756. // then the low order nibble.
  757. wsprintf((PTCHAR)&pszBootConfig[2*b + 1],
  758. TEXT("%X"),
  759. pBootConfig[b] % (0x10));
  760. }
  761. }
  762. }
  763. MyFree(pBootConfig);
  764. pBootConfig = NULL;
  765. }
  766. } else {
  767. //
  768. // No "LogConf\BootConfig" value to migrate.
  769. //
  770. pszBootConfig = NULL;
  771. }
  772. RegCloseKey(hLogConfKey);
  773. }
  774. //
  775. // Check for the "FirmwareIdentified" value
  776. //
  777. dwBufferSize = sizeof(dwFirmwareIdentified);
  778. result = RegQueryValueEx(hInstanceKey,
  779. REGSTR_VAL_FIRMWAREIDENTIFIED,
  780. 0,
  781. &dwType,
  782. (LPBYTE)&dwFirmwareIdentified,
  783. &dwBufferSize);
  784. if ((result == ERROR_SUCCESS) &&
  785. (dwType == REG_DWORD)){
  786. //
  787. // Write the FirmwareIdentified value to the sif as a base 16 value.
  788. // (see admin\ntsetup\textmode\kernel\spsetup.c)
  789. //
  790. wsprintf(szFirmwareIdentified,
  791. TEXT("%X"), // base 16
  792. dwFirmwareIdentified);
  793. } else {
  794. //
  795. // No "FirmwareIdentified" value to migrate.
  796. //
  797. *szFirmwareIdentified = TEXT('\0');
  798. }
  799. } else {
  800. //
  801. // We only migrate Service, BootConfig, and FirmwareIdentified
  802. // values for Root enumerated devices.
  803. //
  804. *szService = TEXT('\0');
  805. pszBootConfig = NULL;
  806. *szFirmwareIdentified = TEXT('\0');
  807. }
  808. //
  809. // If there are no values to migrate for this device instance, skip it.
  810. //
  811. if (!*szUniqueParentID &&
  812. !*szDriver &&
  813. !*szParentIdPrefix &&
  814. !*szService &&
  815. !pszBootConfig &&
  816. !*szFirmwareIdentified) {
  817. continue;
  818. }
  819. //
  820. // If any of the strings cannot be migrated, skip it.
  821. //
  822. if ((!CanStringBeMigrated(szDriver)) ||
  823. (!CanStringBeMigrated(szService)) ||
  824. (!CanStringBeMigrated(Enumerator)) ||
  825. (!CanStringBeMigrated(Device)) ||
  826. (!CanStringBeMigrated(pszDeviceInstanceId))) {
  827. continue;
  828. }
  829. //
  830. // This block appends the class key data we want to migrate to a
  831. // multi-sz style string that will be written to the sif file.
  832. //
  833. //
  834. // Need space in the section buffer for a string of the form:
  835. // Enumerator\Device\Instance,UniqueParentID,ParentIdPrefix,DriverKey,Service,BootConfig
  836. //
  837. //
  838. // First, determine the space required by the common parts.
  839. //
  840. dwSpaceNeeded = 1 + // TEXT('\"')
  841. lstrlen(Enumerator) +
  842. 1 + // TEXT('\\')
  843. lstrlen(Device) +
  844. 1 + // TEXT('\\')
  845. lstrlen(pszDeviceInstanceId) +
  846. 1 + // TEXT('\"')
  847. 1; // TEXT(',')
  848. //
  849. // Next, determine the space required, based on the data we have.
  850. //
  851. if (*szFirmwareIdentified) {
  852. dwSpaceNeeded +=
  853. lstrlen(szUniqueParentID) +
  854. 1 + // TEXT(',')
  855. lstrlen(szParentIdPrefix) +
  856. 1 + // TEXT(',')
  857. lstrlen(szDriver) +
  858. 1 + // TEXT(',')
  859. 1 + // TEXT('"')
  860. lstrlen(szService) +
  861. 1 + // TEXT('"')
  862. 1 + // TEXT(',')
  863. (pszBootConfig ? lstrlen(pszBootConfig) : 0) +
  864. 1 + // TEXT(',')
  865. lstrlen(szFirmwareIdentified);
  866. } else if (pszBootConfig) {
  867. dwSpaceNeeded +=
  868. lstrlen(szUniqueParentID) +
  869. 1 + // TEXT(',')
  870. lstrlen(szParentIdPrefix) +
  871. 1 + // TEXT(',')
  872. lstrlen(szDriver) +
  873. 1 + // TEXT(',')
  874. 1 + // TEXT('"')
  875. lstrlen(szService) +
  876. 1 + // TEXT('"')
  877. 1 + // TEXT(',')
  878. lstrlen(pszBootConfig);
  879. } else if (*szService) {
  880. dwSpaceNeeded +=
  881. lstrlen(szUniqueParentID) +
  882. 1 + // TEXT(',')
  883. lstrlen(szParentIdPrefix) +
  884. 1 + // TEXT(',')
  885. lstrlen(szDriver) +
  886. 1 + // TEXT(',')
  887. 1 + // TEXT('"')
  888. lstrlen(szService) +
  889. 1; // TEXT('"')
  890. } else if (*szDriver) {
  891. dwSpaceNeeded +=
  892. lstrlen(szUniqueParentID) +
  893. 1 + // TEXT(',')
  894. lstrlen(szParentIdPrefix) +
  895. 1 + // TEXT(',')
  896. lstrlen(szDriver);
  897. } else if (*szParentIdPrefix) {
  898. dwSpaceNeeded +=
  899. lstrlen(szUniqueParentID) +
  900. 1 + // TEXT(',')
  901. lstrlen(szParentIdPrefix);
  902. } else if (*szUniqueParentID) {
  903. dwSpaceNeeded +=
  904. lstrlen(szUniqueParentID);
  905. }
  906. //
  907. // Account for the NULL terminator.
  908. //
  909. dwSpaceNeeded += 1;
  910. if (*dwDeviceInstanceSectionRemaining <= dwSpaceNeeded) {
  911. //
  912. // ReAllocate the section block.
  913. //
  914. LPTSTR p;
  915. DWORD dwTempSectionLength, dwTempSectionRemaining;
  916. dwTempSectionRemaining = *dwDeviceInstanceSectionRemaining + *dwDeviceInstanceSectionLength;
  917. dwTempSectionLength = *dwDeviceInstanceSectionLength * 2;
  918. p = *pszDeviceInstanceSection;
  919. p = MyRealloc(p,
  920. dwTempSectionLength*sizeof(TCHAR));
  921. if (!p) {
  922. DBGTRACE( DBGF_ERRORS,
  923. (TEXT("EnumerateInstanceKeys: REALLOC failed!!!\n") ));
  924. result = ERROR_NOT_ENOUGH_MEMORY;
  925. RegCloseKey(hInstanceKey);
  926. goto Clean0;
  927. }
  928. *pszDeviceInstanceSection = p;
  929. *dwDeviceInstanceSectionRemaining = dwTempSectionRemaining;
  930. *dwDeviceInstanceSectionLength = dwTempSectionLength;
  931. *pszDeviceInstanceCurrent = *pszDeviceInstanceSection +
  932. (*dwDeviceInstanceSectionLength -
  933. *dwDeviceInstanceSectionRemaining);
  934. }
  935. //
  936. // Write the current line to the section block.
  937. //
  938. if (*szFirmwareIdentified) {
  939. dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
  940. TEXT("\"%s\\%s\\%s\",%s,%s,%s,\"%s\",%s,%s"),
  941. Enumerator, Device, pszDeviceInstanceId,
  942. szUniqueParentID,
  943. szParentIdPrefix,
  944. szDriver,
  945. szService,
  946. (pszBootConfig ? pszBootConfig : TEXT("\0")),
  947. szFirmwareIdentified);
  948. } else if (pszBootConfig) {
  949. dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
  950. TEXT("\"%s\\%s\\%s\",%s,%s,%s,\"%s\",%s"),
  951. Enumerator, Device, pszDeviceInstanceId,
  952. szUniqueParentID,
  953. szParentIdPrefix,
  954. szDriver,
  955. szService,
  956. pszBootConfig);
  957. } else if (*szService) {
  958. dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
  959. TEXT("\"%s\\%s\\%s\",%s,%s,%s,\"%s\""),
  960. Enumerator, Device, pszDeviceInstanceId,
  961. szUniqueParentID,
  962. szParentIdPrefix,
  963. szDriver,
  964. szService);
  965. } else if (*szDriver) {
  966. dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
  967. TEXT("\"%s\\%s\\%s\",%s,%s,%s"),
  968. Enumerator, Device, pszDeviceInstanceId,
  969. szUniqueParentID,
  970. szParentIdPrefix,
  971. szDriver);
  972. } else if (*szParentIdPrefix) {
  973. dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
  974. TEXT("\"%s\\%s\\%s\",%s,%s"),
  975. Enumerator, Device, pszDeviceInstanceId,
  976. szUniqueParentID,
  977. szParentIdPrefix);
  978. } else if (*szUniqueParentID) {
  979. dwSpaceConsumed = wsprintf(*pszDeviceInstanceCurrent,
  980. TEXT("\"%s\\%s\\%s\",%s"),
  981. Enumerator, Device, pszDeviceInstanceId,
  982. szUniqueParentID);
  983. }
  984. //
  985. // Free the allocated BootConfig string buffer.
  986. //
  987. if (pszBootConfig) {
  988. MyFree(pszBootConfig);
  989. pszBootConfig = NULL;
  990. }
  991. //
  992. // Account for the NULL terminator
  993. //
  994. dwSpaceConsumed += 1;
  995. *pszDeviceInstanceCurrent += dwSpaceConsumed;
  996. *dwDeviceInstanceSectionRemaining -= dwSpaceConsumed;
  997. //
  998. // Close the device instance key
  999. //
  1000. RegCloseKey(hInstanceKey);
  1001. }
  1002. Clean0:
  1003. //
  1004. // Do some cleanup
  1005. //
  1006. if (pszDeviceInstanceId) {
  1007. MyFree(pszDeviceInstanceId);
  1008. }
  1009. if (hDeviceKey != NULL) {
  1010. RegCloseKey(hDeviceKey);
  1011. }
  1012. if (result != ERROR_SUCCESS) {
  1013. SetLastError(result);
  1014. }
  1015. return (result == ERROR_SUCCESS);
  1016. } // EnumerateInstanceKeys()
  1017. BOOL
  1018. CanStringBeMigrated(
  1019. IN LPTSTR pszBuffer
  1020. )
  1021. {
  1022. LPTSTR p;
  1023. BOOL bStatus;
  1024. try {
  1025. //
  1026. // An empty string can be migrated.
  1027. //
  1028. if (!ARGUMENT_PRESENT(pszBuffer)) {
  1029. bStatus = TRUE;
  1030. goto Clean0;
  1031. }
  1032. for (p = pszBuffer; *p; p++) {
  1033. //
  1034. // Check for the presence of non-migratable characters.
  1035. //
  1036. if ((*p == TEXT('=')) || (*p == TEXT('"'))) {
  1037. bStatus = FALSE;
  1038. goto Clean0;
  1039. }
  1040. }
  1041. //
  1042. // Found no problems with the string.
  1043. //
  1044. bStatus = TRUE;
  1045. Clean0:
  1046. NOTHING;
  1047. } except(EXCEPTION_EXECUTE_HANDLER) {
  1048. bStatus = FALSE;
  1049. }
  1050. return bStatus;
  1051. } // CanStringBeMigrated
  1052. //
  1053. // Class key enumeration routines
  1054. //
  1055. BOOL
  1056. MigrateClassKeys(
  1057. OUT LPTSTR *Buffer
  1058. )
  1059. /*++
  1060. Routine Description:
  1061. This routine walks the Plug and Play setup class branch of the registry, and
  1062. collects the data about what keys currently exist. This information is
  1063. relevant to maintaining plug and play state during textmode setup, such that
  1064. the names of existing keys are not reassigned before they have been migrated
  1065. to the registry at the end of textmode setup.
  1066. Specifically, a multi-sz string will be returned to the caller that contains
  1067. each subkey of the class branch.
  1068. Arguments:
  1069. Buffer - Supplies the address of a character pointer, that on success will
  1070. contain a multi-sz list of setup class subkeys to migrate.
  1071. The caller is responsible for freeing the memory via LocalFree.
  1072. Return Value:
  1073. TRUE if successful, FALSE otherwise. Upon failure, additional information
  1074. can be retrieved by calling GetLastError().
  1075. --*/
  1076. {
  1077. LONG result = ERROR_SUCCESS;
  1078. HKEY hClassKey = NULL;
  1079. DWORD dwSubkeyCount, dwMaxSubKeyLength, i;
  1080. LPTSTR pszClassKeyName = NULL;
  1081. LPTSTR pszClassKeySection = NULL;
  1082. LPTSTR pszClassKeyCurrent = NULL;
  1083. DWORD dwClassKeySectionLength = 0;
  1084. DWORD dwClassKeySectionRemaining = 0;
  1085. //
  1086. // Initialize the output parameter.
  1087. //
  1088. *Buffer = NULL;
  1089. //
  1090. // Allocate storage and initialize variables for the class Key migration
  1091. // section.
  1092. //
  1093. if (pszClassKeySection == NULL) {
  1094. dwClassKeySectionLength = dwClassKeySectionRemaining = 256;
  1095. pszClassKeySection = MyMalloc(dwClassKeySectionLength * sizeof(TCHAR));
  1096. if (!pszClassKeySection) {
  1097. DBGTRACE( DBGF_ERRORS,
  1098. (TEXT("MigrateClassKeys: initial ALLOC for ClassKeySection failed!!\n") ));
  1099. result = ERROR_NOT_ENOUGH_MEMORY;
  1100. goto Clean0;
  1101. }
  1102. pszClassKeyCurrent = pszClassKeySection;
  1103. }
  1104. //
  1105. // Open a handle to the HKLM\SYSTEM\CCS\Control\Class key.
  1106. //
  1107. result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1108. REGSTR_PATH_CLASS_NT,
  1109. 0,
  1110. KEY_READ,
  1111. &hClassKey);
  1112. if (result != ERROR_SUCCESS) {
  1113. DBGTRACE( DBGF_ERRORS,
  1114. (TEXT("MigrateClassKeys: failed to open %s, error=0x%08lx\n"),
  1115. REGSTR_PATH_CLASS_NT, result));
  1116. goto Clean0;
  1117. }
  1118. //
  1119. // Query the Class key for class GUID subkey information.
  1120. //
  1121. result = RegQueryInfoKey(hClassKey,
  1122. NULL,
  1123. NULL,
  1124. NULL,
  1125. &dwSubkeyCount,
  1126. &dwMaxSubKeyLength,
  1127. NULL,
  1128. NULL,
  1129. NULL,
  1130. NULL,
  1131. NULL,
  1132. NULL);
  1133. if (result != ERROR_SUCCESS) {
  1134. DBGTRACE( DBGF_ERRORS,
  1135. (TEXT("MigrateClassKeys: failed to query %s key, error=0x%08lx\n"),
  1136. REGSTR_PATH_CLASS_NT, result));
  1137. goto Clean0;
  1138. }
  1139. //
  1140. // Allocate a buffer to hold the largest setup class GUID subkey name.
  1141. //
  1142. dwMaxSubKeyLength++;
  1143. MYASSERT(dwMaxSubKeyLength == MAX_GUID_STRING_LEN);
  1144. pszClassKeyName = MyMalloc(dwMaxSubKeyLength * sizeof(TCHAR));
  1145. if (!pszClassKeyName) {
  1146. result = ERROR_NOT_ENOUGH_MEMORY;
  1147. DBGTRACE( DBGF_ERRORS,
  1148. (TEXT("MigrateClassKeys: ALLOC for Class GUID key names failed!!\n") ));
  1149. goto Clean0;
  1150. }
  1151. //
  1152. // Enumerate the setup class GUIDs.
  1153. //
  1154. for (i = 0; i < dwSubkeyCount; i++) {
  1155. DWORD dwClassKeyLength;
  1156. dwClassKeyLength = dwMaxSubKeyLength;
  1157. result = RegEnumKeyEx(hClassKey,
  1158. i,
  1159. pszClassKeyName,
  1160. &dwClassKeyLength,
  1161. 0,
  1162. NULL,
  1163. NULL,
  1164. NULL);
  1165. if (result != ERROR_SUCCESS) {
  1166. //
  1167. // If there was some error enumerating this key, skip it.
  1168. //
  1169. MYASSERT(result != ERROR_NO_MORE_ITEMS);
  1170. DBGTRACE( DBGF_WARNINGS,
  1171. (TEXT("MigrateClassKeys: failed to enumerate a class subkey, error=0x%08lx\n"),
  1172. result));
  1173. result = ERROR_SUCCESS;
  1174. continue;
  1175. }
  1176. //
  1177. // Enumerate all subkeys for a given setup class key, and append them to
  1178. // the section buffer.
  1179. //
  1180. if (!EnumerateClassSubkeys(hClassKey,
  1181. pszClassKeyName,
  1182. &pszClassKeySection,
  1183. &pszClassKeyCurrent,
  1184. &dwClassKeySectionLength,
  1185. &dwClassKeySectionRemaining)) {
  1186. DBGTRACE( DBGF_ERRORS,
  1187. (TEXT("EnumerateClassSubkeys failed, error=0x%08lx\n"),
  1188. GetLastError()));
  1189. }
  1190. }
  1191. //
  1192. // Once we've enumerated all class subkeys, add the final NULL terminator to
  1193. // the multi-sz buffer. There must be enough space for the final NULL
  1194. // terminator because the buffer is always reallocated unless there is room.
  1195. //
  1196. MYASSERT(dwClassKeySectionRemaining > 0);
  1197. MYASSERT(pszClassKeyCurrent);
  1198. *pszClassKeyCurrent = TEXT('\0');
  1199. dwClassKeySectionRemaining -= 1;
  1200. Clean0:
  1201. //
  1202. // Do some cleanup.
  1203. //
  1204. if (pszClassKeyName) {
  1205. MyFree(pszClassKeyName);
  1206. }
  1207. if (hClassKey) {
  1208. RegCloseKey(hClassKey);
  1209. }
  1210. //
  1211. // Return the buffer to the caller only if successful.
  1212. //
  1213. if (result == ERROR_SUCCESS) {
  1214. *Buffer = pszClassKeySection;
  1215. } else {
  1216. SetLastError(result);
  1217. if (pszClassKeySection) {
  1218. MyFree(pszClassKeySection);
  1219. }
  1220. }
  1221. return (result == ERROR_SUCCESS);
  1222. } // MigrateClassKeys()
  1223. BOOL
  1224. EnumerateClassSubkeys(
  1225. IN HKEY ClassKey,
  1226. IN LPTSTR ClassKeyName,
  1227. IN OUT LPTSTR *pszClassKeySection,
  1228. IN OUT LPTSTR *pszClassKeyCurrent,
  1229. IN OUT DWORD *dwClassKeySectionLength,
  1230. IN OUT DWORD *dwClassKeySectionRemaining
  1231. )
  1232. /*++
  1233. Routine Description:
  1234. Enumerates subkeys of a setup class key.
  1235. Worker routine for MigrateClassKeys.
  1236. Return Value:
  1237. TRUE if successful, FALSE otherwise. Upon failure, additional information
  1238. can be retrieved by calling GetLastError().
  1239. --*/
  1240. {
  1241. LONG result = ERROR_SUCCESS;
  1242. HKEY hClassSubkey = NULL;
  1243. LPTSTR pszClassSubkey = NULL;
  1244. DWORD dwSubkeyCount, dwMaxSubKeyLength, dwSpaceNeeded, dwSpaceConsumed, i;
  1245. //
  1246. // Open the class subkey.
  1247. //
  1248. result = RegOpenKeyEx(ClassKey,
  1249. ClassKeyName,
  1250. 0,
  1251. KEY_READ,
  1252. &hClassSubkey);
  1253. if (result != ERROR_SUCCESS) {
  1254. DBGTRACE( DBGF_ERRORS,
  1255. (TEXT("EnumerateClassSubkeys: failed to open '%s' class key, error=0x%08lx\n"),
  1256. ClassKeyName, result));
  1257. goto Clean0;
  1258. }
  1259. //
  1260. // Query the class GUID key for setup class subkey information.
  1261. //
  1262. result = RegQueryInfoKey(hClassSubkey,
  1263. NULL,
  1264. NULL,
  1265. NULL,
  1266. &dwSubkeyCount,
  1267. &dwMaxSubKeyLength,
  1268. NULL,
  1269. NULL,
  1270. NULL,
  1271. NULL,
  1272. NULL,
  1273. NULL);
  1274. if (result != ERROR_SUCCESS) {
  1275. DBGTRACE( DBGF_ERRORS,
  1276. (TEXT("EnumerateClassSubkeys: failed to query '%s' class key, error=0x%08lx\n"),
  1277. ClassKeyName, result));
  1278. goto Clean0;
  1279. }
  1280. //
  1281. // Allocate a buffer to hold the largest setup class subkey name.
  1282. //
  1283. dwMaxSubKeyLength++;
  1284. pszClassSubkey = MyMalloc(dwMaxSubKeyLength * sizeof(TCHAR));
  1285. if (!pszClassSubkey) {
  1286. result = ERROR_NOT_ENOUGH_MEMORY;
  1287. DBGTRACE( DBGF_ERRORS,
  1288. (TEXT("EnumerateClassSubkeys: ALLOC for Class GUID subkey names failed!!\n") ));
  1289. goto Clean0;
  1290. }
  1291. //
  1292. // Enumerate the setup class's "software" subkeys.
  1293. //
  1294. for (i = 0; i < dwSubkeyCount; i++) {
  1295. DWORD dwClassSubkeyLength;
  1296. dwClassSubkeyLength = dwMaxSubKeyLength;
  1297. result = RegEnumKeyEx(hClassSubkey,
  1298. i,
  1299. pszClassSubkey,
  1300. &dwClassSubkeyLength,
  1301. 0,
  1302. NULL,
  1303. NULL,
  1304. NULL);
  1305. if ((result != ERROR_SUCCESS) ||
  1306. (dwClassSubkeyLength != 4)) {
  1307. //
  1308. // if there was some error, or this is not an actual "software" key
  1309. // (in the form "XXXX"), skip this key and move on.
  1310. //
  1311. if (result != ERROR_SUCCESS) {
  1312. MYASSERT(result != ERROR_NO_MORE_ITEMS);
  1313. DBGTRACE( DBGF_WARNINGS,
  1314. (TEXT("EnumerateClassSubkeys: failed to enumerate a '%s' subkey, error=0x%08lx\n"),
  1315. ClassKeyName, result));
  1316. }
  1317. result = ERROR_SUCCESS;
  1318. continue;
  1319. }
  1320. //
  1321. // This block appends the class key data we want to migrate to a
  1322. // multi-sz style string that will be written to the sif file.
  1323. //
  1324. //
  1325. // Need space in the section buffer for a string of the form:
  1326. // ClassKeyName\pszClassSubkey
  1327. //
  1328. dwSpaceNeeded = lstrlen(ClassKeyName) +
  1329. 1 + // TEXT('\\')
  1330. lstrlen(pszClassSubkey);
  1331. //
  1332. // Account for the NULL terminator.
  1333. //
  1334. dwSpaceNeeded += 1;
  1335. if (*dwClassKeySectionRemaining <= dwSpaceNeeded) {
  1336. //
  1337. // ReAllocate the section block.
  1338. //
  1339. LPTSTR p;
  1340. DWORD dwTempSectionLength, dwTempSectionRemaining;
  1341. dwTempSectionRemaining = *dwClassKeySectionRemaining + *dwClassKeySectionLength;
  1342. dwTempSectionLength = *dwClassKeySectionLength * 2;
  1343. p = *pszClassKeySection;
  1344. p = MyRealloc(p,
  1345. dwTempSectionLength*sizeof(TCHAR));
  1346. if (!p) {
  1347. DBGTRACE( DBGF_ERRORS,
  1348. (TEXT("EnumerateClassSubkeys: REALLOC failed!!!\n") ));
  1349. result = ERROR_NOT_ENOUGH_MEMORY;
  1350. goto Clean0;
  1351. }
  1352. *pszClassKeySection = p;
  1353. *dwClassKeySectionRemaining = dwTempSectionRemaining;
  1354. *dwClassKeySectionLength = dwTempSectionLength;
  1355. *pszClassKeyCurrent = *pszClassKeySection +
  1356. (*dwClassKeySectionLength -
  1357. *dwClassKeySectionRemaining);
  1358. }
  1359. //
  1360. // Write the current line to the section block.
  1361. //
  1362. dwSpaceConsumed = wsprintf(*pszClassKeyCurrent,
  1363. TEXT("%s\\%s"),
  1364. ClassKeyName,
  1365. pszClassSubkey);
  1366. //
  1367. // Account for the NULL terminator.
  1368. //
  1369. dwSpaceConsumed += 1;
  1370. *pszClassKeyCurrent += dwSpaceConsumed;
  1371. *dwClassKeySectionRemaining -= dwSpaceConsumed;
  1372. }
  1373. Clean0:
  1374. //
  1375. // Do some cleanup.
  1376. //
  1377. if (hClassSubkey != NULL) {
  1378. RegCloseKey(hClassSubkey);
  1379. }
  1380. if (pszClassSubkey) {
  1381. MyFree(pszClassSubkey);
  1382. }
  1383. if (result != ERROR_SUCCESS) {
  1384. SetLastError(result);
  1385. }
  1386. return (result == ERROR_SUCCESS);
  1387. } // EnumerateClassSubkeys()
  1388. //
  1389. // Hash value migration routines
  1390. //
  1391. BOOL
  1392. MigrateHashValues(
  1393. OUT LPTSTR *Buffer
  1394. )
  1395. /*++
  1396. Routine Description:
  1397. This routine searches the Plug and Play Enum key of the registry, and
  1398. collects the data about what hash value entries currently exist. This
  1399. information is relevant to maintaining plug and play state during textmode
  1400. setup, such that the names of existing device instances are not reassigned
  1401. before they have been migrated to the registry at the end of textmode setup.
  1402. Specifically, a multi-sz string will be returned to the caller that contains
  1403. the name of the hash value, and its count.
  1404. Arguments:
  1405. Buffer - Supplies the address of a character pointer, that on success will
  1406. contain a multi-sz list of hash values to migrate.
  1407. The caller is responsible for freeing the memory via LocalFree.
  1408. Return Value:
  1409. TRUE if successful, FALSE otherwise. Upon failure, additional information
  1410. can be retrieved by calling GetLastError().
  1411. --*/
  1412. {
  1413. LONG result = ERROR_SUCCESS;
  1414. HKEY hEnumKey = NULL;
  1415. DWORD dwValueCount, dwMaxValueNameLength, dwSpaceNeeded, dwSpaceConsumed, i;
  1416. LPTSTR pszHashValueName = NULL;
  1417. LPTSTR pszHashValueSection = NULL;
  1418. LPTSTR pszHashValueCurrent = NULL;
  1419. DWORD dwHashValueSectionLength = 0;
  1420. DWORD dwHashValueSectionRemaining = 0;
  1421. //
  1422. // Initialize the output parameter.
  1423. //
  1424. *Buffer = NULL;
  1425. #if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
  1426. //
  1427. // Unlock the Enum key
  1428. //
  1429. LockUnlockEnumTree(FALSE);
  1430. #endif // DO_LOCK_UNLOCK
  1431. //
  1432. // Allocate storage and initialize variables for the hash value migration
  1433. // section.
  1434. //
  1435. if (pszHashValueSection == NULL) {
  1436. dwHashValueSectionLength = dwHashValueSectionRemaining = 256;
  1437. pszHashValueSection = MyMalloc(dwHashValueSectionLength * sizeof(TCHAR));
  1438. if (!pszHashValueSection) {
  1439. result = ERROR_NOT_ENOUGH_MEMORY;
  1440. DBGTRACE( DBGF_ERRORS,
  1441. (TEXT("MigrateHashValues: initial ALLOC for HashValueSection failed!!\n") ));
  1442. goto Clean0;
  1443. }
  1444. pszHashValueCurrent = pszHashValueSection;
  1445. }
  1446. //
  1447. // Open a handle to the HKLM\SYSTEM\CCS\Enum key.
  1448. //
  1449. result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1450. REGSTR_PATH_SYSTEMENUM,
  1451. 0,
  1452. KEY_READ,
  1453. &hEnumKey);
  1454. if (result != ERROR_SUCCESS) {
  1455. DBGTRACE( DBGF_ERRORS,
  1456. (TEXT("MigrateHashValues: failed to open %s, error=0x%08lx\n"),
  1457. REGSTR_PATH_SYSTEMENUM, result));
  1458. goto Clean0;
  1459. }
  1460. //
  1461. // Query the Enum key for hash value information.
  1462. //
  1463. result = RegQueryInfoKey(hEnumKey,
  1464. NULL,
  1465. NULL,
  1466. NULL,
  1467. NULL,
  1468. NULL,
  1469. NULL,
  1470. &dwValueCount,
  1471. &dwMaxValueNameLength,
  1472. NULL,
  1473. NULL,
  1474. NULL);
  1475. if (result != ERROR_SUCCESS) {
  1476. DBGTRACE( DBGF_ERRORS,
  1477. (TEXT("MigrateHashValues: failed to query %s key, error=0x%08lx\n"),
  1478. REGSTR_PATH_SYSTEMENUM, result));
  1479. goto Clean0;
  1480. }
  1481. //
  1482. // Allocate a variable to hold the largest hash value key name.
  1483. //
  1484. dwMaxValueNameLength++;
  1485. pszHashValueName = MyMalloc(dwMaxValueNameLength * sizeof(TCHAR));
  1486. if (!pszHashValueName) {
  1487. DBGTRACE( DBGF_ERRORS,
  1488. (TEXT("MigrateHashValues: failed to allocate buffer for Enum key hash values\n") ));
  1489. result = ERROR_NOT_ENOUGH_MEMORY;
  1490. goto Clean0;
  1491. }
  1492. //
  1493. // Enumerate all values and append them to the supplied buffer.
  1494. //
  1495. for (i = 0; i < dwValueCount; i++) {
  1496. DWORD dwHashValueLength, dwType, dwData, dwSize;
  1497. TCHAR szHashValueData[11];
  1498. dwHashValueLength = dwMaxValueNameLength;
  1499. dwType = REG_DWORD;
  1500. dwData = 0;
  1501. dwSize = sizeof(DWORD);
  1502. result = RegEnumValue(hEnumKey,
  1503. i,
  1504. pszHashValueName,
  1505. &dwHashValueLength,
  1506. 0,
  1507. &dwType,
  1508. (LPBYTE)&dwData,
  1509. &dwSize);
  1510. if ((result != ERROR_SUCCESS) ||
  1511. (dwType != REG_DWORD) ||
  1512. (dwSize != sizeof(DWORD))) {
  1513. //
  1514. // If there was some error enumerating this value, or the value
  1515. // return was not expected, skip it.
  1516. //
  1517. MYASSERT(result != ERROR_NO_MORE_ITEMS);
  1518. DBGTRACE( DBGF_WARNINGS,
  1519. (TEXT("MigrateHashValues: failed to enumerate Enum values, error=0x%08lx\n"),
  1520. result));
  1521. result = ERROR_SUCCESS;
  1522. continue;
  1523. }
  1524. //
  1525. // Write the hash value data to the sif as a base 10 value.
  1526. // (see admin\ntsetup\textmode\kernel\spsetup.c)
  1527. //
  1528. wsprintf(szHashValueData,
  1529. TEXT("%d"), dwData); // base 10
  1530. //
  1531. // This block appends the class key data we want to migrate to a
  1532. // multi-sz style string that will be written to the sif file.
  1533. //
  1534. //
  1535. // Need space in the section buffer for a string of the form:
  1536. // HashValueName=HashValueData
  1537. //
  1538. dwSpaceNeeded = lstrlen(pszHashValueName) +
  1539. 1 + // TEXT('=')
  1540. lstrlen(szHashValueData);
  1541. //
  1542. // Account for the NULL terminator.
  1543. //
  1544. dwSpaceNeeded += 1;
  1545. if (dwHashValueSectionRemaining <= dwSpaceNeeded) {
  1546. //
  1547. // ReAllocate the section block.
  1548. //
  1549. LPTSTR p;
  1550. DWORD dwTempSectionLength, dwTempSectionRemaining;
  1551. dwTempSectionRemaining = dwHashValueSectionRemaining + dwHashValueSectionLength;
  1552. dwTempSectionLength = dwHashValueSectionLength * 2;
  1553. p = pszHashValueSection;
  1554. p = MyRealloc(p,
  1555. dwTempSectionLength*sizeof(TCHAR));
  1556. if (!p) {
  1557. DBGTRACE( DBGF_ERRORS,
  1558. (TEXT("MigrateHashValues: REALLOC failed!!!\n") ));
  1559. result = ERROR_NOT_ENOUGH_MEMORY;
  1560. goto Clean0;
  1561. }
  1562. pszHashValueSection = p;
  1563. dwHashValueSectionRemaining = dwTempSectionRemaining;
  1564. dwHashValueSectionLength = dwTempSectionLength;
  1565. pszHashValueCurrent = pszHashValueSection +
  1566. (dwHashValueSectionLength -
  1567. dwHashValueSectionRemaining);
  1568. }
  1569. //
  1570. // Write the current line to the section block.
  1571. //
  1572. dwSpaceConsumed = wsprintf(pszHashValueCurrent,
  1573. TEXT("%s=%s"),
  1574. pszHashValueName,
  1575. szHashValueData);
  1576. //
  1577. // Account for the NULL terminator.
  1578. //
  1579. dwSpaceConsumed += 1;
  1580. pszHashValueCurrent += dwSpaceConsumed;
  1581. dwHashValueSectionRemaining -= dwSpaceConsumed;
  1582. }
  1583. //
  1584. // Once we've enumerated all hash values, add the final NULL terminator to
  1585. // the multi-sz buffer. There must be enough space for the final NULL
  1586. // terminator because the buffer is always reallocated unless there is room.
  1587. //
  1588. MYASSERT(dwHashValueSectionRemaining > 0);
  1589. MYASSERT(pszHashValueCurrent);
  1590. *pszHashValueCurrent = TEXT('\0');
  1591. dwHashValueSectionRemaining -= 1;
  1592. Clean0:
  1593. //
  1594. // Do some cleanup
  1595. //
  1596. if (pszHashValueName) {
  1597. MyFree(pszHashValueName);
  1598. }
  1599. if (hEnumKey) {
  1600. RegCloseKey(hEnumKey);
  1601. }
  1602. #if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
  1603. //
  1604. // Lock the Enum tree
  1605. //
  1606. LockUnlockEnumTree(TRUE);
  1607. #endif // DO_LOCK_UNLOCK
  1608. //
  1609. // Return the buffer to the caller only if successful.
  1610. //
  1611. if (result == ERROR_SUCCESS) {
  1612. *Buffer = pszHashValueSection;
  1613. } else {
  1614. SetLastError(result);
  1615. if (pszHashValueSection) {
  1616. MyFree(pszHashValueSection);
  1617. }
  1618. }
  1619. return (result == ERROR_SUCCESS);
  1620. } // MigrateHashValues()
  1621. //
  1622. // Enum branch lock/unlock and security routines - taken from PNPREG.
  1623. // (we only need these if we're doing the Enum lock/unlock thing)
  1624. //
  1625. #if DO_LOCK_UNLOCK // DO_LOCK_UNLOCK
  1626. VOID
  1627. LockUnlockEnumTree(
  1628. IN BOOL bLock
  1629. )
  1630. /*++
  1631. Routine Description:
  1632. This function "locks" or "unlocks" the Plug and Play Enum tree in the
  1633. registry.
  1634. Arguments:
  1635. bLock - If TRUE, specifies that the Enum tree should be "locked".
  1636. Otherwise, specifies that the Enum tree should be "unlocked".
  1637. Return Value:
  1638. None.
  1639. --*/
  1640. {
  1641. PSECURITY_DESCRIPTOR pSD;
  1642. HKEY hParentKey;
  1643. LONG RegStatus;
  1644. if (CreateSecurityDescriptors()) {
  1645. EnumKeysAndApplyDacls(HKEY_LOCAL_MACHINE,
  1646. REGSTR_PATH_SYSTEMENUM,
  1647. 0,
  1648. FALSE,
  1649. !bLock,
  1650. bLock ? &g_LockedPrivateKeysSD : &g_DeviceParametersSD,
  1651. &g_DeviceParametersSD);
  1652. FreeSecurityDescriptors();
  1653. }
  1654. return;
  1655. } // LockUnlockEnumTree()
  1656. VOID
  1657. EnumKeysAndApplyDacls(
  1658. IN HKEY hParentKey,
  1659. IN LPTSTR pszKeyName,
  1660. IN DWORD dwLevel,
  1661. IN BOOL bInDeviceParameters,
  1662. IN BOOL bApplyTopDown,
  1663. IN PSECURITY_DESCRIPTOR pPrivateKeySD,
  1664. IN PSECURITY_DESCRIPTOR pDeviceParametersSD
  1665. )
  1666. /*++
  1667. Routine Description:
  1668. This function applies the DACL in pSD to all the keys rooted at hKey
  1669. including hKey itself.
  1670. Arguments:
  1671. hParentKey - Handle to a registry key.
  1672. pszKeyName - Name of the key.
  1673. dwLevel - Number of levels remaining to recurse.
  1674. pSD - Pointer to a security descriptor containing a DACL.
  1675. Return Value:
  1676. None.
  1677. --*/
  1678. {
  1679. LONG regStatus;
  1680. DWORD dwMaxSubKeySize;
  1681. LPTSTR pszSubKey;
  1682. DWORD index;
  1683. HKEY hKey;
  1684. BOOL bNewInDeviceParameters;
  1685. #if 0 //#if DBG // DBG
  1686. DWORD dwStartKeyNameLength = g_dwCurrentKeyNameLength;
  1687. if (g_dwCurrentKeyNameLength != 0) {
  1688. g_szCurrentKeyName[ g_dwCurrentKeyNameLength++ ] = TEXT('\\');
  1689. }
  1690. _tcscpy(&g_szCurrentKeyName[g_dwCurrentKeyNameLength], pszKeyName);
  1691. g_dwCurrentKeyNameLength += _tcslen(pszKeyName);
  1692. #endif // DBG
  1693. DBGTRACE( DBGF_REGISTRY,
  1694. (TEXT("EnumKeysAndApplyDacls(0x%08X, \"%s\", %d, %s, %s, 0x%08X, 0x%08X)\n"),
  1695. hParentKey,
  1696. g_szCurrentKeyName,
  1697. dwLevel,
  1698. bInDeviceParameters ? TEXT("TRUE") : TEXT("FALSE"),
  1699. bApplyTopDown ? TEXT("TRUE") : TEXT("FALSE"),
  1700. pPrivateKeySD,
  1701. pDeviceParametersSD) );
  1702. if (bApplyTopDown) {
  1703. regStatus = RegOpenKeyEx( hParentKey,
  1704. pszKeyName,
  1705. 0,
  1706. WRITE_DAC,
  1707. &hKey
  1708. );
  1709. if (regStatus != ERROR_SUCCESS) {
  1710. DBGTRACE( DBGF_ERRORS,
  1711. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegOpenKeyEx() failed, error = %d\n"),
  1712. g_szCurrentKeyName, regStatus));
  1713. return;
  1714. }
  1715. DBGTRACE( DBGF_REGISTRY,
  1716. (TEXT("Setting security on %s on the way down\n"),
  1717. g_szCurrentKeyName) );
  1718. //
  1719. // apply the new security to the registry key
  1720. //
  1721. regStatus = RegSetKeySecurity( hKey,
  1722. DACL_SECURITY_INFORMATION,
  1723. bInDeviceParameters ?
  1724. pDeviceParametersSD :
  1725. pPrivateKeySD
  1726. );
  1727. if (regStatus != ERROR_SUCCESS) {
  1728. DBGTRACE( DBGF_ERRORS,
  1729. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegSetKeySecurity() failed, error = %d\n"),
  1730. g_szCurrentKeyName, regStatus));
  1731. }
  1732. //
  1733. // Close the key and reopen it later for read (which hopefully was just
  1734. // granted in the DACL we just wrote
  1735. //
  1736. RegCloseKey( hKey );
  1737. }
  1738. regStatus = RegOpenKeyEx( hParentKey,
  1739. pszKeyName,
  1740. 0,
  1741. KEY_READ | WRITE_DAC,
  1742. &hKey
  1743. );
  1744. if (regStatus != ERROR_SUCCESS) {
  1745. DBGTRACE( DBGF_ERRORS,
  1746. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegOpenKeyEx() failed, error = %d\n"),
  1747. g_szCurrentKeyName, regStatus));
  1748. return;
  1749. }
  1750. //
  1751. // Determine length of longest subkey
  1752. //
  1753. regStatus = RegQueryInfoKey( hKey,
  1754. NULL,
  1755. NULL,
  1756. NULL,
  1757. NULL,
  1758. &dwMaxSubKeySize,
  1759. NULL,
  1760. NULL,
  1761. NULL,
  1762. NULL,
  1763. NULL,
  1764. NULL );
  1765. if (regStatus == ERROR_SUCCESS) {
  1766. //
  1767. // Allocate a buffer to hold the subkey names. RegQueryInfoKey returns the
  1768. // size in characters and doesn't include the NUL terminator.
  1769. //
  1770. pszSubKey = LocalAlloc(0, ++dwMaxSubKeySize * sizeof(TCHAR));
  1771. if (pszSubKey != NULL) {
  1772. //
  1773. // Enumerate all the subkeys and then call ourselves recursively for each
  1774. // until dwLevel reaches 0.
  1775. //
  1776. for (index = 0; ; index++) {
  1777. regStatus = RegEnumKey( hKey,
  1778. index,
  1779. pszSubKey,
  1780. dwMaxSubKeySize
  1781. );
  1782. if (regStatus != ERROR_SUCCESS) {
  1783. if (regStatus != ERROR_NO_MORE_ITEMS) {
  1784. DBGTRACE( DBGF_ERRORS,
  1785. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegEnumKeyEx() failed, error = %d\n"),
  1786. g_szCurrentKeyName,
  1787. regStatus) );
  1788. }
  1789. break;
  1790. }
  1791. bNewInDeviceParameters = bInDeviceParameters ||
  1792. (dwLevel == 3 &&
  1793. _tcsicmp( pszSubKey,
  1794. REGSTR_KEY_DEVICEPARAMETERS ) == 0);
  1795. EnumKeysAndApplyDacls( hKey,
  1796. pszSubKey,
  1797. dwLevel + 1,
  1798. bNewInDeviceParameters,
  1799. bApplyTopDown,
  1800. pPrivateKeySD,
  1801. pDeviceParametersSD
  1802. );
  1803. }
  1804. LocalFree( pszSubKey );
  1805. }
  1806. }
  1807. else
  1808. {
  1809. DBGTRACE( DBGF_ERRORS,
  1810. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegQueryInfoKey() failed, error = %d\n"),
  1811. g_szCurrentKeyName, regStatus));
  1812. }
  1813. if (!bApplyTopDown) {
  1814. DBGTRACE( DBGF_REGISTRY,
  1815. (TEXT("Setting security on %s on the way back up\n"),
  1816. g_szCurrentKeyName) );
  1817. //
  1818. // apply the new security to the registry key
  1819. //
  1820. regStatus = RegSetKeySecurity( hKey,
  1821. DACL_SECURITY_INFORMATION,
  1822. bInDeviceParameters ?
  1823. pDeviceParametersSD :
  1824. pPrivateKeySD
  1825. );
  1826. if (regStatus != ERROR_SUCCESS) {
  1827. DBGTRACE( DBGF_ERRORS,
  1828. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegSetKeySecurity() failed, error = %d\n"),
  1829. g_szCurrentKeyName, regStatus));
  1830. }
  1831. }
  1832. RegCloseKey( hKey );
  1833. #if 0 //#if DBG // DBG
  1834. g_dwCurrentKeyNameLength = dwStartKeyNameLength;
  1835. g_szCurrentKeyName[g_dwCurrentKeyNameLength] = TEXT('\0');
  1836. #endif // DBG
  1837. return;
  1838. } // EnumKeysAndApplyDacls()
  1839. BOOL
  1840. CreateSecurityDescriptors(
  1841. VOID
  1842. )
  1843. /*++
  1844. Routine Description:
  1845. This function creates a properly initialized Security Descriptor for the
  1846. Device Parameters key and its subkeys. The SIDs and DACL created by this
  1847. routine must be freed by calling FreeSecurityDescriptors.
  1848. Arguments:
  1849. None.
  1850. Return Value:
  1851. Pointer to the initialized Security Descriptor. NULL is returned if an
  1852. error occurs.
  1853. --*/
  1854. {
  1855. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1856. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1857. EXPLICIT_ACCESS ExplicitAccess[3];
  1858. DWORD dwError;
  1859. BOOL bSuccess;
  1860. DWORD i;
  1861. FARPROC pSetEntriesInAcl;
  1862. HMODULE pAdvApi32;
  1863. pAdvApi32 = LoadLibrary( TEXT("advapi32.dll"));
  1864. if (!pAdvApi32) {
  1865. return(FALSE);
  1866. }
  1867. #ifdef UNICODE
  1868. pSetEntriesInAcl = GetProcAddress( pAdvApi32, "SetEntriesInAclW" );
  1869. #else
  1870. pSetEntriesInAcl = GetProcAddress( pAdvApi32, "SetEntriesInAclA" );
  1871. #endif
  1872. if (!pSetEntriesInAcl) {
  1873. FreeLibrary( pAdvApi32 );
  1874. return(FALSE);
  1875. }
  1876. //
  1877. // Create SIDs - Admins and System
  1878. //
  1879. bSuccess = AllocateAndInitializeSid( &NtAuthority,
  1880. 2,
  1881. SECURITY_BUILTIN_DOMAIN_RID,
  1882. DOMAIN_ALIAS_RID_ADMINS,
  1883. 0, 0, 0, 0, 0, 0,
  1884. &g_pAdminSid);
  1885. bSuccess = bSuccess && AllocateAndInitializeSid( &NtAuthority,
  1886. 1,
  1887. SECURITY_LOCAL_SYSTEM_RID,
  1888. 0, 0, 0, 0, 0, 0, 0,
  1889. &g_pSystemSid);
  1890. bSuccess = bSuccess && AllocateAndInitializeSid( &WorldAuthority,
  1891. 1,
  1892. SECURITY_WORLD_RID,
  1893. 0, 0, 0, 0, 0, 0, 0,
  1894. &g_pWorldSid);
  1895. if (bSuccess) {
  1896. //
  1897. // Initialize Access structures describing the ACEs we want:
  1898. // System Full Control
  1899. // Admins Full Control
  1900. //
  1901. // We'll take advantage of the fact that the unlocked private keys is
  1902. // the same as the device parameters key and they are a superset of the
  1903. // locked private keys.
  1904. //
  1905. // When we create the DACL for the private key we'll specify a subset of
  1906. // the ExplicitAccess array.
  1907. //
  1908. for (i = 0; i < 3; i++) {
  1909. ExplicitAccess[i].grfAccessMode = SET_ACCESS;
  1910. ExplicitAccess[i].grfInheritance = CONTAINER_INHERIT_ACE;
  1911. ExplicitAccess[i].Trustee.pMultipleTrustee = NULL;
  1912. ExplicitAccess[i].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  1913. ExplicitAccess[i].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  1914. ExplicitAccess[i].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  1915. }
  1916. ExplicitAccess[0].grfAccessPermissions = KEY_ALL_ACCESS;
  1917. ExplicitAccess[0].Trustee.ptstrName = (LPTSTR)g_pAdminSid;
  1918. ExplicitAccess[1].grfAccessPermissions = KEY_ALL_ACCESS;
  1919. ExplicitAccess[1].Trustee.ptstrName = (LPTSTR)g_pSystemSid;
  1920. ExplicitAccess[2].grfAccessPermissions = KEY_READ;
  1921. ExplicitAccess[2].Trustee.ptstrName = (LPTSTR)g_pWorldSid;
  1922. //
  1923. // Create the DACL with the both the above ACEs for the DeviceParameters
  1924. //
  1925. dwError = (DWORD)pSetEntriesInAcl( 3,
  1926. ExplicitAccess,
  1927. NULL,
  1928. &g_pDeviceParametersDacl );
  1929. if (dwError == ERROR_SUCCESS) {
  1930. //
  1931. // Create the DACL with just the system ACE for the locked private
  1932. // keys.
  1933. //
  1934. dwError = (DWORD)pSetEntriesInAcl( 2,
  1935. ExplicitAccess + 1,
  1936. NULL,
  1937. &g_pLockedPrivateKeysDacl );
  1938. }
  1939. bSuccess = dwError == ERROR_SUCCESS;
  1940. }
  1941. //
  1942. // Initialize the DeviceParameters security descriptor
  1943. //
  1944. bSuccess = bSuccess && InitializeSecurityDescriptor( &g_DeviceParametersSD,
  1945. SECURITY_DESCRIPTOR_REVISION );
  1946. //
  1947. // Set the new DACL in the security descriptor
  1948. //
  1949. bSuccess = bSuccess && SetSecurityDescriptorDacl( &g_DeviceParametersSD,
  1950. TRUE,
  1951. g_pDeviceParametersDacl,
  1952. FALSE);
  1953. //
  1954. // validate the new security descriptor
  1955. //
  1956. bSuccess = bSuccess && IsValidSecurityDescriptor( &g_DeviceParametersSD );
  1957. //
  1958. // Initialize the DeviceParameters security descriptor
  1959. //
  1960. bSuccess = bSuccess && InitializeSecurityDescriptor( &g_LockedPrivateKeysSD,
  1961. SECURITY_DESCRIPTOR_REVISION );
  1962. //
  1963. // Set the new DACL in the security descriptor
  1964. //
  1965. bSuccess = bSuccess && SetSecurityDescriptorDacl( &g_LockedPrivateKeysSD,
  1966. TRUE,
  1967. g_pLockedPrivateKeysDacl,
  1968. FALSE);
  1969. //
  1970. // validate the new security descriptor
  1971. //
  1972. bSuccess = bSuccess && IsValidSecurityDescriptor( &g_LockedPrivateKeysSD );
  1973. if (!bSuccess) {
  1974. FreeSecurityDescriptors();
  1975. }
  1976. FreeLibrary( pAdvApi32 );
  1977. return bSuccess;
  1978. } // CreateSecurityDescriptors()
  1979. VOID
  1980. FreeSecurityDescriptors(
  1981. VOID
  1982. )
  1983. /*++
  1984. Routine Description:
  1985. This function deallocates the data structures allocated and initialized by
  1986. CreateSecurityDescriptors.
  1987. Arguments:
  1988. None.
  1989. Return Value:
  1990. None.
  1991. --*/
  1992. {
  1993. if (g_pDeviceParametersDacl) {
  1994. LocalFree(g_pDeviceParametersDacl);
  1995. g_pDeviceParametersDacl = NULL;
  1996. }
  1997. if (g_pLockedPrivateKeysDacl) {
  1998. LocalFree(g_pLockedPrivateKeysDacl);
  1999. g_pLockedPrivateKeysDacl = NULL;
  2000. }
  2001. if (g_pAdminSid != NULL) {
  2002. FreeSid(g_pAdminSid);
  2003. g_pAdminSid = NULL;
  2004. }
  2005. if (g_pSystemSid != NULL) {
  2006. FreeSid(g_pSystemSid);
  2007. g_pSystemSid = NULL;
  2008. }
  2009. if (g_pWorldSid != NULL) {
  2010. FreeSid(g_pWorldSid);
  2011. g_pWorldSid = NULL;
  2012. }
  2013. return;
  2014. } // FreeSecurityDescriptors()
  2015. #endif // DO_LOCK_UNLOCK
  2016.