//
// $Id: RegistryKeysProbe.cpp,v 1.2 2004/08/24 13:57:59 bakerj Exp $
//
//************************** Property of the MITRE Corporation ***************************//
//
// Copyright (c) 2003 - The MITRE Corporation
//
// This file is part of the OVAL Definition Interpreter.
//
// The OVAL Definition Interpreter 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.
//
// The OVAL Definition Interpreter 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 the OVAL
// Definition Interpreter; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA
//
//****************************************************************************************//

#include "RegistryKeysProbe.h"

//****************************************************************************************//
//								RegistryKeysProbe Class									  //	
//****************************************************************************************//
RegistryKeysProbe::RegistryKeysProbe()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Do nothing for now
	//
	// -----------------------------------------------------------------------
}

RegistryKeysProbe::~RegistryKeysProbe()
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Do nothing for now
	//
	// -----------------------------------------------------------------------
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Public Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

pdVector RegistryKeysProbe::Run(ProbeData *probeDataIn)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Run the registry probe. Return a vector of RegistryKeyData's
	//	Pattern match is supported on Hive, Key, and Name only
	//
	//	If in verbose loggind mode write out a record for each match found 
	//	even if a later refinement excludes that match. For example, if
	//	a key pattern match is specified of .* all keys will match. Now a name
	//	of 'foo' under the key has been specified. In verbose mode a record for 
	//	all keys that matched will be printed and any key that doesn't have 
	//	a name of 'foo under it will have a message stating that the name was 
	//	not found. If not in verbose mode only keys that have a matching name 
	//	are printed.
	// -----------------------------------------------------------------------
	pdVector returnVector;
	sVector hives;
	sVector keys;
	sVector names;
	RegistryKeyData *regKeyIn = (RegistryKeyData*)probeDataIn;
	RegistryKeyData *tmp = NULL;

	//	Hive, Key, and Name are litteral
	if((regKeyIn->hive)->type == LITTERAL_TYPE && (regKeyIn->key)->type == LITTERAL_TYPE && (regKeyIn->name)->type == LITTERAL_TYPE)
	{
		try
		{
			//	Call GetRegistryKeysProbe
			tmp = GetRegistryKey(regKeyIn->hive->data, regKeyIn->key->data, regKeyIn->name->data); 
			returnVector.push_back(tmp);
		}catch(...)
		{
			tmp = new RegistryKeyData();
			tmp->msg = "Error: (RegistryKeysProbe) Unknown exception occured while running registry probe";
			returnVector.push_back(tmp);
			tmp = NULL;
		}

	//	At least one pattern match
	}else
	{
		// Must be in a try/catch block
		try
		{
			//	Reset the matcher
			myMatcher->Reset();

			//	Get matching Hives
			if((regKeyIn->hive)->type == PATTERN_MATCH_TYPE)
			{
				GetMatchingHives(regKeyIn->hive->data, &hives);
				
				if(hives.size() == 0)
					throw RegistryKeysProbeException("(RegistryKeysProbe) No hives found that match pattern: '" + regKeyIn->hive->data + "' does not exists.");

			}else 
			{
				//	Use input hive if it exists
				if(GetRootKey(regKeyIn->hive->data)!= NULL)
					hives.push_back(regKeyIn->hive->data);
				else 
					throw RegistryKeysProbeException("(RegistryKeysProbe) The hive '" + regKeyIn->hive->data + "' does not exists.");
			}

			//	For each matching hive found
			sVector::iterator hive;
			for (hive=hives.begin(); hive!=hives.end(); hive++)
			{
				//	Reset the keys vector
				keys.clear();

				//	Key is a pattern match
				if((regKeyIn->key)->type == PATTERN_MATCH_TYPE)
				{
					//	Get matching keys
					KeyPatternMatch((*hive), regKeyIn->key->data, &keys);

				//	Key is not a pattern match
				}else
				{
					//	Use the input key only
					keys.push_back(regKeyIn->key->data);				
				}

				//	If no matching keys are found add a RegistryKeyData with the 
				//	hive set and a message indicating that no keys matched
				if(keys.size() == 0 && Log::verboseMode)
				{
					tmp = new RegistryKeyData();
					tmp->hive->data = (*hive);
					tmp->msg = "(RegistryKeysProbe) The registry key '" + regKeyIn->key->data + "' does not exist.";
					returnVector.push_back(tmp);
					tmp = NULL;
				}

				//	For each matching key found
				sVector::iterator key;
				for (key=keys.begin(); key!=keys.end(); key++)
				{

					//Reset the names Vector
					names.clear();

					//	Name is a pattern match
					if(regKeyIn->name->type == PATTERN_MATCH_TYPE)
					{
						//	Get matching names
						GetMatchingNames((*hive), (*key), regKeyIn->name->data, &names);

					//	Name is not a pattern match
					}else
					{
						//	Use the input name only
						names.push_back(regKeyIn->name->data);				
					}

					//	If no matching names are found add a RegistryKeyData with the 
					//	hive and key set and a message indicating that no names matched
					if(names.size() == 0  && Log::verboseMode)
					{
						tmp = new RegistryKeyData();
						tmp->hive->data = (*hive);
						tmp->key->data = (*key);
						tmp->msg = "(RegistryKeysProbe) The name '" + regKeyIn->name->data + "' does not exist under the specified hive and key.";
						returnVector.push_back(tmp);
						tmp = NULL;
					}

					//	For each matching name
					sVector::iterator name;
					for (name=names.begin(); name!=names.end(); name++)
					{
						//	Call GetRegistryKeysProbe
						tmp =  GetRegistryKey((*hive), (*key), (*name));
						returnVector.push_back(tmp);
					}
				}
			}

		//	Might be an error with hive key or name... The exception caught should specify the error
		}catch(Exception ex)
		{
			tmp = new RegistryKeyData();
			tmp->msg = ex.GetErrorMessage();
			returnVector.push_back(tmp);
			tmp = NULL;

		//	Unknown error
		}catch(...)
		{
			tmp = new RegistryKeyData();
			tmp->msg = "Error: (RegistryKeysProbe) Unknown exception occured while running registry probe";
			returnVector.push_back(tmp);
			tmp = NULL;
		}
	}

	// Ensure taht all tests have at least one return item
	if(returnVector.size() == 0)
	{
		tmp = new RegistryKeyData();

		// Create an appropriate mesage
		if(hives.size() == 0)
		{
			tmp->msg = "(RegistryKeysProbe) The hive '" + regKeyIn->hive->data + "' does not exists.";

		}else if(keys.size() == 0)
		{
			tmp->msg = "(RegistryKeysProbe) The registry key '" + regKeyIn->key->data + "' does not exist.";

		}else if(names.size() == 0)
		{
			tmp->msg = "(RegistryKeysProbe) The name '" + regKeyIn->name->data + "' does not exist under the specified hive and key.";

		}else {
			tmp->msg = "Unknown Error: (RegistryKeysProbe) Unable to prosses test.";

		}
		
		returnVector.push_back(tmp);
		tmp = NULL;
	}

	//	Before returning ensure that all tests have the testId set
	pdVector::iterator pdIterator;
	for (pdIterator=returnVector.begin(); pdIterator!=returnVector.end(); pdIterator++)
	{
		(*pdIterator)->SetTestId(regKeyIn->GetTestId());
	}

	return returnVector;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Private Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void RegistryKeysProbe::GetMatchingHives(string pattern, sVector *hives)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Return a vector of hives as strings that match the pattern 
	//	Supported hives:
	//		"HKEY_CLASSES_ROOT"
	//		"HKEY_CURRENT_CONFIG"
	//		"HKEY_CURRENT_USER"
	//		"HKEY_LOCAL_MACHINE"
	//		"HKEY_USERS"
	//
	//	May throw REGEXException if the pattern is invalid.
	//
	// -----------------------------------------------------------------------

	try {
		if(myMatcher->IsMatch(pattern.c_str(), "HKEY_CLASSES_ROOT"))
			hives->push_back("HKEY_CLASSES_ROOT");

		if(myMatcher->IsMatch(pattern.c_str(), "HKEY_CURRENT_CONFIG"))
			hives->push_back("HKEY_CURRENT_CONFIG");

		if(myMatcher->IsMatch(pattern.c_str(), "HKEY_CURRENT_USER"))
			hives->push_back("HKEY_CURRENT_USER");

		if(myMatcher->IsMatch(pattern.c_str(), "HKEY_LOCAL_MACHINE"))
			hives->push_back("HKEY_LOCAL_MACHINE");

		if(myMatcher->IsMatch(pattern.c_str(), "HKEY_USERS"))
			hives->push_back("HKEY_USERS");
		
	}catch(REGEXException ex) {
		if(ex.GetSeverity() == ERROR_WARN) {
			string pcreMsg = "";
			pcreMsg.append("Registry Keys Probe Warning - while searching for matching hives:\n");
			pcreMsg.append("-----------------------------\n");
			pcreMsg.append(ex.GetErrorMessage());
			if(Log::verboseMode) {
				cout << pcreMsg << "\n"<< endl;
				Log::WriteLog(pcreMsg + "\n\n");
			}
		}
		
		throw;
	}
}

