// RegSR.cpp : Defines the class behaviors for the application.
//
// RegSR.h : main header file for the REGSR application
// Author: A.YEZZA
// Date: August 2004
// Subject: Save/Restore registry keys in very safe mode
// Comment: Use with your own risk
// Licence: This code and application are free. The unique
// condition is preserving author name
///////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "RegSR.h"
#include "MainDlg.h"
#include "CmdLineParser.h"
#include "Winreg.h"
#include <Sddl.h> //This means: "Security Descriptor Definition Language"
//introduced since Win2K
#include "CRC32.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CRegSRApp
BEGIN_MESSAGE_MAP(CRegSRApp, CWinApp)
//{{AFX_MSG_MAP(CRegSRApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CRegSRApp construction
CRegSRApp::CRegSRApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CRegSRApp object
CRegSRApp theApp;
CString CRegSRApp::GetFileDirectory(CString &FilePathName)
{
CString Temp=FilePathName;
int Pos=Temp.ReverseFind('\\');
if ( Pos>0 )
return FilePathName.Mid(0, Pos);
else return "";
}
CString CRegSRApp::AddBackSlash(CString &strPath)
{
if (strPath.Right(1)!="\\")
return strPath+CString("\\");
return strPath;
}
// Get settings
void CRegSRApp::GetSettings()
{
DWORD dw=GetPrivateProfileString(SEC_SETTINGS, DATA_SERVER_PATH, "",
ServerPath.GetBuffer(255), 20, Params.ConfigFile);
ServerPath.ReleaseBuffer();
if ( (dw<=0) || (ServerPath==".") ) {
//set ServerPath as to be in the program directory
TCHAR Temp[MAX_PATH];
GetModuleFileName(GetModuleHandle(NULL), Temp, MAX_PATH);
ServerPath=GetFileDirectory(CString(Temp));
}
dw=GetPrivateProfileString(SEC_SETTINGS, DATA_CONFIG_FILE, "",
ConfigFile.GetBuffer(255), 20, Params.ConfigFile);
ConfigFile.ReleaseBuffer();
//set ConfigFile as to be the same as the config file passed as parameter
if (dw<=0) ConfigFile=Params.ConfigFile;
}
HKEY CRegSRApp::GetHiveFromString(LPCSTR strHive)
{
if (stricmp(strHive,HKCU)==0)
return HKEY_CURRENT_USER;
else if (stricmp(strHive,HKLM)==0)
return HKEY_LOCAL_MACHINE;
else if (stricmp(strHive,HKUSERS)==0)
return HKEY_USERS;
else if (stricmp(strHive,HKCURCFG)==0)
return HKEY_CURRENT_CONFIG;
else return 0;
}
BOOL CRegSRApp::Get_CRC32()
{
BOOL ret=TRUE;
CString strCRC32="";
CCRC32 ClassCRC32;
ClassCRC32.InitTable();
ret=(ClassCRC32.FileCrc32String(SavResFile.FileName, strCRC32)==0)?TRUE:FALSE;
ClassCRC32.FreeTable();
SavResFile.CRC32=strCRC32;
return ret;
}
// Set privilege lpszPrivilege to the current user to Enabled or Disabled
// depending on bEnablePrivilege if it is TRUE or FALSE
BOOL CRegSRApp::SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
LUID luid;
HANDLE hToken;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
if ( !LookupPrivilegeValue(NULL, lpszPrivilege, &luid) )
return FALSE;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
return ( (GetLastError()!=ERROR_SUCCESS)?FALSE:TRUE);
}
// Test if the key KeyPath exist
// Return TRUE if it exists, otherwise return FALSE
BOOL CRegSRApp::IsKeyExist(HKEY hRoot, LPCSTR KeyPath)
{
HKEY hKey;
BOOL ret;
if ( hRoot == NULL ) return FALSE;
if ( KeyPath == NULL || (!lstrlen(KeyPath)) ) return FALSE;
if ( (RegOpenKeyEx (hRoot, KeyPath, 0, KEY_EXECUTE, &hKey)==ERROR_FILE_NOT_FOUND) ||
(RegOpenKeyEx (hRoot, KeyPath, 0, KEY_EXECUTE, &hKey)!=ERROR_SUCCESS) )
ret=FALSE;
else ret=TRUE;
if (hKey) RegCloseKey (hKey);
return ret;
}
// Test if the file/directory FilePath exist
// Return TRUE if it exists, otherwise return FALSE
BOOL CRegSRApp::IsFileExist(LPCSTR FilePath)
{
HANDLE hSearch;
WIN32_FIND_DATA FileData;
hSearch = FindFirstFile(FilePath, &FileData);
return (hSearch != INVALID_HANDLE_VALUE);
}
void CRegSRApp::SetSavResFile()
{
SavResFile.ConfigFile=Params.ConfigFile;
SavResFile.FileName=Params.InOutFile;
SavResFile.KeyPath=Params.KeyPath;
SavResFile.hHive=Params.Root;
}
// This function checks 2 things:
// 1.The fact that the file from which we restore the key
// has the right CRC32 already reported to config file
// 2.The fact that the file corresponds exactly to the key
// to restore from the file
// NOTE: These 2 informations have been written in the save stage
// Return TRUE if OKAY else FALSE
BOOL CRegSRApp::CheckIntegrity(CString &Root, CString &SubKey,
CString &InFile)
{
BOOL ret=TRUE;
CString KeyPath=AddBackSlash(Root)+SubKey;
if (Get_CRC32()!=FALSE) {
CString RetCRC32;
DWORD dw=GetPrivateProfileString(SEC_CRC32, SavResFile.FileName,
"", RetCRC32.GetBuffer(128), 128,
AddBackSlash(ServerPath)+ConfigFile);
RetCRC32.ReleaseBuffer();
if (dw>0) {
//Compare calculated CRC32 and the reported one
if (RetCRC32.CompareNoCase(SavResFile.CRC32)==0){
//Get the corresponding key and compare
CString strKeyPath;
DWORD dw=GetPrivateProfileString(SEC_KEYS_FILES, SavResFile.FileName,
"", strKeyPath.GetBuffer(255), 255,
AddBackSlash(ServerPath)+ConfigFile);
strKeyPath.ReleaseBuffer();
ret = (strKeyPath.CompareNoCase(KeyPath)==0)?TRUE:FALSE;
} else ret=FALSE;
} else ret=FALSE;
} else ret=FALSE;
return ret;
}
// Restore registry key Root\SubKey from file InFile
// Return TRUE if success, otherwise it returns FALSE
BOOL CRegSRApp::RestoreRegKeyPath(CString &Root, CString &SubKey,
CString &InFile, DWORD &RetError)
{
SetSavResFile();
//Before restoring data, we have to ensure that:
// 1-InFile corresponds to Root\SubKey
// 2-InFile has the right already saved CRC32
if (CheckIntegrity(Root, SubKey,InFile)==FALSE){
MessageBox(NULL, "Check data integrity failled.\nRestoring Data is impossible.","",MB_OK|MB_ICONEXCLAMATION|MB_SYSTEMMODAL);
return FALSE;
}
BOOL ret=TRUE;
DWORD d=0;
HKEY hRoot;
SetPrivilege(SE_RESTORE_NAME,TRUE);
SetPrivilege(SE_BACKUP_NAME,TRUE);
hRoot=(HKEY)GetHiveFromString(Root);
if (!IsFileExist(InFile)) {
d=ERROR_FILE_NOT_FOUND;
ret=FALSE;
}
else {
HKEY hhKey;
char lpClass[80];
DWORD lpDisposition=0;
LONG l=RegCreateKeyEx(hRoot,SubKey,0,lpClass, REG_OPTION_BACKUP_RESTORE,
KEY_WRITE, NULL, &hhKey, &lpDisposition);
if ( (l==ERROR_SUCCESS) || (l==ERROR_FILE_NOT_FOUND) ) {
d=RegRestoreKey(hhKey,InFile,REG_NO_LAZY_FLUSH);
RegCloseKey(hhKey);
if (d!=ERROR_SUCCESS)
ret=FALSE;
}
else {
d=(DWORD)l;
ret=FALSE;
}
}
SetPrivilege(SE_RESTORE_NAME,FALSE);
SetPrivilege(SE_BACKUP_NAME,FALSE);
RetError=d;
return ret;
}
// Save registry key SubKey to file OutFile
// Return TRUE if success, otherwise it returns FALSE
BOOL CRegSRApp::SaveRegKeyPath(CString &Root, CString &SubKey,
CString &OutFile, DWORD &RetError)
{
BOOL ret=TRUE;
HKEY hKey=NULL;
DWORD d=0;
HKEY hRoot;
SetPrivilege(SE_BACKUP_NAME,TRUE);
hRoot=(HKEY)GetHiveFromString(Root);
if (RegOpenKeyEx(hRoot, SubKey,0,KEY_READ, &hKey)==ERROR_SUCCESS) {
if (IsFileExist(OutFile)){
//we must delete file before saving, otherwise it doesn't work !
if (DeleteFile(OutFile))
d=RegSaveKey(hKey,OutFile,NULL);
} else d=RegSaveKey(hKey,OutFile,NULL);
if (d!=ERROR_SUCCESS)
ret=FALSE;
else {//Save CRC32 file
SetSavResFile();
//save CRC32 file and file name/key path correspondance
//These 2 informations should be used to secure restoring data
if (Get_CRC32()!=FALSE) {
ret=WritePrivateProfileString(SEC_CRC32, SavResFile.FileName,
SavResFile.CRC32, AddBackSlash(ServerPath)+ConfigFile);
ret=WritePrivateProfileString(SEC_KEYS_FILES, SavResFile.FileName,
SavResFile.hHive+CString("\\")+SavResFile.KeyPath,
AddBackSlash(ServerPath)+ConfigFile);
}
}
RegCloseKey(hKey);
}
else {
if (IsKeyExist(hRoot,SubKey)==FALSE)
d=ERROR_FILE_NOT_FOUND;
else d=GetLastError();
ret=FALSE;
}
SetPrivilege(SE_BACKUP_NAME,FALSE);
RetError=d;
return ret;
}
// Print how to use it
void CRegSRApp::Usage()
{
CString Usage, Example,Copyright;
if ( (Usage.LoadString(IDS_USAGE)>0) &&
(Example.LoadString(IDS_EXAMPLE)>0) &&
(Copyright.LoadString(IDS_COPYRIGHT)>0) )
MessageBox(NULL, Usage+Example+Copyright,"Registry Save/Restore",MB_OK);
}
void CRegSRApp::SetParams(CmdParams &P, int &PNum)
{
PNum=0;
Params.Op=P.Op;
if (Params.Op!="") PNum++;
Params.Root=P.Root;
if (Params.Root!="") PNum++;
Params.KeyPath=P.KeyPath;
if (Params.KeyPath!="") PNum++;
Params.InOutFile=P.InOutFile;
if (Params.InOutFile!="") PNum++;
Params.ConfigFile=P.ConfigFile;
if (Params.ConfigFile!="") PNum++;
SetSavResFile();
}
void CRegSRApp::GetParams(CString& CmdLine, int &ParamsNum)
{
static CString Switchs[]={ "S",
"R",
"H",
"K",
"P",
"C"
};
ParamsNum=0;
CCmdLineParser CmdLinePars(CmdLine);
CCmdLineParser::POSITION pos = CmdLinePars.getFirst();
CString sKey,sVal;
while (!CmdLinePars.isLast(pos)) {
CmdLinePars.getNext(pos, sKey, sVal);
sKey.MakeUpper(); sVal.MakeUpper();
if ( (sKey==Switchs[0]) || (sKey==Switchs[1]) ){
Params.Op=(sKey==Switchs[0])?"S":"R";
ParamsNum++;
}else if (sKey==Switchs[2]){
Params.Root=sVal;
ParamsNum++;
}
else if (sKey==Switchs[3]){
Params.KeyPath=sVal;
ParamsNum++;
}
else if (sKey==Switchs[4]){
Params.InOutFile=sVal;
ParamsNum++;
}
else if (sKey==Switchs[5]){
Params.ConfigFile=sVal;
ParamsNum++;
}
}
}
void CRegSRApp::DoSaveRestore(DWORD &RetErr)
{
GetSettings();
if (Params.Op=="S"){
SaveRegKeyPath(Params.Root,Params.KeyPath, Params.InOutFile, RetErr);
}
else if (Params.Op=="R"){
RestoreRegKeyPath(Params.Root,Params.KeyPath, Params.InOutFile, RetErr);
}
}
/////////////////////////////////////////////////////////////////////////////
// CRegSRApp initialization
BOOL CRegSRApp::InitInstance()
{
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
CString CmdLine;
CmdLine=theApp.m_lpCmdLine;
CmdLine.MakeUpper();
if (CmdLine==""){
Usage();
return FALSE;
}
else {
if (CmdLine=="/UI") {
CMainDlg dlg;
m_pMainWnd = &dlg;
dlg.DoModal();
return FALSE;
}
else {
int ParamsNum;
GetParams(CmdLine, ParamsNum);
if (ParamsNum<4){
Usage();
return FALSE;
}
else {
DWORD RetErr=0;
DoSaveRestore(RetErr);
if (RetErr<32736) exit(RetErr);
else return FALSE;
}
}
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
//return FALSE;
}