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

/*++
Copyright (c) 1996, 1997 Microsoft Corporation
Module Name:
migrate.cpp
Abstract:
This module contains routines to support migration of protected storage
data from beta1 to beta2.
Hopefully this code will be pitched after beta2, prior to final release.
Author:
Scott Field (sfield) 15-Apr-97
--*/
#include <pch.cpp>
#pragma hdrstop
#include <lmcons.h>
#include "provif.h"
#include "storage.h"
#include "secure.h"
#include "secmisc.h"
#include "passwd.h"
#include "migrate.h"
//#define MIGRATE_FLAG 1 // indicates whether beta1 -> beta2 migration done.
#define MIGRATE_FLAG 2 // indicates whether beta2 -> RTW migration done.
extern DISPIF_CALLBACKS g_sCallbacks;
BOOL
IsMigrationComplete(
HKEY hKey
);
BOOL
SetMigrationComplete(
HKEY hKey
);
BOOL
MigrateWin9xData(
PST_PROVIDER_HANDLE *phPSTProv,
HKEY hKeySource,
HKEY hKeyDestination,
LPWSTR szUserName9x,
LPWSTR szUserNameNT // Windows NT username
);
BOOL
MigrateWin9xDataRetry(
PST_PROVIDER_HANDLE *phPSTProv,
HKEY hKeyDestination,
LPWSTR szUserName9x,
LPWSTR szUserNameNT
);
BOOL
SetRegistrySecurityEnumerated(
HKEY hKey,
PSECURITY_DESCRIPTOR pSD
);
BOOL
SetRegistrySecuritySingle(
HKEY hKey,
PSECURITY_DESCRIPTOR pSD
);
BOOL
MigrateData(
PST_PROVIDER_HANDLE *phPSTProv,
BOOL fMigrationNeeded
)
{
LPWSTR szUser = NULL;
HKEY hKeyUsers = NULL;
HKEY hKeyUserKey = NULL;
HKEY hKey = NULL;
BYTE rgbPwd[A_SHA_DIGEST_LEN];
LONG lRet;
DWORD dwDisposition;
BOOL bUpdateMigrationStatus = FALSE;
BOOL bSuccess = FALSE;
// get current user
if (!g_sCallbacks.pfnFGetUser(
phPSTProv,
&szUser))
goto cleanup;
//
// open up the registry key associated with the protected storage
// note: this opens the old registry location.
//
// HKEY_USERS\<Name>
if(!GetUserHKEY(
szUser,
KEY_QUERY_VALUE,
&hKeyUsers
)) {
if(FIsWinNT())
goto cleanup;
//
// Win95, profiles may be disabled, so go to
// HKEY_LOCAL_MACHINE\xxx\szContainer
// see secstor\prov\storage.cpp for details
//
hKeyUsers = HKEY_LOCAL_MACHINE;
}
// SOFTWARE\Microsoft\...
// Here, CreateKeyEx is used, because win9x profiles may have been
// disabled, which leads to a non-existent HKCU ProtectedStorageKey.
//
lRet = RegCreateKeyExU(
hKeyUsers,
REG_PSTTREE_LOC,
0,
NULL,
0,
KEY_QUERY_VALUE,
NULL,
&hKeyUserKey,
&dwDisposition
);
//
// close the intermediate key
//
RegCloseKey(hKeyUsers);
if( lRet != ERROR_SUCCESS ) {
goto cleanup;
}
// ...\<Name>
lRet = RegOpenKeyExU(
hKeyUserKey,
szUser,
0,
KEY_SET_VALUE | KEY_QUERY_VALUE |
DELETE | KEY_ENUMERATE_SUB_KEYS, // for failed migration
&hKey
);
if(FIsWinNT() && lRet != ERROR_SUCCESS) {
WCHAR szUserName[ UNLEN + 1 ];
WCHAR szUserName9x[ UNLEN + 1 ];
DWORD cch;
BOOL fRet;
//
// get win9x form of username.
//
if(!g_sCallbacks.pfnFImpersonateClient( phPSTProv ))
goto tried_migration;
cch = sizeof(szUserName) / sizeof( szUserName[0] );
fRet = GetUserNameW(szUserName, &cch);
g_sCallbacks.pfnFRevertToSelf( phPSTProv );
if( !fRet )
goto tried_migration;
if(LCMapStringW(
LOCALE_SYSTEM_DEFAULT,
LCMAP_LOWERCASE,
szUserName,
cch,
szUserName9x,
cch) == 0)
goto tried_migration;
//
// failed to open the key:
// check if win9x migration is necessary.
//
if(!MigrateWin9xData( phPSTProv, hKeyUserKey, hKeyUserKey, szUserName9x, szUser )) {
MigrateWin9xDataRetry( phPSTProv, hKeyUserKey, szUserName9x, szUser );
}
tried_migration:
//
// tried moving any win9x data, so proceed with any other
// migration activities.
//
lRet = RegOpenKeyExU(
hKeyUserKey,
szUser,
0,
KEY_SET_VALUE | KEY_QUERY_VALUE |
DELETE | KEY_ENUMERATE_SUB_KEYS, // for failed migration
&hKey
);
}
RegCloseKey( hKeyUserKey );
if( lRet != ERROR_SUCCESS ) {
goto cleanup;
}
//
// see if migration has already been done. If so, get out with SUCCESS.
//
if( IsMigrationComplete( hKey ) ) {
bSuccess = TRUE;
goto cleanup;
}
if(fMigrationNeeded) {
//
// do the migration
//
if(BPVerifyPwd(
phPSTProv,
szUser,
WSZ_PASSWORD_WINDOWS,
rgbPwd,
BP_CONFIRM_NONE
) == PST_E_WRONG_PASSWORD) {
//
// if password could not be changed/verified correctly, nuke existing
// data.
//
DeleteAllUserData( hKey );
}
}
//
// set the flag to update migration status, regardless of whether migration
// succeeds. If it doesn't succeed the first time, it isn't likely to
// ever succeed, so get on with life.
//
bUpdateMigrationStatus = TRUE;
cleanup:
if(bUpdateMigrationStatus && hKey) {
SetMigrationComplete( hKey );
}
if(szUser != NULL)
SSFree(szUser);
if(hKey != NULL)
RegCloseKey(hKey);
return bSuccess;
}
BOOL
IsMigrationComplete(
HKEY hKey
)
/*++
This function determines if migration has been performed for the user
specified by the supplied hKey registry key.
--*/
{
DWORD dwType;
DWORD dwMigrationStatus;
DWORD cbMigrationStatus = sizeof(dwMigrationStatus);
LONG lRet;
lRet = RegQueryValueExU(
hKey,
L"Migrate",
NULL,
&dwType,
(LPBYTE)&dwMigrationStatus,
&cbMigrationStatus
);
if(lRet != ERROR_SUCCESS)
return FALSE;
if(dwType == REG_DWORD && dwMigrationStatus >= MIGRATE_FLAG)
return TRUE;
return FALSE;
}
BOOL
SetMigrationComplete(
HKEY hKey
)
/*++
This function sets the data migration flag associated with the user
specified by the supplied hKey registry key.
The flag is set to indicate that migration has been completed and no
future processing is required for this user.
--*/
{
DWORD dwMigrationStatus = MIGRATE_FLAG;
DWORD cbMigrationStatus = sizeof(dwMigrationStatus);
LONG lRet;
lRet = RegSetValueExU(
hKey,
L"Migrate",
0,
REG_DWORD,
(LPBYTE)&dwMigrationStatus,
cbMigrationStatus
);
if(lRet != ERROR_SUCCESS)
return FALSE;
return TRUE;
}
BOOL
MigrateWin9xData(
PST_PROVIDER_HANDLE *phPSTProv,
HKEY hKeySource,
HKEY hKeyDestination,
LPWSTR szUserName9x,
LPWSTR szUserNameNT // Windows NT username
)
{
HKEY hKeyOldData = NULL;
HKEY hKeyNewData = NULL;
DWORD dwDisposition;
WCHAR szTempPath[ MAX_PATH + 1 ];
DWORD cchTempPath;
DWORD cch;
WCHAR szTempFile[ MAX_PATH + 1 ];
BOOL fTempFile = FALSE;
HANDLE hThreadToken = NULL;
BOOL fRevertToSelf = FALSE;
BYTE rgbOldPwd[ A_SHA_DIGEST_LEN ];
BYTE rgbNewPwd[ A_SHA_DIGEST_LEN ];
BYTE rgbSalt[PASSWORD_SALT_LEN];
BYTE rgbConfirm[A_SHA_DIGEST_LEN];
PBYTE pbMK = NULL;
DWORD cbMK;
BOOL fRemoveImported = FALSE;
HKEY hKeyMasterKey = NULL;
HKEY hKeyIntermediate = NULL;
BOOL fProfilesDisabled = FALSE;
PSID pLocalSystemSid = NULL;
PACL pDacl = NULL;
LONG lRet;
BOOL fSuccess = FALSE;
//
// see if win9x data present.
//
lRet = RegOpenKeyExW(
hKeySource,
szUserName9x,
0,
KEY_ALL_ACCESS,
&hKeyOldData
);
if( lRet != ERROR_SUCCESS )
return FALSE;
//
// attempt decrypt with computed win9x style pwd.
//
if( hKeySource != hKeyDestination && lstrcmpW(szUserName9x, L"*Default*") == 0) {
//
// win9x profiles were disabled, don't nuke old data either.
//
fProfilesDisabled = TRUE;
if(!FMyGetWinPassword( phPSTProv, L"", rgbOldPwd ))
goto cleanup;
} else {
if(!FMyGetWinPassword( phPSTProv, szUserName9x, rgbOldPwd ))
goto cleanup;
}
lRet = RegOpenKeyExW(
hKeyOldData,
L"Data 2",
0,
KEY_QUERY_VALUE,
&hKeyIntermediate
);
if( lRet != ERROR_SUCCESS )
goto cleanup;
lRet = RegOpenKeyExW(
hKeyIntermediate,
WSZ_PASSWORD_WINDOWS,
0,
KEY_QUERY_VALUE,
&hKeyMasterKey
);
RegCloseKey( hKeyIntermediate );
hKeyIntermediate = NULL;
if( lRet != ERROR_SUCCESS )
goto cleanup;
// confirm is just get state and attempt MK decrypt
if (!FBPGetSecurityStateFromHKEY(
hKeyMasterKey,
rgbSalt,
sizeof(rgbSalt),
rgbConfirm,
sizeof(rgbConfirm),
&pbMK,
&cbMK
))
{
goto cleanup;
}
RegCloseKey( hKeyMasterKey );
hKeyMasterKey = NULL;
// found state; is pwd correct?
if (!FMyDecryptMK(
rgbSalt,
sizeof(rgbSalt),
rgbOldPwd,
rgbConfirm,
&pbMK,
&cbMK
))
{
goto cleanup;
}
//
// masterkey is now decrypted.
//
//
// construct temporary file path to hold registry branch.
//
cchTempPath = sizeof(szTempPath) / sizeof( szTempPath[0] );
cch = GetTempPathW(cchTempPath, szTempPath);
if( cch == 0 || cch > cchTempPath )
goto cleanup;
if( GetTempFileNameW( szTempPath, L"PST", 0, szTempFile ) == 0 )
goto cleanup;
if(!DeleteFileW( szTempFile ))
goto cleanup;
//
// impersonate self, so we can enable and use backup&restore privs
// in a thread safe fashion.
//
if(!ImpersonateSelf( SecurityImpersonation ))
goto cleanup;
fRevertToSelf = TRUE;
if(!OpenThreadToken(
GetCurrentThread(),
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
FALSE,
&hThreadToken
)) {
goto cleanup;
}
if(!SetPrivilege( hThreadToken, L"SeRestorePrivilege", TRUE ))
goto cleanup;
if(!SetPrivilege( hThreadToken, L"SeBackupPrivilege", TRUE ))
goto cleanup;
//
// save registry branch as file.
//
lRet = RegSaveKeyW( hKeyOldData, szTempFile, NULL );
if( lRet != ERROR_SUCCESS )
goto cleanup;
fTempFile = TRUE;
//
// import branch into new location.
//
lRet = RegCreateKeyExW(
hKeyDestination,
szUserNameNT,
0,
NULL,
0,
KEY_ALL_ACCESS,
NULL,
&hKeyNewData,
&dwDisposition
);
if( lRet != ERROR_SUCCESS )
goto cleanup;
lRet = RegRestoreKeyW( hKeyNewData, szTempFile, 0 );
if( lRet != ERROR_SUCCESS )
goto cleanup;
//
// update acls on imported data, since none were present on win9x.
// note that sebackup & serestore privileges enabled above, which
// allows REG_OPTION_BACKUP_RESTORE to work.
//
while (TRUE) {
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
SECURITY_DESCRIPTOR sd;
DWORD dwAclSize;
if(!AllocateAndInitializeSid(
&sia,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&pLocalSystemSid
)) break;
//
// compute size of new acl
//
dwAclSize = sizeof(ACL) +
1 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +
GetLengthSid(pLocalSystemSid) ;
//
// allocate storage for Acl
//
pDacl = (PACL)SSAlloc(dwAclSize);
if(pDacl == NULL)
break;
if(!InitializeAcl(pDacl, dwAclSize, ACL_REVISION))
break;
if(!AddAccessAllowedAce(
pDacl,
ACL_REVISION,
KEY_ALL_ACCESS,
pLocalSystemSid
)) break;
if(!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
break;
if(!SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE))
break;
SetRegistrySecurityEnumerated(hKeyNewData, &sd);
// add SYSTEM inherit Ace to base
SetRegistrySecurity( hKeyNewData );
break;
}
//
// change existing password data.
// assume worst case: we fail to change the state, in which case we
// cleanup the restored registry key.
//
if(!FMyGetWinPassword( phPSTProv, szUserNameNT, rgbNewPwd ))
goto cleanup;
fRemoveImported = TRUE;
if (!FMyEncryptMK(
rgbSalt,
sizeof(rgbSalt),
rgbNewPwd,
rgbConfirm,
&pbMK,
&cbMK))
{
goto cleanup;
}
if (!FBPSetSecurityState(
szUserNameNT,
WSZ_PASSWORD_WINDOWS,
rgbSalt,
PASSWORD_SALT_LEN,
rgbConfirm,
sizeof(rgbConfirm),
pbMK,
cbMK))
{
goto cleanup;
}
fRemoveImported = FALSE;
//
// everything went ok: nuke the old data.
//
// NTBUG 413234: do not delete old user data, because, user may not
// have joined domain during Win9x upgrade. so allow data to migrate
// again to domain user once joined.
//
#if 0
if(!fProfilesDisabled && DeleteAllUserData( hKeyOldData )) {
RegCloseKey( hKeyOldData );
hKeyOldData = NULL;
RegDeleteKeyW( hKeySource, szUserName9x );
}
#endif
fSuccess = TRUE;
cleanup:
if( fTempFile ) {
DeleteFileW( szTempFile );
}
if( fRevertToSelf )
RevertToSelf();
if( fRemoveImported ) {
DeleteAllUserData( hKeyNewData );
// but leave parent key alone, since it will contain an indicator
// of a failed attempt, which prevents futile retries.
}
if( hThreadToken )
CloseHandle( hThreadToken );
if( hKeyOldData )
RegCloseKey( hKeyOldData );
if( hKeyNewData )
RegCloseKey( hKeyNewData );
if( hKeyMasterKey )
RegCloseKey( hKeyMasterKey );
if( hKeyIntermediate )
RegCloseKey( hKeyIntermediate );
if ( pbMK ) {
RtlSecureZeroMemory( pbMK, cbMK );
SSFree( pbMK );
}
if( pLocalSystemSid )
FreeSid( pLocalSystemSid );
if( pDacl )
SSFree( pDacl );
return fSuccess;
}
BOOL
MigrateWin9xDataRetry(
PST_PROVIDER_HANDLE *phPSTProv,
HKEY hKeyDestination,
LPWSTR szUserName9x,
LPWSTR szUserNameNT
)
{
HKEY hKeyBaseLM = NULL;
BOOL fSuccess = FALSE;
// HKLM\SOFTWARE\Microsoft\...
if(RegOpenKeyExU(
HKEY_LOCAL_MACHINE,
REG_PSTTREE_LOC,
0,
KEY_QUERY_VALUE,
&hKeyBaseLM
) != ERROR_SUCCESS )
{
return FALSE;
}
//
// try HKLM\Username
// (profiles disabled on win9x)
//
fSuccess = MigrateWin9xData( phPSTProv, hKeyBaseLM, hKeyDestination, szUserName9x, szUserNameNT );
if( !fSuccess ) {
//
// try HKLM\*Default*
// (escape from logon)
//
fSuccess = MigrateWin9xData( phPSTProv, hKeyBaseLM, hKeyDestination, L"*Default*", szUserNameNT );
}
if( hKeyBaseLM )
RegCloseKey( hKeyBaseLM );
return fSuccess;
}
BOOL
SetRegistrySecurityEnumerated(
HKEY hKey,
PSECURITY_DESCRIPTOR pSD
)
{
LONG rc;
WCHAR szSubKey[MAX_PATH];
DWORD dwSubKeyLength;
DWORD dwSubKeyIndex;
DWORD dwDisposition;
dwSubKeyIndex = 0;
dwSubKeyLength = MAX_PATH;
//
// update security on specified key
//
if(!SetRegistrySecuritySingle(hKey, pSD))
return FALSE;
while((rc=RegEnumKeyExU(
hKey,
dwSubKeyIndex,
szSubKey,
&dwSubKeyLength,
NULL,
NULL,
NULL,
NULL)
) != ERROR_NO_MORE_ITEMS) { // are we done?
if(rc == ERROR_SUCCESS)
{
HKEY hSubKey;
LONG lRet;
lRet = RegCreateKeyExU(
hKey,
szSubKey,
0,
NULL,
REG_OPTION_BACKUP_RESTORE, // in winnt.h
KEY_ENUMERATE_SUB_KEYS | WRITE_DAC,
NULL,
&hSubKey,
&dwDisposition
);
if(lRet != ERROR_SUCCESS)
return FALSE;
//
// recurse
//
SetRegistrySecurityEnumerated(hSubKey, pSD);
RegCloseKey(hSubKey);
// increment index into the key
dwSubKeyIndex++;
// reset buffer size
dwSubKeyLength=MAX_PATH;
// Continue the festivities
continue;
}
else
{
//
// note: we need to watch for ERROR_MORE_DATA
// this indicates we need a bigger szSubKey buffer
//
return FALSE;
}
} // while
return TRUE;
}
BOOL
SetRegistrySecuritySingle(
HKEY hKey,
PSECURITY_DESCRIPTOR pSD
)
{
LONG lRetCode;
//
// apply the security descriptor to the registry key
//
lRetCode = RegSetKeySecurity(
hKey,
(SECURITY_INFORMATION)DACL_SECURITY_INFORMATION,
pSD
);
if(lRetCode != ERROR_SUCCESS)
return FALSE;
return TRUE;
}