void RegistryKeysProbe::GetMatchingKeys(string hiveIn, string keyIn, string pattern, sVector *keys)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Search the registry for keys under the designated hive and input key 
	//	that match the pattern. add all matches to the keys vector. For every sub key
	//	found make recursive call. stop when all subkeys have been searched
	//
	// -----------------------------------------------------------------------
	HKEY hkey;								//	pointer to the key that will be opened
	LONG res;								//	result from enumerating the subkeys
	LONG openRes;							//	result from opening the key
	LPTSTR lpName = (LPTSTR)malloc(1024);	//	buffer to store the subkey name
	DWORD dwName = 1024;					//	number of chars in the subkey
	DWORD dwIndex = 0;						//	index of subkey to enumerate
	FILETIME ftLastWriteTime;				//	time the cur subkey was last written to
	string workingKey = "";					//	The name of the keyIn and the subkey concatenated
	string errorMessage = "";				//	

	/////////////////////////////////////////////////////////////////
	//	Open the specified key
	/////////////////////////////////////////////////////////////////
	HKEY rootKey = GetRootKey(hiveIn);
	if(rootKey == NULL)
	{
		errorMessage.append("(RegistryKeysProbe) The registry hive '");
		errorMessage.append(hiveIn);
		errorMessage.append("' does not exist.");
		throw RegistryKeysProbeException(errorMessage);
	}
			

	openRes = RegOpenKeyEx(	rootKey,		// handle to open hive
							keyIn.c_str(),	// subkey name
							0,				// reserved
							KEY_READ,		// security access mask
							&hkey);			// pointer to open key

	/////////////////////////////////////////////////////////////////
	//	Check attempt to open key
	/////////////////////////////////////////////////////////////////
	if (openRes == ERROR_SUCCESS)
	{
		for (dwIndex = 0, res = ERROR_SUCCESS; res == ERROR_SUCCESS; dwIndex++)
		{
			//	Get the working key as a string
			workingKey = keyIn;
			if(workingKey.compare("") != 0)
			{
				if(workingKey.at(workingKey.length()-1) != '\\')
				{
					workingKey.append("\\");
				}
			}

			//	Reset the buffer and the buffer size
			dwName = 1024;
			ZeroMemory(lpName, dwName);
						
			res = RegEnumKeyEx(	hkey,				// handle to key to enumerate
								dwIndex,			// subkey index
								lpName,				// subkey name
								&dwName,			// size of subkey buffer
								NULL,				// reserved
								NULL,				// class string buffer
								NULL,				// size of class string buffer
								&ftLastWriteTime);	// last write time

			//	Check results
			if(res == ERROR_SUCCESS)
			{
				//	Add the subkey to the working key
				workingKey.append(lpName);

				//	Make recursive call
				GetMatchingKeys(hiveIn, workingKey, pattern, keys);

				//	If a match add the new key to the keys vector
				if(myMatcher->IsMatch(pattern.c_str(), workingKey.c_str()))
					keys->push_back(workingKey);
			}
		}
	}
	
	RegCloseKey(hkey);	
}

