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.

1060 lines
35 KiB

  1. //*************************************************************
  2. //
  3. // HKCR management routines
  4. //
  5. // hkcr.c
  6. //
  7. // Microsoft Confidential
  8. // Copyright (c) Microsoft Corporation 1997
  9. // All rights reserved
  10. //
  11. //*************************************************************
  12. /*++
  13. Abstract:
  14. This module contains the code executed at logon for
  15. creating a user classes hive and mapping it into the standard
  16. user hive. The user classes hive and its machine classes
  17. counterpart make up the registry subtree known as
  18. HKEY_CLASSES_ROOT.
  19. Author:
  20. Adam P. Edwards (adamed) 10-Oct-1997
  21. Gregory Jensenworth (gregjen) 1-Jul-1997
  22. Key Functions:
  23. LoadUserClasses
  24. UnloadClasses
  25. Notes:
  26. Starting with NT5, the HKEY_CLASSES_ROOT key is per-user
  27. instead of per-machine -- previously, HKCR was an alias for
  28. HKLM\Software\Classes.
  29. The per-user HKCR combines machine classes stored it the
  30. traditional HKLM\Software\Classes location with classes
  31. stored in HKCU\Software\Classes.
  32. Certain keys, such as CLSID, will have subkeys that come
  33. from both the machine and user locations. When there is a conflict
  34. in key names, the user oriented key overrides the other one --
  35. only the user key is seen in that case.
  36. Originally, the code in this module was responsible for
  37. creating this combined view. That responsibility has moved
  38. to the win32 registry api's, so the main responsibility of
  39. this module is the mapping of the user-specific classes into
  40. the registry.
  41. It should be noted that HKCU\Software\Classes is not the true
  42. location of the user-only class data. If it were, all the class
  43. data would be in ntuser.dat, which roams with the user. Since
  44. class data can get very large, installation of a few apps
  45. would cause HKCU (ntuser.dat) to grow from a few hundred thousand K
  46. to several megabytes. Since user-only class data comes from
  47. the directory, it does not need to roam and therefore it was
  48. separated from HKCU (ntuser.dat) and stored in another hive
  49. mounted under HKEY_USERS.
  50. It is still desirable to allow access to this hive through
  51. HKCU\Software\Classes, so we use some trickery (symlinks) to
  52. make it seem as if the user class data exists there.
  53. --*/
  54. #include "uenv.h"
  55. #include <malloc.h>
  56. #define USER_CLASSES_HIVE_NAME TEXT("\\UsrClass.dat")
  57. #define CLASSES_SUBTREE TEXT("Software\\Classes\\")
  58. #define CLASSES_SUBDIRECTORY TEXT("\\Microsoft\\Windows\\")
  59. #define MAX_HIVE_DIR_CCH (MAX_PATH + 1 + sizeof(CLASSES_SUBDIRECTORY))
  60. #define TEMPHIVE_FILENAME TEXT("TempClassesHive.dat")
  61. #define CLASSES_CLSID_SUBTREE TEXT("Software\\Classes\\Clsid\\")
  62. #define EXPLORER_CLASSES_SUBTREE TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Clsid\\")
  63. #define LENGTH(x) (sizeof(x) - sizeof(WCHAR))
  64. #define INIT_SPECIALKEY(x) x
  65. typedef WCHAR* SpecialKey;
  66. SpecialKey SpecialSubtrees[]= {
  67. INIT_SPECIALKEY(L"*"),
  68. INIT_SPECIALKEY(L"*\\shellex"),
  69. INIT_SPECIALKEY(L"*\\shellex\\ContextMenuHandlers"),
  70. INIT_SPECIALKEY(L"*\\shellex\\PropertyShellHandlers"),
  71. INIT_SPECIALKEY(L"AppID"),
  72. INIT_SPECIALKEY(L"ClsID"),
  73. INIT_SPECIALKEY(L"Component Categories"),
  74. INIT_SPECIALKEY(L"Drive"),
  75. INIT_SPECIALKEY(L"Drive\\shellex"),
  76. INIT_SPECIALKEY(L"Drive\\shellex\\ContextMenuHandlers"),
  77. INIT_SPECIALKEY(L"Drive\\shellex\\PropertyShellHandlers"),
  78. INIT_SPECIALKEY(L"FileType"),
  79. INIT_SPECIALKEY(L"Folder"),
  80. INIT_SPECIALKEY(L"Folder\\shellex"),
  81. INIT_SPECIALKEY(L"Folder\\shellex\\ColumnHandler"),
  82. INIT_SPECIALKEY(L"Folder\\shellex\\ContextMenuHandlers"),
  83. INIT_SPECIALKEY(L"Folder\\shellex\\ExtShellFolderViews"),
  84. INIT_SPECIALKEY(L"Folder\\shellex\\PropertySheetHandlers"),
  85. INIT_SPECIALKEY(L"Installer\\Components"),
  86. INIT_SPECIALKEY(L"Installer\\Features"),
  87. INIT_SPECIALKEY(L"Installer\\Products"),
  88. INIT_SPECIALKEY(L"Interface"),
  89. INIT_SPECIALKEY(L"Mime"),
  90. INIT_SPECIALKEY(L"Mime\\Database"),
  91. INIT_SPECIALKEY(L"Mime\\Database\\Charset"),
  92. INIT_SPECIALKEY(L"Mime\\Database\\Codepage"),
  93. INIT_SPECIALKEY(L"Mime\\Database\\Content Type"),
  94. INIT_SPECIALKEY(L"Typelib")
  95. };
  96. #define NUM_SPECIAL_SUBTREES (sizeof(SpecialSubtrees)/sizeof(*SpecialSubtrees))
  97. //*************************************************************
  98. //
  99. // CreateRegLink()
  100. //
  101. // Purpose: Create a link from the hkDest + SubKeyName
  102. // pointing to lpSourceRootName
  103. //
  104. // if the key (link) already exists, do nothing
  105. //
  106. // Parameters: hkDest - root of destination
  107. // SubKeyName - subkey of destination
  108. // lpSourceName - target of link
  109. //
  110. // Return: ERROR_SUCCESS if successful
  111. // other NTSTATUS if an error occurs
  112. //
  113. //*************************************************************/
  114. LONG CreateRegLink(HKEY hkDest,
  115. LPTSTR SubKeyName,
  116. LPTSTR lpSourceName)
  117. {
  118. NTSTATUS Status;
  119. UNICODE_STRING LinkTarget;
  120. UNICODE_STRING SubKey;
  121. OBJECT_ATTRIBUTES Attributes;
  122. HANDLE hkInternal;
  123. UNICODE_STRING SymbolicLinkValueName;
  124. //
  125. // Initialize special key value used to make symbolic links
  126. //
  127. RtlInitUnicodeString(&SymbolicLinkValueName, L"SymbolicLinkValue");
  128. //
  129. // Initialize unicode string for our in params
  130. //
  131. RtlInitUnicodeString(&LinkTarget, lpSourceName);
  132. RtlInitUnicodeString(&SubKey, SubKeyName);
  133. //
  134. // See if this link already exists -- this is necessary because
  135. // NtCreateKey fails with STATUS_OBJECT_NAME_COLLISION if a link
  136. // already exists and will not return a handle to the existing
  137. // link.
  138. //
  139. InitializeObjectAttributes(&Attributes,
  140. &SubKey,
  141. OBJ_CASE_INSENSITIVE | OBJ_OPENLINK,
  142. hkDest,
  143. NULL);
  144. //
  145. // If this call succeeds, we get a handle to the existing link
  146. //
  147. Status = NtOpenKey( &hkInternal,
  148. MAXIMUM_ALLOWED,
  149. &Attributes );
  150. if (STATUS_OBJECT_NAME_NOT_FOUND == Status) {
  151. //
  152. // There is no existing link, so use NtCreateKey to make a new one
  153. //
  154. Status = NtCreateKey( &hkInternal,
  155. KEY_CREATE_LINK | KEY_SET_VALUE,
  156. &Attributes,
  157. 0,
  158. NULL,
  159. REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
  160. NULL);
  161. }
  162. //
  163. // Whether the link existed already or not, we should still set
  164. // the value which determines the link target
  165. //
  166. if (NT_SUCCESS(Status)) {
  167. Status = NtSetValueKey( hkInternal,
  168. &SymbolicLinkValueName,
  169. 0,
  170. REG_LINK,
  171. LinkTarget.Buffer,
  172. LinkTarget.Length);
  173. NtClose(hkInternal);
  174. }
  175. return RtlNtStatusToDosError(Status);
  176. }
  177. //*************************************************************
  178. //
  179. // DeleteRegLink()
  180. //
  181. // Purpose: Deletes a registry key (or link) without
  182. // using the advapi32 registry apis
  183. //
  184. //
  185. // Parameters: hkRoot - parent key
  186. // lpSubKey - subkey to delete
  187. //
  188. // Return: ERROR_SUCCESS if successful
  189. // other error if not
  190. //
  191. // Comments:
  192. //
  193. // History: Date Author Comment
  194. // 3/6/98 adamed Created
  195. //
  196. //*************************************************************
  197. LONG DeleteRegLink(HKEY hkRoot, LPTSTR lpSubKey)
  198. {
  199. OBJECT_ATTRIBUTES Attributes;
  200. HKEY hKey;
  201. NTSTATUS Status;
  202. UNICODE_STRING Subtree;
  203. //
  204. // Initialize string for lpSubKey param
  205. //
  206. RtlInitUnicodeString(&Subtree, lpSubKey);
  207. InitializeObjectAttributes(&Attributes,
  208. &Subtree,
  209. OBJ_CASE_INSENSITIVE | OBJ_OPENLINK,
  210. hkRoot,
  211. NULL);
  212. //
  213. // Open the link
  214. //
  215. Status = NtOpenKey( &hKey,
  216. MAXIMUM_ALLOWED,
  217. &Attributes );
  218. //
  219. // If we succeeded in opening it, delete it
  220. //
  221. if (NT_SUCCESS(Status)) {
  222. Status = NtDeleteKey(hKey);
  223. NtClose(hKey);
  224. }
  225. return RtlNtStatusToDosError(Status);
  226. }
  227. //*************************************************************
  228. //
  229. // MapUserClassesIntoUserHive()
  230. //
  231. // Purpose: Makes HKCU\\Software\\Classes point to
  232. // the user classes hive. This is done by using
  233. // a symbolic link, a feature of the kernel's
  234. // object manager. We use this to make
  235. // HKCU\Software\Classes poing to another hive
  236. // where the classes exist physically.
  237. // If there is an existing HKCU\\Software\\Classes,
  238. // it is deleted along with everything below it.
  239. //
  240. //
  241. // Parameters: lpProfile - user's profile
  242. // lpSidString - string representing user's sid
  243. //
  244. // Return: ERROR_SUCCESS if successful
  245. // other error if not
  246. //
  247. // Comments:
  248. //
  249. // History: Date Author Comment
  250. // 3/6/98 adamed Created
  251. //
  252. //*************************************************************
  253. LONG MapUserClassesIntoUserHive(
  254. LPPROFILE lpProfile,
  255. LPTSTR lpSidString)
  256. {
  257. LONG Error;
  258. LPTSTR lpClassesKeyName;
  259. //
  260. // get memory for user classes keyname
  261. //
  262. lpClassesKeyName = alloca( lstrlen(lpSidString) * sizeof(TCHAR)
  263. + sizeof( USER_CLASSES_HIVE_SUFFIX )
  264. + sizeof( USER_KEY_PREFIX )
  265. + sizeof(TCHAR) );
  266. //
  267. // Can't continue if no memory;
  268. //
  269. if ( !lpClassesKeyName ) {
  270. return ERROR_NOT_ENOUGH_MEMORY;
  271. }
  272. //
  273. // concoct user classes keyname
  274. //
  275. lstrcpy( lpClassesKeyName, USER_KEY_PREFIX);
  276. lstrcat( lpClassesKeyName, lpSidString );
  277. lstrcat( lpClassesKeyName, USER_CLASSES_HIVE_SUFFIX);
  278. //
  279. // Eliminate any existing form of HKCU\Software\Classes
  280. //
  281. //
  282. // First, delete existing link
  283. //
  284. Error = DeleteRegLink(lpProfile->hKeyCurrentUser, CLASSES_SUBTREE);
  285. //
  286. // It's ok if the deletion fails because the classes key, link or nonlink,
  287. // doesn't exist. It's also ok if it fails because the key exists but is not
  288. // a link and has children -- in this case, the key and its children will
  289. // be eliminated by a subsequent call to RegDelNode.
  290. //
  291. if (ERROR_SUCCESS != Error) {
  292. if ((ERROR_FILE_NOT_FOUND != Error) && (ERROR_ACCESS_DENIED != Error)) {
  293. return Error;
  294. }
  295. }
  296. //
  297. // Just to be safe, destroy any existing HKCU\Software\Classes and children.
  298. // This key may exist from previous unreleased versions of NT5, or from
  299. // someone playing around with hive files and adding bogus keys
  300. //
  301. if (!RegDelnode (lpProfile->hKeyCurrentUser, CLASSES_SUBTREE)) {
  302. Error = GetLastError();
  303. //
  304. // It's ok if this fails because the key doesn't exist, since
  305. // nonexistence is our goal.
  306. //
  307. if (ERROR_FILE_NOT_FOUND != Error) {
  308. return Error;
  309. }
  310. }
  311. //
  312. // At this point, we know that no HKCU\Software\Classes exists, so we should
  313. // be able to make a link there which points to the hive with the user class
  314. // data.
  315. //
  316. Error = CreateRegLink(lpProfile->hKeyCurrentUser,
  317. CLASSES_SUBTREE,
  318. lpClassesKeyName);
  319. return Error;
  320. }
  321. //*************************************************************
  322. //
  323. // CreateClassesFolder()
  324. //
  325. // Purpose: Create the directory for the classes hives
  326. //
  327. //
  328. // Parameters:
  329. // pProfile - pointer to profile struct
  330. // szLocalHiveDir - out param for location of
  331. // classes hive folder.
  332. //
  333. // Return: ERROR_SUCCESS if successful
  334. // other error if an error occurs
  335. //
  336. //
  337. //*************************************************************
  338. LONG CreateClassesFolder(LPPROFILE pProfile, LPTSTR szLocalHiveDir)
  339. {
  340. BOOL fGotLocalData;
  341. BOOL fCreatedSubdirectory;
  342. //
  343. // Find out the correct shell location for our subdir --
  344. // this call will create it if it doesn't exist.
  345. // This is a subdir of the user profile which does not
  346. // roam.
  347. //
  348. //
  349. // Need to do this to fix up a localisation prob. in NT4
  350. //
  351. PatchLocalAppData(pProfile->hTokenUser);
  352. fGotLocalData = GetFolderPath (
  353. CSIDL_LOCAL_APPDATA,
  354. pProfile->hTokenUser,
  355. szLocalHiveDir);
  356. if (!fGotLocalData) {
  357. return ERROR_NOT_ENOUGH_MEMORY;
  358. }
  359. //
  360. // append the terminating pathsep so we can
  361. // add more paths to the newly retrieved subdir
  362. //
  363. lstrcat(szLocalHiveDir, CLASSES_SUBDIRECTORY);
  364. //
  365. // We will now create our own subdir, CLASSES_SUBDIRECTORY,
  366. // inside the local appdata subdir we just received above.
  367. //
  368. fCreatedSubdirectory = CreateNestedDirectory(szLocalHiveDir, NULL);
  369. if (fCreatedSubdirectory) {
  370. return ERROR_SUCCESS;
  371. }
  372. return GetLastError();
  373. }
  374. //*************************************************************
  375. //
  376. // UnloadClassHive()
  377. //
  378. // Purpose: unmounts a classes hive
  379. //
  380. // Parameters: lpSidString - string representing user's
  381. // sid
  382. // lpSuffix - hive name suffix
  383. //
  384. // Return: ERROR_SUCCESS if successful,
  385. // other error if not
  386. //
  387. // Comments:
  388. //
  389. // History: Date Author Comment
  390. // 3/6/98 adamed Created
  391. //
  392. //*************************************************************
  393. LONG UnloadClassHive(
  394. LPTSTR lpSidString,
  395. LPTSTR lpSuffix)
  396. {
  397. LPTSTR lpHiveName;
  398. LONG error;
  399. OBJECT_ATTRIBUTES Attributes;
  400. NTSTATUS Status;
  401. HKEY hKey;
  402. UNICODE_STRING ClassesFullPath;
  403. //
  404. // Get memory for the combined hive key name
  405. //
  406. lpHiveName = alloca( lstrlen(lpSidString) * sizeof(TCHAR)
  407. + sizeof(USER_KEY_PREFIX)
  408. + (lstrlen(lpSuffix) + 1) *sizeof( TCHAR )
  409. + sizeof(TCHAR) );
  410. //
  411. // build the key name of the combined hive
  412. //
  413. lstrcpy( lpHiveName, USER_KEY_PREFIX );
  414. lstrcat( lpHiveName, lpSidString );
  415. lstrcat( lpHiveName, lpSuffix);
  416. //
  417. // Prepare to open the root of the classes hive
  418. //
  419. RtlInitUnicodeString(&ClassesFullPath, lpHiveName);
  420. InitializeObjectAttributes(&Attributes,
  421. &ClassesFullPath,
  422. OBJ_CASE_INSENSITIVE,
  423. NULL,
  424. NULL);
  425. Status = NtOpenKey( &hKey,
  426. KEY_READ,
  427. &Attributes );
  428. if (NT_SUCCESS(Status)) {
  429. //
  430. // Make sure the hive is persisted properly
  431. //
  432. RegFlushKey(hKey);
  433. RegCloseKey(hKey);
  434. //
  435. // Unmount the hive -- this should only fail if
  436. // someone has a subkey of the hive open -- this
  437. // should not normally happen and probably means there's a service
  438. // that is leaking keys.
  439. //
  440. if (MyRegUnLoadKey(HKEY_USERS,
  441. lpHiveName + ((sizeof(USER_KEY_PREFIX) / sizeof(TCHAR))-1))) {
  442. error = ERROR_SUCCESS;
  443. } else {
  444. error = GetLastError();
  445. }
  446. } else {
  447. error = RtlNtStatusToDosError(Status);
  448. }
  449. if (error != ERROR_SUCCESS) {
  450. DebugMsg((DM_WARNING, TEXT("UnLoadClassHive: failed to unload classes key with %x"), error));
  451. } else {
  452. DebugMsg((DM_VERBOSE, TEXT("UnLoadClassHive: Successfully unmounted %s%s"), lpSidString, lpSuffix));
  453. }
  454. return error;
  455. }
  456. //*************************************************************
  457. //
  458. // UnloadClasses()
  459. //
  460. // Purpose: Free the special combined hive
  461. //
  462. // Parameters: lpProfile - Profile information
  463. // SidString - User's Sid as a string
  464. //
  465. // Return: TRUE if successful
  466. // FALSE if not
  467. //
  468. //*************************************************************
  469. BOOL UnloadClasses(
  470. LPTSTR lpSidString)
  471. {
  472. LONG Error;
  473. // remove the implicit reference held by this process
  474. RegCloseKey(HKEY_CLASSES_ROOT);
  475. // unload user classes hive
  476. Error = UnloadClassHive(
  477. lpSidString,
  478. USER_CLASSES_HIVE_SUFFIX);
  479. return ERROR_SUCCESS == Error;
  480. }
  481. //*************************************************************
  482. //
  483. // CreateUserClasses()
  484. //
  485. // Purpose: Creates necessary hives for user classes
  486. //
  487. // Parameters: lpProfile - Profile information
  488. // lpSidString - User's Sid as a string
  489. // lpSuffix - Suffix to follow the user's sid
  490. // when naming the hive
  491. // lpHiveFileName - full path for backing hive file
  492. // of user classes
  493. // phkResult - root of created hive on
  494. // success
  495. //
  496. // Return: ERROR_SUCCESS if successful
  497. // other NTSTATUS if an error occurs
  498. //
  499. //*************************************************************
  500. LONG CreateClassHive(
  501. LPPROFILE lpProfile,
  502. LPTSTR lpSidString,
  503. LPTSTR lpSuffix,
  504. LPTSTR lpHiveFilename,
  505. BOOL bNewlyIssued)
  506. {
  507. LONG res;
  508. LPTSTR lpHiveKeyName;
  509. WIN32_FILE_ATTRIBUTE_DATA fd;
  510. BOOL fHiveExists;
  511. HKEY hkRoot;
  512. hkRoot = NULL;
  513. //
  514. // allocate a space big enough for the hive name
  515. //
  516. lpHiveKeyName = alloca( lstrlen(lpSidString) * sizeof(TCHAR) +
  517. (lstrlen(lpSuffix) + 1) * sizeof(TCHAR)
  518. + sizeof(TCHAR) );
  519. if ( !lpHiveKeyName ) {
  520. return ERROR_NOT_ENOUGH_MEMORY;
  521. }
  522. //
  523. // construct the hive name by appending the suffix
  524. // to the sid
  525. //
  526. lstrcpy(lpHiveKeyName, lpSidString);
  527. lstrcat(lpHiveKeyName, lpSuffix);
  528. //
  529. // First, see if this hive already exists. We need to do this rather than just letting
  530. // RegLoadKey create or load the existing hive because if the hive is new,
  531. // we need to apply security.
  532. //
  533. fHiveExists = GetFileAttributesEx(
  534. lpHiveFilename,
  535. GetFileExInfoStandard,
  536. &fd );
  537. //
  538. // mount the hive
  539. //
  540. res = MyRegLoadKey(HKEY_USERS, lpHiveKeyName, lpHiveFilename);
  541. if (ERROR_SUCCESS != res) {
  542. return res;
  543. }
  544. //
  545. // If we succeeded, open the root
  546. //
  547. res = RegOpenKeyEx( HKEY_USERS,
  548. lpHiveKeyName,
  549. 0,
  550. WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL,
  551. &hkRoot);
  552. if (ERROR_SUCCESS != res) {
  553. MyRegUnLoadKey(HKEY_USERS, lpHiveKeyName);
  554. DebugMsg((DM_WARNING, TEXT("CreateClassHive: fail to open classes hive. Error %d"),res));
  555. return res;
  556. }
  557. if (!fHiveExists || bNewlyIssued) {
  558. if (!fHiveExists) {
  559. DebugMsg((DM_VERBOSE, TEXT("CreateClassHive: existing user classes hive not found")));
  560. }
  561. else {
  562. DebugMsg((DM_VERBOSE, TEXT("CreateClassHive: user classes hive copied from Default User")));
  563. }
  564. //
  565. // This hive is newly issued i.e. either created fresh or copied from
  566. // "Default User" profile, so we need to set security on the new hive
  567. //
  568. //
  569. // set security on this hive
  570. //
  571. if (!SetDefaultUserHiveSecurity(lpProfile, NULL, hkRoot)) {
  572. res = GetLastError();
  573. DebugMsg((DM_WARNING, TEXT("CreateClassHive: Fail to assign proper security on new classes hive")));
  574. }
  575. //
  576. // If we succeed, set the hidden attribute on the backing hive file
  577. //
  578. if (ERROR_SUCCESS == res) {
  579. if (!SetFileAttributes (lpHiveFilename, FILE_ATTRIBUTE_HIDDEN)) {
  580. DebugMsg((DM_WARNING, TEXT("CreateClassHive: unable to set file attributes")
  581. TEXT(" on classes hive %s with error %x"), lpHiveFilename, GetLastError()));
  582. }
  583. }
  584. } else {
  585. DebugMsg((DM_VERBOSE, TEXT("CreateClassHive: existing user classes hive found")));
  586. }
  587. if (hkRoot) {
  588. RegCloseKey(hkRoot);
  589. }
  590. return res;
  591. }
  592. //*************************************************************
  593. //
  594. // CreateUserClassesHive()
  595. //
  596. // Purpose: create the user-specific classes hive
  597. //
  598. // Parameters: lpProfile - Profile information
  599. // SidString - User's Sid as a string
  600. // szLocalHiveDir - directory in userprofile
  601. // where hive should be located
  602. //
  603. // Return: ERROR_SUCCESS if successful,
  604. // other error if not
  605. //
  606. // Comments:
  607. //
  608. // History: Date Author Comment
  609. // 3/6/98 adamed Created
  610. //
  611. //*************************************************************
  612. LONG CreateUserClassesHive(
  613. LPPROFILE lpProfile,
  614. LPTSTR SidString,
  615. LPTSTR szLocalHiveDir,
  616. BOOL bNewlyIssued)
  617. {
  618. LPTSTR lpHiveFilename;
  619. LONG res;
  620. // allocate a space big enough for the hive filename (including trailing null)
  621. lpHiveFilename = alloca( lstrlen(szLocalHiveDir) * sizeof(TCHAR)
  622. + sizeof( USER_CLASSES_HIVE_NAME )
  623. + sizeof(TCHAR) * 2);
  624. if ( !lpHiveFilename ) {
  625. return ERROR_NOT_ENOUGH_MEMORY;
  626. }
  627. lstrcpy( lpHiveFilename, szLocalHiveDir);
  628. lstrcat( lpHiveFilename, USER_CLASSES_HIVE_NAME);
  629. res = CreateClassHive(
  630. lpProfile,
  631. SidString,
  632. USER_CLASSES_HIVE_SUFFIX,
  633. lpHiveFilename,
  634. bNewlyIssued);
  635. if (ERROR_SUCCESS != res) {
  636. return res;
  637. }
  638. res = MapUserClassesIntoUserHive(lpProfile, SidString);
  639. return res;
  640. }
  641. //*************************************************************
  642. //
  643. // MoveUserClassesBeforeMerge
  644. //
  645. // Purpose: move HKCU\Software\Classes before
  646. // MapUserClassesIntoUserHive() deletes it.
  647. //
  648. // Parameters: lpProfile - Profile information
  649. // lpcszLocalHiveDir - Temp Hive location
  650. //
  651. // Return: ERROR_SUCCESS if successful,
  652. // other error if not
  653. //
  654. // Comments:
  655. //
  656. // History: Date Author Comment
  657. // 5/6/99 vtan Created
  658. //
  659. //*************************************************************
  660. LONG MoveUserClassesBeforeMerge(
  661. LPPROFILE lpProfile,
  662. LPCTSTR lpcszLocalHiveDir)
  663. {
  664. LONG res;
  665. HKEY hKeySource;
  666. // Open HKCU\Software\Classes and see if there is a subkey.
  667. // No subkeys would indicate that the move has already been
  668. // done or there is no data to move.
  669. res = RegOpenKeyEx(lpProfile->hKeyCurrentUser, CLASSES_CLSID_SUBTREE, 0, KEY_ALL_ACCESS, &hKeySource);
  670. if (ERROR_SUCCESS == res)
  671. {
  672. DWORD dwSubKeyCount;
  673. if ((ERROR_SUCCESS == RegQueryInfoKey(hKeySource, NULL, NULL, NULL, &dwSubKeyCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) &&
  674. (dwSubKeyCount > 0))
  675. {
  676. LPTSTR pszLocalTempHive;
  677. // Allocate enough space for the local hive directory and the temp hive filename.
  678. pszLocalTempHive = alloca((lstrlen(lpcszLocalHiveDir) * sizeof(TCHAR)) +
  679. sizeof(TEMPHIVE_FILENAME) +
  680. (sizeof('\0') * sizeof(TCHAR)));
  681. // Get a path to a file to save HKCU\Software\Classes into.
  682. if (pszLocalTempHive != NULL)
  683. {
  684. HANDLE hToken = NULL;
  685. BOOL bAdjustPriv = FALSE;
  686. lstrcpy(pszLocalTempHive, lpcszLocalHiveDir);
  687. lstrcat(pszLocalTempHive, TEMPHIVE_FILENAME);
  688. // RegSaveKey() fails if the file exists so delete it first.
  689. DeleteFile(pszLocalTempHive);
  690. //
  691. // Check to see if we are impersonating.
  692. //
  693. if(!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken) || hToken == NULL) {
  694. bAdjustPriv = TRUE;
  695. }
  696. else {
  697. CloseHandle(hToken);
  698. }
  699. if(!bAdjustPriv) {
  700. DWORD dwDisposition;
  701. HKEY hKeyTarget;
  702. BOOL fSavedHive;
  703. // Save HKCU\Software\Classes into the temp hive
  704. // and restore the state of SE_BACKUP_NAME privilege
  705. res = RegSaveKey(hKeySource, pszLocalTempHive, NULL);
  706. if (ERROR_SUCCESS == res)
  707. {
  708. res = RegCreateKeyEx(lpProfile->hKeyCurrentUser, EXPLORER_CLASSES_SUBTREE, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyTarget, &dwDisposition);
  709. if (ERROR_SUCCESS == res)
  710. {
  711. // Restore temp hive to a new location at
  712. // HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer
  713. // This performs the upgrade from NT4 to NT5.
  714. res = RegRestoreKey(hKeyTarget, pszLocalTempHive, 0);
  715. if (ERROR_SUCCESS != res)
  716. {
  717. DebugMsg((DM_WARNING, TEXT("RegRestoreKey failed with error %d"), res));
  718. }
  719. RegCloseKey(hKeyTarget);
  720. }
  721. else
  722. {
  723. DebugMsg((DM_WARNING, TEXT("RegCreateKeyEx failed to create key %s with error %d"), EXPLORER_CLASSES_SUBTREE, res));
  724. }
  725. }
  726. else
  727. {
  728. DebugMsg((DM_WARNING, TEXT("RegSaveKey failed with error %d"), res));
  729. }
  730. }
  731. else {
  732. if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
  733. {
  734. DWORD dwReturnTokenPrivilegesSize;
  735. TOKEN_PRIVILEGES oldTokenPrivileges, newTokenPrivileges;
  736. // Enable SE_BACKUP_NAME privilege
  737. if (LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &newTokenPrivileges.Privileges[0].Luid))
  738. {
  739. newTokenPrivileges.PrivilegeCount = 1;
  740. newTokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  741. if (AdjustTokenPrivileges(hToken, FALSE, &newTokenPrivileges, sizeof(newTokenPrivileges), &oldTokenPrivileges, &dwReturnTokenPrivilegesSize))
  742. {
  743. BOOL fSavedHive;
  744. // Save HKCU\Software\Classes into the temp hive
  745. // and restore the state of SE_BACKUP_NAME privilege
  746. res = RegSaveKey(hKeySource, pszLocalTempHive, NULL);
  747. if (!AdjustTokenPrivileges(hToken, FALSE, &oldTokenPrivileges, 0, NULL, NULL))
  748. {
  749. DebugMsg((DM_WARNING, TEXT("AdjustTokenPrivileges failed to restore old privileges with error %d"), GetLastError()));
  750. }
  751. if (ERROR_SUCCESS == res)
  752. {
  753. // Enable SE_RESTORE_NAME privilege.
  754. if (LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &newTokenPrivileges.Privileges[0].Luid))
  755. {
  756. newTokenPrivileges.PrivilegeCount = 1;
  757. newTokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  758. if (AdjustTokenPrivileges(hToken, FALSE, &newTokenPrivileges, sizeof(newTokenPrivileges), &oldTokenPrivileges, &dwReturnTokenPrivilegesSize))
  759. {
  760. DWORD dwDisposition;
  761. HKEY hKeyTarget;
  762. res = RegCreateKeyEx(lpProfile->hKeyCurrentUser, EXPLORER_CLASSES_SUBTREE, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyTarget, &dwDisposition);
  763. if (ERROR_SUCCESS == res)
  764. {
  765. // Restore temp hive to a new location at
  766. // HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer
  767. // This performs the upgrade from NT4 to NT5.
  768. res = RegRestoreKey(hKeyTarget, pszLocalTempHive, 0);
  769. if (ERROR_SUCCESS != res)
  770. {
  771. DebugMsg((DM_WARNING, TEXT("RegRestoreKey failed with error %d"), res));
  772. }
  773. RegCloseKey(hKeyTarget);
  774. }
  775. else
  776. {
  777. DebugMsg((DM_WARNING, TEXT("RegCreateKeyEx failed to create key %s with error %d"), EXPLORER_CLASSES_SUBTREE, res));
  778. }
  779. if (!AdjustTokenPrivileges(hToken, FALSE, &oldTokenPrivileges, 0, NULL, NULL))
  780. {
  781. DebugMsg((DM_WARNING, TEXT("AdjustTokenPrivileges failed to restore old privileges with error %d"), GetLastError()));
  782. }
  783. }
  784. else
  785. {
  786. res = GetLastError();
  787. DebugMsg((DM_WARNING, TEXT("AdjustTokenPrivileges failed with error %d"), res));
  788. }
  789. }
  790. else
  791. {
  792. res = GetLastError();
  793. DebugMsg((DM_WARNING, TEXT("LookupPrivilegeValue failed with error %d"), res));
  794. }
  795. }
  796. else
  797. {
  798. DebugMsg((DM_WARNING, TEXT("RegSaveKey failed with error %d"), res));
  799. }
  800. }
  801. else
  802. {
  803. res = GetLastError();
  804. DebugMsg((DM_WARNING, TEXT("AdjustTokenPrivileges failed with error %d"), res));
  805. }
  806. }
  807. else
  808. {
  809. res = GetLastError();
  810. DebugMsg((DM_WARNING, TEXT("LookupPrivilegeValue failed with error %d"), res));
  811. }
  812. CloseHandle(hToken);
  813. }
  814. else
  815. {
  816. res = GetLastError();
  817. DebugMsg((DM_WARNING, TEXT("OpenProcessToken failed to get token with error %d"), res));
  818. }
  819. } // if(!bAdjustPriv) else
  820. // Delete local temporary hive file.
  821. DeleteFile(pszLocalTempHive);
  822. }
  823. else
  824. {
  825. DebugMsg((DM_WARNING, TEXT("alloca failed to allocate temp hive path buffer")));
  826. }
  827. }
  828. RegCloseKey(hKeySource);
  829. }
  830. else if (ERROR_FILE_NOT_FOUND == res)
  831. {
  832. res = ERROR_SUCCESS;
  833. }
  834. return res;
  835. }
  836. //*************************************************************
  837. //
  838. // LoadUserClasses()
  839. //
  840. // Purpose: Combines the HKLM\Software\Classes subtree with the
  841. // HKCU\Software\Classes subtree
  842. //
  843. // Parameters: lpProfile - Profile information
  844. // SidString - User's Sid as a string
  845. //
  846. // Return: ERROR_SUCCESS if successful
  847. // other NTSTATUS if an error occurs
  848. //
  849. //*************************************************************
  850. LONG LoadUserClasses( LPPROFILE lpProfile, LPTSTR SidString, BOOL bNewlyIssued)
  851. {
  852. LONG error;
  853. LPTSTR szLocalHiveDir;
  854. error = ERROR_SUCCESS;
  855. //
  856. // first, we will create a directory for the user-specific
  857. // classes hive -- we need memory for it:
  858. //
  859. szLocalHiveDir = (LPTSTR) alloca(MAX_HIVE_DIR_CCH);
  860. if (!szLocalHiveDir) {
  861. return ERROR_NOT_ENOUGH_MEMORY;
  862. }
  863. //
  864. // create the directory for the user-specific classes hive
  865. //
  866. error = CreateClassesFolder(lpProfile, szLocalHiveDir);
  867. if (ERROR_SUCCESS != error) {
  868. DebugMsg((DM_WARNING, TEXT("LoadUserClasses: Failed to create folder for combined hive (%d)."),
  869. error));
  870. return error;
  871. }
  872. // Move HKCU\Software\Classes before merging the two
  873. // branches. Ignore any errors here as this branch is
  874. // about to be deleted by the merge anyway.
  875. // The reason for this move is because NT4 stores customized
  876. // shell icons in HKCU\Software\Classes\CLSID\{CLSID_x} and
  877. // NT5 stores this at HKCU\Software\Microsoft\Windows\
  878. // CurrentVersion\Explorer\CLSID\{CLSID_x} and must be moved
  879. // now before being deleted.
  880. error = MoveUserClassesBeforeMerge(lpProfile, szLocalHiveDir);
  881. if (ERROR_SUCCESS != error) {
  882. DebugMsg((DM_WARNING, TEXT("MoveUserClassesBeforeMerge: Failed unexpectedly (%d)."),
  883. error));
  884. }
  885. //
  886. // Now create the user classes hive
  887. //
  888. error = CreateUserClassesHive( lpProfile, SidString, szLocalHiveDir, bNewlyIssued);
  889. if (ERROR_SUCCESS != error) {
  890. DebugMsg((DM_WARNING, TEXT("LoadUserClasses: Failed to create user classes hive (%d)."),
  891. error));
  892. }
  893. return error;
  894. }