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.

1302 lines
43 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. #include <wow64reg.h>
  57. #include "strsafe.h"
  58. #define USER_CLASSES_HIVE_NAME TEXT("\\UsrClass.dat")
  59. #define CLASSES_SUBTREE TEXT("Software\\Classes\\")
  60. #define CLASSES_SUBDIRECTORY TEXT("\\Microsoft\\Windows\\")
  61. #define MAX_HIVE_DIR_CCH (MAX_PATH + 1 + lstrlen(CLASSES_SUBDIRECTORY))
  62. #define TEMPHIVE_FILENAME TEXT("TempClassesHive.dat")
  63. #define CLASSES_CLSID_SUBTREE TEXT("Software\\Classes\\Clsid\\")
  64. #define EXPLORER_CLASSES_SUBTREE TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Clsid\\")
  65. #define LENGTH(x) (sizeof(x) - sizeof(WCHAR))
  66. #define INIT_SPECIALKEY(x) x
  67. typedef WCHAR* SpecialKey;
  68. SpecialKey SpecialSubtrees[]= {
  69. INIT_SPECIALKEY(L"*"),
  70. INIT_SPECIALKEY(L"*\\shellex"),
  71. INIT_SPECIALKEY(L"*\\shellex\\ContextMenuHandlers"),
  72. INIT_SPECIALKEY(L"*\\shellex\\PropertyShellHandlers"),
  73. INIT_SPECIALKEY(L"AppID"),
  74. INIT_SPECIALKEY(L"ClsID"),
  75. INIT_SPECIALKEY(L"Component Categories"),
  76. INIT_SPECIALKEY(L"Drive"),
  77. INIT_SPECIALKEY(L"Drive\\shellex"),
  78. INIT_SPECIALKEY(L"Drive\\shellex\\ContextMenuHandlers"),
  79. INIT_SPECIALKEY(L"Drive\\shellex\\PropertyShellHandlers"),
  80. INIT_SPECIALKEY(L"FileType"),
  81. INIT_SPECIALKEY(L"Folder"),
  82. INIT_SPECIALKEY(L"Folder\\shellex"),
  83. INIT_SPECIALKEY(L"Folder\\shellex\\ColumnHandler"),
  84. INIT_SPECIALKEY(L"Folder\\shellex\\ContextMenuHandlers"),
  85. INIT_SPECIALKEY(L"Folder\\shellex\\ExtShellFolderViews"),
  86. INIT_SPECIALKEY(L"Folder\\shellex\\PropertySheetHandlers"),
  87. INIT_SPECIALKEY(L"Installer\\Components"),
  88. INIT_SPECIALKEY(L"Installer\\Features"),
  89. INIT_SPECIALKEY(L"Installer\\Products"),
  90. INIT_SPECIALKEY(L"Interface"),
  91. INIT_SPECIALKEY(L"Mime"),
  92. INIT_SPECIALKEY(L"Mime\\Database"),
  93. INIT_SPECIALKEY(L"Mime\\Database\\Charset"),
  94. INIT_SPECIALKEY(L"Mime\\Database\\Codepage"),
  95. INIT_SPECIALKEY(L"Mime\\Database\\Content Type"),
  96. INIT_SPECIALKEY(L"Typelib")
  97. };
  98. #define NUM_SPECIAL_SUBTREES (sizeof(SpecialSubtrees)/sizeof(*SpecialSubtrees))
  99. //*************************************************************
  100. //
  101. // CreateRegLink()
  102. //
  103. // Purpose: Create a link from the hkDest + SubKeyName
  104. // pointing to lpSourceRootName
  105. //
  106. // if the key (link) already exists, do nothing
  107. //
  108. // Parameters: hkDest - root of destination
  109. // SubKeyName - subkey of destination
  110. // lpSourceName - target of link
  111. //
  112. // Return: ERROR_SUCCESS if successful
  113. // other NTSTATUS if an error occurs
  114. //
  115. //*************************************************************/
  116. LONG CreateRegLink(HKEY hkDest,
  117. LPTSTR SubKeyName,
  118. LPTSTR lpSourceName)
  119. {
  120. NTSTATUS Status;
  121. UNICODE_STRING LinkTarget;
  122. UNICODE_STRING SubKey;
  123. OBJECT_ATTRIBUTES Attributes;
  124. HANDLE hkInternal;
  125. UNICODE_STRING SymbolicLinkValueName;
  126. //
  127. // Initialize special key value used to make symbolic links
  128. //
  129. RtlInitUnicodeString(&SymbolicLinkValueName, L"SymbolicLinkValue");
  130. //
  131. // Initialize unicode string for our in params
  132. //
  133. RtlInitUnicodeString(&LinkTarget, lpSourceName);
  134. RtlInitUnicodeString(&SubKey, SubKeyName);
  135. //
  136. // See if this link already exists -- this is necessary because
  137. // NtCreateKey fails with STATUS_OBJECT_NAME_COLLISION if a link
  138. // already exists and will not return a handle to the existing
  139. // link.
  140. //
  141. InitializeObjectAttributes(&Attributes,
  142. &SubKey,
  143. OBJ_CASE_INSENSITIVE | OBJ_OPENLINK,
  144. hkDest,
  145. NULL);
  146. //
  147. // If this call succeeds, we get a handle to the existing link
  148. //
  149. Status = NtOpenKey( &hkInternal,
  150. MAXIMUM_ALLOWED,
  151. &Attributes );
  152. if (STATUS_OBJECT_NAME_NOT_FOUND == Status) {
  153. //
  154. // There is no existing link, so use NtCreateKey to make a new one
  155. //
  156. Status = NtCreateKey( &hkInternal,
  157. KEY_CREATE_LINK | KEY_SET_VALUE,
  158. &Attributes,
  159. 0,
  160. NULL,
  161. REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
  162. NULL);
  163. }
  164. //
  165. // Whether the link existed already or not, we should still set
  166. // the value which determines the link target
  167. //
  168. if (NT_SUCCESS(Status)) {
  169. Status = NtSetValueKey( hkInternal,
  170. &SymbolicLinkValueName,
  171. 0,
  172. REG_LINK,
  173. LinkTarget.Buffer,
  174. LinkTarget.Length);
  175. NtClose(hkInternal);
  176. }
  177. return RtlNtStatusToDosError(Status);
  178. }
  179. //*************************************************************
  180. //
  181. // DeleteRegLink()
  182. //
  183. // Purpose: Deletes a registry key (or link) without
  184. // using the advapi32 registry apis
  185. //
  186. //
  187. // Parameters: hkRoot - parent key
  188. // lpSubKey - subkey to delete
  189. //
  190. // Return: ERROR_SUCCESS if successful
  191. // other error if not
  192. //
  193. // Comments:
  194. //
  195. // History: Date Author Comment
  196. // 3/6/98 adamed Created
  197. //
  198. //*************************************************************
  199. LONG DeleteRegLink(HKEY hkRoot, LPTSTR lpSubKey)
  200. {
  201. OBJECT_ATTRIBUTES Attributes;
  202. HKEY hKey;
  203. NTSTATUS Status;
  204. UNICODE_STRING Subtree;
  205. //
  206. // Initialize string for lpSubKey param
  207. //
  208. RtlInitUnicodeString(&Subtree, lpSubKey);
  209. InitializeObjectAttributes(&Attributes,
  210. &Subtree,
  211. OBJ_CASE_INSENSITIVE | OBJ_OPENLINK,
  212. hkRoot,
  213. NULL);
  214. //
  215. // Open the link
  216. //
  217. Status = NtOpenKey( &hKey,
  218. MAXIMUM_ALLOWED,
  219. &Attributes );
  220. //
  221. // If we succeeded in opening it, delete it
  222. //
  223. if (NT_SUCCESS(Status)) {
  224. Status = NtDeleteKey(hKey);
  225. NtClose(hKey);
  226. }
  227. return RtlNtStatusToDosError(Status);
  228. }
  229. //*************************************************************
  230. //
  231. // MapUserClassesIntoUserHive()
  232. //
  233. // Purpose: Makes HKCU\\Software\\Classes point to
  234. // the user classes hive. This is done by using
  235. // a symbolic link, a feature of the kernel's
  236. // object manager. We use this to make
  237. // HKCU\Software\Classes poing to another hive
  238. // where the classes exist physically.
  239. // If there is an existing HKCU\\Software\\Classes,
  240. // it is deleted along with everything below it.
  241. //
  242. //
  243. // Parameters: lpProfile - user's profile
  244. // lpSidString - string representing user's sid
  245. //
  246. // Return: ERROR_SUCCESS if successful
  247. // other error if not
  248. //
  249. // Comments:
  250. //
  251. // History: Date Author Comment
  252. // 3/6/98 adamed Created
  253. //
  254. //*************************************************************
  255. LONG MapUserClassesIntoUserHive(
  256. LPPROFILE lpProfile,
  257. LPTSTR lpSidString)
  258. {
  259. LONG Error;
  260. LPTSTR lpClassesKeyName = NULL;
  261. DWORD cchClassesKeyName;
  262. //
  263. // get memory for user classes keyname
  264. //
  265. cchClassesKeyName = lstrlen(lpSidString) +
  266. lstrlen(USER_CLASSES_HIVE_SUFFIX) +
  267. lstrlen(USER_KEY_PREFIX) +
  268. 1;
  269. lpClassesKeyName = (LPTSTR) LocalAlloc(LPTR, cchClassesKeyName * sizeof(TCHAR));
  270. //
  271. // Can't continue if no memory;
  272. //
  273. if ( !lpClassesKeyName ) {
  274. Error = ERROR_NOT_ENOUGH_MEMORY;
  275. goto Exit;
  276. }
  277. //
  278. // concoct user classes keyname
  279. //
  280. StringCchCopy( lpClassesKeyName, cchClassesKeyName, USER_KEY_PREFIX);
  281. StringCchCat ( lpClassesKeyName, cchClassesKeyName, lpSidString );
  282. StringCchCat ( lpClassesKeyName, cchClassesKeyName, USER_CLASSES_HIVE_SUFFIX);
  283. //
  284. // Eliminate any existing form of HKCU\Software\Classes
  285. //
  286. //
  287. // First, delete existing link
  288. //
  289. Error = DeleteRegLink(lpProfile->hKeyCurrentUser, CLASSES_SUBTREE);
  290. //
  291. // It's ok if the deletion fails because the classes key, link or nonlink,
  292. // doesn't exist. It's also ok if it fails because the key exists but is not
  293. // a link and has children -- in this case, the key and its children will
  294. // be eliminated by a subsequent call to RegDelNode.
  295. //
  296. if (ERROR_SUCCESS != Error) {
  297. if ((ERROR_FILE_NOT_FOUND != Error) && (ERROR_ACCESS_DENIED != Error)) {
  298. goto Exit;
  299. }
  300. }
  301. //
  302. // Just to be safe, destroy any existing HKCU\Software\Classes and children.
  303. // This key may exist from previous unreleased versions of NT5, or from
  304. // someone playing around with hive files and adding bogus keys
  305. //
  306. if ((Error = RegDelnode (lpProfile->hKeyCurrentUser, CLASSES_SUBTREE)) != ERROR_SUCCESS) {
  307. //
  308. // It's ok if this fails because the key doesn't exist, since
  309. // nonexistence is our goal.
  310. //
  311. if (ERROR_FILE_NOT_FOUND != Error) {
  312. goto Exit;
  313. }
  314. }
  315. //
  316. // At this point, we know that no HKCU\Software\Classes exists, so we should
  317. // be able to make a link there which points to the hive with the user class
  318. // data.
  319. //
  320. Error = CreateRegLink(lpProfile->hKeyCurrentUser,
  321. CLASSES_SUBTREE,
  322. lpClassesKeyName);
  323. Exit:
  324. if (lpClassesKeyName)
  325. LocalFree(lpClassesKeyName);
  326. return Error;
  327. }
  328. //*************************************************************
  329. //
  330. // CreateClassesFolder()
  331. //
  332. // Purpose: Create the directory for the classes hives
  333. //
  334. //
  335. // Parameters:
  336. // pProfile - pointer to profile struct
  337. // szLocalHiveDir - out param for location of
  338. // classes hive folder.
  339. // cchLocalHiveDir - size of the buffer, in TCHARs
  340. //
  341. // Return: ERROR_SUCCESS if successful
  342. // other error if an error occurs
  343. //
  344. //
  345. //*************************************************************
  346. LONG CreateClassesFolder(LPPROFILE pProfile, LPTSTR szLocalHiveDir, DWORD cchLocalHiveDir)
  347. {
  348. BOOL fGotLocalData;
  349. BOOL fCreatedSubdirectory;
  350. //
  351. // Find out the correct shell location for our subdir --
  352. // this call will create it if it doesn't exist.
  353. // This is a subdir of the user profile which does not
  354. // roam.
  355. //
  356. //
  357. // Need to do this to fix up a localisation prob. in NT4
  358. //
  359. PatchLocalAppData(pProfile->hTokenUser);
  360. fGotLocalData = GetFolderPath (
  361. CSIDL_LOCAL_APPDATA,
  362. pProfile->hTokenUser,
  363. szLocalHiveDir);
  364. if (!fGotLocalData) {
  365. // a bogus error, check the debug output of GetFolderPath() for correct
  366. // error code.
  367. return ERROR_INVALID_FUNCTION;
  368. }
  369. //
  370. // append the terminating pathsep so we can
  371. // add more paths to the newly retrieved subdir
  372. //
  373. StringCchCat(szLocalHiveDir, cchLocalHiveDir, CLASSES_SUBDIRECTORY);
  374. //
  375. // We will now create our own subdir, CLASSES_SUBDIRECTORY,
  376. // inside the local appdata subdir we just received above.
  377. //
  378. fCreatedSubdirectory = CreateNestedDirectory(szLocalHiveDir, NULL);
  379. if (fCreatedSubdirectory) {
  380. return ERROR_SUCCESS;
  381. }
  382. return GetLastError();
  383. }
  384. //*************************************************************
  385. //
  386. // UnloadClassHive()
  387. //
  388. // Purpose: unmounts a classes hive
  389. //
  390. // Parameters: lpSidString - string representing user's
  391. // sid
  392. // lpSuffix - hive name suffix
  393. //
  394. // Return: ERROR_SUCCESS if successful,
  395. // other error if not
  396. //
  397. // Comments:
  398. //
  399. // History: Date Author Comment
  400. // 3/6/98 adamed Created
  401. //
  402. //*************************************************************
  403. LONG UnloadClassHive(
  404. LPTSTR lpSidString,
  405. LPTSTR lpSuffix)
  406. {
  407. LPTSTR lpHiveName = NULL;
  408. LONG error;
  409. OBJECT_ATTRIBUTES Attributes;
  410. NTSTATUS Status;
  411. HKEY hKey;
  412. UNICODE_STRING ClassesFullPath;
  413. DWORD cchHiveName;
  414. //
  415. // Get memory for the combined hive key name
  416. //
  417. cchHiveName = lstrlen(lpSidString) +
  418. lstrlen(USER_KEY_PREFIX) +
  419. lstrlen(lpSuffix) +
  420. 1;
  421. lpHiveName = (LPTSTR) LocalAlloc(LPTR, cchHiveName * sizeof(TCHAR));
  422. if (!lpHiveName)
  423. {
  424. error = ERROR_NOT_ENOUGH_MEMORY;
  425. goto Exit;
  426. }
  427. //
  428. // build the key name of the combined hive
  429. //
  430. StringCchCopy( lpHiveName, cchHiveName, USER_KEY_PREFIX );
  431. StringCchCat ( lpHiveName, cchHiveName, lpSidString );
  432. StringCchCat ( lpHiveName, cchHiveName, lpSuffix);
  433. //
  434. // Prepare to open the root of the classes hive
  435. //
  436. RtlInitUnicodeString(&ClassesFullPath, lpHiveName);
  437. InitializeObjectAttributes(&Attributes,
  438. &ClassesFullPath,
  439. OBJ_CASE_INSENSITIVE,
  440. NULL,
  441. NULL);
  442. Status = NtOpenKey( &hKey,
  443. KEY_READ,
  444. &Attributes );
  445. if (NT_SUCCESS(Status)) {
  446. //
  447. // Make sure the hive is persisted properly
  448. //
  449. RegFlushKey(hKey);
  450. RegCloseKey(hKey);
  451. //
  452. // Unmount the hive -- this should only fail if
  453. // someone has a subkey of the hive open -- this
  454. // should not normally happen and probably means there's a service
  455. // that is leaking keys.
  456. //
  457. if (MyRegUnLoadKey(HKEY_USERS,
  458. lpHiveName + ((sizeof(USER_KEY_PREFIX) / sizeof(TCHAR))-1))) {
  459. error = ERROR_SUCCESS;
  460. } else {
  461. error = GetLastError();
  462. }
  463. } else {
  464. error = RtlNtStatusToDosError(Status);
  465. }
  466. Exit:
  467. if (lpHiveName)
  468. LocalFree(lpHiveName);
  469. if (error != ERROR_SUCCESS) {
  470. DebugMsg((DM_WARNING, TEXT("UnLoadClassHive: failed to unload classes key with %x"), error));
  471. } else {
  472. DebugMsg((DM_VERBOSE, TEXT("UnLoadClassHive: Successfully unmounted %s%s"), lpSidString, lpSuffix));
  473. }
  474. return error;
  475. }
  476. //*************************************************************
  477. //
  478. // UnloadClasses()
  479. //
  480. // Purpose: Free the special combined hive
  481. //
  482. // Parameters: lpProfile - Profile information
  483. // SidString - User's Sid as a string
  484. //
  485. // Return: TRUE if successful
  486. // FALSE if not
  487. //
  488. //*************************************************************
  489. BOOL UnloadClasses(
  490. LPTSTR lpSidString)
  491. {
  492. LONG Error;
  493. // unload user classes hive
  494. Error = UnloadClassHive(
  495. lpSidString,
  496. USER_CLASSES_HIVE_SUFFIX);
  497. return ERROR_SUCCESS == Error;
  498. }
  499. HRESULT MyRegLoadKeyEx(HKEY hKeyRoot, LPTSTR lpSubKey, LPTSTR lpFile, HKEY hKeyTrustClass)
  500. {
  501. HRESULT hr = E_FAIL;
  502. NTSTATUS Status;
  503. TCHAR lpKeyName[MAX_PATH];
  504. UNICODE_STRING UnicodeKeyName;
  505. UNICODE_STRING UnicodeFileName;
  506. OBJECT_ATTRIBUTES keyAttributes;
  507. OBJECT_ATTRIBUTES fileAttributes;
  508. BOOLEAN WasEnabled;
  509. BOOL bAdjustPriv = FALSE;
  510. BOOL bAllocatedFileName = FALSE;
  511. HANDLE hToken = NULL;
  512. DebugMsg((DM_VERBOSE, TEXT("MyRegLoadKeyEx: Loading key <%s>"), lpSubKey));
  513. //
  514. // Only support loading hive to HKU or HKLM
  515. //
  516. if (hKeyRoot != HKEY_USERS && hKeyRoot != HKEY_LOCAL_MACHINE)
  517. {
  518. DebugMsg((DM_WARNING, TEXT("MyRegLoadKeyEx: only HKU or HKLM is supported!")));
  519. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  520. goto Exit;
  521. }
  522. //
  523. // Construct the key name for kernel object
  524. //
  525. hr = StringCchCopy(lpKeyName, ARRAYSIZE(lpKeyName), (hKeyRoot == HKEY_USERS) ? TEXT("\\Registry\\User\\") : TEXT("\\Registry\\Machine\\"));
  526. if (FAILED(hr))
  527. {
  528. DebugMsg((DM_WARNING, TEXT("MyRegLoadKeyEx: StringCchCopy failed, hr = %08X"), hr));
  529. goto Exit;
  530. }
  531. hr = StringCchCat (lpKeyName, ARRAYSIZE(lpKeyName), lpSubKey);
  532. if (FAILED(hr))
  533. {
  534. DebugMsg((DM_WARNING, TEXT("MyRegLoadKeyEx: StringCchCat failed, hr = %08X"), hr));
  535. goto Exit;
  536. }
  537. //
  538. // Initialize the key object attribute
  539. //
  540. RtlInitUnicodeString(&UnicodeKeyName, lpKeyName);
  541. InitializeObjectAttributes(&keyAttributes,
  542. &UnicodeKeyName,
  543. OBJ_CASE_INSENSITIVE,
  544. NULL,
  545. NULL);
  546. //
  547. // Convert the file name to kernel file name
  548. //
  549. if (!RtlDosPathNameToNtPathName_U(lpFile,
  550. &UnicodeFileName,
  551. NULL,
  552. NULL))
  553. {
  554. DebugMsg((DM_WARNING, TEXT("MyRegLoadKeyEx: RtlDosPathNameToNtPathName_U failed for <%s>!"), lpFile));
  555. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  556. goto Exit;
  557. }
  558. bAllocatedFileName = TRUE;
  559. //
  560. // Initialize the file object attribute
  561. //
  562. InitializeObjectAttributes(&fileAttributes,
  563. &UnicodeFileName,
  564. OBJ_CASE_INSENSITIVE,
  565. NULL,
  566. NULL);
  567. //
  568. // Check to see if we are impersonating, if not, we need to enable the Restore privilege
  569. //
  570. if(!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken) || hToken == NULL)
  571. {
  572. Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled);
  573. if (!NT_SUCCESS(Status))
  574. {
  575. DebugMsg((DM_WARNING, TEXT("MyRegLoadKeyEx: Failed to enable restore privilege to load registry key, Status = %08x"), Status));
  576. hr = HRESULT_FROM_WIN32(RtlNtStatusToDosError(Status));
  577. goto Exit;
  578. }
  579. bAdjustPriv = TRUE;
  580. }
  581. else
  582. {
  583. CloseHandle(hToken);
  584. }
  585. //
  586. // Now loading the key
  587. //
  588. /*
  589. Status = NtLoadKey(&keyAttributes,
  590. &fileAttributes);
  591. */
  592. Status = NtLoadKeyEx(&keyAttributes,
  593. &fileAttributes,
  594. 0,
  595. hKeyTrustClass);
  596. if (!NT_SUCCESS(Status))
  597. {
  598. TCHAR szErr[MAX_PATH];
  599. DWORD dwErr;
  600. DebugMsg((DM_WARNING, TEXT("MyRegLoadKeyEx: NtLoadKey failed for <%s>, Status = %08x"), lpSubKey, Status));
  601. dwErr = RtlNtStatusToDosError(Status);
  602. ReportError(NULL, PI_NOUI, 2, EVENT_REGLOADKEYFAILED, GetErrString(dwErr, szErr), lpFile);
  603. hr = HRESULT_FROM_WIN32(dwErr);
  604. goto Exit;
  605. }
  606. #if defined(_WIN64)
  607. else
  608. {
  609. //
  610. // Notify Wow64 service that it need to watch this hive if it care to do so
  611. //
  612. if ( hKeyRoot == HKEY_USERS )
  613. Wow64RegNotifyLoadHiveUserSid ( lpSubKey );
  614. }
  615. #endif
  616. DebugMsg((DM_VERBOSE, TEXT("MyRegLoadKeyEx: Successfully loaded <%s>"), lpSubKey));
  617. hr = S_OK;
  618. Exit:
  619. //
  620. // Restore the privilege to its previous state
  621. //
  622. if(bAdjustPriv)
  623. {
  624. Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled);
  625. if (!NT_SUCCESS(Status))
  626. {
  627. DebugMsg((DM_WARNING, TEXT("MyRegLoadKeyEx: Failed to restore RESTORE privilege to previous enabled state. Status = %08X"), Status));
  628. }
  629. }
  630. if (bAllocatedFileName)
  631. {
  632. RtlFreeUnicodeString(&UnicodeFileName);
  633. }
  634. return hr;
  635. }
  636. //*************************************************************
  637. //
  638. // CreateUserClasses()
  639. //
  640. // Purpose: Creates necessary hives for user classes
  641. //
  642. // Parameters: lpProfile - Profile information
  643. // lpSidString - User's Sid as a string
  644. // lpSuffix - Suffix to follow the user's sid
  645. // when naming the hive
  646. // lpHiveFileName - full path for backing hive file
  647. // of user classes
  648. // phkResult - root of created hive on
  649. // success
  650. //
  651. // Return: ERROR_SUCCESS if successful
  652. // other NTSTATUS if an error occurs
  653. //
  654. //*************************************************************
  655. LONG CreateClassHive(
  656. LPPROFILE lpProfile,
  657. LPTSTR lpSidString,
  658. LPTSTR lpSuffix,
  659. LPTSTR lpHiveFilename,
  660. BOOL bNewlyIssued)
  661. {
  662. LONG res;
  663. LPTSTR lpHiveKeyName = NULL;
  664. WIN32_FILE_ATTRIBUTE_DATA fd;
  665. BOOL fHiveExists;
  666. HKEY hkRoot = NULL;
  667. DWORD cchHiveKeyName;
  668. HKEY hKeyUser = NULL;
  669. HRESULT hr;
  670. //
  671. // allocate a space big enough for the hive name
  672. //
  673. cchHiveKeyName = lstrlen(lpSidString) +
  674. lstrlen(lpSuffix) +
  675. 1;
  676. lpHiveKeyName = (LPTSTR) LocalAlloc(LPTR, cchHiveKeyName * sizeof(TCHAR) );
  677. if ( !lpHiveKeyName )
  678. {
  679. res = ERROR_NOT_ENOUGH_MEMORY;
  680. goto Exit;
  681. }
  682. //
  683. // Open the HKU\{Sid} first, we use this handle as the trust class
  684. //
  685. StringCchCopy(lpHiveKeyName, cchHiveKeyName, lpSidString);
  686. res = RegOpenKeyEx(HKEY_USERS,
  687. lpHiveKeyName,
  688. 0,
  689. KEY_READ,
  690. &hKeyUser);
  691. if (res != ERROR_SUCCESS)
  692. {
  693. DebugMsg((DM_WARNING, TEXT("CreateClassHive: fail to open user hive. Error %d"),res));
  694. goto Exit;
  695. }
  696. //
  697. // Append the suffix to construct the class hive key name
  698. //
  699. StringCchCat (lpHiveKeyName, cchHiveKeyName, lpSuffix);
  700. //
  701. // First, see if this hive already exists. We need to do this rather than just letting
  702. // RegLoadKey create or load the existing hive because if the hive is new,
  703. // we need to apply security.
  704. //
  705. fHiveExists = GetFileAttributesEx(
  706. lpHiveFilename,
  707. GetFileExInfoStandard,
  708. &fd );
  709. //
  710. // mount the hive
  711. //
  712. hr = MyRegLoadKeyEx(HKEY_USERS, lpHiveKeyName, lpHiveFilename, hKeyUser);
  713. if (FAILED(hr))
  714. {
  715. DebugMsg((DM_WARNING, TEXT("CreateClassHive: MyRegLoadKeyEx failed, hr = %08X"), hr));
  716. res = HRESULT_CODE(hr);
  717. goto Exit;
  718. }
  719. //
  720. // If we succeeded, open the root
  721. //
  722. res = RegOpenKeyEx( HKEY_USERS,
  723. lpHiveKeyName,
  724. 0,
  725. WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL,
  726. &hkRoot);
  727. if (ERROR_SUCCESS != res) {
  728. MyRegUnLoadKey(HKEY_USERS, lpHiveKeyName);
  729. DebugMsg((DM_WARNING, TEXT("CreateClassHive: fail to open classes hive. Error %d"),res));
  730. goto Exit;
  731. }
  732. if (!fHiveExists || bNewlyIssued) {
  733. if (!fHiveExists) {
  734. DebugMsg((DM_VERBOSE, TEXT("CreateClassHive: existing user classes hive not found")));
  735. }
  736. else {
  737. DebugMsg((DM_VERBOSE, TEXT("CreateClassHive: user classes hive copied from Default User")));
  738. }
  739. //
  740. // This hive is newly issued i.e. either created fresh or copied from
  741. // "Default User" profile, so we need to set security on the new hive
  742. //
  743. //
  744. // set security on this hive
  745. //
  746. if (!SetDefaultUserHiveSecurity(lpProfile, NULL, hkRoot)) {
  747. res = GetLastError();
  748. DebugMsg((DM_WARNING, TEXT("CreateClassHive: Fail to assign proper security on new classes hive")));
  749. }
  750. //
  751. // If we succeed, set the hidden attribute on the backing hive file
  752. //
  753. if (ERROR_SUCCESS == res) {
  754. if (!SetFileAttributes (lpHiveFilename, FILE_ATTRIBUTE_HIDDEN)) {
  755. DebugMsg((DM_WARNING, TEXT("CreateClassHive: unable to set file attributes")
  756. TEXT(" on classes hive %s with error %x"), lpHiveFilename, GetLastError()));
  757. }
  758. }
  759. } else {
  760. DebugMsg((DM_VERBOSE, TEXT("CreateClassHive: existing user classes hive found")));
  761. }
  762. Exit:
  763. if (hKeyUser)
  764. {
  765. RegCloseKey(hKeyUser);
  766. }
  767. if (hkRoot) {
  768. RegCloseKey(hkRoot);
  769. }
  770. if (lpHiveKeyName)
  771. LocalFree(lpHiveKeyName);
  772. return res;
  773. }
  774. //*************************************************************
  775. //
  776. // CreateUserClassesHive()
  777. //
  778. // Purpose: create the user-specific classes hive
  779. //
  780. // Parameters: lpProfile - Profile information
  781. // SidString - User's Sid as a string
  782. // szLocalHiveDir - directory in userprofile
  783. // where hive should be located
  784. //
  785. // Return: ERROR_SUCCESS if successful,
  786. // other error if not
  787. //
  788. // Comments:
  789. //
  790. // History: Date Author Comment
  791. // 3/6/98 adamed Created
  792. //
  793. //*************************************************************
  794. LONG CreateUserClassesHive(
  795. LPPROFILE lpProfile,
  796. LPTSTR SidString,
  797. LPTSTR szLocalHiveDir,
  798. BOOL bNewlyIssued)
  799. {
  800. LPTSTR lpHiveFilename = NULL;
  801. LONG res;
  802. DWORD cchHiveFilename;
  803. // allocate a space big enough for the hive filename (including trailing null)
  804. cchHiveFilename = lstrlen(szLocalHiveDir) +
  805. lstrlen(USER_CLASSES_HIVE_NAME) +
  806. 1;
  807. lpHiveFilename = (LPTSTR) LocalAlloc(LPTR, cchHiveFilename * sizeof(TCHAR));
  808. if ( !lpHiveFilename ) {
  809. res = ERROR_NOT_ENOUGH_MEMORY;
  810. goto Exit;
  811. }
  812. StringCchCopy( lpHiveFilename, cchHiveFilename, szLocalHiveDir);
  813. StringCchCat ( lpHiveFilename, cchHiveFilename, USER_CLASSES_HIVE_NAME);
  814. res = CreateClassHive(
  815. lpProfile,
  816. SidString,
  817. USER_CLASSES_HIVE_SUFFIX,
  818. lpHiveFilename,
  819. bNewlyIssued);
  820. if (ERROR_SUCCESS != res) {
  821. goto Exit;
  822. }
  823. res = MapUserClassesIntoUserHive(lpProfile, SidString);
  824. Exit:
  825. if (lpHiveFilename)
  826. LocalFree(lpHiveFilename);
  827. return res;
  828. }
  829. //*************************************************************
  830. //
  831. // MoveUserClassesBeforeMerge
  832. //
  833. // Purpose: move HKCU\Software\Classes before
  834. // MapUserClassesIntoUserHive() deletes it.
  835. //
  836. // Parameters: lpProfile - Profile information
  837. // lpcszLocalHiveDir - Temp Hive location
  838. //
  839. // Return: ERROR_SUCCESS if successful,
  840. // other error if not
  841. //
  842. // Comments:
  843. //
  844. // History: Date Author Comment
  845. // 5/6/99 vtan Created
  846. //
  847. //*************************************************************
  848. LONG MoveUserClassesBeforeMerge(
  849. LPPROFILE lpProfile,
  850. LPCTSTR lpcszLocalHiveDir)
  851. {
  852. LONG res;
  853. HKEY hKeySource;
  854. // Open HKCU\Software\Classes and see if there is a subkey.
  855. // No subkeys would indicate that the move has already been
  856. // done or there is no data to move.
  857. res = RegOpenKeyEx(lpProfile->hKeyCurrentUser, CLASSES_CLSID_SUBTREE, 0, KEY_ALL_ACCESS, &hKeySource);
  858. if (ERROR_SUCCESS == res)
  859. {
  860. DWORD dwSubKeyCount;
  861. if ((ERROR_SUCCESS == RegQueryInfoKey(hKeySource, NULL, NULL, NULL, &dwSubKeyCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) &&
  862. (dwSubKeyCount > 0))
  863. {
  864. LPTSTR pszLocalTempHive;
  865. DWORD cchLocalTempHive;
  866. // Allocate enough space for the local hive directory and the temp hive filename.
  867. cchLocalTempHive = lstrlen(lpcszLocalHiveDir) + lstrlen(TEMPHIVE_FILENAME) + 1;
  868. pszLocalTempHive = (LPTSTR) LocalAlloc(LPTR, cchLocalTempHive * sizeof(TCHAR));
  869. // Get a path to a file to save HKCU\Software\Classes into.
  870. if (pszLocalTempHive != NULL)
  871. {
  872. HANDLE hToken = NULL;
  873. BOOL bAdjustPriv = FALSE;
  874. StringCchCopy(pszLocalTempHive, cchLocalTempHive, lpcszLocalHiveDir);
  875. StringCchCat (pszLocalTempHive, cchLocalTempHive, TEMPHIVE_FILENAME);
  876. // RegSaveKey() fails if the file exists so delete it first.
  877. DeleteFile(pszLocalTempHive);
  878. //
  879. // Check to see if we are impersonating.
  880. //
  881. if(!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken) || hToken == NULL) {
  882. bAdjustPriv = TRUE;
  883. }
  884. else {
  885. CloseHandle(hToken);
  886. }
  887. if(!bAdjustPriv) {
  888. DWORD dwDisposition;
  889. HKEY hKeyTarget;
  890. BOOL fSavedHive;
  891. // Save HKCU\Software\Classes into the temp hive
  892. // and restore the state of SE_BACKUP_NAME privilege
  893. res = RegSaveKey(hKeySource, pszLocalTempHive, NULL);
  894. if (ERROR_SUCCESS == res)
  895. {
  896. res = RegCreateKeyEx(lpProfile->hKeyCurrentUser, EXPLORER_CLASSES_SUBTREE, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyTarget, &dwDisposition);
  897. if (ERROR_SUCCESS == res)
  898. {
  899. // Restore temp hive to a new location at
  900. // HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer
  901. // This performs the upgrade from NT4 to NT5.
  902. res = RegRestoreKey(hKeyTarget, pszLocalTempHive, 0);
  903. if (ERROR_SUCCESS != res)
  904. {
  905. DebugMsg((DM_WARNING, TEXT("RegRestoreKey failed with error %d"), res));
  906. }
  907. RegCloseKey(hKeyTarget);
  908. }
  909. else
  910. {
  911. DebugMsg((DM_WARNING, TEXT("RegCreateKeyEx failed to create key %s with error %d"), EXPLORER_CLASSES_SUBTREE, res));
  912. }
  913. }
  914. else
  915. {
  916. DebugMsg((DM_WARNING, TEXT("RegSaveKey failed with error %d"), res));
  917. }
  918. }
  919. else {
  920. if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
  921. {
  922. DWORD dwReturnTokenPrivilegesSize;
  923. TOKEN_PRIVILEGES oldTokenPrivileges, newTokenPrivileges;
  924. // Enable SE_BACKUP_NAME privilege
  925. if (LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &newTokenPrivileges.Privileges[0].Luid))
  926. {
  927. newTokenPrivileges.PrivilegeCount = 1;
  928. newTokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  929. if (AdjustTokenPrivileges(hToken, FALSE, &newTokenPrivileges, sizeof(newTokenPrivileges), &oldTokenPrivileges, &dwReturnTokenPrivilegesSize))
  930. {
  931. BOOL fSavedHive;
  932. // Save HKCU\Software\Classes into the temp hive
  933. // and restore the state of SE_BACKUP_NAME privilege
  934. res = RegSaveKey(hKeySource, pszLocalTempHive, NULL);
  935. if (!AdjustTokenPrivileges(hToken, FALSE, &oldTokenPrivileges, 0, NULL, NULL))
  936. {
  937. DebugMsg((DM_WARNING, TEXT("AdjustTokenPrivileges failed to restore old privileges with error %d"), GetLastError()));
  938. }
  939. if (ERROR_SUCCESS == res)
  940. {
  941. // Enable SE_RESTORE_NAME privilege.
  942. if (LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &newTokenPrivileges.Privileges[0].Luid))
  943. {
  944. newTokenPrivileges.PrivilegeCount = 1;
  945. newTokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  946. if (AdjustTokenPrivileges(hToken, FALSE, &newTokenPrivileges, sizeof(newTokenPrivileges), &oldTokenPrivileges, &dwReturnTokenPrivilegesSize))
  947. {
  948. DWORD dwDisposition;
  949. HKEY hKeyTarget;
  950. res = RegCreateKeyEx(lpProfile->hKeyCurrentUser, EXPLORER_CLASSES_SUBTREE, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyTarget, &dwDisposition);
  951. if (ERROR_SUCCESS == res)
  952. {
  953. // Restore temp hive to a new location at
  954. // HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer
  955. // This performs the upgrade from NT4 to NT5.
  956. res = RegRestoreKey(hKeyTarget, pszLocalTempHive, 0);
  957. if (ERROR_SUCCESS != res)
  958. {
  959. DebugMsg((DM_WARNING, TEXT("RegRestoreKey failed with error %d"), res));
  960. }
  961. RegCloseKey(hKeyTarget);
  962. }
  963. else
  964. {
  965. DebugMsg((DM_WARNING, TEXT("RegCreateKeyEx failed to create key %s with error %d"), EXPLORER_CLASSES_SUBTREE, res));
  966. }
  967. if (!AdjustTokenPrivileges(hToken, FALSE, &oldTokenPrivileges, 0, NULL, NULL))
  968. {
  969. DebugMsg((DM_WARNING, TEXT("AdjustTokenPrivileges failed to restore old privileges with error %d"), GetLastError()));
  970. }
  971. }
  972. else
  973. {
  974. res = GetLastError();
  975. DebugMsg((DM_WARNING, TEXT("AdjustTokenPrivileges failed with error %d"), res));
  976. }
  977. }
  978. else
  979. {
  980. res = GetLastError();
  981. DebugMsg((DM_WARNING, TEXT("LookupPrivilegeValue failed with error %d"), res));
  982. }
  983. }
  984. else
  985. {
  986. DebugMsg((DM_WARNING, TEXT("RegSaveKey failed with error %d"), res));
  987. }
  988. }
  989. else
  990. {
  991. res = GetLastError();
  992. DebugMsg((DM_WARNING, TEXT("AdjustTokenPrivileges failed with error %d"), res));
  993. }
  994. }
  995. else
  996. {
  997. res = GetLastError();
  998. DebugMsg((DM_WARNING, TEXT("LookupPrivilegeValue failed with error %d"), res));
  999. }
  1000. CloseHandle(hToken);
  1001. }
  1002. else
  1003. {
  1004. res = GetLastError();
  1005. DebugMsg((DM_WARNING, TEXT("OpenProcessToken failed to get token with error %d"), res));
  1006. }
  1007. } // if(!bAdjustPriv) else
  1008. // Delete local temporary hive file.
  1009. DeleteFile(pszLocalTempHive);
  1010. LocalFree(pszLocalTempHive);
  1011. }
  1012. else
  1013. {
  1014. res = ERROR_NOT_ENOUGH_MEMORY;
  1015. DebugMsg((DM_WARNING, TEXT("LocalAlloc failed to allocate temp hive path buffer")));
  1016. }
  1017. }
  1018. RegCloseKey(hKeySource);
  1019. }
  1020. else if (ERROR_FILE_NOT_FOUND == res)
  1021. {
  1022. res = ERROR_SUCCESS;
  1023. }
  1024. return res;
  1025. }
  1026. //*************************************************************
  1027. //
  1028. // LoadUserClasses()
  1029. //
  1030. // Purpose: Combines the HKLM\Software\Classes subtree with the
  1031. // HKCU\Software\Classes subtree
  1032. //
  1033. // Parameters: lpProfile - Profile information
  1034. // SidString - User's Sid as a string
  1035. //
  1036. // Return: ERROR_SUCCESS if successful
  1037. // other NTSTATUS if an error occurs
  1038. //
  1039. //*************************************************************
  1040. LONG LoadUserClasses( LPPROFILE lpProfile, LPTSTR SidString, BOOL bNewlyIssued)
  1041. {
  1042. LONG error;
  1043. LPTSTR szLocalHiveDir = NULL;
  1044. error = ERROR_SUCCESS;
  1045. //
  1046. // first, we will create a directory for the user-specific
  1047. // classes hive -- we need memory for it:
  1048. //
  1049. szLocalHiveDir = (LPTSTR) LocalAlloc(LPTR, MAX_HIVE_DIR_CCH * sizeof(TCHAR));
  1050. if (!szLocalHiveDir) {
  1051. error =ERROR_NOT_ENOUGH_MEMORY;
  1052. goto Exit;
  1053. }
  1054. //
  1055. // create the directory for the user-specific classes hive
  1056. //
  1057. error = CreateClassesFolder(lpProfile, szLocalHiveDir, MAX_HIVE_DIR_CCH);
  1058. if (ERROR_SUCCESS != error) {
  1059. DebugMsg((DM_WARNING, TEXT("LoadUserClasses: Failed to create folder for combined hive (%d)."),
  1060. error));
  1061. goto Exit;
  1062. }
  1063. // Move HKCU\Software\Classes before merging the two
  1064. // branches. Ignore any errors here as this branch is
  1065. // about to be deleted by the merge anyway.
  1066. // The reason for this move is because NT4 stores customized
  1067. // shell icons in HKCU\Software\Classes\CLSID\{CLSID_x} and
  1068. // NT5 stores this at HKCU\Software\Microsoft\Windows\
  1069. // CurrentVersion\Explorer\CLSID\{CLSID_x} and must be moved
  1070. // now before being deleted.
  1071. error = MoveUserClassesBeforeMerge(lpProfile, szLocalHiveDir);
  1072. if (ERROR_SUCCESS != error) {
  1073. DebugMsg((DM_WARNING, TEXT("MoveUserClassesBeforeMerge: Failed unexpectedly (%d)."),
  1074. error));
  1075. }
  1076. //
  1077. // Now create the user classes hive
  1078. //
  1079. error = CreateUserClassesHive( lpProfile, SidString, szLocalHiveDir, bNewlyIssued);
  1080. if (ERROR_SUCCESS != error) {
  1081. DebugMsg((DM_WARNING, TEXT("LoadUserClasses: Failed to create user classes hive (%d)."),
  1082. error));
  1083. }
  1084. Exit:
  1085. if (szLocalHiveDir)
  1086. LocalFree(szLocalHiveDir);
  1087. return error;
  1088. }