void RegistryKeysProbe::GetMatchingNames(string hiveIn, string keyIn, string pattern, sVector *names)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Search the registry for names under the designated hive and input key 
	//	that match the pattern. add all matches to the names vector. 
	//	stop when all names have been searched
	//
	// -----------------------------------------------------------------------
	HKEY hkey;								//	pointer to the key that will be opened
	LONG res;								//	result from enumerating the subkeys
	LONG openRes;							//	result from opening the key
	LPTSTR lpName = (LPTSTR)malloc(1024);	//	buffer to store the subkey name
	DWORD dwName = 1024;					//	number of chars in the subkey
	DWORD dwIndex = 0;						//	index of subkey to enumerate
	string name = "";						//	The name of the keyIn and the subkey concatenated
	string errorMessage = "";				//

	/////////////////////////////////////////////////////////////////
	//	Open the specified key
	/////////////////////////////////////////////////////////////////
	HKEY rootKey = GetRootKey(hiveIn);
	if(rootKey == NULL)
	{
		errorMessage.append("(RegistryKeysProbe) The registry hive '");
		errorMessage.append(hiveIn);
		errorMessage.append("' does not exist.");
		throw RegistryKeysProbeException(errorMessage);
	}
			

	openRes = RegOpenKeyEx(	rootKey,		// handle to open hive
							keyIn.c_str(),	// subkey name
							0,				// reserved
							KEY_QUERY_VALUE,// security access mask
							&hkey);			// pointer to open key

	/////////////////////////////////////////////////////////////////
	//	Check attempt to open key
	/////////////////////////////////////////////////////////////////
	if (openRes == ERROR_SUCCESS)
	{
		try {
			myMatcher->Reset();
			for (dwIndex = 0, res = ERROR_SUCCESS; res == ERROR_SUCCESS; dwIndex++)
			{
				//	Reset the buffer and the buffer size
				dwName = 1024;
				ZeroMemory(lpName, dwName);
						
				res = RegEnumValue(	hkey,		// handle to key to query
									dwIndex,	// index of value to query
									lpName,		// value buffer
									&dwName,	// size of value buffer
									NULL,		// reserved
									NULL,		// type buffer
									NULL,		// data buffer
									NULL);		// size of data buffer

				//	Check results
				if(res == ERROR_SUCCESS)
				{
					//	Get the name
					name = "";
					name.append(lpName);

					//	If a match add the new name to the names vector
					if(myMatcher->IsMatch(pattern.c_str(), name.c_str()))
						names->push_back(name);

				}
			}
		}catch(REGEXException ex) 
		{
			if(ex.GetSeverity() == ERROR_WARN) 
			{
				string pcreMsg = "";
				pcreMsg.append("Registry Keys Probe Warning - when searching for matching names:\n");
				pcreMsg.append("-----------------------------\n");
				pcreMsg.append(ex.GetErrorMessage());
				if(Log::verboseMode) 
				{
					cout << pcreMsg << "\n"<< endl;
					Log::WriteLog(pcreMsg + "\n\n");
				}
			}else
				throw;
		}
	}
	
	RegCloseKey(hkey);	
}

