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.

1121 lines
29 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. usermig.c
  5. Abstract:
  6. The functions in this module are called to perform migration of
  7. per-user settings.
  8. Author:
  9. Jim Schmidt (jimschm) 04-Feb-1997
  10. Revision History:
  11. jimschm 23-Sep-1998 Redesigned for new progress bar and
  12. shell code
  13. jimschm 11-Jul-1998 Support for dynamic user profile dir,
  14. removal of MikeCo code.
  15. calinn 12-Dec-1997 Added RestoreMMSettings_User
  16. jimschm 21-Apr-1997 Added UserProfileExt
  17. --*/
  18. #include "pch.h"
  19. #include "migmainp.h"
  20. #ifndef UNICODE
  21. #error UNICODE required
  22. #endif
  23. VOID
  24. pSuppressEmptyWallpaper (
  25. VOID
  26. );
  27. VOID
  28. pCheckY2KCompliance (
  29. VOID
  30. );
  31. DWORD
  32. PrepareUserForMigration (
  33. IN DWORD Request,
  34. IN PMIGRATE_USER_ENUM EnumPtr
  35. )
  36. {
  37. static USERMIGDATA Data;
  38. static BOOL DefaultHiveLoaded = FALSE;
  39. LONG rc;
  40. MEMDB_ENUM e;
  41. TCHAR RegKey[MAX_REGISTRY_KEY];
  42. TCHAR RegValueName[MAX_REGISTRY_VALUE_NAME];
  43. TCHAR RegValueKey[MEMDB_MAX];
  44. PCTSTR RegValue;
  45. TCHAR DefaultUserHive[MAX_TCHAR_PATH];
  46. static TCHAR ReferenceDefaultUserHive[MAX_TCHAR_PATH];
  47. PTSTR p, q;
  48. HKEY Key;
  49. DWORD Size;
  50. PTSTR LogFile;
  51. DWORD valueType;
  52. if (Request == REQUEST_QUERYTICKS) {
  53. return TICKS_PERUSER_INIT;
  54. } else if (Request == REQUEST_BEGINUSERPROCESSING) {
  55. //
  56. // Save current state of memdb (to be reloaded for each user)
  57. //
  58. MemDbSave (GetMemDbDat());
  59. return ERROR_SUCCESS;
  60. } else if (Request != REQUEST_RUN &&
  61. Request != REQUEST_ENDUSERPROCESSING
  62. ) {
  63. return ERROR_SUCCESS;
  64. }
  65. //
  66. // We are now begining to process another user, or we are being
  67. // called one last time after all users are processed. Clean up
  68. // the previous state.
  69. //
  70. if (Data.UserHiveRootOpen) {
  71. CloseRegKey (Data.UserHiveRoot);
  72. }
  73. if (Data.UserHiveRootCreated) {
  74. pSetupRegistryDelnode (HKEY_CURRENT_CONFIG, S_TEMP_USER_KEY);
  75. }
  76. if (Data.LastUserWasDefault) {
  77. RegUnLoadKey (HKEY_LOCAL_MACHINE, S_TEMP_USER_KEY);
  78. }
  79. if (Data.ProfileToDelete[0]) {
  80. if (Data.LastUserWasDefault && !Data.DefaultHiveSaved) {
  81. //
  82. // Default User hive could not be saved, so restore the file
  83. //
  84. OurMoveFile (Data.ProfileToDelete, Data.TempProfile);
  85. } else {
  86. //
  87. // The original default hive needs to be removed
  88. //
  89. DeleteFile (Data.ProfileToDelete);
  90. LogFile = DuplicatePathString (Data.ProfileToDelete, 5);
  91. StringCat (LogFile, TEXT(".log"));
  92. DeleteFile (LogFile);
  93. FreePathString (LogFile);
  94. }
  95. }
  96. ZeroMemory (&Data, sizeof (Data));
  97. if (Request == REQUEST_ENDUSERPROCESSING) {
  98. if (DefaultHiveLoaded) {
  99. rc = RegUnLoadKey (HKEY_LOCAL_MACHINE, S_MAPPED_DEFAULT_USER_KEY);
  100. if (rc != ERROR_SUCCESS) {
  101. SetLastError (rc);
  102. DEBUGMSG ((DBG_ERROR, "Can't unload Default User hive in cleanup"));
  103. }
  104. SetFileAttributes (ReferenceDefaultUserHive, FILE_ATTRIBUTE_NORMAL);
  105. DeleteFile (ReferenceDefaultUserHive);
  106. DefaultHiveLoaded = FALSE;
  107. }
  108. return ERROR_SUCCESS;
  109. }
  110. MYASSERT (Request == REQUEST_RUN);
  111. //
  112. // Initialize globals
  113. //
  114. if (EnumPtr->AccountType != LOGON_USER_SETTINGS) {
  115. g_DomainUserName = EnumPtr->FixedDomainName;
  116. g_Win9xUserName = EnumPtr->Win9xUserName;
  117. g_FixedUserName = EnumPtr->FixedUserName;
  118. } else {
  119. g_DomainUserName = NULL;
  120. g_Win9xUserName = NULL;
  121. g_FixedUserName = NULL;
  122. }
  123. //
  124. // If default user hive has not been mapped in yet, map it in now.
  125. // This will stay open as a reference.
  126. //
  127. if (!DefaultHiveLoaded) {
  128. Size = ARRAYSIZE(DefaultUserHive)- 12;
  129. if (!GetDefaultUserProfileDirectory (DefaultUserHive, &Size)) {
  130. LOG ((
  131. LOG_ERROR,
  132. "Process User: Can't get default user profile directory"
  133. ));
  134. return GetLastError();
  135. }
  136. StringCopy (AppendWack (DefaultUserHive), TEXT("ntuser.dat"));
  137. StringCopy (ReferenceDefaultUserHive, DefaultUserHive);
  138. StringCat (ReferenceDefaultUserHive, TEXT(".ref"));
  139. SetFileAttributes (ReferenceDefaultUserHive, FILE_ATTRIBUTE_NORMAL);
  140. DeleteFile (ReferenceDefaultUserHive);
  141. if (!CopyFile (DefaultUserHive, ReferenceDefaultUserHive, FALSE)) {
  142. LOG ((
  143. LOG_ERROR,
  144. "Process User: Can't copy default user hive %s",
  145. DefaultUserHive
  146. ));
  147. return GetLastError();
  148. }
  149. rc = RegLoadKey (
  150. HKEY_LOCAL_MACHINE,
  151. S_MAPPED_DEFAULT_USER_KEY,
  152. ReferenceDefaultUserHive
  153. );
  154. if (rc != ERROR_SUCCESS) {
  155. SetLastError (rc);
  156. LOG ((
  157. LOG_ERROR,
  158. "Process User: RegLoadKey could not load NT Default User from %s",
  159. ReferenceDefaultUserHive
  160. ));
  161. return rc;
  162. }
  163. DefaultHiveLoaded = TRUE;
  164. }
  165. //
  166. // Prepare temp registry key
  167. //
  168. ZeroMemory (&Data, sizeof (Data));
  169. EnumPtr->ExtraData = &Data;
  170. switch (EnumPtr->AccountType) {
  171. case DEFAULT_USER_ACCOUNT:
  172. Size = MAX_TCHAR_PATH;
  173. GetDefaultUserProfileDirectory (Data.TempProfile, &Size);
  174. StringCopy (AppendWack (Data.TempProfile), TEXT("ntuser.dat"));
  175. //
  176. // Move the default user hive to a new file, so we can update
  177. // it with RegSaveKey later.
  178. //
  179. wsprintf (
  180. Data.ProfileToDelete,
  181. TEXT("%s.$$$"),
  182. Data.TempProfile
  183. );
  184. SetFileAttributes (Data.ProfileToDelete, FILE_ATTRIBUTE_NORMAL);
  185. DeleteFile (Data.ProfileToDelete);
  186. MYASSERT (!DoesFileExist (Data.ProfileToDelete));
  187. if (!OurMoveFile (Data.TempProfile, Data.ProfileToDelete)) {
  188. rc = GetLastError();
  189. LOG ((
  190. LOG_ERROR,
  191. "Process User: OurMoveFile failed to move %s to %s",
  192. Data.TempProfile,
  193. Data.ProfileToDelete
  194. ));
  195. return rc;
  196. }
  197. //
  198. // Load the true Default User hive from its new location
  199. //
  200. rc = RegLoadKey (
  201. HKEY_LOCAL_MACHINE,
  202. S_TEMP_USER_KEY,
  203. Data.ProfileToDelete
  204. );
  205. if (rc != ERROR_SUCCESS) {
  206. SetLastError (rc);
  207. LOG ((
  208. LOG_ERROR,
  209. "Process User: RegLoadKey could not load NT Default User from %s",
  210. Data.ProfileToDelete
  211. ));
  212. return rc;
  213. }
  214. Data.UserHiveRoot = OpenRegKey (HKEY_LOCAL_MACHINE, S_TEMP_USER_KEY);
  215. if (!Data.UserHiveRoot) {
  216. LOG ((LOG_ERROR, "Process User: RegOpenKey could not open NT Default User hive"));
  217. return GetLastError();
  218. }
  219. Data.UserHiveRootOpen = TRUE;
  220. Data.LastUserWasDefault = TRUE;
  221. break;
  222. case LOGON_USER_SETTINGS:
  223. //
  224. // Set Data.UserHiveRoot to HKU\.Default
  225. //
  226. Data.UserHiveRoot = OpenRegKey (HKEY_USERS, S_DOT_DEFAULT);
  227. if (!Data.UserHiveRoot) {
  228. LOG ((LOG_ERROR, "Process User: RegOpenKey could not open HKU\\.Default"));
  229. return GetLastError();
  230. }
  231. Data.UserHiveRootOpen = TRUE;
  232. //
  233. // Suppress wallpaper if it is an empty string
  234. //
  235. pSuppressEmptyWallpaper();
  236. break;
  237. default:
  238. MYASSERT (g_Win9xUserName);
  239. //
  240. // Prepare the string "c:\windows\setup\ntuser.dat"
  241. //
  242. StringCopy (Data.TempProfile, g_TempDir);
  243. StringCopy (AppendWack (Data.TempProfile), TEXT("NTUSER.DAT"));
  244. //
  245. // Save this string in ProfileToDelete for cleanup later
  246. //
  247. StringCopy (Data.ProfileToDelete, Data.TempProfile);
  248. //
  249. // Create HKCC\$$$ and set Data.UserHiveRoot
  250. //
  251. rc = TrackedRegCreateKey (HKEY_CURRENT_CONFIG, S_TEMP_USER_KEY, &Data.UserHiveRoot);
  252. if (rc != ERROR_SUCCESS) {
  253. SetLastError (rc);
  254. LOG ((LOG_ERROR, "Process User: WinNTRegCreateKey failed to make %s in HKCC", S_TEMP_USER_KEY));
  255. return rc;
  256. }
  257. Data.UserHiveRootCreated = TRUE;
  258. Data.UserHiveRootOpen = TRUE;
  259. //
  260. // Set the per-user registry values
  261. //
  262. if (MemDbGetValueEx (&e, MEMDB_CATEGORY_SET_USER_REGISTRY, g_FixedUserName, NULL)) {
  263. do {
  264. p = _tcschr (e.szName, TEXT('['));
  265. if (p) {
  266. DecodeRuleCharsAB (RegKey, ARRAYSIZE(RegKey), e.szName, p);
  267. q = _tcsrchr (RegKey, TEXT('\\'));
  268. if (!q[1]) {
  269. *q = 0;
  270. }
  271. p = _tcsinc (p);
  272. q = _tcschr (p, TEXT(']'));
  273. if (q) {
  274. DecodeRuleCharsAB (RegValueName, ARRAYSIZE(RegValueName), p, q);
  275. MemDbBuildKeyFromOffset (e.dwValue, RegValueKey, 0, NULL);
  276. RegValue = _tcschr (RegValueKey, TEXT('\\'));
  277. MYASSERT (RegValue);
  278. if (!RegValue) {
  279. RegValue = RegValueKey;
  280. } else {
  281. RegValue = _tcsinc (RegValue);
  282. }
  283. if (!MemDbGetValue (RegValueKey, &valueType) || valueType == 0) {
  284. valueType = REG_SZ;
  285. }
  286. Key = CreateRegKey (Data.UserHiveRoot, RegKey);
  287. if (!Key) {
  288. DEBUGMSG ((DBG_WHOOPS, "Can't create %s", RegKey));
  289. } else {
  290. rc = RegSetValueEx (
  291. Key,
  292. RegValueName,
  293. 0,
  294. valueType,
  295. (PBYTE) RegValue,
  296. SizeOfString (RegValue)
  297. );
  298. CloseRegKey (Key);
  299. DEBUGMSG_IF ((
  300. rc != ERROR_SUCCESS,
  301. DBG_WHOOPS,
  302. "Can't save %s [%s] = %s (rc = %u)",
  303. RegKey,
  304. RegValueName,
  305. RegValue,
  306. rc
  307. ));
  308. }
  309. }
  310. ELSE_DEBUGMSG ((DBG_WHOOPS, "Key not encoded properly: %s", e.szName));
  311. }
  312. ELSE_DEBUGMSG ((DBG_WHOOPS, "Key not encoded properly: %s", e.szName));
  313. } while (MemDbEnumNextValue (&e));
  314. }
  315. break;
  316. }
  317. //
  318. // Data.UserHiveRoot is either HKCU\$$$ or HKU\.Default
  319. //
  320. g_hKeyRootNT = Data.UserHiveRoot;
  321. //
  322. // Load in default MemDb state
  323. //
  324. MemDbLoad (GetMemDbDat());
  325. return ERROR_SUCCESS;
  326. }
  327. DWORD
  328. MigrateUserRegistry (
  329. IN DWORD Request,
  330. IN PMIGRATE_USER_ENUM EnumPtr
  331. )
  332. {
  333. if (Request == REQUEST_QUERYTICKS) {
  334. return TICKS_USER_REGISTRY_MIGRATION;
  335. } else if (Request != REQUEST_RUN) {
  336. return ERROR_SUCCESS;
  337. }
  338. if (!MergeRegistry (S_USERMIG_INF, g_DomainUserName ? g_DomainUserName : S_EMPTY)) {
  339. LOG ((LOG_ERROR, "Process User: MergeRegistry failed"));
  340. return GetLastError();
  341. }
  342. return ERROR_SUCCESS;
  343. }
  344. DWORD
  345. MigrateLogonPromptSettings (
  346. IN DWORD Request,
  347. IN PMIGRATE_USER_ENUM EnumPtr
  348. )
  349. {
  350. if (Request == REQUEST_QUERYTICKS) {
  351. return TICKS_LOGON_PROMPT_SETTINGS;
  352. } else if (Request != REQUEST_RUN) {
  353. return ERROR_SUCCESS;
  354. }
  355. if (EnumPtr->AccountType != LOGON_USER_SETTINGS) {
  356. return ERROR_SUCCESS;
  357. }
  358. MYASSERT (EnumPtr->ExtraData);
  359. return ERROR_SUCCESS;
  360. }
  361. DWORD
  362. MigrateUserSettings (
  363. IN DWORD Request,
  364. IN PMIGRATE_USER_ENUM EnumPtr
  365. )
  366. {
  367. if (Request == REQUEST_QUERYTICKS) {
  368. return TICKS_USER_SETTINGS;
  369. } else if (Request != REQUEST_RUN) {
  370. return ERROR_SUCCESS;
  371. }
  372. if (EnumPtr->AccountType == LOGON_USER_SETTINGS) {
  373. return ERROR_SUCCESS;
  374. }
  375. MYASSERT (EnumPtr->ExtraData);
  376. //
  377. // Copy any settings from DOS configuration files that need to be
  378. // saved into the per user configuration.
  379. //
  380. if (EnumPtr->AccountType != DEFAULT_USER_ACCOUNT) {
  381. if (DosMigNt_User (g_hKeyRootNT) != EXIT_SUCCESS) {
  382. LOG ((LOG_ERROR,"DosMigNt failed."));
  383. }
  384. }
  385. //
  386. // Pull in all the per-user INI settings (TRUE indicates per-user settings)
  387. //
  388. if (!ProcessIniFileMapping (TRUE)) {
  389. LOG ((LOG_ERROR, "Process User: Could not migrate one or more .INI files."));
  390. }
  391. //
  392. // Now look for Short Date format settings
  393. //
  394. pCheckY2KCompliance ();
  395. //
  396. // Restore multimedia settings
  397. //
  398. if (!RestoreMMSettings_User (g_FixedUserName, g_hKeyRootNT)) {
  399. LOG ((LOG_ERROR, "Process User: Could not restore multimedia settings."));
  400. }
  401. //
  402. // Create the RAS entries for the user.
  403. //
  404. if (!Ras_MigrateUser (g_FixedUserName, g_hKeyRootNT)) {
  405. LOG ((LOG_ERROR,"Ras user migration failed."));
  406. }
  407. //
  408. // Create the TAPI entries that are per user.
  409. //
  410. if (!Tapi_MigrateUser (g_FixedUserName, g_hKeyRootNT)) {
  411. LOG ((LOG_ERROR,"Tapi user migration failed."));
  412. }
  413. return ERROR_SUCCESS;
  414. }
  415. DWORD
  416. SaveMigratedUserHive (
  417. IN DWORD Request,
  418. IN PMIGRATE_USER_ENUM EnumPtr
  419. )
  420. {
  421. PTSTR UserProfile = NULL;
  422. PCTSTR UserNameWithSuffix;
  423. PSID Sid;
  424. LONG rc = ERROR_SUCCESS;
  425. PUSERMIGDATA Data;
  426. PCTSTR CopyOfProfile;
  427. PTSTR Path;
  428. MIGRATE_USER_ENUM e;
  429. if (Request == REQUEST_QUERYTICKS) {
  430. return TICKS_SAVE_USER_HIVE;
  431. } else if (Request != REQUEST_RUN) {
  432. return ERROR_SUCCESS;
  433. }
  434. MYASSERT (EnumPtr->ExtraData);
  435. Data = EnumPtr->ExtraData;
  436. if (EnumPtr->AccountType == LOGON_USER_SETTINGS) {
  437. return ERROR_SUCCESS;
  438. }
  439. if (Data->TempProfile[0] && !Data->LastUserWasDefault) {
  440. //
  441. // Save the hive to disk
  442. //
  443. SetFileAttributes (Data->TempProfile, FILE_ATTRIBUTE_NORMAL);
  444. DeleteFile (Data->TempProfile);
  445. MYASSERT (Data->UserHiveRootOpen);
  446. rc = RegSaveKey (Data->UserHiveRoot, Data->TempProfile, NULL);
  447. if (rc != ERROR_SUCCESS) {
  448. SetLastError (rc);
  449. LOG ((LOG_ERROR, "RegSaveKey failed to save %s", Data->TempProfile));
  450. return rc;
  451. } else {
  452. SetFileAttributes (Data->TempProfile, FILE_ATTRIBUTE_HIDDEN);
  453. }
  454. //
  455. // Look up account SID
  456. //
  457. Sid = GetSidForUser (g_FixedUserName);
  458. if (!Sid) {
  459. DEBUGMSG ((DBG_WARNING, "Could not obtain SID for %s", g_FixedUserName));
  460. return GetLastError();
  461. }
  462. //
  463. // Add the user to the local power users or administrators group
  464. //
  465. if (g_PersonalSKU) {
  466. if (EnumPtr->AccountType != ADMINISTRATOR_ACCOUNT) {
  467. LOG_IF ((
  468. g_ConfigOptions.MigrateUsersAsPowerUsers,
  469. LOG_WARNING,
  470. "MigrateUsersAsPowerUsers option is ignored on upgrade to Personal SKU"
  471. ));
  472. LOG_IF ((
  473. g_ConfigOptions.MigrateUsersAsAdmin,
  474. LOG_WARNING,
  475. "MigrateUsersAsAdmin option is ignored on upgrade to Personal SKU"
  476. ));
  477. if (!AddSidToLocalGroup (Sid, g_AdministratorsGroupStr)) {
  478. DEBUGMSG ((DBG_WARNING, "Could not add %s to %s group", g_FixedUserName, g_AdministratorsGroupStr));
  479. }
  480. }
  481. } else {
  482. if (g_ConfigOptions.MigrateUsersAsPowerUsers) {
  483. if (!AddSidToLocalGroup (Sid, g_PowerUsersGroupStr)) {
  484. DEBUGMSG ((DBG_WARNING, "Could not add %s to %s group", g_FixedUserName, g_PowerUsersGroupStr));
  485. }
  486. } else if (EnumPtr->AccountType != ADMINISTRATOR_ACCOUNT &&
  487. g_ConfigOptions.MigrateUsersAsAdmin
  488. ) {
  489. if (!AddSidToLocalGroup (Sid, g_AdministratorsGroupStr)) {
  490. DEBUGMSG ((DBG_WARNING, "Could not add %s to %s group", g_FixedUserName, g_AdministratorsGroupStr));
  491. }
  492. } else {
  493. SetClassicLogonType();
  494. }
  495. }
  496. __try {
  497. //
  498. // Prepare profile directory
  499. //
  500. UserNameWithSuffix = GetUserProfilePath (g_FixedUserName, &UserProfile);
  501. MYASSERT (UserNameWithSuffix);
  502. MYASSERT (UserProfile);
  503. if (!UserNameWithSuffix) {
  504. rc = GetLastError();
  505. __leave;
  506. }
  507. //
  508. // The recommendation here (UserNameWithSuffix) is no longer used, because
  509. // we already created the user profile dir before processing the user.
  510. //
  511. if (!CreateUserProfile (
  512. Sid,
  513. UserNameWithSuffix, // User or User.000
  514. Data->TempProfile,
  515. NULL,
  516. 0
  517. )) {
  518. LOG ((LOG_ERROR, "Create User Profile failed"));
  519. rc = GetLastError();
  520. __leave;
  521. }
  522. //
  523. // Build the final location of the user's hive, so migdlls.c
  524. // can load the hive.
  525. //
  526. wsprintf (
  527. Data->TempProfile,
  528. TEXT("%s\\ntuser.dat"),
  529. UserProfile
  530. );
  531. }
  532. __finally {
  533. FreePathString (UserProfile);
  534. }
  535. } else if (Data->LastUserWasDefault) {
  536. SetFileAttributes (Data->TempProfile, FILE_ATTRIBUTE_NORMAL);
  537. DeleteFile (Data->TempProfile);
  538. //
  539. // Save the hive
  540. //
  541. rc = RegSaveKey (Data->UserHiveRoot, Data->TempProfile, NULL);
  542. if (rc != ERROR_SUCCESS) {
  543. SetLastError (rc);
  544. LOG ((LOG_ERROR, "Process User: RegSaveKey failed to save %s", Data->TempProfile));
  545. } else {
  546. SetFileAttributes (Data->TempProfile, FILE_ATTRIBUTE_HIDDEN);
  547. Data->DefaultHiveSaved = TRUE;
  548. //
  549. // Find Administrator
  550. //
  551. if (EnumFirstUserToMigrate (&e, ENUM_ALL_USERS)) {
  552. do {
  553. if (e.AccountType == ADMINISTRATOR_ACCOUNT) {
  554. break;
  555. }
  556. } while (EnumNextUserToMigrate (&e));
  557. }
  558. if (e.AccountType == ADMINISTRATOR_ACCOUNT && e.CreateOnly) {
  559. //
  560. // Copy the hive to Administrator if (A) the Administrator is
  561. // not a migrated user, and (B) the hive exists
  562. //
  563. if (GetUserProfilePath (e.FixedUserName, &Path)) {
  564. DeleteDirectoryContents (Path);
  565. SetFileAttributes (Path, FILE_ATTRIBUTE_NORMAL);
  566. if (!RemoveDirectory (Path)) {
  567. DEBUGMSG ((DBG_ERROR, "Can't remove %s", Path));
  568. }
  569. ELSE_DEBUGMSG ((DBG_VERBOSE, "Administrator profile %s removed", Path));
  570. FreePathString (Path);
  571. }
  572. ELSE_DEBUGMSG ((DBG_WHOOPS, "User %s does not have a profile path", e.FixedUserName));
  573. }
  574. }
  575. }
  576. if (rc == ERROR_SUCCESS) {
  577. //
  578. // Add hive location to string table
  579. //
  580. CopyOfProfile = PoolMemDuplicateString (g_HivePool, Data->TempProfile);
  581. DEBUGMSG ((
  582. DBG_NAUSEA,
  583. "ProcessUser: Adding hive location %s for user %s",
  584. CopyOfProfile,
  585. g_FixedUserName
  586. ));
  587. pSetupStringTableAddStringEx (
  588. g_HiveTable,
  589. (PTSTR) g_FixedUserName,
  590. STRTAB_CASE_INSENSITIVE,
  591. (PTSTR) CopyOfProfile,
  592. SizeOfString (CopyOfProfile)
  593. );
  594. } else {
  595. //
  596. // The hive couldn't be saved for this user!! Tell the user.
  597. //
  598. LOG ((LOG_ERROR, (PCSTR)MSG_PROFILE_ERROR, g_FixedUserName));
  599. }
  600. return rc;
  601. }
  602. PCTSTR
  603. GetUserProfilePath (
  604. IN PCTSTR AccountName,
  605. OUT PTSTR *BufferPtr
  606. )
  607. /*++
  608. Routine Description:
  609. Generates the full path to a user's profile. The user profile directory may have
  610. an extension (joeuser.001), and we must maintain that extension.
  611. Arguments:
  612. AccountName - Supplies the name of the user (fixed version, without the domain)
  613. BufferPtr - Receives the full path to the user's profile directory, for example:
  614. c:\windows\profiles\joeuser.001
  615. This buffer must be freed with FreePathString.
  616. Return Value:
  617. A pointer to the user name with extension (joeuser.001) or NULL if something went
  618. terribly wrong.
  619. --*/
  620. {
  621. PTSTR p;
  622. TCHAR ProfileNameWithExt[MEMDB_MAX];
  623. //
  624. // Get the profile path obtained from CreateUserProfile
  625. //
  626. p = (PTSTR) GetProfilePathForUser (AccountName);
  627. if (p) {
  628. *BufferPtr = DuplicatePathString (p, 0);
  629. } else {
  630. //
  631. // This is to guard against unexpected errors. The user
  632. // will lose profile folder contents, but they can be recovered.
  633. //
  634. // Create %windir%\<user> (or <ProfileNameWithExt> if it exists)
  635. //
  636. MYASSERT (FALSE); // this should not happen
  637. ProfileNameWithExt[0] = 0;
  638. MemDbGetEndpointValueEx (
  639. MEMDB_CATEGORY_USER_PROFILE_EXT,
  640. AccountName,
  641. NULL,
  642. ProfileNameWithExt
  643. );
  644. *BufferPtr = JoinPaths (g_WinDir, ProfileNameWithExt[0] ? ProfileNameWithExt : AccountName);
  645. }
  646. //
  647. // Return user name with suffix (i.e. joeuser.001)
  648. //
  649. p = _tcsrchr (*BufferPtr, TEXT('\\'));
  650. if (p) {
  651. p = _tcsinc (p);
  652. }
  653. DEBUGMSG ((DBG_VERBOSE, "GetUserProfilePath: Account %s profile extension is %s", AccountName, p));
  654. return p;
  655. }
  656. BOOL
  657. pCopyDefaultShellFolders (
  658. IN PCTSTR DestRoot
  659. )
  660. {
  661. TCHAR DefFolders[MAX_TCHAR_PATH];
  662. GetEnvironmentVariable (S_USERPROFILE, DefFolders, MAX_TCHAR_PATH);
  663. return CopyTree (
  664. DefFolders,
  665. DestRoot,
  666. 0, // no EnumTree ID
  667. COPYTREE_DOCOPY | COPYTREE_NOOVERWRITE,
  668. ENUM_ALL_LEVELS,
  669. FILTER_ALL,
  670. NULL, // no exclude.inf struct
  671. NULL, // no callback
  672. NULL // no error callback
  673. );
  674. }
  675. VOID
  676. pSuppressEmptyWallpaper(
  677. VOID
  678. )
  679. {
  680. HKEY Key;
  681. LONG rc;
  682. DWORD Size;
  683. TCHAR Buffer[MAX_TCHAR_PATH];
  684. rc = TrackedRegOpenKeyEx95 (g_hKeyRoot95, S_DESKTOP_KEY, 0, KEY_READ, &Key);
  685. if (rc == ERROR_SUCCESS) {
  686. Size = sizeof (Buffer);
  687. rc = Win95RegQueryValueEx (
  688. Key,
  689. S_WALLPAPER,
  690. NULL,
  691. NULL,
  692. (PBYTE) Buffer,
  693. &Size
  694. );
  695. if (rc == ERROR_SUCCESS) {
  696. if (!Buffer[0]) {
  697. TCHAR Node[MEMDB_MAX];
  698. wsprintf (
  699. Node,
  700. TEXT("%s\\%s\\[%s]"),
  701. S_HKR,
  702. S_DESKTOP_KEY,
  703. S_WALLPAPER
  704. );
  705. DEBUGMSG ((DBG_VERBOSE, "Logon wallpaper is (none), suppressing %s", Node));
  706. SuppressWin95Object (Node);
  707. wsprintf (
  708. Node,
  709. TEXT("%s\\%s\\[%s]"),
  710. S_HKR,
  711. S_DESKTOP_KEY,
  712. S_WALLPAPER_STYLE
  713. );
  714. SuppressWin95Object (Node);
  715. wsprintf (
  716. Node,
  717. TEXT("%s\\%s\\[%s]"),
  718. S_HKR,
  719. S_DESKTOP_KEY,
  720. S_TILE_WALLPAPER
  721. );
  722. SuppressWin95Object (Node);
  723. }
  724. ELSE_DEBUGMSG ((DBG_VERBOSE, "Logon wallpaper is '%s'", Buffer));
  725. }
  726. ELSE_DEBUGMSG ((DBG_VERBOSE, "Logon wallpaper not specified in desktop key"));
  727. CloseRegKey95 (Key);
  728. }
  729. ELSE_DEBUGMSG ((DBG_VERBOSE, "Logon wallpaper not specified"));
  730. }
  731. DWORD
  732. RunPerUserExternalProcesses (
  733. IN DWORD Request,
  734. IN PMIGRATE_USER_ENUM EnumPtr
  735. )
  736. {
  737. LONG Count;
  738. if (Request == REQUEST_QUERYTICKS) {
  739. //
  740. // Count the number of entries and multiply by a constant
  741. //
  742. Count = SetupGetLineCount (g_UserMigInf, S_EXTERNAL_PROCESSES);
  743. if (Count < 1) {
  744. return 0;
  745. }
  746. return Count * TICKS_USER_EXTERN_PROCESSES;
  747. }
  748. if (Request != REQUEST_RUN) {
  749. return ERROR_SUCCESS;
  750. }
  751. //
  752. // Loop through the processes and run each of them
  753. //
  754. RunExternalProcesses (g_UserMigInf, EnumPtr);
  755. return ERROR_SUCCESS;
  756. }
  757. VOID
  758. pCheckY2KCompliance (
  759. VOID
  760. )
  761. {
  762. HKEY Key95, KeyNT;
  763. LONG rc;
  764. TCHAR Buffer[100];
  765. DWORD Locale;
  766. int Result;
  767. PCTSTR ShortDate;
  768. //
  769. // read registry setting for sShortDate from Win9x registry
  770. //
  771. Key95 = OpenRegKey95 (g_hKeyRoot95, S_INTERNATIONAL_KEY);
  772. if (Key95) {
  773. ShortDate = GetRegValueString95 (Key95, S_SHORT_DATE_VALUE);
  774. if (!ShortDate) {
  775. //
  776. // set the new date format
  777. //
  778. GetGlobalCodePage (NULL, &Locale);
  779. Result = GetLocaleInfo (
  780. Locale,
  781. LOCALE_SSHORTDATE | LOCALE_NOUSEROVERRIDE,
  782. Buffer,
  783. sizeof (Buffer) / sizeof (TCHAR)
  784. );
  785. if (Result > 0) {
  786. KeyNT = OpenRegKey (g_hKeyRootNT, S_INTERNATIONAL_KEY);
  787. if (KeyNT) {
  788. rc = RegSetValueEx (
  789. KeyNT,
  790. S_SHORT_DATE_VALUE,
  791. 0,
  792. REG_SZ,
  793. (PCBYTE)Buffer,
  794. SizeOfString (Buffer)
  795. );
  796. LOG_IF ((rc != ERROR_SUCCESS, LOG_ERROR, "Could not set [sShortDate] default format"));
  797. CloseRegKey (KeyNT);
  798. }
  799. }
  800. ELSE_DEBUGMSG ((DBG_ERROR, "GetLocaleInfo returned 0 for LOCALE_SSHORTDATE | LOCALE_NOUSEROVERRIDE"));
  801. } else {
  802. DEBUGMSG ((
  803. DBG_VERBOSE,
  804. "HKR\\Control Panel\\International [sShortDate] already set to [%s] for user %s",
  805. ShortDate,
  806. g_FixedUserName
  807. ));
  808. MemFree (g_hHeap, 0, (PVOID)ShortDate);
  809. }
  810. CloseRegKey95 (Key95);
  811. }
  812. }
  813. DWORD
  814. RunPerUserUninstallUserProfileCleanupPreparation(
  815. IN DWORD Request,
  816. IN PMIGRATE_USER_ENUM EnumPtr
  817. )
  818. {
  819. LONG Count;
  820. if (Request == REQUEST_QUERYTICKS) {
  821. //
  822. // Count the number of entries and multiply by a constant
  823. //
  824. Count = SetupGetLineCount (g_UserMigInf, S_UNINSTALL_PROFILE_CLEAN_OUT);
  825. #ifdef PROGRESS_BAR
  826. DEBUGLOGTIME (("RunPerUserUninstallUserProfileCleanupPreparation: FileNumber=%ld", Count));
  827. #endif
  828. if (Count < 1) {
  829. return 0;
  830. }
  831. return Count * TICKS_USER_UNINSTALL_CLEANUP;
  832. }
  833. if (Request != REQUEST_RUN) {
  834. return ERROR_SUCCESS;
  835. }
  836. //
  837. // Loop through the files and mark them to be deleted during uninstall
  838. //
  839. UninstallUserProfileCleanupPreparation (g_UserMigInf, EnumPtr, FALSE);
  840. return ERROR_SUCCESS;
  841. }