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
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;
|
|
}
|
|
|