string RegistryKeysProbe::GetRegKeyValue(string strKeyIn)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Break string into a hive, a key, and a name. Then call the 
	//	RegistryKeys probe to get the value
	//
	// -----------------------------------------------------------------------
	
	int tmp					= 0;
	string value			= "";
	RegistryKeyData *rkIn	= new RegistryKeyData();

	//	Remove leading and trailing \ if they exist
	if(strKeyIn.find("\\") == 0)
		strKeyIn = strKeyIn.substr(1, strKeyIn.length()-1);

	if(strKeyIn.find_last_of("\\") == strKeyIn.length()-1)
		strKeyIn = strKeyIn.substr(0, strKeyIn.length()-2);

	//	Parse the input
	tmp = strKeyIn.find("\\");
	rkIn->hive->data = strKeyIn.substr(0, tmp);
	strKeyIn = strKeyIn.substr(tmp+1, strKeyIn.length());
	tmp = strKeyIn.find_last_of("\\");
	rkIn->name->data = strKeyIn.substr(tmp+1, strKeyIn.length());
	rkIn->key->data = strKeyIn.substr(0, tmp);


	//	Call the probe
	RegistryKeysProbe *ptrRK = new RegistryKeysProbe();
	pdVector rksOut;
	rksOut = ptrRK->Run(rkIn);
	delete ptrRK;
	delete rkIn;
	ptrRK = NULL;
	rkIn = NULL;

	//	Check the value 
	value = ((RegistryKeyData*)rksOut[0])->value;
	if(value.compare("") == 0)
	{
		string errMsg = "Message: No value found for: " + strKeyIn + "\n";
		errMsg.append("Probe message: " + ((RegistryKeyData*)rksOut[0])->msg);
		throw RegistryKeysProbeException(errMsg);
	}

	//	Return the Value
	return (value);
}

