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

2725 lines
84 KiB

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