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.

920 lines
20 KiB

  1. /*++
  2. Copyright (c) 1996, 1997 Microsoft Corporation
  3. Module Name:
  4. migrate.cpp
  5. Abstract:
  6. This module contains routines to support migration of protected storage
  7. data from beta1 to beta2.
  8. Hopefully this code will be pitched after beta2, prior to final release.
  9. Author:
  10. Scott Field (sfield) 15-Apr-97
  11. --*/
  12. #include <pch.cpp>
  13. #pragma hdrstop
  14. #include <lmcons.h>
  15. #include "provif.h"
  16. #include "storage.h"
  17. #include "secure.h"
  18. #include "secmisc.h"
  19. #include "passwd.h"
  20. #include "migrate.h"
  21. //#define MIGRATE_FLAG 1 // indicates whether beta1 -> beta2 migration done.
  22. #define MIGRATE_FLAG 2 // indicates whether beta2 -> RTW migration done.
  23. extern DISPIF_CALLBACKS g_sCallbacks;
  24. BOOL
  25. IsMigrationComplete(
  26. HKEY hKey
  27. );
  28. BOOL
  29. SetMigrationComplete(
  30. HKEY hKey
  31. );
  32. BOOL
  33. MigrateWin9xData(
  34. PST_PROVIDER_HANDLE *phPSTProv,
  35. HKEY hKeySource,
  36. HKEY hKeyDestination,
  37. LPWSTR szUserName9x,
  38. LPWSTR szUserNameNT // Windows NT username
  39. );
  40. BOOL
  41. MigrateWin9xDataRetry(
  42. PST_PROVIDER_HANDLE *phPSTProv,
  43. HKEY hKeyDestination,
  44. LPWSTR szUserName9x,
  45. LPWSTR szUserNameNT
  46. );
  47. BOOL
  48. SetRegistrySecurityEnumerated(
  49. HKEY hKey,
  50. PSECURITY_DESCRIPTOR pSD
  51. );
  52. BOOL
  53. SetRegistrySecuritySingle(
  54. HKEY hKey,
  55. PSECURITY_DESCRIPTOR pSD
  56. );
  57. BOOL
  58. MigrateData(
  59. PST_PROVIDER_HANDLE *phPSTProv,
  60. BOOL fMigrationNeeded
  61. )
  62. {
  63. LPWSTR szUser = NULL;
  64. HKEY hKeyUsers = NULL;
  65. HKEY hKeyUserKey = NULL;
  66. HKEY hKey = NULL;
  67. BYTE rgbPwd[A_SHA_DIGEST_LEN];
  68. LONG lRet;
  69. DWORD dwDisposition;
  70. BOOL bUpdateMigrationStatus = FALSE;
  71. BOOL bSuccess = FALSE;
  72. // get current user
  73. if (!g_sCallbacks.pfnFGetUser(
  74. phPSTProv,
  75. &szUser))
  76. goto cleanup;
  77. //
  78. // open up the registry key associated with the protected storage
  79. // note: this opens the old registry location.
  80. //
  81. // HKEY_USERS\<Name>
  82. if(!GetUserHKEY(
  83. szUser,
  84. KEY_QUERY_VALUE,
  85. &hKeyUsers
  86. )) {
  87. if(FIsWinNT())
  88. goto cleanup;
  89. //
  90. // Win95, profiles may be disabled, so go to
  91. // HKEY_LOCAL_MACHINE\xxx\szContainer
  92. // see secstor\prov\storage.cpp for details
  93. //
  94. hKeyUsers = HKEY_LOCAL_MACHINE;
  95. }
  96. // SOFTWARE\Microsoft\...
  97. // Here, CreateKeyEx is used, because win9x profiles may have been
  98. // disabled, which leads to a non-existent HKCU ProtectedStorageKey.
  99. //
  100. lRet = RegCreateKeyExU(
  101. hKeyUsers,
  102. REG_PSTTREE_LOC,
  103. 0,
  104. NULL,
  105. 0,
  106. KEY_QUERY_VALUE,
  107. NULL,
  108. &hKeyUserKey,
  109. &dwDisposition
  110. );
  111. //
  112. // close the intermediate key
  113. //
  114. RegCloseKey(hKeyUsers);
  115. if( lRet != ERROR_SUCCESS ) {
  116. goto cleanup;
  117. }
  118. // ...\<Name>
  119. lRet = RegOpenKeyExU(
  120. hKeyUserKey,
  121. szUser,
  122. 0,
  123. KEY_SET_VALUE | KEY_QUERY_VALUE |
  124. DELETE | KEY_ENUMERATE_SUB_KEYS, // for failed migration
  125. &hKey
  126. );
  127. if(FIsWinNT() && lRet != ERROR_SUCCESS) {
  128. WCHAR szUserName[ UNLEN + 1 ];
  129. WCHAR szUserName9x[ UNLEN + 1 ];
  130. DWORD cch;
  131. BOOL fRet;
  132. //
  133. // get win9x form of username.
  134. //
  135. if(!g_sCallbacks.pfnFImpersonateClient( phPSTProv ))
  136. goto tried_migration;
  137. cch = sizeof(szUserName) / sizeof( szUserName[0] );
  138. fRet = GetUserNameW(szUserName, &cch);
  139. g_sCallbacks.pfnFRevertToSelf( phPSTProv );
  140. if( !fRet )
  141. goto tried_migration;
  142. if(LCMapStringW(
  143. LOCALE_SYSTEM_DEFAULT,
  144. LCMAP_LOWERCASE,
  145. szUserName,
  146. cch,
  147. szUserName9x,
  148. cch) == 0)
  149. goto tried_migration;
  150. //
  151. // failed to open the key:
  152. // check if win9x migration is necessary.
  153. //
  154. if(!MigrateWin9xData( phPSTProv, hKeyUserKey, hKeyUserKey, szUserName9x, szUser )) {
  155. MigrateWin9xDataRetry( phPSTProv, hKeyUserKey, szUserName9x, szUser );
  156. }
  157. tried_migration:
  158. //
  159. // tried moving any win9x data, so proceed with any other
  160. // migration activities.
  161. //
  162. lRet = RegOpenKeyExU(
  163. hKeyUserKey,
  164. szUser,
  165. 0,
  166. KEY_SET_VALUE | KEY_QUERY_VALUE |
  167. DELETE | KEY_ENUMERATE_SUB_KEYS, // for failed migration
  168. &hKey
  169. );
  170. }
  171. RegCloseKey( hKeyUserKey );
  172. if( lRet != ERROR_SUCCESS ) {
  173. goto cleanup;
  174. }
  175. //
  176. // see if migration has already been done. If so, get out with SUCCESS.
  177. //
  178. if( IsMigrationComplete( hKey ) ) {
  179. bSuccess = TRUE;
  180. goto cleanup;
  181. }
  182. if(fMigrationNeeded) {
  183. //
  184. // do the migration
  185. //
  186. if(BPVerifyPwd(
  187. phPSTProv,
  188. szUser,
  189. WSZ_PASSWORD_WINDOWS,
  190. rgbPwd,
  191. BP_CONFIRM_NONE
  192. ) == PST_E_WRONG_PASSWORD) {
  193. //
  194. // if password could not be changed/verified correctly, nuke existing
  195. // data.
  196. //
  197. DeleteAllUserData( hKey );
  198. }
  199. }
  200. //
  201. // set the flag to update migration status, regardless of whether migration
  202. // succeeds. If it doesn't succeed the first time, it isn't likely to
  203. // ever succeed, so get on with life.
  204. //
  205. bUpdateMigrationStatus = TRUE;
  206. cleanup:
  207. if(bUpdateMigrationStatus && hKey) {
  208. SetMigrationComplete( hKey );
  209. }
  210. if(szUser != NULL)
  211. SSFree(szUser);
  212. if(hKey != NULL)
  213. RegCloseKey(hKey);
  214. return bSuccess;
  215. }
  216. BOOL
  217. IsMigrationComplete(
  218. HKEY hKey
  219. )
  220. /*++
  221. This function determines if migration has been performed for the user
  222. specified by the supplied hKey registry key.
  223. --*/
  224. {
  225. DWORD dwType;
  226. DWORD dwMigrationStatus;
  227. DWORD cbMigrationStatus = sizeof(dwMigrationStatus);
  228. LONG lRet;
  229. lRet = RegQueryValueExU(
  230. hKey,
  231. L"Migrate",
  232. NULL,
  233. &dwType,
  234. (LPBYTE)&dwMigrationStatus,
  235. &cbMigrationStatus
  236. );
  237. if(lRet != ERROR_SUCCESS)
  238. return FALSE;
  239. if(dwType == REG_DWORD && dwMigrationStatus >= MIGRATE_FLAG)
  240. return TRUE;
  241. return FALSE;
  242. }
  243. BOOL
  244. SetMigrationComplete(
  245. HKEY hKey
  246. )
  247. /*++
  248. This function sets the data migration flag associated with the user
  249. specified by the supplied hKey registry key.
  250. The flag is set to indicate that migration has been completed and no
  251. future processing is required for this user.
  252. --*/
  253. {
  254. DWORD dwMigrationStatus = MIGRATE_FLAG;
  255. DWORD cbMigrationStatus = sizeof(dwMigrationStatus);
  256. LONG lRet;
  257. lRet = RegSetValueExU(
  258. hKey,
  259. L"Migrate",
  260. 0,
  261. REG_DWORD,
  262. (LPBYTE)&dwMigrationStatus,
  263. cbMigrationStatus
  264. );
  265. if(lRet != ERROR_SUCCESS)
  266. return FALSE;
  267. return TRUE;
  268. }
  269. BOOL
  270. MigrateWin9xData(
  271. PST_PROVIDER_HANDLE *phPSTProv,
  272. HKEY hKeySource,
  273. HKEY hKeyDestination,
  274. LPWSTR szUserName9x,
  275. LPWSTR szUserNameNT // Windows NT username
  276. )
  277. {
  278. HKEY hKeyOldData = NULL;
  279. HKEY hKeyNewData = NULL;
  280. DWORD dwDisposition;
  281. WCHAR szTempPath[ MAX_PATH + 1 ];
  282. DWORD cchTempPath;
  283. DWORD cch;
  284. WCHAR szTempFile[ MAX_PATH + 1 ];
  285. BOOL fTempFile = FALSE;
  286. HANDLE hThreadToken = NULL;
  287. BOOL fRevertToSelf = FALSE;
  288. BYTE rgbOldPwd[ A_SHA_DIGEST_LEN ];
  289. BYTE rgbNewPwd[ A_SHA_DIGEST_LEN ];
  290. BYTE rgbSalt[PASSWORD_SALT_LEN];
  291. BYTE rgbConfirm[A_SHA_DIGEST_LEN];
  292. PBYTE pbMK = NULL;
  293. DWORD cbMK;
  294. BOOL fRemoveImported = FALSE;
  295. HKEY hKeyMasterKey = NULL;
  296. HKEY hKeyIntermediate = NULL;
  297. BOOL fProfilesDisabled = FALSE;
  298. PSID pLocalSystemSid = NULL;
  299. PACL pDacl = NULL;
  300. LONG lRet;
  301. BOOL fSuccess = FALSE;
  302. //
  303. // see if win9x data present.
  304. //
  305. lRet = RegOpenKeyExW(
  306. hKeySource,
  307. szUserName9x,
  308. 0,
  309. KEY_ALL_ACCESS,
  310. &hKeyOldData
  311. );
  312. if( lRet != ERROR_SUCCESS )
  313. return FALSE;
  314. //
  315. // attempt decrypt with computed win9x style pwd.
  316. //
  317. if( hKeySource != hKeyDestination && lstrcmpW(szUserName9x, L"*Default*") == 0) {
  318. //
  319. // win9x profiles were disabled, don't nuke old data either.
  320. //
  321. fProfilesDisabled = TRUE;
  322. if(!FMyGetWinPassword( phPSTProv, L"", rgbOldPwd ))
  323. goto cleanup;
  324. } else {
  325. if(!FMyGetWinPassword( phPSTProv, szUserName9x, rgbOldPwd ))
  326. goto cleanup;
  327. }
  328. lRet = RegOpenKeyExW(
  329. hKeyOldData,
  330. L"Data 2",
  331. 0,
  332. KEY_QUERY_VALUE,
  333. &hKeyIntermediate
  334. );
  335. if( lRet != ERROR_SUCCESS )
  336. goto cleanup;
  337. lRet = RegOpenKeyExW(
  338. hKeyIntermediate,
  339. WSZ_PASSWORD_WINDOWS,
  340. 0,
  341. KEY_QUERY_VALUE,
  342. &hKeyMasterKey
  343. );
  344. RegCloseKey( hKeyIntermediate );
  345. hKeyIntermediate = NULL;
  346. if( lRet != ERROR_SUCCESS )
  347. goto cleanup;
  348. // confirm is just get state and attempt MK decrypt
  349. if (!FBPGetSecurityStateFromHKEY(
  350. hKeyMasterKey,
  351. rgbSalt,
  352. sizeof(rgbSalt),
  353. rgbConfirm,
  354. sizeof(rgbConfirm),
  355. &pbMK,
  356. &cbMK
  357. ))
  358. {
  359. goto cleanup;
  360. }
  361. RegCloseKey( hKeyMasterKey );
  362. hKeyMasterKey = NULL;
  363. // found state; is pwd correct?
  364. if (!FMyDecryptMK(
  365. rgbSalt,
  366. sizeof(rgbSalt),
  367. rgbOldPwd,
  368. rgbConfirm,
  369. &pbMK,
  370. &cbMK
  371. ))
  372. {
  373. goto cleanup;
  374. }
  375. //
  376. // masterkey is now decrypted.
  377. //
  378. //
  379. // construct temporary file path to hold registry branch.
  380. //
  381. cchTempPath = sizeof(szTempPath) / sizeof( szTempPath[0] );
  382. cch = GetTempPathW(cchTempPath, szTempPath);
  383. if( cch == 0 || cch > cchTempPath )
  384. goto cleanup;
  385. if( GetTempFileNameW( szTempPath, L"PST", 0, szTempFile ) == 0 )
  386. goto cleanup;
  387. if(!DeleteFileW( szTempFile ))
  388. goto cleanup;
  389. //
  390. // impersonate self, so we can enable and use backup&restore privs
  391. // in a thread safe fashion.
  392. //
  393. if(!ImpersonateSelf( SecurityImpersonation ))
  394. goto cleanup;
  395. fRevertToSelf = TRUE;
  396. if(!OpenThreadToken(
  397. GetCurrentThread(),
  398. TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  399. FALSE,
  400. &hThreadToken
  401. )) {
  402. goto cleanup;
  403. }
  404. if(!SetPrivilege( hThreadToken, L"SeRestorePrivilege", TRUE ))
  405. goto cleanup;
  406. if(!SetPrivilege( hThreadToken, L"SeBackupPrivilege", TRUE ))
  407. goto cleanup;
  408. //
  409. // save registry branch as file.
  410. //
  411. lRet = RegSaveKeyW( hKeyOldData, szTempFile, NULL );
  412. if( lRet != ERROR_SUCCESS )
  413. goto cleanup;
  414. fTempFile = TRUE;
  415. //
  416. // import branch into new location.
  417. //
  418. lRet = RegCreateKeyExW(
  419. hKeyDestination,
  420. szUserNameNT,
  421. 0,
  422. NULL,
  423. 0,
  424. KEY_ALL_ACCESS,
  425. NULL,
  426. &hKeyNewData,
  427. &dwDisposition
  428. );
  429. if( lRet != ERROR_SUCCESS )
  430. goto cleanup;
  431. lRet = RegRestoreKeyW( hKeyNewData, szTempFile, 0 );
  432. if( lRet != ERROR_SUCCESS )
  433. goto cleanup;
  434. //
  435. // update acls on imported data, since none were present on win9x.
  436. // note that sebackup & serestore privileges enabled above, which
  437. // allows REG_OPTION_BACKUP_RESTORE to work.
  438. //
  439. while (TRUE) {
  440. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  441. SECURITY_DESCRIPTOR sd;
  442. DWORD dwAclSize;
  443. if(!AllocateAndInitializeSid(
  444. &sia,
  445. 1,
  446. SECURITY_LOCAL_SYSTEM_RID,
  447. 0, 0, 0, 0, 0, 0, 0,
  448. &pLocalSystemSid
  449. )) break;
  450. //
  451. // compute size of new acl
  452. //
  453. dwAclSize = sizeof(ACL) +
  454. 1 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +
  455. GetLengthSid(pLocalSystemSid) ;
  456. //
  457. // allocate storage for Acl
  458. //
  459. pDacl = (PACL)SSAlloc(dwAclSize);
  460. if(pDacl == NULL)
  461. break;
  462. if(!InitializeAcl(pDacl, dwAclSize, ACL_REVISION))
  463. break;
  464. if(!AddAccessAllowedAce(
  465. pDacl,
  466. ACL_REVISION,
  467. KEY_ALL_ACCESS,
  468. pLocalSystemSid
  469. )) break;
  470. if(!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
  471. break;
  472. if(!SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE))
  473. break;
  474. SetRegistrySecurityEnumerated(hKeyNewData, &sd);
  475. // add SYSTEM inherit Ace to base
  476. SetRegistrySecurity( hKeyNewData );
  477. break;
  478. }
  479. //
  480. // change existing password data.
  481. // assume worst case: we fail to change the state, in which case we
  482. // cleanup the restored registry key.
  483. //
  484. if(!FMyGetWinPassword( phPSTProv, szUserNameNT, rgbNewPwd ))
  485. goto cleanup;
  486. fRemoveImported = TRUE;
  487. if (!FMyEncryptMK(
  488. rgbSalt,
  489. sizeof(rgbSalt),
  490. rgbNewPwd,
  491. rgbConfirm,
  492. &pbMK,
  493. &cbMK))
  494. {
  495. goto cleanup;
  496. }
  497. if (!FBPSetSecurityState(
  498. szUserNameNT,
  499. WSZ_PASSWORD_WINDOWS,
  500. rgbSalt,
  501. PASSWORD_SALT_LEN,
  502. rgbConfirm,
  503. sizeof(rgbConfirm),
  504. pbMK,
  505. cbMK))
  506. {
  507. goto cleanup;
  508. }
  509. fRemoveImported = FALSE;
  510. //
  511. // everything went ok: nuke the old data.
  512. //
  513. // NTBUG 413234: do not delete old user data, because, user may not
  514. // have joined domain during Win9x upgrade. so allow data to migrate
  515. // again to domain user once joined.
  516. //
  517. #if 0
  518. if(!fProfilesDisabled && DeleteAllUserData( hKeyOldData )) {
  519. RegCloseKey( hKeyOldData );
  520. hKeyOldData = NULL;
  521. RegDeleteKeyW( hKeySource, szUserName9x );
  522. }
  523. #endif
  524. fSuccess = TRUE;
  525. cleanup:
  526. if( fTempFile ) {
  527. DeleteFileW( szTempFile );
  528. }
  529. if( fRevertToSelf )
  530. RevertToSelf();
  531. if( fRemoveImported ) {
  532. DeleteAllUserData( hKeyNewData );
  533. // but leave parent key alone, since it will contain an indicator
  534. // of a failed attempt, which prevents futile retries.
  535. }
  536. if( hThreadToken )
  537. CloseHandle( hThreadToken );
  538. if( hKeyOldData )
  539. RegCloseKey( hKeyOldData );
  540. if( hKeyNewData )
  541. RegCloseKey( hKeyNewData );
  542. if( hKeyMasterKey )
  543. RegCloseKey( hKeyMasterKey );
  544. if( hKeyIntermediate )
  545. RegCloseKey( hKeyIntermediate );
  546. if ( pbMK ) {
  547. RtlSecureZeroMemory( pbMK, cbMK );
  548. SSFree( pbMK );
  549. }
  550. if( pLocalSystemSid )
  551. FreeSid( pLocalSystemSid );
  552. if( pDacl )
  553. SSFree( pDacl );
  554. return fSuccess;
  555. }
  556. BOOL
  557. MigrateWin9xDataRetry(
  558. PST_PROVIDER_HANDLE *phPSTProv,
  559. HKEY hKeyDestination,
  560. LPWSTR szUserName9x,
  561. LPWSTR szUserNameNT
  562. )
  563. {
  564. HKEY hKeyBaseLM = NULL;
  565. BOOL fSuccess = FALSE;
  566. // HKLM\SOFTWARE\Microsoft\...
  567. if(RegOpenKeyExU(
  568. HKEY_LOCAL_MACHINE,
  569. REG_PSTTREE_LOC,
  570. 0,
  571. KEY_QUERY_VALUE,
  572. &hKeyBaseLM
  573. ) != ERROR_SUCCESS )
  574. {
  575. return FALSE;
  576. }
  577. //
  578. // try HKLM\Username
  579. // (profiles disabled on win9x)
  580. //
  581. fSuccess = MigrateWin9xData( phPSTProv, hKeyBaseLM, hKeyDestination, szUserName9x, szUserNameNT );
  582. if( !fSuccess ) {
  583. //
  584. // try HKLM\*Default*
  585. // (escape from logon)
  586. //
  587. fSuccess = MigrateWin9xData( phPSTProv, hKeyBaseLM, hKeyDestination, L"*Default*", szUserNameNT );
  588. }
  589. if( hKeyBaseLM )
  590. RegCloseKey( hKeyBaseLM );
  591. return fSuccess;
  592. }
  593. BOOL
  594. SetRegistrySecurityEnumerated(
  595. HKEY hKey,
  596. PSECURITY_DESCRIPTOR pSD
  597. )
  598. {
  599. LONG rc;
  600. WCHAR szSubKey[MAX_PATH];
  601. DWORD dwSubKeyLength;
  602. DWORD dwSubKeyIndex;
  603. DWORD dwDisposition;
  604. dwSubKeyIndex = 0;
  605. dwSubKeyLength = MAX_PATH;
  606. //
  607. // update security on specified key
  608. //
  609. if(!SetRegistrySecuritySingle(hKey, pSD))
  610. return FALSE;
  611. while((rc=RegEnumKeyExU(
  612. hKey,
  613. dwSubKeyIndex,
  614. szSubKey,
  615. &dwSubKeyLength,
  616. NULL,
  617. NULL,
  618. NULL,
  619. NULL)
  620. ) != ERROR_NO_MORE_ITEMS) { // are we done?
  621. if(rc == ERROR_SUCCESS)
  622. {
  623. HKEY hSubKey;
  624. LONG lRet;
  625. lRet = RegCreateKeyExU(
  626. hKey,
  627. szSubKey,
  628. 0,
  629. NULL,
  630. REG_OPTION_BACKUP_RESTORE, // in winnt.h
  631. KEY_ENUMERATE_SUB_KEYS | WRITE_DAC,
  632. NULL,
  633. &hSubKey,
  634. &dwDisposition
  635. );
  636. if(lRet != ERROR_SUCCESS)
  637. return FALSE;
  638. //
  639. // recurse
  640. //
  641. SetRegistrySecurityEnumerated(hSubKey, pSD);
  642. RegCloseKey(hSubKey);
  643. // increment index into the key
  644. dwSubKeyIndex++;
  645. // reset buffer size
  646. dwSubKeyLength=MAX_PATH;
  647. // Continue the festivities
  648. continue;
  649. }
  650. else
  651. {
  652. //
  653. // note: we need to watch for ERROR_MORE_DATA
  654. // this indicates we need a bigger szSubKey buffer
  655. //
  656. return FALSE;
  657. }
  658. } // while
  659. return TRUE;
  660. }
  661. BOOL
  662. SetRegistrySecuritySingle(
  663. HKEY hKey,
  664. PSECURITY_DESCRIPTOR pSD
  665. )
  666. {
  667. LONG lRetCode;
  668. //
  669. // apply the security descriptor to the registry key
  670. //
  671. lRetCode = RegSetKeySecurity(
  672. hKey,
  673. (SECURITY_INFORMATION)DACL_SECURITY_INFORMATION,
  674. pSD
  675. );
  676. if(lRetCode != ERROR_SUCCESS)
  677. return FALSE;
  678. return TRUE;
  679. }