RegistryKeyData* RegistryKeysProbe::GetRegistryKey(string hiveIn, string keyIn, string nameIn)
{
	// -----------------------------------------------------------------------
	//  ABSTRACT
	//
	//  Gather new data and put in a RegistryKeyData object.
	//
	// -----------------------------------------------------------------------

    HKEY hkey;
	DWORD parse_depth = 0;
	LONG res;

	string errorMessage = "";

	//	init output RegistryKeyData
	RegistryKeyData *resultKey = new RegistryKeyData();

	// NOTE: An error getting the root key will result in a NULL key and
	// will be caught by RegOpenKeyEx().

	HKEY rootKey = GetRootKey(hiveIn);		

	res = RegOpenKeyEx(rootKey,				// handle to open hive
	                   keyIn.c_str(),		// subkey name
					   0,					// reserved
					   KEY_READ,			// security access mask
					   &hkey);				// pointer to open key

	if (res != ERROR_SUCCESS)
	{
		if(rootKey == NULL)
		{
			errorMessage.append("(RegistryKeysProbe) The registry hive '");
			errorMessage.append(hiveIn);
			errorMessage.append("' does not exist.");

			resultKey->msg.append(errorMessage);

		}else if (res == ERROR_FILE_NOT_FOUND)
		{
			errorMessage.append("(RegistryKeysProbe) The registry key '");
			errorMessage.append(keyIn.c_str());
			errorMessage.append("' does not exist.");

			resultKey->hive->data = hiveIn;
			resultKey->msg.append(errorMessage);
		}else if (res == ERROR_INVALID_HANDLE)
		{
			errorMessage.append("(RegistryKeysProbe) The handle for the registry key '");
			errorMessage.append(keyIn.c_str());
			errorMessage.append("' is not valid.");

			resultKey->hive->data = hiveIn;
			resultKey->msg.append(errorMessage);
		}else
		{
			char errorCodeBuffer[20];
			_ltoa(res, errorCodeBuffer, 20);

			errorMessage.append("(RegistryKeysProbe) Unable to get values for registry key '");
			errorMessage.append(keyIn.c_str());
			errorMessage.append("'.  Error Code - ");
			errorMessage.append(errorCodeBuffer);

			resultKey->hive->data = hiveIn;
			resultKey->msg.append(errorMessage);
		}		
		
	}else
	{
		//	The hive exists 
		(resultKey->hive)->data.append(hiveIn);

		//	The key exists
		resultKey->key->data = keyIn;

		DWORD type = 0;
		DWORD valuelen = 0;

		// Determine how big the buffer must be to store the data.  By specifying NULL for the
		// buffer size parameter, the function returns the value ERROR_MORE_DATA, and stores
		// the required buffer size, in bytes, into valuelen.

		res = RegQueryValueEx(hkey,				// handle to key
							  nameIn.c_str(),	// value name
							  NULL,				// reserved
							  NULL,				// type buffer
							  NULL,				// data buffer
							  &valuelen);		// size of data buffer

		// Allocate space for the buffer.

		LPBYTE value = (LPBYTE) malloc(valuelen);

		// Retrieve the type and value for the specified name associated with an open registry
		// key.

		res = RegQueryValueEx(hkey,				// handle to key
							  nameIn.c_str(),	// value name
							  NULL,				// reserved
							  &type,			// type buffer
							  value,			// data buffer
							  &valuelen);		// size of data buffer

		if (res == ERROR_FILE_NOT_FOUND)
		{
			errorMessage.append("(RegistryKeysProbe) The name '");
			errorMessage.append(nameIn.c_str());
			errorMessage.append("' does not exist under ");
			errorMessage.append(hiveIn.c_str());
			errorMessage.append("\\");
			errorMessage.append(keyIn.c_str());
			errorMessage.append(".");

			resultKey->msg.append(errorMessage);

		}else if (res != ERROR_SUCCESS)
		{
			char errorCodeBuffer[20];
			_ltoa(res, errorCodeBuffer, 20);

			string errorMessage = "";
			errorMessage.append("(RegistryKeysProbe) Unable to get values for '");
			errorMessage.append(nameIn.c_str());
			errorMessage.append("' under registry key '");
			errorMessage.append(hiveIn.c_str());
			errorMessage.append("\\");
			errorMessage.append(keyIn.c_str());
			errorMessage.append("'.  Error Code - ");
			errorMessage.append(errorCodeBuffer);

			resultKey->msg.append(errorMessage);

		//	Only call RetrieveInfo() if res == ERROR_SUCCESS
		}else
		{
			//	The name exists
			resultKey->name->data = nameIn;

			// We now have all the info we need.
			RetrieveInfo(hiveIn, keyIn, nameIn, type, value, valuelen, resultKey);
		}

		free(value);
	}


	RegCloseKey(hkey);

	return resultKey;
}

