3547 lines
101 KiB
C++
3547 lines
101 KiB
C++
/******************************************************************************
|
|
*
|
|
* Copyright (c) 2000 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
* snapshot.cpp
|
|
*
|
|
* Abstract:
|
|
* CSnapshot, CSnapshot class functions
|
|
*
|
|
* Revision History:
|
|
* Ashish Sikka (ashishs) 05/05/2000
|
|
* created
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "snapshoth.h"
|
|
#include "srrpcapi.h"
|
|
#include "srapi.h"
|
|
#include "..\datastor\datastormgr.h"
|
|
#include "..\service\evthandler.h"
|
|
|
|
|
|
#ifdef THIS_FILE
|
|
#undef THIS_FILE
|
|
#endif
|
|
static char __szTraceSourceFile[] = __FILE__;
|
|
#define THIS_FILE __szTraceSourceFile
|
|
|
|
|
|
static LPCWSTR s_cszCOMDBBackupFile = L"ComDb.Dat";
|
|
static LPCWSTR s_cszWMIBackupFile = L"Repository";
|
|
static LPCWSTR s_cszIISBackupFile = L"IISDB";
|
|
static LPCWSTR s_cszIISSuffix = L".MD";
|
|
static LPCWSTR s_cszIISBackupPath = L"%windir%\\system32\\inetsrv\\metaback\\";
|
|
static LPCWSTR s_cszIISOriginalPath = L"%windir%\\system32\\inetsrv\\metabase.bin";
|
|
static LPCWSTR s_cszSnapshotUsrClassLocation = L"Local Settings\\Application Data\\Microsoft\\Windows\\UsrClass.dat";
|
|
static LPCWSTR s_cszSnapshotUsrClass = L"USRCLASS_";
|
|
static LPCWSTR s_cszSnapshotNtUser = L"NTUSER_";
|
|
static LPCWSTR s_cszClassesKey = L"_Classes";
|
|
static LPCWSTR s_cszSnapshotUsersDefaultKey = L".DEFAULT";
|
|
static LPCWSTR s_cszSnapshotHiveList = L"System\\CurrentControlSet\\Control\\Hivelist";
|
|
static LPCWSTR s_cszRestoreTempKey = L"Restore122312";
|
|
static LPCWSTR s_cszHKLMPrefix = L"\\Registry\\Machine\\";
|
|
static LPCSTR s_cszRegDBBackupFn = "RegDBBackup";
|
|
static LPCSTR s_cszRegDBRestoreFn = "RegDBRestore";
|
|
|
|
#define VALIDATE_DWRET(str) \
|
|
if ( dwRet != ERROR_SUCCESS ) \
|
|
{ \
|
|
ErrorTrace(0, str " failed ec=%d", dwRet); \
|
|
goto Exit; \
|
|
} \
|
|
|
|
#define LOAD_KEY_NAME TEXT("BackupExecReg")
|
|
|
|
|
|
DWORD SnapshotCopyFile(WCHAR * pszSrc,
|
|
WCHAR * pszDest);
|
|
|
|
struct WMISnapshotParam
|
|
{
|
|
HANDLE hEvent;
|
|
CRestorePoint *pRpLast;
|
|
BOOL fSerialized;
|
|
WCHAR szSnapshotDir[MAX_PATH];
|
|
};
|
|
|
|
DWORD WINAPI DoWMISnapshot(VOID * pParam);
|
|
|
|
DWORD DoIISSnapshot(WCHAR * pszSnapshotDir);
|
|
|
|
DWORD SnapshotRestoreFilelistFiles(WCHAR * pszSnapshotDir, BOOL fSnapshot);
|
|
|
|
DWORD CallSnapshotCallbacks(LPCWSTR pszEnumKey, LPCWSTR pszSnapshotDir, BOOL fSnapshot);
|
|
|
|
CSnapshot::CSnapshot()
|
|
{
|
|
TraceFunctEnter("CSnapshot::CSnapshot");
|
|
|
|
m_hRegdbDll = NULL;
|
|
m_pfnRegDbBackup = NULL;
|
|
m_pfnRegDbRestore = NULL;
|
|
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
CSnapshot::~CSnapshot()
|
|
{
|
|
TraceFunctEnter("CSnapshot::~CSnapshot");
|
|
m_pfnRegDbBackup = NULL;
|
|
m_pfnRegDbRestore = NULL;
|
|
if (NULL != m_hRegdbDll)
|
|
{
|
|
_VERIFY(TRUE==FreeLibrary(m_hRegdbDll));
|
|
}
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
DWORD
|
|
CSnapshot::DeleteSnapshot(WCHAR * pszRestoreDir)
|
|
{
|
|
TraceFunctEnter("CSnapshot::DeleteSnapshot");
|
|
|
|
WCHAR szSnapshotDir[MAX_PATH];
|
|
BOOL fStop=FALSE;
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
|
|
|
|
// create the snapshot directory name from the restore directory
|
|
// name and create the actual directory.
|
|
lstrcpy(szSnapshotDir, pszRestoreDir);
|
|
lstrcat(szSnapshotDir, SNAPSHOT_DIR_NAME);
|
|
|
|
|
|
dwErr = Delnode_Recurse(szSnapshotDir,
|
|
TRUE, // Delete the ROOT dir
|
|
&fStop);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
ErrorTrace(0, "Fatal error %ld deleting snapshot directory",dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
// the following function checks to see if the file passed in is a
|
|
// temporary copy of a reghive created before the restore.
|
|
// It does this by checking if the file suffix is s_cszRegHiveCopySuffix
|
|
BOOL IsRestoreCopy(const WCHAR * pszFileName)
|
|
{
|
|
BOOL fReturn=FALSE;
|
|
DWORD dwLength, dwSuffixLen;
|
|
|
|
// Find
|
|
dwLength = lstrlen(pszFileName);
|
|
dwSuffixLen = lstrlen(s_cszRegHiveCopySuffix);
|
|
if (dwSuffixLen > dwLength)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
dwLength -= dwSuffixLen;
|
|
|
|
// If the file is indeed a restore copy, dwLength points to the
|
|
// first character of s_cszRegHiveCopySuffix
|
|
if (0==lstrcmpi(pszFileName+dwLength, s_cszRegHiveCopySuffix))
|
|
{
|
|
fReturn = TRUE;
|
|
}
|
|
|
|
cleanup:
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
DWORD
|
|
ProcessPendingRenames(LPWSTR pszSnapshotDir)
|
|
{
|
|
TraceFunctEnter("ProcessPendingRenames");
|
|
|
|
WCHAR szDest[MAX_PATH];
|
|
DWORD dwRc;
|
|
HKEY hKey = NULL;
|
|
|
|
dwRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
s_cszSessionManagerRegKey,
|
|
0,
|
|
KEY_READ,
|
|
&hKey);
|
|
if (ERROR_SUCCESS == dwRc)
|
|
{
|
|
DWORD dwType = REG_MULTI_SZ;
|
|
DWORD dwSize = 0;
|
|
|
|
dwRc = RegQueryValueEx(hKey, s_cszMoveFileExRegValue, 0, &dwType, NULL, &dwSize);
|
|
if (dwRc == ERROR_SUCCESS && dwSize > 0)
|
|
{
|
|
WCHAR * pwcBuffer = new WCHAR [dwSize / 2];
|
|
|
|
if (pwcBuffer == NULL)
|
|
{
|
|
trace(0, "Error allocating pwcBuffer");
|
|
dwRc = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto done;
|
|
}
|
|
|
|
dwRc = RegQueryValueEx(hKey, s_cszMoveFileExRegValue,
|
|
NULL, &dwType, (BYTE *) pwcBuffer, &dwSize);
|
|
|
|
if (ERROR_SUCCESS == dwRc && REG_MULTI_SZ == dwType)
|
|
{
|
|
int iFirst = 0;
|
|
int iSecond = 0;
|
|
int iFile = 1;
|
|
|
|
while ((iFirst < (int) dwSize/2) && pwcBuffer[iFirst] != L'\0')
|
|
{
|
|
iSecond = iFirst + lstrlenW(&pwcBuffer[iFirst]) + 1;
|
|
DebugTrace(0, "Src : %S, Dest : %S", &pwcBuffer[iFirst], &pwcBuffer[iSecond]);
|
|
|
|
if (pwcBuffer[iSecond] != L'\0')
|
|
{
|
|
// snapshot the source file to a file MFEX-i.DAT in the snapshot dir
|
|
|
|
wsprintf(szDest, L"%s\\MFEX-%d.DAT", pszSnapshotDir, iFile++);
|
|
|
|
SRCopyFile(&pwcBuffer[iFirst+4], szDest);
|
|
}
|
|
iFirst = iSecond + lstrlenW(&pwcBuffer[iSecond]) + 1;
|
|
}
|
|
}
|
|
delete [] pwcBuffer;
|
|
}
|
|
else
|
|
{
|
|
dwRc = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
trace(0, "! RegOpenKeyEx on %S : %ld", s_cszSessionManagerRegKey, dwRc);
|
|
}
|
|
|
|
done:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
TraceFunctLeave();
|
|
return dwRc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CSnapshot::CreateSnapshot(WCHAR * pszRestoreDir, HMODULE hCOMDll, LPWSTR pszRpLast, BOOL fSerialized)
|
|
{
|
|
TraceFunctEnter("CSnapshot::CreateSnapshot");
|
|
|
|
HANDLE hThread = NULL;
|
|
HANDLE hEvent = NULL;
|
|
WMISnapshotParam * pwsp = NULL;
|
|
WCHAR pszSnapShotDir[MAX_PATH];
|
|
DWORD dwErr, dwAttrs;
|
|
DWORD dwReturn = ERROR_INTERNAL_ERROR;
|
|
BOOL fCoInitialized = FALSE;
|
|
BOOL fWMISnapshotParamCleanup = TRUE;
|
|
HRESULT hr;
|
|
CTokenPrivilege tp;
|
|
|
|
// create the snapshot directory name from the restore directory
|
|
// name and create the actual directory.
|
|
lstrcpy(pszSnapShotDir, pszRestoreDir);
|
|
lstrcat(pszSnapShotDir, SNAPSHOT_DIR_NAME);
|
|
if (FALSE == CreateDirectory( pszSnapShotDir, // directory name
|
|
NULL)) // SD
|
|
{
|
|
dwErr = GetLastError();
|
|
if (ERROR_ALREADY_EXISTS != dwErr)
|
|
{
|
|
ErrorTrace(0, "Fatal error %ld creating snapshot directory",dwErr);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
// set the directory to be uncompressed by default
|
|
dwAttrs = GetFileAttributesW (pszSnapShotDir);
|
|
if ( (dwAttrs != INVALID_FILE_SIZE) &&
|
|
(0 != (FILE_ATTRIBUTE_COMPRESSED & dwAttrs)) )
|
|
{
|
|
dwErr = CompressFile ( pszSnapShotDir,
|
|
FALSE, // uncompress
|
|
TRUE ); // target is a directory
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
ErrorTrace(0, "! CreateDataStore CompressFile : %ld", dwErr);
|
|
// this is not a fatal error
|
|
}
|
|
}
|
|
|
|
pwsp = new WMISnapshotParam;
|
|
if (NULL == pwsp)
|
|
{
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
ErrorTrace(0, "cannot allocate CWMISnapshotParam");
|
|
goto cleanup;
|
|
}
|
|
|
|
if (pszRpLast)
|
|
{
|
|
pwsp->pRpLast = new CRestorePoint;
|
|
if (NULL == pwsp->pRpLast)
|
|
{
|
|
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
|
|
ErrorTrace(0, "cannot allocate CRestorePoint");
|
|
goto cleanup;
|
|
}
|
|
pwsp->pRpLast->SetDir(pszRpLast);
|
|
}
|
|
else
|
|
{
|
|
pwsp->pRpLast = NULL;
|
|
}
|
|
|
|
lstrcpyW (pwsp->szSnapshotDir, pszSnapShotDir);
|
|
pwsp->fSerialized = fSerialized;
|
|
hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); // manual reset
|
|
if (NULL == hEvent )
|
|
{
|
|
dwReturn = GetLastError();
|
|
ErrorTrace(0, "! CreateEvent : %ld", dwReturn);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (FALSE == DuplicateHandle (GetCurrentProcess(),
|
|
hEvent,
|
|
GetCurrentProcess(),
|
|
&pwsp->hEvent,
|
|
0, FALSE, DUPLICATE_SAME_ACCESS))
|
|
{
|
|
dwReturn = GetLastError();
|
|
ErrorTrace(0, "! DuplicateHandle : %ld", dwReturn);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (! fSerialized)
|
|
{
|
|
trace(0, "Parallellizing WMI snapshot");
|
|
hThread = CreateThread (NULL, 0, DoWMISnapshot, pwsp, 0, NULL);
|
|
if (hThread == NULL)
|
|
{
|
|
dwReturn = GetLastError();
|
|
ErrorTrace(0, "! CreateThread : %ld", dwReturn);
|
|
CloseHandle (pwsp->hEvent);
|
|
pwsp->hEvent = NULL;
|
|
goto cleanup;
|
|
}
|
|
if (g_pEventHandler)
|
|
g_pEventHandler->GetCounter()->Up();
|
|
fWMISnapshotParamCleanup = FALSE; // ownership transferred
|
|
}
|
|
|
|
// before doing the registry snapshot, clear the restore error
|
|
// this will prevent us from snapshotting a registry that has
|
|
// this error set. Note this that error is only used for the
|
|
// restore process and we do not want to restore any regsitries
|
|
// what have this error set.
|
|
_VERIFY(TRUE==SetRestoreError(ERROR_SUCCESS)); // clear this error
|
|
|
|
dwErr = ProcessPendingRenames(pszSnapShotDir);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwErr = tp.SetPrivilegeInAccessToken(SE_BACKUP_NAME);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "SetPrivilegeInAccessToken failed ec=%d", dwErr);
|
|
dwReturn = ERROR_PRIVILEGE_NOT_HELD;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Create resgistry snapshot
|
|
dwErr = DoRegistrySnapshot(pszSnapShotDir);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
//snapshot files listed in filelist.xml
|
|
dwErr = SnapshotRestoreFilelistFiles(pszSnapShotDir, TRUE);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
// do COM snapshot
|
|
dwErr = DoCOMDbSnapshot(pszSnapShotDir, hCOMDll);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
|
|
if (hr == RPC_E_CHANGED_MODE)
|
|
{
|
|
//
|
|
// someone called it with other mode
|
|
//
|
|
|
|
hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
dwReturn = (DWORD) hr;
|
|
ErrorTrace(0, "! CoInitializeEx : %ld", dwReturn);
|
|
goto cleanup;
|
|
}
|
|
|
|
fCoInitialized = TRUE;
|
|
|
|
// do IIS snapshot
|
|
dwErr = DoIISSnapshot(pszSnapShotDir);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
lstrcatW (pszSnapShotDir, L"\\domain.txt");
|
|
dwErr = GetDomainMembershipInfo (pszSnapShotDir, NULL);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwReturn = dwErr;
|
|
trace(0, "! GetDomainMembershipInfo : %ld", dwErr);
|
|
goto cleanup;
|
|
}
|
|
|
|
// if serialized WMI snapshot, do it here
|
|
if (fSerialized)
|
|
{
|
|
trace(0, "Serializing WMI snapshot");
|
|
fWMISnapshotParamCleanup = FALSE;
|
|
dwReturn = DoWMISnapshot(pwsp);
|
|
if (dwReturn != ERROR_SUCCESS)
|
|
{
|
|
trace(0, "! DoWMISnapshot : %ld", dwErr);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// wait for the WMI Pause to finish
|
|
dwErr = WaitForSingleObject (hEvent, CLock::TIMEOUT);
|
|
if (WAIT_TIMEOUT == dwErr)
|
|
{
|
|
trace (0, "WMI thread timed out");
|
|
}
|
|
else if (WAIT_FAILED == dwErr)
|
|
{
|
|
trace (0, "WaitForSingleObject failed");
|
|
}
|
|
trace(0, "WMI Pause is done");
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
if (hEvent != NULL)
|
|
{
|
|
CloseHandle (hEvent);
|
|
}
|
|
|
|
if (fWMISnapshotParamCleanup && NULL != pwsp)
|
|
{
|
|
if (pwsp->pRpLast)
|
|
delete pwsp->pRpLast;
|
|
delete pwsp;
|
|
trace(0, "CreateSnapshot released pwsp");
|
|
}
|
|
|
|
if (fCoInitialized)
|
|
CoUninitialize();
|
|
|
|
if (hThread != NULL)
|
|
CloseHandle (hThread);
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
BOOL IsWellKnownHKLMHive(WCHAR * pszHiveName)
|
|
{
|
|
return ( (0==lstrcmpi(pszHiveName, s_cszSoftwareHiveName)) ||
|
|
(0==lstrcmpi(pszHiveName, s_cszSystemHiveName )) ||
|
|
(0==lstrcmpi(pszHiveName, s_cszSamHiveName )) ||
|
|
(0==lstrcmpi(pszHiveName, s_cszSecurityHiveName)) );
|
|
}
|
|
|
|
DWORD SaveRegKey(HKEY hKey, // handle to parent key
|
|
const WCHAR * pszSubKeyName, // name of subkey to backup
|
|
WCHAR * pszFileName) // filename of backup file
|
|
{
|
|
TraceFunctEnter("SaveRegKey");
|
|
|
|
DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
|
|
DWORD dwDisposition;
|
|
|
|
HKEY hKeyToBackup = NULL;
|
|
|
|
|
|
// open the key - pass the REG_OPTION_BACKUP_RESTORE to bypass
|
|
// security checking
|
|
dwErr = RegCreateKeyEx(hKey, // handle to open key
|
|
pszSubKeyName, // subkey name
|
|
0, // reserved
|
|
NULL, // class string
|
|
REG_OPTION_BACKUP_RESTORE, // special options
|
|
KEY_READ, // desired security access
|
|
NULL, // inheritance
|
|
&hKeyToBackup, // key handle
|
|
&dwDisposition); // disposition value buffer
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "RegCreateKeyEx failed for %S, error %ld",
|
|
pszSubKeyName, dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
// now make sure that the key already existed - else delete the key
|
|
if (REG_OPENED_EXISTING_KEY != dwDisposition)
|
|
{
|
|
// no key existed - delete the key
|
|
ErrorTrace(0, "Key %S did not exist, error %ld",
|
|
pszSubKeyName, dwErr);
|
|
dwReturn = ERROR_FILE_NOT_FOUND;
|
|
|
|
_VERIFY(ERROR_SUCCESS==RegCloseKey(hKeyToBackup));
|
|
hKeyToBackup = NULL;
|
|
|
|
_VERIFY(ERROR_SUCCESS==RegDeleteKey(hKey, // handle to open key
|
|
pszSubKeyName));// subkey name
|
|
|
|
// BUGBUG test above case
|
|
goto cleanup;
|
|
}
|
|
|
|
dwErr = RegSaveKeyEx(hKeyToBackup,// handle to key
|
|
pszFileName,// data file
|
|
NULL,// SD
|
|
REG_NO_COMPRESSION);
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "RegSaveKey failed for %S, error %ld",
|
|
pszSubKeyName, dwErr);
|
|
LogDSFileTrace(0,L"File was ", pszFileName);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
if (NULL != hKeyToBackup)
|
|
{
|
|
_VERIFY(ERROR_SUCCESS==RegCloseKey(hKeyToBackup));
|
|
}
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// the saved NTUser.dat file name is of the form
|
|
// _REGISTRY_USER_NTUSER_S-1-9-9-09
|
|
DWORD CreateNTUserDatPath(WCHAR * pszDest,
|
|
DWORD dwDestLength, // length in characters
|
|
WCHAR * pszSnapshotDir,
|
|
WCHAR * pszUserSID)
|
|
{
|
|
TraceFunctEnter("CreateNTUserDatPath");
|
|
|
|
DWORD dwLengthRequired;
|
|
|
|
dwLengthRequired = lstrlen(pszSnapshotDir) + lstrlen(s_cszUserPrefix) +
|
|
lstrlen(s_cszSnapshotNtUser)+ lstrlen(pszUserSID) +2;
|
|
|
|
if (dwDestLength < dwLengthRequired)
|
|
{
|
|
ErrorTrace(0, "Insuffcient buffer. Buffer passed in %d, Required %d",
|
|
dwDestLength, dwLengthRequired);
|
|
|
|
TraceFunctLeave();
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
wsprintf(pszDest, L"%s\\%s%s%s", pszSnapshotDir, s_cszUserPrefix,
|
|
s_cszSnapshotNtUser, pszUserSID);
|
|
|
|
TraceFunctLeave();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
// the saved UsrClass.dat file name is of the form
|
|
// _REGISTRY_USER_USRCLASS_S-1-9-9-09
|
|
DWORD CreateUsrClassPath(WCHAR * pszDest,
|
|
DWORD dwDestLength, // length in characters
|
|
WCHAR * pszSnapshotDir,
|
|
WCHAR * pszUserSID)
|
|
{
|
|
TraceFunctEnter("CreateUsrClassPath");
|
|
|
|
DWORD dwLengthRequired;
|
|
|
|
dwLengthRequired = lstrlen(pszSnapshotDir) + lstrlen(s_cszUserPrefix) +
|
|
lstrlen(s_cszSnapshotUsrClass)+ lstrlen(pszUserSID) +2;
|
|
|
|
if (dwDestLength < dwLengthRequired)
|
|
{
|
|
ErrorTrace(0, "Insuffcient buffer. Buffer passed in %d, Required %d",
|
|
dwDestLength, dwLengthRequired);
|
|
|
|
TraceFunctLeave();
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
wsprintf(pszDest, L"%s\\%s%s%s", pszSnapshotDir, s_cszUserPrefix,
|
|
s_cszSnapshotUsrClass, pszUserSID);
|
|
|
|
TraceFunctLeave();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
//
|
|
// function to write movefileex entries to a saved system hive file
|
|
//
|
|
DWORD
|
|
SrMoveFileEx(
|
|
LPWSTR pszSnapshotDir,
|
|
LPWSTR pszSrc,
|
|
LPWSTR pszDest)
|
|
{
|
|
TraceFunctEnter("SrMoveFileEx");
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
HKEY hkMount = NULL;
|
|
DWORD cbData1 = 0;
|
|
PBYTE pNewMFE = NULL, pOldMFE = NULL, pNewPos = NULL;
|
|
BOOL fRegLoaded = FALSE;
|
|
WCHAR szNewEntry1[MAX_PATH];
|
|
WCHAR szNewEntry2[MAX_PATH];
|
|
WCHAR szNewEntry3[MAX_PATH];
|
|
DWORD cbNewEntry1 = 0, cbNewEntry2 = 0, cbNewEntry3 = 0;
|
|
WCHAR szSysHive[MAX_PATH];
|
|
|
|
//
|
|
// load system hive file
|
|
//
|
|
|
|
wsprintf(szSysHive, L"%s\\%s%s%s", pszSnapshotDir,
|
|
s_cszHKLMFilePrefix, s_cszSystemHiveName, s_cszRegHiveCopySuffix);
|
|
|
|
CHECKERR(RegLoadKey( HKEY_LOCAL_MACHINE, s_cszRegHiveTmp, szSysHive ),
|
|
L"RegLoadKey");
|
|
|
|
fRegLoaded = TRUE;
|
|
|
|
CHECKERR(RegOpenKey( HKEY_LOCAL_MACHINE, s_cszRegHiveTmp, &hkMount ),
|
|
L"RegOpenKey");
|
|
|
|
//
|
|
// get old entries
|
|
//
|
|
|
|
lstrcpy(szSysHive, s_cszRegLMSYSSessionMan);
|
|
ChangeCCS(hkMount, szSysHive);
|
|
|
|
pOldMFE = (PBYTE) SRGetRegMultiSz( hkMount, szSysHive, SRREG_VAL_MOVEFILEEX, &cbData1 );
|
|
|
|
//
|
|
// alloc mem for old + new
|
|
// allocate enough to hold 3 new paths + some extra characters
|
|
//
|
|
|
|
pNewMFE = (PBYTE) malloc(cbData1 + 4*MAX_PATH*sizeof(WCHAR));
|
|
if (! pNewMFE)
|
|
{
|
|
ErrorTrace(0, "Out of memory");
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
goto Err;
|
|
}
|
|
if (pOldMFE)
|
|
memcpy(pNewMFE, pOldMFE, cbData1);
|
|
|
|
//
|
|
// format new entries - a delete and a rename
|
|
//
|
|
|
|
wsprintf(szNewEntry2, L"\\\?\?\\%s", pszSrc);
|
|
cbNewEntry2 = (lstrlen(szNewEntry2) + 1)*sizeof(WCHAR);
|
|
|
|
wsprintf(szNewEntry3, L"!\\\?\?\\%s", pszDest);
|
|
cbNewEntry3 = (lstrlen(szNewEntry3) + 1)*sizeof(WCHAR);
|
|
|
|
DebugTrace(0, "%S", szNewEntry2);
|
|
DebugTrace(0, "%S", szNewEntry3);
|
|
|
|
//
|
|
// find position to insert new entries - overwrite trailing '\0'
|
|
//
|
|
|
|
if (pOldMFE)
|
|
{
|
|
DebugTrace(0, "Old MFE entries exist");
|
|
cbData1 -= sizeof(WCHAR);
|
|
pNewPos = pNewMFE + cbData1;
|
|
}
|
|
else
|
|
{
|
|
DebugTrace(0, "No old MFE entries exist");
|
|
pNewPos = pNewMFE;
|
|
}
|
|
|
|
//
|
|
// append rename
|
|
//
|
|
|
|
memcpy(pNewPos, (BYTE *) szNewEntry2, cbNewEntry2);
|
|
pNewPos += cbNewEntry2;
|
|
memcpy(pNewPos, (BYTE *) szNewEntry3, cbNewEntry3);
|
|
pNewPos += cbNewEntry3;
|
|
|
|
//
|
|
// add trailing '\0'
|
|
//
|
|
|
|
*((LPWSTR) pNewPos) = L'\0';
|
|
|
|
//
|
|
// write back to registry
|
|
//
|
|
|
|
if (! SRSetRegMultiSz( hkMount,
|
|
szSysHive,
|
|
SRREG_VAL_MOVEFILEEX,
|
|
(LPWSTR) pNewMFE,
|
|
cbData1 + cbNewEntry2 + cbNewEntry3 + sizeof(WCHAR)))
|
|
{
|
|
ErrorTrace(0, "! SRSetRegMultiSz");
|
|
dwErr = ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
|
|
Err:
|
|
if (hkMount != NULL)
|
|
RegCloseKey(hkMount);
|
|
|
|
if (fRegLoaded)
|
|
RegUnLoadKey(HKEY_LOCAL_MACHINE, s_cszRegHiveTmp);
|
|
|
|
if (pOldMFE)
|
|
delete pOldMFE;
|
|
|
|
if (pNewMFE)
|
|
free(pNewMFE);
|
|
|
|
TraceFunctLeave();
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
// the saved UsrClass.dat file name is of the form
|
|
// _REGISTRY_USER_USRCLASS_S-1-9-9-09
|
|
DWORD CreateUsrDefaultPath(WCHAR * pszDest,
|
|
DWORD dwDestLength, // length in characters
|
|
WCHAR * pszSnapshotDir)
|
|
{
|
|
TraceFunctEnter("CreateUsrDefaultPath");
|
|
|
|
DWORD dwLengthRequired;
|
|
|
|
dwLengthRequired = lstrlen(pszSnapshotDir) + lstrlen(s_cszUserPrefix) +
|
|
lstrlen(s_cszSnapshotUsersDefaultKey) +2;
|
|
|
|
if (dwDestLength < dwLengthRequired)
|
|
{
|
|
ErrorTrace(0, "Insuffcient buffer. Buffer passed in %d, Required %d",
|
|
dwDestLength, dwLengthRequired);
|
|
|
|
TraceFunctLeave();
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
wsprintf(pszDest, L"%s\\%s%s", pszSnapshotDir, s_cszUserPrefix,
|
|
s_cszSnapshotUsersDefaultKey);
|
|
|
|
TraceFunctLeave();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD SetNewRegistry(HKEY hBigKey, // handle to open key
|
|
const WCHAR * pszHiveName, // subkey name
|
|
WCHAR * pszDataFile, // data file
|
|
WCHAR * pszOriginalFile,
|
|
WCHAR * pszSnapshotDir)
|
|
{
|
|
TraceFunctEnter("SetNewRegistry");
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR, dwDisposition;
|
|
WCHAR szBackupFile[MAX_PATH]; // backup file
|
|
HKEY hLocalKey=NULL;
|
|
REGSAM samDesired = MAXIMUM_ALLOWED;
|
|
WCHAR szTempRegCopy[MAX_PATH];
|
|
|
|
// first check to see if the file is a copy created for this
|
|
// restore process. If not, we need to create a copy since
|
|
// RegReplaceKey removes the input file.
|
|
if (FALSE == IsRestoreCopy(pszDataFile))
|
|
{
|
|
wsprintf(szTempRegCopy, L"%s%s", pszDataFile,
|
|
s_cszRegHiveCopySuffix);
|
|
|
|
dwErr = SnapshotCopyFile(pszDataFile, szTempRegCopy);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lstrcpy(szTempRegCopy, pszDataFile);
|
|
}
|
|
|
|
wsprintf(szBackupFile, L"%s%s",szTempRegCopy,s_cszRegReplaceBackupSuffix);
|
|
|
|
dwErr = RegCreateKeyEx( hBigKey,// handle to open key
|
|
pszHiveName,// subkey name
|
|
0,// reserved
|
|
NULL,// class string
|
|
REG_OPTION_BACKUP_RESTORE,// special options
|
|
samDesired,// desired security access
|
|
NULL,// inheritance
|
|
&hLocalKey,// key handle
|
|
&dwDisposition );// disposition value buffer
|
|
|
|
|
|
if ( ERROR_SUCCESS != dwErr )
|
|
{
|
|
ErrorTrace(0, "RegCreateKeyEx failed for %S, error %ld",
|
|
pszHiveName, dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwErr = RegReplaceKey( hLocalKey,
|
|
NULL,
|
|
szTempRegCopy,
|
|
szBackupFile );
|
|
|
|
if ( dwErr != ERROR_SUCCESS )
|
|
{
|
|
ErrorTrace(0, "RegReplaceKey failed for %S, error %ld",
|
|
pszHiveName, dwErr);
|
|
LogDSFileTrace(0,L"File was ", szTempRegCopy);
|
|
|
|
//
|
|
// last ditch effort - try movefileex
|
|
//
|
|
if (pszSnapshotDir)
|
|
{
|
|
DebugTrace(0, "Trying movefileex");
|
|
dwReturn = SrMoveFileEx(pszSnapshotDir, szTempRegCopy, pszOriginalFile);
|
|
if (dwReturn != ERROR_SUCCESS)
|
|
{
|
|
ErrorTrace(0, "! SrMoveFileEx : %ld", dwReturn);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_ASSERT(0);
|
|
// we can't do anything here
|
|
}
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
if (NULL != hLocalKey)
|
|
{
|
|
dwErr = RegCloseKey( hLocalKey );
|
|
_ASSERT(ERROR_SUCCESS==dwErr);
|
|
}
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
// this function copies the file - it takes care of the attributes
|
|
// (like read only and hidden) which prevent overwrite of the file.
|
|
DWORD SnapshotCopyFile(WCHAR * pszSrc,
|
|
WCHAR * pszDest)
|
|
{
|
|
TraceFunctEnter("SnapshotCopyFile");
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR, dwAttr;
|
|
BOOL fRestoreAttr = FALSE;
|
|
|
|
// if destination file does not exist, ignore
|
|
if (DoesFileExist(pszDest))
|
|
{
|
|
dwAttr =GetFileAttributes(pszDest); // name of file or directory
|
|
if (dwAttr == -1)
|
|
{
|
|
// keep going. Maybe the copy will succeed
|
|
dwErr = GetLastError();
|
|
ErrorTrace(0, "GetFileAttributes failed %d", dwErr);
|
|
LogDSFileTrace(0,L"File was ", pszDest);
|
|
}
|
|
else
|
|
{
|
|
// we need to keep track of which attributes we will restore.
|
|
dwAttr = dwAttr & (FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|
|
|
FILE_ATTRIBUTE_NORMAL|
|
|
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED|
|
|
FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|
|
|
FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY);
|
|
fRestoreAttr = TRUE;
|
|
|
|
// now set the attributes of the destination file to be
|
|
// normal so that we can overwrite this file
|
|
if (!SetFileAttributes( pszDest, // file name
|
|
FILE_ATTRIBUTE_NORMAL )) // attributes
|
|
{
|
|
// keep going. Maybe the copy will succeed
|
|
dwErr = GetLastError();
|
|
ErrorTrace(0, "SetFileAttributes failed %d", dwErr);
|
|
LogDSFileTrace(0,L"File was ", pszDest);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
dwErr = SRCopyFile(pszSrc, pszDest);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
ErrorTrace(0, "SRCopyFile failed. ec=%d", dwErr);
|
|
LogDSFileTrace(0,L"src= ", pszSrc);
|
|
LogDSFileTrace(0,L"dst= ", pszDest);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
if (TRUE == fRestoreAttr)
|
|
{
|
|
// now restore the attributes of the destination file
|
|
if (!SetFileAttributes( pszDest, // file name
|
|
dwAttr )) // attributes
|
|
{
|
|
dwErr = GetLastError();
|
|
ErrorTrace(0, "SetFileAttributes failed %d", dwErr);
|
|
LogDSFileTrace(0,L"File was ", pszDest);
|
|
}
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
// the following function attempts to copy the user profile hives
|
|
// (ntuser.dat and usrclass.dat) from the profile path (or vice versa).
|
|
// This can fail if the user's profile is in use.
|
|
//
|
|
// if fRestore is TRUE it restores the profile
|
|
// if fRestore is FALSE it snapshots the profile
|
|
DWORD CopyUserProfile(HKEY hKeyProfileList,
|
|
WCHAR * pszUserSID,
|
|
WCHAR * pszSnapshotDir,
|
|
BOOL fRestore,
|
|
WCHAR * pszNTUserPath)
|
|
{
|
|
TraceFunctEnter("CopyUserProfile");
|
|
|
|
DWORD dwReturn=ERROR_INTERNAL_ERROR, dwErr,dwSize,dwType;
|
|
HKEY hKeySID = NULL;
|
|
WCHAR szNTUserPath[MAX_PATH];
|
|
int cbNTUserPath = 0;
|
|
PWCHAR pszSrc, pszDest;
|
|
|
|
// find the ProfileImagePath
|
|
|
|
//open the parent key
|
|
dwErr = RegOpenKeyEx(hKeyProfileList,// handle to open key
|
|
pszUserSID,// subkey name
|
|
0,// reserved
|
|
KEY_READ,// security access mask
|
|
&hKeySID);// handle to open key
|
|
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0,"Error %d in opening ProfileList of %S",
|
|
dwErr, pszUserSID);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
//now query for the profile image path
|
|
{
|
|
WCHAR szData[MAX_PATH];
|
|
dwSize = sizeof(szData)/sizeof(WCHAR);
|
|
dwType = REG_EXPAND_SZ;
|
|
|
|
dwErr = RegQueryValueEx(hKeySID,// handle to key
|
|
s_cszSnapshotProfileImagePath, // value name
|
|
NULL, // reserved
|
|
&dwType, // type buffer
|
|
(LPBYTE) szData, // data buffer
|
|
&dwSize);// size of data buffer
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0,"Error %d in querying Profilepath of %S", dwErr,
|
|
pszUserSID);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (0 == ExpandEnvironmentStrings( szData,
|
|
szNTUserPath,
|
|
sizeof(szNTUserPath)/sizeof(WCHAR)))
|
|
{
|
|
dwErr = GetLastError();
|
|
ErrorTrace(0, "ExpandEnvironmentStrings failed for %S, ec=%d",
|
|
szData, dwErr);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
dwReturn = dwErr;
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
cbNTUserPath = lstrlen(szNTUserPath);
|
|
}
|
|
|
|
|
|
{
|
|
WCHAR szSnapshotPath[MAX_PATH];
|
|
|
|
// save off the ntuser.dat into datastore
|
|
lstrcat(szNTUserPath, L"\\");
|
|
lstrcat(szNTUserPath, s_cszSnapshotNTUserDat);
|
|
|
|
lstrcpy(pszNTUserPath, szNTUserPath);
|
|
|
|
if (ERROR_SUCCESS!= CreateNTUserDatPath(
|
|
szSnapshotPath,
|
|
sizeof(szSnapshotPath)/sizeof(WCHAR),
|
|
pszSnapshotDir, pszUserSID))
|
|
{
|
|
dwReturn=ERROR_INSUFFICIENT_BUFFER;
|
|
goto cleanup;
|
|
}
|
|
if (fRestore == TRUE)
|
|
{
|
|
pszSrc=szSnapshotPath;
|
|
pszDest=szNTUserPath;
|
|
}
|
|
else
|
|
{
|
|
pszSrc=szNTUserPath;
|
|
pszDest=szSnapshotPath;
|
|
}
|
|
|
|
|
|
if (fRestore)
|
|
{
|
|
//
|
|
// delete current ntuser.dat before putting old one back
|
|
//
|
|
|
|
if (FALSE == DeleteFile(pszDest))
|
|
{
|
|
ErrorTrace(0, "! DeleteFile on ntuser.dat : %ld", GetLastError());
|
|
}
|
|
else
|
|
{
|
|
DebugTrace(0, "NTuser.dat deleted");
|
|
}
|
|
}
|
|
|
|
dwErr = SnapshotCopyFile(pszSrc, pszDest);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
// save off the usrclass.dat also into datastore
|
|
szNTUserPath[cbNTUserPath] = L'\0';
|
|
lstrcat(szNTUserPath, L"\\");
|
|
lstrcat(szNTUserPath, s_cszSnapshotUsrClassLocation);
|
|
|
|
if (ERROR_SUCCESS!= CreateUsrClassPath(
|
|
szSnapshotPath,
|
|
sizeof(szSnapshotPath)/sizeof(WCHAR),
|
|
pszSnapshotDir, pszUserSID))
|
|
{
|
|
dwReturn=ERROR_INSUFFICIENT_BUFFER;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (fRestore == TRUE)
|
|
{
|
|
pszSrc=szSnapshotPath;
|
|
pszDest=szNTUserPath;
|
|
}
|
|
else
|
|
{
|
|
pszSrc=szNTUserPath;
|
|
pszDest=szSnapshotPath;
|
|
}
|
|
|
|
if (fRestore)
|
|
{
|
|
//
|
|
// delete current usrclass.dat before putting old one back
|
|
//
|
|
|
|
if (FALSE == DeleteFile(pszDest))
|
|
{
|
|
ErrorTrace(0, "! DeleteFile on usrclass.dat", GetLastError());
|
|
}
|
|
else
|
|
{
|
|
DebugTrace(0, "Usrclass.dat deleted");
|
|
}
|
|
}
|
|
|
|
dwErr = SnapshotCopyFile(pszSrc, pszDest);
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
// if we are here and the usrclass file could not be copied,
|
|
// then we can ignore this error since the usrclass file may
|
|
// not exist.
|
|
DebugTrace(0, "UsrClass cannot be copied. ec=%d. Ignoring this error",
|
|
dwErr);
|
|
//dwReturn = dwErr;
|
|
//goto cleanup;
|
|
}
|
|
}
|
|
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
cleanup:
|
|
if (NULL != hKeySID)
|
|
{
|
|
_VERIFY(ERROR_SUCCESS==RegCloseKey(hKeySID));
|
|
}
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
void CreateClassesKeyName( WCHAR * pszKeyName,
|
|
WCHAR * pszUserSID)
|
|
{
|
|
wsprintf(pszKeyName, L"%s%s", pszUserSID, s_cszClassesKey);
|
|
}
|
|
|
|
DWORD ProcessUserRegKeys( WCHAR * pszUserSID,
|
|
WCHAR * pszSnapshotDir,
|
|
BOOL fRestore,
|
|
WCHAR * pszOriginalFile)
|
|
{
|
|
TraceFunctEnter("ProcessUserRegKeys");
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
|
|
|
|
LPWSTR szDest = new WCHAR[MAX_PATH];
|
|
LPWSTR szKeyName = new WCHAR[MAX_PATH];
|
|
|
|
if (!szDest || !szKeyName)
|
|
{
|
|
ErrorTrace(0, "Cannot allocate memory");
|
|
dwReturn = ERROR_OUTOFMEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (ERROR_SUCCESS != CreateNTUserDatPath(szDest,
|
|
MAX_PATH,
|
|
pszSnapshotDir, pszUserSID))
|
|
{
|
|
dwReturn=ERROR_INSUFFICIENT_BUFFER;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (FALSE == fRestore)
|
|
{
|
|
dwErr = SaveRegKey(HKEY_USERS,
|
|
pszUserSID, // Subkey to save
|
|
szDest); // File to save in
|
|
}
|
|
else
|
|
{
|
|
dwErr = SetNewRegistry(HKEY_USERS, // handle to open key
|
|
pszUserSID, // subkey name
|
|
szDest, // snapshot file
|
|
pszOriginalFile, // original file
|
|
pszSnapshotDir);
|
|
}
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "SaveRegKey or SetNewRegistry failed ec=%d", dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (ERROR_SUCCESS != CreateUsrClassPath(szDest,
|
|
MAX_PATH,
|
|
pszSnapshotDir, pszUserSID))
|
|
{
|
|
dwReturn=ERROR_INSUFFICIENT_BUFFER;
|
|
goto cleanup;
|
|
}
|
|
|
|
CreateClassesKeyName(szKeyName, pszUserSID);
|
|
|
|
if (FALSE == fRestore)
|
|
{
|
|
dwErr = SaveRegKey(HKEY_USERS,
|
|
szKeyName, // Subkey to save
|
|
szDest); // File to save in
|
|
}
|
|
else
|
|
{
|
|
dwErr = SetNewRegistry(HKEY_USERS, // handle to open key
|
|
szKeyName, // subkey name
|
|
szDest, // data file
|
|
pszOriginalFile,
|
|
pszSnapshotDir);
|
|
}
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
// if we are here and the usrclass file could not be copied,
|
|
// then we can ignore this error since the usrclass file may
|
|
// not exist.
|
|
DebugTrace(0, "UsrClass cannot be copied. ec=%d. Ignoring this error",
|
|
dwErr);
|
|
//dwReturn = dwErr;
|
|
//goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
if (szDest)
|
|
delete [] szDest;
|
|
if (szKeyName)
|
|
delete [] szKeyName;
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
// the following function processes the HKeyUsers registry key
|
|
// if fRestore is TRUE it restores the registry key
|
|
// if fRestore is FALSE it snapshots the registry key
|
|
DWORD ProcessHKUsersKey( WCHAR * pszSnapshotDir,
|
|
IN HKEY hKeyHKLM,// handle to an open key from where
|
|
// Software\\Microsoft\\ can be read.
|
|
BOOL fRestore)
|
|
{
|
|
TraceFunctEnter("ProcessHKUsersKey");
|
|
|
|
WCHAR szSID[100];
|
|
DWORD dwReturn=ERROR_INTERNAL_ERROR, dwErr;
|
|
HKEY hKeyProfileList = NULL;
|
|
DWORD dwIndex,dwSize;
|
|
const WCHAR * pszProfileSubKeyName;
|
|
|
|
if (TRUE == fRestore)
|
|
{
|
|
// in this case this is a loaded hive of the system. We need
|
|
// to strip system from the subkey name to bew able to read
|
|
// this subkey.
|
|
pszProfileSubKeyName = s_cszSnapshotProfileList +
|
|
lstrlen(s_cszSoftwareHiveName) + 1;
|
|
}
|
|
else
|
|
{
|
|
pszProfileSubKeyName = s_cszSnapshotProfileList;
|
|
}
|
|
|
|
// open the ProfileList and enumerate
|
|
dwErr = RegOpenKeyEx( hKeyHKLM,// handle to open key
|
|
pszProfileSubKeyName,// subkey name
|
|
0,// subkey name
|
|
KEY_READ,// security access mask
|
|
&hKeyProfileList);// handle to open key
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "RegOpenKeyEx failed for ProfileList, error %ld", dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwIndex = 0;
|
|
dwSize = sizeof(szSID)/sizeof(WCHAR);
|
|
while (ERROR_SUCCESS == (dwErr = RegEnumKeyEx( hKeyProfileList,
|
|
// handle to key to
|
|
// enumerate
|
|
dwIndex, // subkey index
|
|
szSID,// subkey name
|
|
&dwSize, // size of subkey
|
|
// buffer
|
|
NULL, // reserved
|
|
NULL, // class string buffer
|
|
NULL,// size of class
|
|
// string buffer
|
|
NULL)))// last write time
|
|
{
|
|
WCHAR szOriginalFile[MAX_PATH];
|
|
LPWSTR pszOriginalFile = NULL;
|
|
|
|
DebugTrace(0, "Enumerated Key %S", szSID);
|
|
dwIndex++;
|
|
// try to copy the file - if this fails we will try to save
|
|
// the reg key
|
|
|
|
lstrcpy(szOriginalFile, L"");
|
|
dwErr = CopyUserProfile(hKeyProfileList, szSID, pszSnapshotDir,
|
|
fRestore, szOriginalFile);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
DebugTrace(0, "CopyUserProfile for %S failed. Error %d",
|
|
szSID, dwErr);
|
|
|
|
// The copy may have failed since the user profile may be
|
|
// currently loaded - try to use Registry functions for
|
|
// this purpose.
|
|
|
|
DebugTrace(0, "Trying registry APIs for %S", szSID);
|
|
|
|
if (0 == lstrcmp(szOriginalFile, L""))
|
|
pszOriginalFile = NULL;
|
|
else
|
|
pszOriginalFile = szOriginalFile;
|
|
|
|
dwErr = ProcessUserRegKeys(szSID, pszSnapshotDir, fRestore, pszOriginalFile);
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "Error %d saving key %S - ignoring", dwErr, szSID);
|
|
|
|
//
|
|
// ignore error -- if profile was deleted by hand
|
|
// this could happen
|
|
// we will just bravely carry on
|
|
//
|
|
}
|
|
}
|
|
dwSize = sizeof(szSID)/sizeof(WCHAR);
|
|
}
|
|
|
|
{
|
|
WCHAR szDest[MAX_PATH];
|
|
// also save the .default key
|
|
if (ERROR_SUCCESS != CreateUsrDefaultPath(szDest,
|
|
sizeof(szDest)/sizeof(WCHAR),
|
|
pszSnapshotDir))
|
|
{
|
|
dwReturn=ERROR_INSUFFICIENT_BUFFER;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (TRUE == fRestore)
|
|
{
|
|
dwErr = SetNewRegistry(HKEY_USERS, // handle to open key
|
|
s_cszSnapshotUsersDefaultKey, // subkey name
|
|
szDest, // data file
|
|
NULL,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
dwErr = SaveRegKey(HKEY_USERS,
|
|
s_cszSnapshotUsersDefaultKey,
|
|
szDest);
|
|
}
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "Error processing default key ec=%d", dwErr);
|
|
dwReturn = dwErr;
|
|
|
|
_ASSERT(0);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
if (NULL != hKeyProfileList)
|
|
{
|
|
_VERIFY(ERROR_SUCCESS==RegCloseKey(hKeyProfileList));
|
|
}
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
// the following function saves or restores a reg hive.
|
|
// if fRestore == TRUE it restores the reg hive
|
|
// if fRestore == FALSE it saves the reg hive
|
|
DWORD SnapshotRegHive(WCHAR * pszSnapshotDir,
|
|
WCHAR * pszHiveName)
|
|
{
|
|
TraceFunctEnter("SnapshotRegHive");
|
|
|
|
DWORD i,dwSnapDirLen, dwHivelen;
|
|
WCHAR szBackupFile[MAX_PATH];
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
|
|
WCHAR * pszSubhiveName;
|
|
|
|
|
|
// first construct the name of the file to store the hive
|
|
wsprintf(szBackupFile, L"%s\\%s", pszSnapshotDir, pszHiveName);
|
|
|
|
|
|
// now replace all \ in the copy of pszHiveName to _
|
|
dwSnapDirLen=lstrlen(pszSnapshotDir)+1; // +1 is for the \\ after
|
|
//pszSnapshotDir
|
|
|
|
dwHivelen = lstrlen(pszHiveName);
|
|
for (i=dwSnapDirLen; i< dwHivelen+ dwSnapDirLen; i++)
|
|
{
|
|
if (szBackupFile[i] == L'\\')
|
|
{
|
|
szBackupFile[i] = L'_';
|
|
}
|
|
}
|
|
|
|
// figure out if it is the HKLM hive - we already snapshot the HK
|
|
// users hive
|
|
if (0 != _wcsnicmp( pszHiveName, s_cszHKLMPrefix,lstrlen(s_cszHKLMPrefix)))
|
|
{
|
|
DebugTrace(0, "%S is not a HKLM hive", pszHiveName);
|
|
dwReturn = ERROR_SUCCESS;
|
|
goto cleanup;
|
|
}
|
|
|
|
// get the hive name
|
|
pszSubhiveName = pszHiveName + lstrlen(s_cszHKLMPrefix);
|
|
|
|
// now check to see if the hive is one that we have created
|
|
// ourselves. If so, ignore this hive
|
|
if ( (lstrcmpi(pszSubhiveName,s_cszRestoreSAMHiveName)==0) ||
|
|
(lstrcmpi(pszSubhiveName,s_cszRestoreSYSTEMHiveName)==0) ||
|
|
(lstrcmpi(pszSubhiveName,s_cszRestoreSECURITYHiveName)==0) )
|
|
{
|
|
DebugTrace(0, "Ignoring %S since it a hive created by restore",
|
|
pszSubhiveName);
|
|
dwReturn = ERROR_SUCCESS;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwErr = SaveRegKey(HKEY_LOCAL_MACHINE,
|
|
pszSubhiveName,
|
|
szBackupFile);
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "SaveRegKey failed for HiveList, ec=%ld", dwErr);
|
|
// now check to see if this is a well known HKLM hive. If not, ignore any errors in
|
|
// snapshotting this hive
|
|
if (FALSE==IsWellKnownHKLMHive(pszSubhiveName))
|
|
{
|
|
dwReturn=ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
dwReturn = dwErr;
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
// call reg save key on this
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
|
|
|
|
// the following function does processing of the HKLM key. It does it
|
|
// by reading the hives listed in the reg key
|
|
// System\\CurrentControlSet\\Control\\Hivelist. It ignores the Users
|
|
// subkeys.
|
|
DWORD DoHKLMSnapshot(IN WCHAR * pszSnapshotDir)
|
|
{
|
|
TraceFunctEnter("DoHKLMSnapshot");
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
|
|
HKEY hKeyHiveList=NULL;
|
|
WCHAR szHiveName[MAX_PATH], szDataValue[MAX_PATH];
|
|
DWORD dwSize, dwValueIndex, dwDataSize;
|
|
|
|
const WCHAR * pszHiveSubKeyName;
|
|
|
|
// open the ProfileList and enumerate
|
|
dwErr = RegOpenKeyEx( HKEY_LOCAL_MACHINE,// handle to open key
|
|
s_cszSnapshotHiveList,// Subkey name
|
|
0,// options
|
|
KEY_READ,// security access mask
|
|
&hKeyHiveList);// handle to open key
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "RegOpenKeyEx failed for HiveList, ec=%ld", dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
for (dwValueIndex = 0; TRUE; dwValueIndex ++)
|
|
{
|
|
dwSize = sizeof(szHiveName)/sizeof(WCHAR);
|
|
dwDataSize = sizeof(szDataValue); // this is in bytes
|
|
|
|
dwErr= RegEnumValue(hKeyHiveList, // handle to key to query
|
|
dwValueIndex, // index of value to query
|
|
szHiveName, // value buffer
|
|
&dwSize, // size of value buffer
|
|
NULL, // reserved
|
|
NULL, // type buffer
|
|
(PBYTE)szDataValue, // data buffer
|
|
&dwDataSize); // size of data buffer
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
_ASSERT(ERROR_NO_MORE_ITEMS == dwErr);
|
|
break;
|
|
}
|
|
// if the hive does not have a data file, do not back it up.
|
|
if (lstrlen(szDataValue) == 0)
|
|
{
|
|
DebugTrace(0, "There is no data for hive %S. Ignoring",
|
|
szHiveName);
|
|
continue;
|
|
}
|
|
|
|
dwErr = SnapshotRegHive(pszSnapshotDir, szHiveName);
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "Processing failed for Hive %S, ec=%ld",
|
|
szHiveName, dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
cleanup:
|
|
if (NULL != hKeyHiveList)
|
|
{
|
|
_VERIFY(ERROR_SUCCESS==RegCloseKey(hKeyHiveList));
|
|
}
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
CSnapshot::DoRegistrySnapshot(WCHAR * pszSnapshotDir)
|
|
{
|
|
DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
|
|
|
|
TraceFunctEnter("CSnapshot::DoRegistrySnapshot");
|
|
|
|
dwErr = ProcessHKUsersKey(pszSnapshotDir, HKEY_LOCAL_MACHINE,
|
|
FALSE); // need to do a snapshot
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "DoHKUsersSnapshot failed error %ld", dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
// now snapshot other hives also
|
|
dwErr = DoHKLMSnapshot(pszSnapshotDir);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "DoHKLMSnapshot failed error %ld", dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
DWORD CSnapshot::GetCOMplusBackupFN(HMODULE hCOMDll)
|
|
{
|
|
TraceFunctEnter("CSnapshot::GetCOMplusBackupFN");
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
|
|
|
|
if (NULL == hCOMDll)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
// now get the address of the Backup functions
|
|
m_pfnRegDbBackup = (PF_REG_DB_API)GetProcAddress(hCOMDll,
|
|
s_cszRegDBBackupFn);
|
|
if (NULL == m_pfnRegDbBackup)
|
|
{
|
|
dwErr = GetLastError();
|
|
ErrorTrace(0, "Error getting function RegDBBackup. ec=%d", dwErr);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
dwReturn = dwErr;
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn= ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
DWORD CSnapshot::GetCOMplusRestoreFN()
|
|
{
|
|
TraceFunctEnter("CSnapshot::GetCOMplusRestoreFN");
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
|
|
|
|
// first load the COM+ dll
|
|
if (NULL == m_hRegdbDll)
|
|
{
|
|
m_hRegdbDll = LoadLibrary(s_cszCOMDllName);
|
|
if (NULL == m_hRegdbDll)
|
|
{
|
|
dwReturn = GetLastError();
|
|
trace(0, "LoadLibrary of %S failed ec=%d", s_cszCOMDllName, dwReturn);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
// now get the address of the Backup functions
|
|
m_pfnRegDbRestore = (PF_REG_DB_API)GetProcAddress(m_hRegdbDll,
|
|
s_cszRegDBRestoreFn);
|
|
if (NULL == m_pfnRegDbRestore)
|
|
{
|
|
dwErr = GetLastError();
|
|
ErrorTrace(0, "Error getting function RegDBRestore. ec=%d", dwErr);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
dwReturn = dwErr;
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn= ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
void CreateCOMDBSnapShotFileName( WCHAR * pszSnapshotDir,
|
|
WCHAR * pszCOMDBFile )
|
|
{
|
|
wsprintf(pszCOMDBFile, L"%s\\%s", pszSnapshotDir, s_cszCOMDBBackupFile);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
CSnapshot::DoCOMDbSnapshot(WCHAR * pszSnapshotDir, HMODULE hCOMDll)
|
|
{
|
|
TraceFunctEnter("CSnapshot::DoCOMDbSnapshot");
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
|
|
HMODULE hModCOMDll=NULL;
|
|
HRESULT hr;
|
|
WCHAR szCOMDBFile[MAX_PATH];
|
|
|
|
|
|
if (NULL == m_pfnRegDbBackup)
|
|
{
|
|
dwErr = GetCOMplusBackupFN(hCOMDll);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
// construct the path of the database backup file
|
|
CreateCOMDBSnapShotFileName(pszSnapshotDir, szCOMDBFile);
|
|
|
|
hr =m_pfnRegDbBackup( szCOMDBFile );
|
|
|
|
// call the function to backup the file
|
|
if ( FAILED(hr))
|
|
{
|
|
ErrorTrace(0, "Failed to snapshot COM DB. hr=0x%x", hr);
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
void CreateWMISnapShotFileName( WCHAR * pszSnapshotDir,
|
|
WCHAR * pszWMIBackupFile )
|
|
{
|
|
wsprintf(pszWMIBackupFile, L"%s\\%s", pszSnapshotDir,
|
|
s_cszWMIBackupFile);
|
|
return;
|
|
}
|
|
|
|
DWORD DoWMISnapshot(VOID * pParam)
|
|
{
|
|
TraceFunctEnter("DoWMISnapshot");
|
|
|
|
WMISnapshotParam * pwsp = (WMISnapshotParam *) pParam;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
HRESULT hr = S_OK;
|
|
WCHAR szWMIBackupFile[MAX_PATH];
|
|
WCHAR szWMIRepository[MAX_PATH];
|
|
IWbemBackupRestoreEx *wbem ;
|
|
BOOL fCoInitialized = FALSE;
|
|
CTokenPrivilege tp;
|
|
BOOL fHaveLock = FALSE;
|
|
BOOL fSerialized = TRUE;
|
|
|
|
if (NULL == pwsp)
|
|
{
|
|
ErrorTrace(0, "pwsp=NULL");
|
|
TraceFunctLeave();
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
return dwErr;
|
|
}
|
|
|
|
fSerialized = pwsp->fSerialized;
|
|
|
|
dwErr = tp.SetPrivilegeInAccessToken(SE_BACKUP_NAME);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "SetPrivilegeInAccessToken failed ec=%d", dwErr);
|
|
dwErr = ERROR_PRIVILEGE_NOT_HELD;
|
|
goto cleanup;
|
|
}
|
|
|
|
hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
|
|
if (hr == RPC_E_CHANGED_MODE)
|
|
{
|
|
//
|
|
// someone called it with other mode
|
|
//
|
|
|
|
hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
|
|
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
dwErr = (DWORD) hr;
|
|
ErrorTrace(0, "! CoInitializeEx : %ld", dwErr);
|
|
goto cleanup;
|
|
}
|
|
|
|
fCoInitialized = TRUE;
|
|
|
|
// construct the path of the database backup file
|
|
CreateWMISnapShotFileName(pwsp->szSnapshotDir, szWMIBackupFile);
|
|
|
|
GetSystemDirectory (szWMIRepository, MAX_PATH);
|
|
lstrcatW (szWMIRepository, L"\\Wbem\\Repository");
|
|
|
|
if ( SUCCEEDED(CoCreateInstance( CLSID_WbemBackupRestore,
|
|
NULL,
|
|
CLSCTX_LOCAL_SERVER,
|
|
IID_IWbemBackupRestoreEx,
|
|
(LPVOID*)&wbem )) )
|
|
{
|
|
if (FAILED(hr = CoSetProxyBlanket (wbem,
|
|
RPC_C_AUTHN_DEFAULT,
|
|
RPC_C_AUTHZ_DEFAULT,
|
|
COLE_DEFAULT_PRINCIPAL,
|
|
RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL,
|
|
EOAC_DYNAMIC_CLOAKING)))
|
|
{
|
|
TRACE(0, "CoSetProxyBlanket failed ignoring %x ", hr);
|
|
}
|
|
|
|
if (SUCCEEDED(hr = wbem->Pause()))
|
|
{
|
|
// signal to main thread that pause is done
|
|
|
|
if (pwsp->hEvent != NULL)
|
|
{
|
|
SetEvent (pwsp->hEvent);
|
|
}
|
|
|
|
// get the datastore lock
|
|
|
|
if (g_pEventHandler)
|
|
{
|
|
fHaveLock = g_pEventHandler->GetLock()->Lock(CLock::TIMEOUT);
|
|
if (! fHaveLock)
|
|
{
|
|
trace(0, "Cannot get lock");
|
|
dwErr = ERROR_INTERNAL_ERROR;
|
|
wbem->Resume();
|
|
wbem->Release();
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
// do the main wmi snapshotting
|
|
|
|
if (FALSE == CreateDirectoryW (szWMIBackupFile, NULL))
|
|
{
|
|
dwErr = GetLastError();
|
|
if (ERROR_ALREADY_EXISTS != dwErr)
|
|
{
|
|
ErrorTrace(0, "Failed to create repository dir. LastError=%d", dwErr);
|
|
}
|
|
else dwErr = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == dwErr)
|
|
dwErr = CopyFile_Recurse (szWMIRepository, szWMIBackupFile);
|
|
|
|
hr = wbem->Resume();
|
|
if ( FAILED(hr))
|
|
{
|
|
ErrorTrace(0, "Failed to resume WMI DB. ignoring hr=0x%x", hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ErrorTrace(0, "Failed to pause WMI DB. ignoring hr=0x%x", hr);
|
|
|
|
// signal to main thread anyway
|
|
|
|
if (pwsp->hEvent != NULL)
|
|
{
|
|
SetEvent (pwsp->hEvent);
|
|
}
|
|
|
|
if (g_pEventHandler)
|
|
{
|
|
fHaveLock = g_pEventHandler->GetLock()->Lock(CLock::TIMEOUT);
|
|
if (! fHaveLock)
|
|
{
|
|
trace(0, "Cannot get lock with WMI Pause failed");
|
|
dwErr = ERROR_INTERNAL_ERROR;
|
|
wbem->Release();
|
|
goto cleanup;
|
|
}
|
|
}
|
|
}
|
|
wbem->Release() ;
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if (pwsp->hEvent != NULL)
|
|
{
|
|
CloseHandle (pwsp->hEvent);
|
|
pwsp->hEvent = NULL;
|
|
}
|
|
|
|
if (fCoInitialized)
|
|
CoUninitialize();
|
|
|
|
// now calculate accurate complete size of old restore point
|
|
// and snapshot size of current restore point
|
|
|
|
if (g_pDataStoreMgr && fHaveLock)
|
|
{
|
|
dwErr = g_pDataStoreMgr->GetDriveTable()->
|
|
ForAllDrives(&CDataStore::SwitchRestorePoint,
|
|
(LONG_PTR) pwsp->pRpLast);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
trace(0, "! SwitchRestorePoint : %ld", dwErr);
|
|
}
|
|
|
|
// if this is parallelized, then check fifo conditions here
|
|
// else check it in SRSetRestorePointS
|
|
|
|
if (! pwsp->fSerialized)
|
|
{
|
|
g_pDataStoreMgr->TriggerFreezeOrFifo();
|
|
}
|
|
}
|
|
|
|
if (pwsp)
|
|
{
|
|
if (pwsp->pRpLast)
|
|
delete pwsp->pRpLast;
|
|
delete pwsp;
|
|
pwsp = NULL;
|
|
trace(0, "DoWMISnapshot released pwsp");
|
|
}
|
|
|
|
// release the datastore lock
|
|
|
|
if (fHaveLock)
|
|
{
|
|
if (g_pEventHandler)
|
|
g_pEventHandler->GetLock()->Unlock();
|
|
}
|
|
|
|
if (! fSerialized && g_pEventHandler)
|
|
g_pEventHandler->GetCounter()->Down();
|
|
|
|
TraceFunctLeave();
|
|
return dwErr;
|
|
}
|
|
|
|
DWORD RestoreWMISnapshot(WCHAR * pszSnapshotDir)
|
|
{
|
|
TraceFunctEnter("RestoreWMISnapshot");
|
|
|
|
IWbemBackupRestoreEx *wbem = NULL;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
HRESULT hr = S_OK;
|
|
BOOL fPaused = FALSE;
|
|
WCHAR szWMIBackupFile[MAX_PATH];
|
|
WCHAR szWMIRepository[MAX_PATH];
|
|
WCHAR szWMITemp[MAX_PATH];
|
|
CTokenPrivilege tp;
|
|
|
|
// construct the path of the database backup file
|
|
CreateWMISnapShotFileName(pszSnapshotDir, szWMIBackupFile);
|
|
|
|
GetSystemDirectory (szWMIRepository, MAX_PATH);
|
|
lstrcpyW (szWMITemp, szWMIRepository);
|
|
|
|
lstrcatW (szWMIRepository, L"\\Wbem\\Repository");
|
|
lstrcatW (szWMITemp, L"\\Wbem\\Repository.tmp");
|
|
|
|
Delnode_Recurse (szWMITemp, TRUE, NULL); // delete previous temp dirs
|
|
if (FALSE == CreateDirectoryW (szWMITemp, NULL))
|
|
{
|
|
dwErr = GetLastError();
|
|
if (dwErr != ERROR_ALREADY_EXISTS)
|
|
{
|
|
ErrorTrace(0, "Failed to create WMI temp dir. Ignoring error=0x%x", dwErr);
|
|
dwErr = ERROR_SUCCESS;
|
|
goto cleanup;
|
|
}
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
|
|
dwErr = CopyFile_Recurse (szWMIBackupFile, szWMITemp);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "Failed CopyFile_Recurse. Ignoring error=0x%x", dwErr);
|
|
dwErr = ERROR_SUCCESS;
|
|
Delnode_Recurse (szWMITemp, TRUE, NULL);
|
|
goto cleanup;
|
|
}
|
|
|
|
lstrcpyW (szWMIBackupFile, szWMIRepository);
|
|
lstrcatW (szWMIBackupFile, L".bak");
|
|
|
|
// If WMI is still running, try to stop it
|
|
if ( SUCCEEDED(hr = CoCreateInstance( CLSID_WbemBackupRestore,
|
|
NULL,
|
|
CLSCTX_LOCAL_SERVER,
|
|
IID_IWbemBackupRestoreEx,
|
|
(LPVOID*)&wbem )) )
|
|
{
|
|
tp.SetPrivilegeInAccessToken(SE_BACKUP_NAME);
|
|
fPaused = SUCCEEDED(hr = wbem->Pause());
|
|
if (FAILED(hr))
|
|
TRACE(0, "Wbem Pause failed ignoring %x", hr);
|
|
}
|
|
else
|
|
{
|
|
TRACE(0, "CoCreateInstance failed ignoring %x", hr);
|
|
}
|
|
|
|
Delnode_Recurse (szWMIBackupFile, TRUE, NULL); // delete leftover backups
|
|
if (FALSE == MoveFile(szWMIRepository, szWMIBackupFile))
|
|
{
|
|
dwErr = GetLastError();
|
|
ErrorTrace(0, "! MoveFile : %ld trying SrMoveFileEx", dwErr);
|
|
|
|
// WMI has locked files, so try SrMoveFileEx
|
|
dwErr = SrMoveFileEx(pszSnapshotDir, szWMIRepository, szWMIBackupFile);
|
|
if (ERROR_SUCCESS == dwErr)
|
|
{
|
|
dwErr = SrMoveFileEx(pszSnapshotDir, szWMITemp, szWMIRepository);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
ErrorTrace(0, "! SRMoveFileEx : %ld", dwErr);
|
|
}
|
|
else
|
|
{
|
|
ErrorTrace(0, "! SRMoveFileEx : %ld", dwErr);
|
|
Delnode_Recurse (szWMITemp, TRUE, NULL);
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
if (FALSE == MoveFile(szWMITemp, szWMIRepository))
|
|
{
|
|
dwErr = GetLastError();
|
|
ErrorTrace(0, "! MoveFile : %ld", dwErr);
|
|
goto cleanup;
|
|
}
|
|
|
|
Delnode_Recurse (szWMIBackupFile, TRUE, NULL);
|
|
|
|
cleanup:
|
|
|
|
if (wbem != NULL)
|
|
{
|
|
if (fPaused)
|
|
wbem->Resume();
|
|
wbem->Release();
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
DWORD DoIISSnapshot(WCHAR * pszSnapshotDir)
|
|
{
|
|
TraceFunctEnter("DoIISSnapshot");
|
|
|
|
DWORD dwReturn=ERROR_INTERNAL_ERROR;
|
|
HRESULT hr;
|
|
WCHAR szRestorePath[MAX_PATH], szBackup[MAX_PATH], szTemp[MAX_PATH];
|
|
IMSAdminBase2W *pims = NULL;
|
|
|
|
// construct the path of the database backup file
|
|
wsprintf(szRestorePath, L"%s\\%s", pszSnapshotDir, s_cszIISBackupFile);
|
|
|
|
hr = CoCreateInstance( CLSID_MSAdminBase_W,
|
|
NULL,
|
|
CLSCTX_ALL,
|
|
IID_IMSAdminBase2_W,
|
|
(LPVOID*)&pims);
|
|
if (FAILED(hr))
|
|
{
|
|
ErrorTrace(0, "! CoCreateInstance : 0x%x - ignoring error", hr);
|
|
dwReturn = ERROR_SUCCESS;
|
|
goto cleanup;
|
|
}
|
|
|
|
hr = pims->BackupWithPasswd(s_cszIISBackupFile,
|
|
MD_BACKUP_MAX_VERSION,
|
|
MD_BACKUP_OVERWRITE | MD_BACKUP_SAVE_FIRST | MD_BACKUP_FORCE_BACKUP,
|
|
NULL);
|
|
pims->Release() ;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ErrorTrace(0, "! BackupWithPasswd : 0x%x", hr);
|
|
dwReturn = (DWORD) hr;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// move the file from their backup to our backup
|
|
//
|
|
|
|
if (0 == ExpandEnvironmentStrings(s_cszIISBackupPath, szTemp, MAX_PATH))
|
|
{
|
|
dwReturn = GetLastError();
|
|
ErrorTrace(0, "! ExpandEnvironmentStrings : %ld", dwReturn);
|
|
goto cleanup;
|
|
}
|
|
wsprintf(szBackup, L"%s%s%s%d", szTemp, s_cszIISBackupFile, s_cszIISSuffix, MD_BACKUP_MAX_VERSION);
|
|
|
|
if (FALSE == MoveFile(szBackup, szRestorePath))
|
|
{
|
|
dwReturn = GetLastError();
|
|
ErrorTrace(0, "! MoveFile : %ld", dwReturn);
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
DWORD RestoreIISSnapshot(WCHAR * pszSnapshotDir)
|
|
{
|
|
TraceFunctEnter("RestoreIISSnapshot");
|
|
|
|
DWORD dwReturn=ERROR_INTERNAL_ERROR;
|
|
HRESULT hr;
|
|
WCHAR szRestorePath[MAX_PATH], szDest[MAX_PATH];
|
|
IMSAdminBase2W *pims = NULL;
|
|
|
|
// construct the path of the database backup file
|
|
|
|
wsprintf(szRestorePath, L"%s\\%s", pszSnapshotDir, s_cszIISBackupFile);
|
|
|
|
//
|
|
// if we don't have the file
|
|
// there is nothing to restore
|
|
//
|
|
|
|
if (0xFFFFFFFF == GetFileAttributes(szRestorePath))
|
|
{
|
|
DebugTrace(0, "IIS snapshot does not exist");
|
|
dwReturn = ERROR_SUCCESS;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// copy the file from our backup to their original location -
|
|
// we can do a simple copy here because IIS should be shutdown
|
|
// at this time
|
|
//
|
|
|
|
if (0 == ExpandEnvironmentStrings(s_cszIISOriginalPath, szDest, MAX_PATH))
|
|
{
|
|
dwReturn = GetLastError();
|
|
ErrorTrace(0, "! ExpandEnvironmentStrings : %ld", dwReturn);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (ERROR_SUCCESS != (dwReturn = SnapshotCopyFile(szRestorePath, szDest)))
|
|
{
|
|
ErrorTrace(0, "! SnapshotCopyFile : %ld", dwReturn);
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SnapshotRestoreFilelistFiles(LPWSTR pszSnapshotDir, BOOL fSnapshot)
|
|
{
|
|
TraceFunctEnter("SnapshotRestoreFilelistFiles");
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
DWORD dwIndex, dwDataSize, dwSize;
|
|
LPWSTR pszFilePart = NULL ;
|
|
HKEY hKey = NULL;
|
|
BOOL fLoaded = FALSE;
|
|
|
|
if (fSnapshot == FALSE) // restore
|
|
{
|
|
//
|
|
// load the software hive of the registry to be restored
|
|
//
|
|
|
|
WCHAR szSoftwareHive[MAX_PATH];
|
|
|
|
wsprintf(szSoftwareHive,
|
|
L"%s\\%s%s",
|
|
pszSnapshotDir,
|
|
s_cszHKLMFilePrefix,
|
|
s_cszSoftwareHiveName);
|
|
|
|
CHECKERR( RegLoadKey(HKEY_LOCAL_MACHINE,
|
|
LOAD_KEY_NAME,
|
|
szSoftwareHive),
|
|
L"RegLoadKey" );
|
|
|
|
fLoaded = TRUE;
|
|
}
|
|
|
|
|
|
|
|
{
|
|
WCHAR szCallbacksKey[MAX_PATH];
|
|
|
|
wsprintf(szCallbacksKey,
|
|
L"%s\\%s\\%s",
|
|
fSnapshot ? L"Software" : LOAD_KEY_NAME,
|
|
s_cszSRRegKey2, s_cszCallbacksRegKey);
|
|
|
|
DebugTrace(0, "CallbacksKey=%S", szCallbacksKey);
|
|
|
|
//
|
|
// call registered snapshot callbacks
|
|
//
|
|
|
|
dwErr = CallSnapshotCallbacks(szCallbacksKey, pszSnapshotDir, fSnapshot);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
ErrorTrace(0, "! CallSnapshotCallbacks : %ld - ignoring", dwErr);
|
|
}
|
|
}
|
|
|
|
|
|
{
|
|
WCHAR szSnapshotKey[MAX_PATH];
|
|
|
|
wsprintf(szSnapshotKey,
|
|
L"%s\\%s\\%s",
|
|
fSnapshot ? L"Software" : LOAD_KEY_NAME,
|
|
s_cszSRRegKey2, s_cszSRSnapshotRegKey);
|
|
|
|
DebugTrace(0, "SnapshotFilesKey=%S", szSnapshotKey);
|
|
|
|
dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
szSnapshotKey,
|
|
0,
|
|
KEY_READ,
|
|
&hKey);
|
|
if (dwErr != ERROR_SUCCESS) // assume key does not exist
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
DebugTrace(0, "No filelist files to snapshot/restore");
|
|
goto Err;
|
|
}
|
|
}
|
|
|
|
|
|
for (dwIndex = 0; TRUE; dwIndex ++)
|
|
{
|
|
WCHAR szValue[MAX_PATH], szDest[MAX_PATH], szFile[MAX_PATH];
|
|
|
|
dwSize = sizeof(szValue)/sizeof(WCHAR);
|
|
dwDataSize = sizeof(szFile); // this is in bytes
|
|
|
|
dwErr = RegEnumValue(hKey, // handle to key to query
|
|
dwIndex, // index of value to query
|
|
szValue, // value buffer
|
|
&dwSize, // size of value buffer
|
|
NULL, // reserved
|
|
NULL, // type buffer
|
|
(PBYTE) szFile, // data buffer
|
|
&dwDataSize); // size of data buffer
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (lstrlen(szFile) == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// construct snapshot file path
|
|
// make a unique name for it by appending the enum index
|
|
//
|
|
|
|
pszFilePart = wcsrchr(szFile, L'\\');
|
|
if (pszFilePart)
|
|
{
|
|
pszFilePart++;
|
|
}
|
|
else
|
|
{
|
|
pszFilePart = szFile;
|
|
}
|
|
|
|
wsprintf(szDest, L"%s\\%s-%d", pszSnapshotDir, pszFilePart, dwIndex);
|
|
|
|
//
|
|
// copy the file
|
|
// if file does not exist, keep going
|
|
//
|
|
|
|
if (fSnapshot) // from orig location to snapshot dir
|
|
{
|
|
SnapshotCopyFile(szFile, szDest);
|
|
}
|
|
else // from snapshot dir to orig location
|
|
{
|
|
SnapshotCopyFile(szDest, szFile);
|
|
}
|
|
}
|
|
|
|
if (ERROR_NO_MORE_ITEMS == dwErr)
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
ErrorTrace(0, "! RegEnumValue : %ld", dwErr);
|
|
}
|
|
|
|
Err:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
if (fLoaded)
|
|
RegUnLoadKey( HKEY_LOCAL_MACHINE, LOAD_KEY_NAME );
|
|
|
|
TraceFunctLeave();
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
DWORD CTokenPrivilege::SetPrivilegeInAccessToken(WCHAR * pszPrivilegeName)
|
|
{
|
|
TraceFunctEnter("CSnapshot::SetPrivilegeInAccessToken");
|
|
|
|
HANDLE hProcess;
|
|
HANDLE hAccessToken=NULL;
|
|
LUID luidPrivilegeLUID;
|
|
TOKEN_PRIVILEGES tpTokenPrivilege; // enough for 1 priv
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
hProcess = GetCurrentProcess();
|
|
if (!hProcess)
|
|
{
|
|
dwErr = GetLastError();
|
|
ErrorTrace(0, "GetCurrentProcess failed ec=%d", dwErr);
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// If there is a thread token, attempt to use it first
|
|
//
|
|
if (!OpenThreadToken (GetCurrentThread(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
TRUE, // check against process's security context
|
|
&hAccessToken))
|
|
{
|
|
if (!OpenProcessToken(hProcess,
|
|
TOKEN_DUPLICATE | TOKEN_QUERY,
|
|
&hAccessToken))
|
|
{
|
|
dwErr=GetLastError();
|
|
ErrorTrace(0, "OpenProcessToken failed ec=%d", dwErr);
|
|
goto done;
|
|
}
|
|
|
|
HANDLE hNewToken; // dup the process token to workaround RPC problem
|
|
|
|
if (FALSE == DuplicateTokenEx (hAccessToken,
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE,
|
|
NULL, SecurityImpersonation,
|
|
TokenImpersonation, &hNewToken))
|
|
{
|
|
dwErr=GetLastError();
|
|
ErrorTrace(0, "DuplicateTokenEx failed ec=%d", dwErr);
|
|
goto done;
|
|
}
|
|
|
|
CloseHandle (hAccessToken); // close the old process token
|
|
hAccessToken = hNewToken; // use the new thread token
|
|
|
|
if (TRUE == SetThreadToken (NULL, hAccessToken))
|
|
{
|
|
m_fNewToken = TRUE;
|
|
}
|
|
else
|
|
{
|
|
dwErr = GetLastError();
|
|
ErrorTrace(0, "SetThreadToken failed ec=%d", dwErr);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (!LookupPrivilegeValue(NULL,
|
|
pszPrivilegeName,
|
|
&luidPrivilegeLUID))
|
|
{
|
|
dwErr=GetLastError();
|
|
ErrorTrace(0, "LookupPrivilegeValue failed ec=%d",dwErr);
|
|
goto done;
|
|
}
|
|
|
|
tpTokenPrivilege.PrivilegeCount = 1;
|
|
tpTokenPrivilege.Privileges[0].Luid = luidPrivilegeLUID;
|
|
tpTokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
if (!AdjustTokenPrivileges(hAccessToken,
|
|
FALSE, // Do not disable all
|
|
&tpTokenPrivilege,
|
|
sizeof(TOKEN_PRIVILEGES),
|
|
NULL, // Ignore previous info
|
|
NULL)) // Ignore previous info
|
|
{
|
|
dwErr=GetLastError();
|
|
ErrorTrace(0, "AdjustTokenPrivileges %ld", dwErr);
|
|
goto done;
|
|
}
|
|
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
done:
|
|
if (hAccessToken != NULL)
|
|
{
|
|
_VERIFY(TRUE==CloseHandle(hAccessToken));
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return dwErr;
|
|
}
|
|
|
|
void RemoveReliabilityKey(WCHAR * pszSoftwareHive)
|
|
{
|
|
HKEY LocalKey = NULL;
|
|
DWORD dwStatus, disposition;
|
|
|
|
dwStatus = RegLoadKey( HKEY_LOCAL_MACHINE,
|
|
LOAD_KEY_NAME,
|
|
pszSoftwareHive);
|
|
|
|
if ( ERROR_SUCCESS == dwStatus )
|
|
{
|
|
|
|
/*
|
|
* Open the reliability key
|
|
*/
|
|
|
|
dwStatus = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
|
|
LOAD_KEY_NAME TEXT("\\Microsoft\\Windows\\CurrentVersion\\Reliability"),
|
|
0,
|
|
NULL,
|
|
REG_OPTION_BACKUP_RESTORE,
|
|
MAXIMUM_ALLOWED,
|
|
NULL,
|
|
&LocalKey,
|
|
&disposition );
|
|
|
|
if ( ERROR_SUCCESS == dwStatus )
|
|
{
|
|
RegDeleteValue( LocalKey, TEXT("LastAliveStamp") ) ;
|
|
RegCloseKey( LocalKey ) ;
|
|
}
|
|
|
|
RegFlushKey( HKEY_LOCAL_MACHINE );
|
|
RegUnLoadKey( HKEY_LOCAL_MACHINE, LOAD_KEY_NAME );
|
|
}
|
|
}
|
|
|
|
|
|
DWORD CopyHKLMHiveForRestore(WCHAR * pszSnapshotDir, // Directory where
|
|
// snapshot files are kept
|
|
const WCHAR * pszRegBackupFile)
|
|
// Registry backup file
|
|
{
|
|
TraceFunctEnter("CopyHKLMHiveForRestore");
|
|
|
|
DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
|
|
WCHAR szDataFile[MAX_PATH], szBackupFile[MAX_PATH];
|
|
|
|
if (IsRestoreCopy(pszRegBackupFile))
|
|
{
|
|
DebugTrace(0,"%S is already a backup file. Ignoring",pszRegBackupFile);
|
|
dwReturn = ERROR_SUCCESS;
|
|
goto cleanup;
|
|
}
|
|
|
|
/*
|
|
// if patch file, ignore
|
|
|
|
if (lstrcmpi(pszRegBackupFile + lstrlen(pszRegBackupFile) - lstrlen(s_cszPatchExtension), s_cszPatchExtension) != NULL)
|
|
{
|
|
DebugTrace(0, "%S is a patch file. Ignoring", pszRegBackupFile);
|
|
dwReturn = ERROR_SUCCESS;
|
|
goto cleanup;
|
|
}
|
|
*/
|
|
|
|
// construct the path name of the datafile
|
|
wsprintf(szDataFile, L"%s\\%s", pszSnapshotDir, pszRegBackupFile);
|
|
|
|
// construct the path name of the backup file
|
|
wsprintf(szBackupFile, L"%s\\%s%s", pszSnapshotDir, pszRegBackupFile,
|
|
s_cszRegHiveCopySuffix);
|
|
|
|
dwErr = SnapshotCopyFile(szDataFile, szBackupFile);
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
cleanup:
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
DWORD RestoreHKLMHive(WCHAR * pszSnapshotDir, // Directory where
|
|
// snapshot files are kept
|
|
const WCHAR * pszRegBackupFile) // Registry backup file
|
|
{
|
|
TraceFunctEnter("RestoreHKLMHive");
|
|
|
|
DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
|
|
DWORD dwDisposition, dwHiveNameLength;
|
|
WCHAR szHiveName[MAX_PATH];
|
|
WCHAR szDataFile[MAX_PATH];
|
|
|
|
// first ignore anything with a . in it. This is because a
|
|
// valid HKLM hive file will not have a . in it.
|
|
if (wcschr(pszRegBackupFile, L'.'))
|
|
{
|
|
dwReturn = ERROR_SUCCESS;
|
|
goto cleanup;
|
|
}
|
|
|
|
// construct the Hive name
|
|
// 1. copy everything after the HKLM prefix into the buffer
|
|
lstrcpy(szHiveName,
|
|
pszRegBackupFile+ lstrlen(s_cszHKLMPrefix));
|
|
// 2. now NULL terminate where the RestoreCopySuffix starts
|
|
dwHiveNameLength = lstrlen(szHiveName) - lstrlen(s_cszRegHiveCopySuffix);
|
|
szHiveName[dwHiveNameLength] = L'\0';
|
|
|
|
|
|
// construct the path name of the datafile and the backup file
|
|
wsprintf(szDataFile, L"%s\\%s", pszSnapshotDir, pszRegBackupFile);
|
|
|
|
if (0==lstrcmpi(szHiveName, s_cszSoftwareHiveName))
|
|
{
|
|
// if this is the software key then the LastAliveStamp must
|
|
// be deleted
|
|
RemoveReliabilityKey(szDataFile);
|
|
}
|
|
dwErr = SetNewRegistry(HKEY_LOCAL_MACHINE, // handle to open key
|
|
szHiveName, // subkey name
|
|
szDataFile, // data file
|
|
NULL,
|
|
NULL);
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "SetNewRegistry failed for %S, error %ld, file %S",
|
|
szHiveName, dwErr, pszRegBackupFile);
|
|
// now check to see if this is a well known HKLM hive. If not,
|
|
// ignore any errors in restoring this hive
|
|
if (FALSE==IsWellKnownHKLMHive(szHiveName))
|
|
{
|
|
dwReturn=ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
dwReturn = dwErr;
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
// the following loads the HKLM hive stored in the pszSnapshotDir
|
|
// in a temprary place.
|
|
DWORD LoadTempHKLM(IN WCHAR * pszSnapshotDir,
|
|
IN const WCHAR * pszHKLMHiveFile,
|
|
OUT HKEY * phKeyTempHKLM)
|
|
{
|
|
TraceFunctEnter("LoadTempHKLM");
|
|
|
|
DWORD dwErr, dwDisposition, i, dwResult=ERROR_INTERNAL_ERROR;
|
|
|
|
*phKeyTempHKLM = NULL;
|
|
|
|
dwErr = RegLoadKey( HKEY_LOCAL_MACHINE,// handle to open key
|
|
s_cszRestoreTempKey,// subkey name
|
|
pszHKLMHiveFile);// registry file name
|
|
|
|
if ( ERROR_SUCCESS != dwErr )
|
|
{
|
|
ErrorTrace(0, "Failed ::RegLoadKey('%S') ec=%d",
|
|
pszHKLMHiveFile, dwErr);
|
|
dwResult= dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
// this is how to unload the above hive
|
|
// RegUnLoadKey( HKEY_LOCAL_MACHINE, s_cszRestoreTempKey);
|
|
|
|
|
|
dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,// handle to open key
|
|
s_cszRestoreTempKey,// subkey name
|
|
0,// reserved
|
|
KEY_WRITE|KEY_READ,// security access mask
|
|
phKeyTempHKLM);// handle to open key
|
|
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0,"Error %d in opening base key %S",
|
|
dwErr, s_cszRestoreTempKey);
|
|
_VERIFY(ERROR_SUCCESS == RegUnLoadKey( HKEY_LOCAL_MACHINE,
|
|
s_cszRestoreTempKey));
|
|
dwResult= dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwResult = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
TraceFunctLeave();
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CSnapshot::RestoreRegistrySnapshot(WCHAR * pszSnapshotDir)
|
|
{
|
|
|
|
DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
|
|
HKEY hKeyTempHKLM=NULL;
|
|
WCHAR szHKLMHiveCopy[MAX_PATH], szHKLMHive[MAX_PATH];
|
|
WCHAR szHKLMPrefix[MAX_PATH];
|
|
CTokenPrivilege tp;
|
|
|
|
|
|
|
|
TraceFunctEnter("CSnapshot::RestoreRegistrySnapshot");
|
|
|
|
dwErr = tp.SetPrivilegeInAccessToken(SE_RESTORE_NAME);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "SetPrivilegeInAccessToken failed ec=%d", dwErr);
|
|
dwReturn = ERROR_PRIVILEGE_NOT_HELD;
|
|
goto cleanup;
|
|
}
|
|
|
|
// now create the path of the HKLM software hive.
|
|
|
|
// first construct the name of the file that stores the HKLM registry
|
|
// snapshot.
|
|
wsprintf(szHKLMHive,L"%s\\%s%s", pszSnapshotDir, s_cszHKLMFilePrefix,
|
|
s_cszSoftwareHiveName);
|
|
|
|
// to restore the user profiles, we need to first load the HKLM
|
|
// hive in a temporary place so that we can read the profile paths.
|
|
|
|
// copy this hive a temporary file
|
|
wsprintf(szHKLMHiveCopy, L"%s.backuphive", szHKLMHive);
|
|
|
|
DeleteFile(szHKLMHiveCopy); // delete it if it already exists
|
|
|
|
if (! CopyFile(szHKLMHive, szHKLMHiveCopy, FALSE))
|
|
{
|
|
dwErr = GetLastError();
|
|
ErrorTrace(0, "CopyFile failed. ec=%d", dwErr);
|
|
|
|
LogDSFileTrace(0,L"src= ", szHKLMHive);
|
|
LogDSFileTrace(0,L"dst= ", szHKLMHiveCopy);
|
|
|
|
if (ERROR_SUCCESS!= dwErr)
|
|
{
|
|
dwReturn = dwErr;
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
dwErr = LoadTempHKLM(pszSnapshotDir, szHKLMHiveCopy, &hKeyTempHKLM);
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
// could not load hKeyTempHKLM - fatal error
|
|
dwReturn = dwErr;
|
|
ErrorTrace(0, "LoadTempHKLM failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
// need to copy back ntuser.dat for each user
|
|
dwErr = ProcessHKUsersKey(pszSnapshotDir,
|
|
hKeyTempHKLM,
|
|
TRUE); // need to do a restore - not a snapshot
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "DoHKUsersSnapshot failed error %ld", dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
// first construct the prefix of the files that store the HKLM registry
|
|
// snapshot.
|
|
wsprintf(szHKLMPrefix, L"%s\\%s*%s", pszSnapshotDir, s_cszHKLMFilePrefix,
|
|
s_cszRegHiveCopySuffix);
|
|
|
|
// need to use RegReplaceKey to restore each hive of the registry
|
|
dwErr = ProcessGivenFiles(pszSnapshotDir, RestoreHKLMHive,
|
|
szHKLMPrefix);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "ProcessGivenFiles failed error %ld", dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
// if the HKLM hive is loaded, unload it.
|
|
if (NULL != hKeyTempHKLM)
|
|
{
|
|
_VERIFY(ERROR_SUCCESS==RegCloseKey(hKeyTempHKLM));
|
|
_VERIFY(ERROR_SUCCESS == RegUnLoadKey( HKEY_LOCAL_MACHINE,
|
|
s_cszRestoreTempKey));
|
|
}
|
|
|
|
// delete the copy of HKLM software hive - note that this will
|
|
// fail if the copy file failed.
|
|
DeleteFile(szHKLMHiveCopy);
|
|
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CSnapshot::RestoreCOMDbSnapshot(WCHAR * pszSnapShotDir)
|
|
{
|
|
// need to restore COM+ Db using RegDBRestore
|
|
TraceFunctEnter("CSnapshot::RestoreCOMDbSnapshot");
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
|
|
HMODULE hModCOMDll=NULL;
|
|
HRESULT hr;
|
|
WCHAR szCOMDBFile[MAX_PATH];
|
|
|
|
|
|
if (NULL == m_pfnRegDbRestore)
|
|
{
|
|
dwErr = GetCOMplusRestoreFN();
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
// construct the path of the database backup file
|
|
CreateCOMDBSnapShotFileName(pszSnapShotDir, szCOMDBFile);
|
|
|
|
hr =m_pfnRegDbRestore( szCOMDBFile );
|
|
|
|
// call the function to backup the file
|
|
if ( FAILED(hr))
|
|
{
|
|
ErrorTrace(0, "Failed to restore COM DB. hr=0x%x", hr);
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
DWORD
|
|
CSnapshot::RestoreSnapshot(WCHAR * pszRestoreDir)
|
|
{
|
|
TraceFunctEnter("CSnapshot::RestoreSnapshot");
|
|
|
|
WCHAR szSnapShotDir[MAX_PATH];
|
|
DWORD dwErr;
|
|
DWORD dwReturn = ERROR_INTERNAL_ERROR;
|
|
BOOL fCoInitialized = FALSE;
|
|
HKEY hKey = NULL;
|
|
|
|
struct {
|
|
DWORD FilelistFiles : 1;
|
|
DWORD COMDb : 1;
|
|
DWORD WMI : 1;
|
|
DWORD IIS : 1;
|
|
DWORD Registry : 1;
|
|
} ItemsCompleted = {0,0,0,0,0};
|
|
|
|
HRESULT hr;
|
|
|
|
// create the snapshot directory name from the restore directory
|
|
// name and create the actual directory.
|
|
lstrcpy(szSnapShotDir, pszRestoreDir);
|
|
lstrcat(szSnapShotDir, SNAPSHOT_DIR_NAME);
|
|
// does the directory exist ?
|
|
if (FALSE == DoesDirExist( szSnapShotDir)) // SD
|
|
{
|
|
ErrorTrace(0, "Snapshot directory does not exist");
|
|
goto cleanup;
|
|
}
|
|
|
|
// restore files listed in filelist.xml
|
|
dwErr = SnapshotRestoreFilelistFiles(szSnapShotDir, FALSE);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// mark completion
|
|
//
|
|
|
|
ItemsCompleted.FilelistFiles = 1;
|
|
|
|
// Restore COM snapshot
|
|
dwErr = RestoreCOMDbSnapshot(szSnapShotDir);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// mark completion
|
|
//
|
|
|
|
ItemsCompleted.COMDb = 1;
|
|
|
|
hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
|
|
if (hr == RPC_E_CHANGED_MODE)
|
|
{
|
|
//
|
|
// someone called it with other mode
|
|
//
|
|
|
|
hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
dwReturn = (DWORD) hr;
|
|
ErrorTrace(0, "! CoInitializeEx : %ld", dwReturn);
|
|
goto cleanup;
|
|
}
|
|
|
|
fCoInitialized = TRUE;
|
|
|
|
|
|
// restore perf counters
|
|
|
|
// restore WMI snapshot
|
|
dwErr = RestoreWMISnapshot(szSnapShotDir);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// mark completion
|
|
//
|
|
|
|
ItemsCompleted.WMI = 1;
|
|
|
|
// restore IIS snapshot
|
|
dwErr = RestoreIISSnapshot(szSnapShotDir);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// mark completion
|
|
//
|
|
|
|
ItemsCompleted.IIS = 1;
|
|
|
|
//
|
|
// support debug hook to force failure path
|
|
// this is checked before the registry restore
|
|
// because registry revert does not work
|
|
//
|
|
|
|
if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
SRREG_PATH_SHELL,
|
|
0,
|
|
KEY_READ,
|
|
&hKey) )
|
|
{
|
|
DWORD dwDebugTestUndo;
|
|
if (ERROR_SUCCESS == RegReadDWORD(hKey, SRREG_VAL_DEBUGTESTUNDO, &dwDebugTestUndo))
|
|
{
|
|
if (dwDebugTestUndo != 0)
|
|
{
|
|
DebugTrace(0, "*** Initiating UNDO for test purposes ***");
|
|
dwReturn = ERROR_INTERNAL_ERROR;
|
|
RegCloseKey(hKey);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// now the registry snapshot is not atomic, so if we start it,
|
|
// we have should assume it made changes. so we mark it in advance
|
|
// such that it if fails, we will blast the safe registry over the current
|
|
// registry, effectively rolling back the partial changes the failed
|
|
// call made. this is a brute force, but simple, way to handle this error
|
|
// case, which we expect will never happen. InitRestoreSnapshot makes
|
|
// all of the proper checks to ensure this api will succeed when called.
|
|
//
|
|
|
|
//
|
|
// update: rollback of registry is not really working
|
|
// because RegReplaceKey fails on an already replaced hive
|
|
// so this might result in reverted user hives and unreverted software/system
|
|
// hives, which is pretty bad
|
|
// so disable this functionality
|
|
//
|
|
|
|
// ItemsCompleted.Registry = 1;
|
|
|
|
//
|
|
// Restore resgistry snapshot
|
|
//
|
|
|
|
dwErr = this->RestoreRegistrySnapshot(szSnapShotDir);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
//
|
|
// do we need to clean up any completed items due to a failed restore?
|
|
//
|
|
|
|
if (dwReturn != ERROR_SUCCESS)
|
|
{
|
|
CRestorePoint rp;
|
|
WCHAR szSafeDir[MAX_PATH];
|
|
WCHAR szSystemVolume[8];
|
|
|
|
dwErr = 0;
|
|
|
|
DebugTrace(0, "srrstr!Error in RestoreSnapshot\n");
|
|
|
|
//
|
|
// get the "current" restore point location, it has a snapshot
|
|
// of how things where prior to starting this restore
|
|
//
|
|
|
|
dwErr = GetCurrentRestorePoint(rp);
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
DebugTrace(0, "srrstr!GetCurrentRestorePoint failed!\n");
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// make sure the "safe" snapshot is there for us to use
|
|
//
|
|
|
|
GetSystemDrive(szSystemVolume);
|
|
MakeRestorePath(szSafeDir, szSystemVolume, rp.GetDir());
|
|
|
|
|
|
if (ItemsCompleted.Registry) {
|
|
if (ERROR_SUCCESS != InitRestoreSnapshot(szSafeDir)) {
|
|
DebugTrace(0, "! InitRestoreSnapshot");
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
lstrcat(szSafeDir, SNAPSHOT_DIR_NAME);
|
|
if (DoesDirExist(szSafeDir) == FALSE)
|
|
{
|
|
DebugTrace(0, "srrstr!Safe snapshot directory does not exist!\n");
|
|
goto end;
|
|
}
|
|
|
|
DebugTrace(0, "srrstr!Safe restore point %S\n", szSafeDir);
|
|
|
|
//
|
|
// roll them back in reverse order
|
|
//
|
|
|
|
if (ItemsCompleted.Registry) {
|
|
dwErr = RestoreRegistrySnapshot(szSafeDir);
|
|
// ignore any error's, we want to restore as much as we can
|
|
_ASSERT(dwErr == ERROR_SUCCESS);
|
|
DebugTrace(0, "srrstr!Restored registry\n");
|
|
}
|
|
if (ItemsCompleted.IIS) {
|
|
dwErr = RestoreIISSnapshot(szSafeDir);
|
|
// ignore any error's, we want to restore as much as we can
|
|
_ASSERT(dwErr == ERROR_SUCCESS);
|
|
DebugTrace(0, "srrstr!Restored IIS\n");
|
|
}
|
|
if (ItemsCompleted.WMI) {
|
|
dwErr = RestoreWMISnapshot(szSafeDir);
|
|
// ignore any error's, we want to restore as much as we can
|
|
_ASSERT(dwErr == ERROR_SUCCESS);
|
|
DebugTrace(0, "srrstr!Restored WMI\n");
|
|
}
|
|
if (ItemsCompleted.COMDb) {
|
|
dwErr = RestoreCOMDbSnapshot(szSafeDir);
|
|
// ignore any error's, we want to restore as much as we can
|
|
_ASSERT(dwErr == ERROR_SUCCESS);
|
|
DebugTrace(0, "srrstr!Restored COMDb\n");
|
|
}
|
|
if (ItemsCompleted.FilelistFiles) {
|
|
dwErr = SnapshotRestoreFilelistFiles(szSafeDir, FALSE);
|
|
// ignore any error's, we want to restore as much as we can
|
|
_ASSERT(dwErr == ERROR_SUCCESS);
|
|
DebugTrace(0, "srrstr!Restored FilelistFiles\n");
|
|
}
|
|
|
|
end:
|
|
//
|
|
// not much to do
|
|
//
|
|
;
|
|
|
|
}
|
|
|
|
if (fCoInitialized)
|
|
CoUninitialize();
|
|
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
// this returns the path of the system hive. The caller must pass
|
|
// in a buffer with lenght of this buffer in dwNumChars
|
|
DWORD
|
|
CSnapshot::GetSystemHivePath(WCHAR * pszRestoreDir,
|
|
WCHAR * pszHivePath,
|
|
DWORD dwNumChars)
|
|
{
|
|
|
|
// first construct the name of the file that stores the HKLM registry
|
|
// snapshot.
|
|
if (dwNumChars < MAX_PATH)
|
|
{
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
wsprintf(pszHivePath,L"%s%s\\%s%s%s", pszRestoreDir, SNAPSHOT_DIR_NAME,
|
|
s_cszHKLMFilePrefix, s_cszSystemHiveName, s_cszRegHiveCopySuffix);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
// this returns the path of the software hive. The caller must pass
|
|
// in a buffer with lenght of this buffer in dwNumChars
|
|
DWORD
|
|
CSnapshot::GetSoftwareHivePath(WCHAR * pszRestoreDir,
|
|
WCHAR * pszHivePath,
|
|
DWORD dwNumChars)
|
|
{
|
|
|
|
// first construct the name of the file that stores the HKLM registry
|
|
// snapshot.
|
|
if (dwNumChars < MAX_PATH)
|
|
{
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
wsprintf(pszHivePath,L"%s%s\\%s%s%s", pszRestoreDir, SNAPSHOT_DIR_NAME,
|
|
s_cszHKLMFilePrefix, s_cszSoftwareHiveName,
|
|
s_cszRegHiveCopySuffix);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD CSnapshot::GetSamHivePath (WCHAR * pszRestoreDir,
|
|
WCHAR * pszHivePath,
|
|
DWORD dwNumChars)
|
|
{
|
|
if (dwNumChars < MAX_PATH)
|
|
{
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
wsprintf(pszHivePath,L"%s%s\\%s%s%s", pszRestoreDir, SNAPSHOT_DIR_NAME,
|
|
s_cszHKLMFilePrefix, s_cszSamHiveName,
|
|
s_cszRegHiveCopySuffix);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
// this checks whether a specific HKLM registry hive is present in the
|
|
// snapshot directory
|
|
DWORD CheckHKLMFile(const WCHAR * pszSnapShotDir,
|
|
const WCHAR * pszHive)
|
|
{
|
|
BOOL dwReturn = ERROR_FILE_NOT_FOUND;
|
|
|
|
TraceFunctEnter("CheckHKLMFile");
|
|
|
|
WCHAR szHivePath[MAX_PATH];
|
|
|
|
// construct the name of the file
|
|
wsprintf(szHivePath,L"%s\\%s%s", pszSnapShotDir, s_cszHKLMFilePrefix,
|
|
pszHive);
|
|
if (FALSE == DoesFileExist(szHivePath))
|
|
{
|
|
LogDSFileTrace(0, L"Can't find", szHivePath);
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn=ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
// this checks whether all the files necessary to restore a snapshot
|
|
// are present in the snapshot directory
|
|
DWORD CheckforCriticalFiles(WCHAR * pszSnapShotDir)
|
|
{
|
|
TraceFunctEnter("CheckforCriticalFiles");
|
|
WCHAR szCOMDBFile[MAX_PATH];
|
|
DWORD dwRet=ERROR_FILE_NOT_FOUND;
|
|
|
|
dwRet=CheckHKLMFile(pszSnapShotDir,s_cszSoftwareHiveName);
|
|
VALIDATE_DWRET ("CheckHKLM file Software");
|
|
|
|
dwRet=CheckHKLMFile(pszSnapShotDir,s_cszSystemHiveName);
|
|
VALIDATE_DWRET ("CheckHKLM file System");
|
|
|
|
dwRet=CheckHKLMFile(pszSnapShotDir,s_cszSamHiveName);
|
|
VALIDATE_DWRET ("CheckHKLM file SAM");
|
|
|
|
dwRet=CheckHKLMFile(pszSnapShotDir,s_cszSecurityHiveName);
|
|
VALIDATE_DWRET ("CheckHKLM file Security");
|
|
|
|
// construct the path of the database backup file
|
|
CreateCOMDBSnapShotFileName(pszSnapShotDir, szCOMDBFile);
|
|
if (FALSE == DoesFileExist(szCOMDBFile))
|
|
{
|
|
LogDSFileTrace(0, L"Can't find", szCOMDBFile);
|
|
dwRet = ERROR_FILE_NOT_FOUND;
|
|
goto Exit;
|
|
}
|
|
|
|
dwRet=ERROR_SUCCESS;
|
|
|
|
Exit:
|
|
TraceFunctLeave();
|
|
return dwRet;
|
|
}
|
|
|
|
// This function must be called to Initialize a restore
|
|
// operation. This must be called before calling
|
|
// GetSystemHivePath GetSoftwareHivePath
|
|
DWORD
|
|
CSnapshot::InitRestoreSnapshot(WCHAR * pszRestoreDir)
|
|
{
|
|
TraceFunctEnter("InitRestoreSnapshot");
|
|
WCHAR szSnapshotDir[MAX_PATH];
|
|
WCHAR szHKLMPrefix[MAX_PATH];
|
|
|
|
// this copies all the HKLM registry hives to a temporary location
|
|
// since:
|
|
// 1. RegReplaceKey will move the file to another location, so
|
|
// we will lose the original registry hive.
|
|
// 2. We need to do this ahead of time becuase we do not want to
|
|
// run out of disk space in the middle of the restore.
|
|
// 3. Restore makes changes to the HKLM hives, we do not want
|
|
// restore to make these changes to the original registry hives.
|
|
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
|
|
|
|
// create the snapshot directory name from the restore directory
|
|
// name and create the actual directory.
|
|
lstrcpy(szSnapshotDir, pszRestoreDir);
|
|
lstrcat(szSnapshotDir, SNAPSHOT_DIR_NAME);
|
|
|
|
|
|
// make sure no obsolete files are left from the previous restore
|
|
// could have happened if admin did not login since the last restore to this restore
|
|
// point
|
|
|
|
CleanupAfterRestore(pszRestoreDir);
|
|
|
|
|
|
dwErr = CheckforCriticalFiles(szSnapshotDir);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0,"CheckforCriticalFiles failed ec=%d",dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
// first construct the prefix of the file that stores the HKLM registry
|
|
// snapshot.
|
|
wsprintf(szHKLMPrefix, L"%s\\%s*", szSnapshotDir, s_cszHKLMFilePrefix);
|
|
|
|
dwErr = ProcessGivenFiles(szSnapshotDir, CopyHKLMHiveForRestore,
|
|
szHKLMPrefix);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "copying hives failed error %ld", dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
DWORD DeleteTempRestoreFile(WCHAR * pszSnapshotDir, // Directory where
|
|
// snapshot files are kept
|
|
const WCHAR * pszTempRestoreFile)
|
|
// Temp file created during restore
|
|
{
|
|
TraceFunctEnter("DeleteTempRestoreFile");
|
|
|
|
DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
|
|
WCHAR szDataFile[MAX_PATH];
|
|
|
|
// construct the path name of the file
|
|
wsprintf(szDataFile, L"%s\\%s", pszSnapshotDir, pszTempRestoreFile);
|
|
|
|
if (TRUE != DeleteFile(szDataFile))
|
|
{
|
|
dwErr = GetLastError();
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
dwReturn = dwErr;
|
|
}
|
|
|
|
ErrorTrace(0, "DeleteFile failed ec=%d", dwErr);
|
|
LogDSFileTrace(0,L"File was ", szDataFile);
|
|
// we will ignore a failure in deleting a file
|
|
//goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
//cleanup:
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
DWORD DeleteAllFilesBySuffix(WCHAR * pszSnapshotDir,
|
|
const WCHAR * pszSuffix)
|
|
{
|
|
TraceFunctEnter("DeleteAllFilesBySuffix");
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
|
|
WCHAR szFindFileData[MAX_PATH];
|
|
|
|
// first construct the prefix of the file that stores the HKLM registry
|
|
// snapshot.
|
|
wsprintf(szFindFileData, L"%s\\*%s", pszSnapshotDir, pszSuffix);
|
|
|
|
dwErr = ProcessGivenFiles(pszSnapshotDir, DeleteTempRestoreFile,
|
|
szFindFileData);
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "Deleting files failed error %ld", dwErr);
|
|
dwReturn = dwErr;
|
|
goto cleanup;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
cleanup:
|
|
TraceFunctLeave();
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
// delete the reconstructed file corresponding to pszPatchFile
|
|
|
|
DWORD DeleteReconstructedTempFile(WCHAR * pszSnapshotDir,
|
|
const WCHAR * pszPatchFile)
|
|
{
|
|
TraceFunctEnter("DeleteReconstructedTempFile");
|
|
|
|
WCHAR szDataFile[MAX_PATH];
|
|
|
|
wsprintf(szDataFile, L"%s\\%s", pszSnapshotDir, pszPatchFile);
|
|
|
|
// remove the extension
|
|
|
|
szDataFile[lstrlen(szDataFile)-lstrlen(s_cszPatchExtension)] = L'\0';
|
|
|
|
if (TRUE != DeleteFile(szDataFile))
|
|
{
|
|
ErrorTrace(0, "! DeleteFile : %ld", GetLastError);
|
|
LogDSFileTrace(0, L"File was ", szDataFile);
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
DWORD DeleteAllReconstructedFiles(WCHAR * pszSnapshotDir)
|
|
{
|
|
TraceFunctEnter("DeleteAllReconstructedFiles");
|
|
|
|
DWORD dwErr=ERROR_INTERNAL_ERROR;
|
|
WCHAR szFindFileData[MAX_PATH];
|
|
|
|
// first construct the prefix of the file that stores the HKLM registry
|
|
// snapshot.
|
|
wsprintf(szFindFileData, L"%s\\*%s", pszSnapshotDir, s_cszPatchExtension);
|
|
|
|
dwErr = ProcessGivenFiles(pszSnapshotDir, DeleteReconstructedTempFile,
|
|
szFindFileData);
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
ErrorTrace(0, "Deleting files failed error %ld", dwErr);
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
TraceFunctLeave();
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
// this function is called after a restore operation. This deletes all
|
|
// the files that were created as part of the restore operation and
|
|
// are not needed now.
|
|
DWORD
|
|
CSnapshot::CleanupAfterRestore(WCHAR * pszRestoreDir)
|
|
{
|
|
WCHAR szSnapshotDir[MAX_PATH];
|
|
|
|
DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
|
|
|
|
// create the snapshot directory name from the restore directory
|
|
// name and create the actual directory.
|
|
lstrcpy(szSnapshotDir, pszRestoreDir);
|
|
lstrcat(szSnapshotDir, SNAPSHOT_DIR_NAME);
|
|
|
|
DeleteAllFilesBySuffix(szSnapshotDir, L".log");
|
|
DeleteAllFilesBySuffix(szSnapshotDir, s_cszRegHiveCopySuffix);
|
|
DeleteAllFilesBySuffix(szSnapshotDir, s_cszRegReplaceBackupSuffix );
|
|
|
|
//
|
|
// delete reconstructed files
|
|
//
|
|
DeleteAllReconstructedFiles(szSnapshotDir);
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
int MyExceptionFilter(int nExceptionCode)
|
|
{
|
|
TENTER("MyExceptionFilter");
|
|
|
|
trace(0, "Exception code=%d", nExceptionCode);
|
|
|
|
TLEAVE();
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
|
|
//
|
|
// function to call any registered callbacks
|
|
// does not guarantee any order
|
|
//
|
|
|
|
DWORD
|
|
CallSnapshotCallbacks(
|
|
LPCWSTR pszEnumKey,
|
|
LPCWSTR pszSnapshotDir,
|
|
BOOL fSnapshot)
|
|
{
|
|
TraceFunctEnter("CallSnapshotCallbacks");
|
|
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
DWORD dwIndex = 0;
|
|
DWORD dwSize, dwDataSize;
|
|
WCHAR szDllPath[MAX_PATH], szDllName[MAX_PATH];
|
|
PSNAPSHOTCALLBACK pCallbackFn = NULL;
|
|
HKEY hKey = NULL;
|
|
HMODULE hDll = NULL;
|
|
|
|
//
|
|
// read SystemRestore\SnapshotCallbacks regkey
|
|
// enumerate all registered values
|
|
//
|
|
|
|
dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
pszEnumKey,
|
|
0,
|
|
KEY_READ,
|
|
&hKey);
|
|
if (dwErr != ERROR_SUCCESS) // assume key does not exist
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
DebugTrace(0, "No registered callbacks");
|
|
goto Err;
|
|
}
|
|
|
|
|
|
for (dwIndex = 0; TRUE; dwIndex ++)
|
|
{
|
|
dwSize = sizeof(szDllName)/sizeof(WCHAR); // this is in characters
|
|
dwDataSize = sizeof(szDllPath); // this is in bytes
|
|
|
|
dwErr = RegEnumValue(hKey, // handle to key to query
|
|
dwIndex, // index of value to query
|
|
szDllName, // value buffer
|
|
&dwSize, // size of value buffer
|
|
NULL, // reserved
|
|
NULL, // type buffer
|
|
(PBYTE) szDllPath, // data buffer
|
|
&dwDataSize); // size of data buffer
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (0 == lstrcmp(szDllPath, L"") ||
|
|
0 == lstrcmp(szDllPath, L" "))
|
|
continue;
|
|
|
|
//
|
|
// catch any exceptions that may happen in the callback dll
|
|
//
|
|
|
|
_try {
|
|
|
|
_try {
|
|
//
|
|
// load the registered library
|
|
// and call "CreateSnapshot" or "RestoreSnapshot" depending on the situation
|
|
//
|
|
|
|
hDll = LoadLibrary(szDllPath);
|
|
if (hDll != NULL)
|
|
{
|
|
pCallbackFn = (PSNAPSHOTCALLBACK) GetProcAddress(hDll, fSnapshot ? s_cszCreateSnapshotCallback :
|
|
s_cszRestoreSnapshotCallback);
|
|
if (pCallbackFn)
|
|
{
|
|
dwErr = (*pCallbackFn) (pszSnapshotDir);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
ErrorTrace(0, "Dll: %S, Error:%ld - ignoring", szDllPath, dwErr);
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ErrorTrace(0, "! GetProcAddress : %ld", GetLastError());
|
|
dwErr = GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ErrorTrace(0, "! LoadLibrary on %S : %ld", szDllPath, GetLastError());
|
|
}
|
|
}
|
|
_finally {
|
|
|
|
if (hDll)
|
|
{
|
|
FreeLibrary(hDll);
|
|
hDll = NULL;
|
|
}
|
|
}
|
|
}
|
|
_except (MyExceptionFilter(GetExceptionCode())) {
|
|
|
|
//
|
|
// catch all exceptions right here
|
|
// we can't do much, just log it and keep going
|
|
//
|
|
|
|
ErrorTrace(0, "An exception occurred when loading and executing %S", szDllPath);
|
|
ErrorTrace(0, "Handled exception - continuing");
|
|
}
|
|
}
|
|
|
|
if (dwErr == ERROR_NO_MORE_ITEMS)
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
Err:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
TraceFunctLeave();
|
|
return dwErr;
|
|
}
|
|
|