HKEY RegistryKeysProbe::GetRootKey(string hiveIn)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  An application must open a key before it can add data to the registry. To open a
	//  key, an application must supply a handle to another key in the registry that is
	//  already open. The system defines predefined keys that are always open.  Determine
	//  if one of these predefined keys can be used, and if so, return it.
	//
	//  NOTE: We have used _strnicmp() instead of the string compare() function as we need
	//  to do a compare without regard to case.
	//
	// -----------------------------------------------------------------------

    if (_strnicmp(hiveIn.c_str(), "HKEY_LOCAL_MACHINE", 18) == 0)
	{
        return HKEY_LOCAL_MACHINE;
    }
	else if (_strnicmp(hiveIn.c_str(), "HKEY_USERS", 10) == 0)
	{
        return HKEY_USERS;
    }
	else if (_strnicmp(hiveIn.c_str(), "HKEY_CURRENT_USER", 17) == 0)
	{
        return HKEY_CURRENT_USER;
    }
	else if (_strnicmp(hiveIn.c_str(), "HKEY_CURRENT_CONFIG", 19) == 0)
	{
        return HKEY_CURRENT_CONFIG;
    }
	else if (_strnicmp(hiveIn.c_str(), "HKEY_CLASSES_ROOT", 17) == 0)
	{
        return HKEY_CLASSES_ROOT;
    }
	else
	{
		return NULL;
    }
}

void RegistryKeysProbe::KeyPatternMatch(string hive, string pattern, sVector *keys)

{
	// -----------------------------------------------------------------------
	//  ABSTRACT
	//
	//	Attempt to locate any constant portion of the registry key. If a constant
	//	portion can be found then start the pattern matching search from the end of the 
	//	constant portion to save time. This cuts the time to 1/20th of the old time, nad
	//	reduces the memory usage of this probe to 1/30th of the old memory usage.
	//
	// -----------------------------------------------------------------------

	string patternOut= "";
	string constantPortionOut= "";
	this->myMatcher->GetConstantPortion(pattern, "\\", &patternOut, &constantPortionOut);
	// Remove extra slashes
	constantPortionOut = myMatcher->RemoveExtraSlashes(constantPortionOut);


	if(patternOut.compare("") != 0)
	{
		try
		{
			myMatcher->Reset();

			//	Call search function wiht
			//	the constant portion found as the key and
			//	the entire pattern as the pattern
			GetMatchingKeys(hive, constantPortionOut, pattern, keys);

		}catch(REGEXException ex)
		{
			if(ex.GetSeverity() == ERROR_WARN)
			{
				string pcreMsg = "";
				pcreMsg.append("Registry Keys Probe Warning - while searching for matching keys:\n");
				pcreMsg.append("-----------------------------------------------------------------------\n");
				pcreMsg.append(ex.GetErrorMessage());
				if(Log::verboseMode) {
					cout << pcreMsg << "\n"<< endl;
					Log::WriteLog(pcreMsg + "\n\n");
				}
			}else
				throw;
		}

	}else
	{
		//	There are no pattern matching chars treat this as a normal path 
		//	after removing the double '\'
		pattern = myMatcher->RemoveExtraSlashes(pattern);
		keys->push_back(pattern);
	}

}

void RegistryKeysProbe::RetrieveInfo(string hiveIn, string keyIn, string nameIn, 
									  DWORD typeIn, LPBYTE valueIn, DWORD valuelenIn, RegistryKeyData *regKeyIn)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//	Convert the registry data n to string representations and add to the provided
	//	RegistryKeyData object.
	// -----------------------------------------------------------------------

	string tmpValue = "";
	string tmpType = "";
	string errorMessage = "";

	switch (typeIn)
	{
		case REG_BINARY:
		{
			tmpType = "reg_binary";

			// The buffer must be three bytes long, two bytes for each hex charater in the
			// binary data, and one byte for the terminating NULL character.

			char binaryBuf[3];

			// Loop through each hex character.  Make sure the buffer is NULL terminated.
			// Also make sure 0 is in the form 00, and 1 is 01, etc.

			for (DWORD x=0; x<valuelenIn; x++)
			{
				ZeroMemory(binaryBuf, sizeof(binaryBuf));
				_snprintf(binaryBuf, sizeof(binaryBuf)-1, "%x", valueIn[x]);
				binaryBuf[sizeof(binaryBuf)-1] = '\0';
				if (strlen(binaryBuf) == 1) tmpValue.append("0");
				tmpValue.append(binaryBuf);
				tmpValue.append(" ");
			}

			break;
		}

		case REG_DWORD:
		{
			tmpType = "reg_dword";

			// The dwordBuf is 12 bytes since the max DWORD (2,147,483,647) is 10 characters
			// long.  Also add a byte for a possible negative sign and a byte for the
			// terminating NULL character.

			char dwordBuf[12];

			ZeroMemory(dwordBuf, sizeof(dwordBuf));
			_snprintf(dwordBuf, sizeof(dwordBuf)-1, "%d", *((DWORD *)valueIn));
			dwordBuf[sizeof(dwordBuf)-1] = '\0';
			tmpValue.append(dwordBuf);

			break;
		}

		case REG_EXPAND_SZ:
		{
			tmpType = "reg_expand_sz";

			char expandBuf[3];

			for (DWORD x=0; x<(valuelenIn); x++)
			{
				ZeroMemory(expandBuf, sizeof(expandBuf));
				_snprintf(expandBuf, sizeof(expandBuf)-1, "%C", valueIn[x]);
				expandBuf[sizeof(expandBuf)-1] = '\0';
				tmpValue.append(expandBuf);
			}

			break;
		}

		case REG_MULTI_SZ:
		{
			tmpType = "reg_multi_sz";

			char multiszBuf[3];

			// Loop through each character.  Make sure the buffer is NULL terminated.
			// MULTISZ data is an array of null-terminated strings, terminated by two null
			// characters.  Therefore, the loop goes to (valuelenIn - 2) since we can skip
			// the last two characters.  This keeps an extra bar from beeing added to the
			// end of the valueString.  A terminating NULL charater and will be
			// automatically replaced during the append method.

			// NOTE: valuelenIn can be less then 2.  When this is the case, (valuelenIn-2)
			// becomes a very high DWORD.  This is because there are no negative numbers
			// for DWORDS.  Make sure we guard against this by setting valuelenIn = 2 so
			// (valuelenIn-2) = 0 and the loop never runs.

			if (valuelenIn < 2) valuelenIn = 2;

			for (DWORD x=0; x<(valuelenIn-2); x++)
			{
				ZeroMemory(multiszBuf, sizeof(multiszBuf));
				_snprintf(multiszBuf, sizeof(multiszBuf)-1, "%C", valueIn[x]);
				multiszBuf[sizeof(multiszBuf)-1] = '\0';
				if (multiszBuf[0] == '\0') tmpValue.append("|");
				else tmpValue.append(multiszBuf);
			}
			
			break;
		}

		case REG_SZ:
		{
			tmpType = "reg_sz";

			char strBuf[3];

			for (DWORD x=0; x<(valuelenIn); x++)
			{
				ZeroMemory(strBuf, sizeof(strBuf));
				_snprintf(strBuf, sizeof(strBuf)-1, "%C", valueIn[x]);
				strBuf[sizeof(strBuf)-1] = '\0';
				tmpValue.append(strBuf);
			}

			break;
		}

		default:
		{
			errorMessage.append("Error: Unable to determine the type and value of the registry key.");
			tmpType = "";
			tmpValue = "";
			
			break;
		}
	}

	//	Set the type and the value
	regKeyIn->type = tmpType;
	regKeyIn->value = tmpValue;

	//	Get any messages
	regKeyIn->msg = errorMessage;
}

//****************************************************************************************//
//							RegistryKeysProbeException Class							  //	
//****************************************************************************************//
RegistryKeysProbeException::RegistryKeysProbeException() : Exception()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Default constructor simply set the severity to ERROR_FATAL. This is 
	//	done with the explicit call to the Exception class default constructor.
	//
	// -----------------------------------------------------------------------

}

RegistryKeysProbeException::RegistryKeysProbeException(string errMsgIn) : Exception(errMsgIn)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the error message and then set the severity to ERROR_FATAL. This is 
	//	done with the explicit call to the Exception class constructor that 
	//	takes a single string param.
	//
	// -----------------------------------------------------------------------

}

RegistryKeysProbeException::~RegistryKeysProbeException()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Do nothing for now
	//
	// -----------------------------------------------------------------------

}