//
// $Id: RegistryEffectiveRightsProbe.cpp,v 1.7 2005/03/28 15:59:43 bakerj Exp $
//
//****************************************************************************************//
// Copyright (c) 2005, The MITRE Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice, this list
//       of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice, this 
//       list of conditions and the following disclaimer in the documentation and/or other
//       materials provided with the distribution.
//     * Neither the name of The MITRE Corporation nor the names of its contributors may be
//       used to endorse or promote products derived from this software without specific 
//       prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
// SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//****************************************************************************************//

#include "RegistryEffectiveRightsProbe.h"

//****************************************************************************************//
//						RegistryEffectiveRightsProbe Class								  //	
//****************************************************************************************//
RegistryEffectiveRightsProbe *RegistryEffectiveRightsProbe::instance = NULL;

RegistryEffectiveRightsProbe::RegistryEffectiveRightsProbe()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Do nothing for now
	//
	// -----------------------------------------------------------------------
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Public Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
Probe* RegistryEffectiveRightsProbe::Instance()
{

	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//	Ensure that the RegistryEffectiveRightsProbe is a singleton.
	// -----------------------------------------------------------------------

	// Use lazy initialization
	if(instance == NULL) 
		instance = new RegistryEffectiveRightsProbe();

	return instance;	
}

pdVector RegistryEffectiveRightsProbe::Run(ProbeData *probeDataIn)
{
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Run the registry probe. Return a vector of RegistryEffectiveRightsData objects
	//
	//	If in verbose logging 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;
	RegistryEffectiveRightsData *regKeyIn = (RegistryEffectiveRightsData*)probeDataIn;
	RegistryEffectiveRightsData *tmp = NULL;

	//	Hive, Key, and Name are litteral
	if((regKeyIn->hive)->type == literal && (regKeyIn->key)->type == literal) {

		try {

			//	Call GetEffectiveRights
			tmp = GetEffectiveRights(regKeyIn->hive->object, regKeyIn->key->object); 
			returnVector.push_back(tmp);
			tmp = NULL;

		} catch(...) {

			tmp = new RegistryEffectiveRightsData();
			tmp->SetMessage("Error: (RegistryEffectiveRightsProbe) Unknown exception occured while running registry probe");
			tmp->SetStatus(error);
			tmp->hive->object = regKeyIn->hive->object;
			tmp->key->object = regKeyIn->key->object;
			tmp->isPatternMatchObject = regKeyIn->isPatternMatchObject;
			returnVector.push_back(tmp);
			tmp = NULL;
		}

	//	At least one pattern match
	} else {

		try {

			bool foundMatchingHive = false;
			bool foundMatchingKey = false;

			//	Reset the matcher
			myMatcher->Reset();

			//	Get matching Hives
			if((regKeyIn->hive)->type == pattern_match) {

				GetMatchingHives(regKeyIn->hive->object, &hives);
				
				if(hives.size() > 0)
					foundMatchingHive = true;

			} else {

				//	Use input hive if it exists
				if(GetRootKey(regKeyIn->hive->object)!= NULL) {
					hives.push_back(regKeyIn->hive->object);
					foundMatchingHive = true;
				}
			}

			//	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) {

					//	Get matching keys
					KeyPatternMatch((*hive), regKeyIn->key->object, &keys);
					
					if(keys.size() > 0)
						foundMatchingKey = true;


				//	Key is not a pattern match
				} else {

					// should add a check to see if the key exists..
					keys.push_back(regKeyIn->key->object);
					foundMatchingKey = true;
				}

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

					//	Call GetRegistryEffectiveRightsProbe
					tmp = GetEffectiveRights((*hive), (*key)); 
					returnVector.push_back(tmp);

					if (tmp->GetStatus() != doesNotExist){
						returnVector.push_back(tmp);
					} else {
						delete tmp;
					}
				}
			}

			// Add an object indicateing that the patterns either matched an object or did not
			tmp = new RegistryEffectiveRightsData();
			tmp->hive->type = regKeyIn->hive->type;
			tmp->hive->object = regKeyIn->hive->object;
			tmp->key->type = regKeyIn->key->type;
			tmp->key->object = regKeyIn->key->object;
			if(!foundMatchingHive || !foundMatchingKey) {
				
				tmp->SetMessage("No matches were found in the registry for the specified pattern.");
				tmp->SetStatus(doesNotExist);

			} else {

				tmp->SetMessage("The specified pattern matched at least one item in the registry.");
				tmp->SetStatus(exists);
			}
			tmp->isPatternMatchObject = true;
			returnVector.push_back(tmp);
			tmp = NULL;

		//	Might be an error with hive or key... The exception caught should specify the error
		} catch(Exception ex) {

			tmp = new RegistryEffectiveRightsData();
			tmp->hive->type = regKeyIn->hive->type;
			tmp->hive->object = regKeyIn->hive->object;
			tmp->key->type = regKeyIn->key->type;
			tmp->key->object = regKeyIn->key->object;
			tmp->SetMessage(ex.GetErrorMessage());
			tmp->isPatternMatchObject = regKeyIn->isPatternMatchObject;
			// Set the status
			if(ex.GetSeverity() == ERROR_NOTICE) {
				tmp->SetStatus(doesNotExist);
			} else {
				tmp->SetStatus(error);
			}

			returnVector.push_back(tmp);
			tmp = NULL;

		//	Unknown error
		} catch(...) {

			tmp = new RegistryEffectiveRightsData();
			tmp->hive->type = regKeyIn->hive->type;
			tmp->hive->object = regKeyIn->hive->object;
			tmp->key->type = regKeyIn->key->type;
			tmp->key->object = regKeyIn->key->object;
			tmp->SetMessage("Error: (RegistryEffectiveRightsProbe) Unknown exception occured while running registry probe");
			tmp->isPatternMatchObject = regKeyIn->isPatternMatchObject;
			returnVector.push_back(tmp);
			tmp = NULL;
		}
	}

	return returnVector;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Private Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
string RegistryEffectiveRightsProbe::FixKey(string regkeyIn)
{
	//------------------------------------------------------------------------------------//
	//
	//  ABSTRACT
	//
	//  Registy keys begin with one of the predefined keys:
	//
	//      HKEY_CLASSES_ROOT
	//      HKEY_CURRENT_USER
	//      HKEY_LOCAL_MACHINE
	//      HKEY_USERS
	//
	//  But in GetNamedSecurityInfo(), the names of registry keys must use the following
	//  literal strings to identify the predefined registry keys: "CLASSES_ROOT",
	//  "CURRENT_USER", "MACHINE", and "USERS". 
	//
	//------------------------------------------------------------------------------------//

	string returnKey = regkeyIn;

    if (strnicmp(regkeyIn.c_str(), "HKEY_LOCAL_MACHINE", 18) == 0)
	{
		returnKey.replace(0, 18, "MACHINE");
    }
	else if (strnicmp(regkeyIn.c_str(), "HKEY_USERS", 10) == 0)
	{
		returnKey.replace(0, 10, "USERS");
    }
	else if (strnicmp(regkeyIn.c_str(), "HKEY_CURRENT_USER", 17) == 0)
	{
		returnKey.replace(0, 17, "CURRENT_USER");
    }
	else if (strnicmp(regkeyIn.c_str(), "HKEY_CLASSES_ROOT", 17) == 0)
	{
		returnKey.replace(0, 17, "CLASSES_ROOT");
    }

	return returnKey;
}

RegistryEffectiveRightsData* RegistryEffectiveRightsProbe::GetEffectiveRights(string hive, string key)
{
	//------------------------------------------------------------------------------------//
	//
	//  ABSTRACT
	//
	//  This fetches a regkey's acl.  It prints the actual bit mask as a decimal.  It also
	//  prints whether this is an "ALLOWED" ace or "DENIED" ace.
	//
	//------------------------------------------------------------------------------------//

	RegistryEffectiveRightsData *rightsData = new RegistryEffectiveRightsData();
	rightsData->hive->object = hive;
	rightsData->key->object = key;


	// Construct a proprely formatted string for this regisrty kye
	string curRegKey = hive + "\\" + key;
	curRegKey = FixKey(curRegKey);


	// Retrieve a copy of the security descriptor for the specified registry key.
	DWORD res;
	PACL pdacl;
	PSECURITY_DESCRIPTOR pSD;
	res = GetNamedSecurityInfo(const_cast<char*>(curRegKey.c_str()),
							   SE_REGISTRY_KEY,
							   DACL_SECURITY_INFORMATION,
							   NULL,
							   NULL,
							   &pdacl,
							   NULL,
							   &pSD);

	// Make sure that no error occured.  If one did, exit this function.
	if (res != ERROR_SUCCESS) {

		if ((res == ERROR_FILE_NOT_FOUND) || (res == ERROR_PATH_NOT_FOUND)) {

			// The specified registry key does not exist on this system.
			string errorMessage = "";
			errorMessage.append("ERROR: The registry key does not exist.");
			
			rightsData->SetMessage(errorMessage);
			rightsData->SetStatus(error);

		} else {
			char buffer[33];
			_itoa(res, buffer, 10);

			string errorMessage = "";
			errorMessage.append("ERROR: Unable to retrieve the ");
			errorMessage.append("security descriptor for the registry key due to error ");
			errorMessage.append(buffer);
			errorMessage.append(".");

			rightsData->SetMessage(errorMessage);
			rightsData->SetStatus(error);
		}

		return rightsData;
	}

	// Check to see if a valid DACL and security descriptor were returned.  If either is
	// invalid, then exit the function.
    if ((IsValidSecurityDescriptor(pSD) == 0) || (IsValidAcl(pdacl) == 0)) {
		LocalFree(pSD);

		string errorMessage = "";
		errorMessage.append("ERROR: Invalid DACL or security ");
		errorMessage.append("descriptor for the registry key.");

		rightsData->SetMessage(errorMessage);
		rightsData->SetStatus(error);

		return rightsData;
	}

	// Get the access control list.
	ACL_SIZE_INFORMATION acl_size_info;
	DWORD acl_size = sizeof(ACL_SIZE_INFORMATION);

	if (GetAclInformation(pdacl, (LPVOID) & acl_size_info, acl_size, AclSizeInformation) == 0) {

		LocalFree(pSD);

		string errorMessage = "";
		errorMessage.append("ERROR: Unable to get the access ");
		errorMessage.append("control list for the registry key.");
		
		rightsData->SetMessage(errorMessage);
		rightsData->SetStatus(error);
		
		return rightsData;
	}

	// Loop through each ACE found in the ACL.
	LPTSTR owner_name = NULL;
	LPTSTR domain_name = NULL;
	DWORD ace_number;
	for (ace_number = 0; ace_number < acl_size_info.AceCount; ace_number++) {

		// Get the ACE.
		ACCESS_ALLOWED_ACE* ace;
        if (GetAce(pdacl, ace_number, (LPVOID *) & ace) == 0) {
			string errorMessage = "";
			errorMessage.append("ERROR: Unable to get next ACE for the registry key.");
			
			rightsData->SetMessage(errorMessage);
			rightsData->SetStatus(error);

			continue;
        }

		// Get the SID associated with this ACE.
		PSID psid = (PSID) & (ace->SidStart);

		// Check to make sure the SID is valid.
        if (!(IsValidSid(psid))) {
			string errorMessage = "";
			errorMessage.append("ERROR: Invalid SID associated ");
			errorMessage.append("with the ACE for the registry key.");
			
			rightsData->SetMessage(errorMessage);
			rightsData->SetStatus(error);

			continue;
        }

		// Call LookupAccountSid with owner_name_size = 0 and domain_name_size =0. This
		// will cause LookupAccountSid to fail and return with the required buffer sizes.

		SID_NAME_USE sid_type;

		DWORD owner_name_size = 0;
		DWORD domain_name_size = 0;

		LookupAccountSid(NULL,
						 psid,
						 owner_name,
						 &owner_name_size,
						 domain_name,
						 &domain_name_size,
						 &sid_type);

        owner_name_size++;
        owner_name = (LPTSTR) realloc(owner_name, owner_name_size * sizeof(TCHAR));
        if (owner_name == NULL) {
			string errorMessage = "";
			errorMessage.append("ERROR: Unable to allocate ");
			errorMessage.append(" enough space for owner's name for the registy key.");
			
			rightsData->SetMessage(errorMessage);
			rightsData->SetStatus(error);

			continue;
        }

        domain_name_size++;
        domain_name = (LPTSTR) realloc(domain_name, domain_name_size * sizeof(TCHAR));
        if (domain_name == NULL) {
			string errorMessage = "";
			errorMessage.append("ERROR: Unable to allocate ");
			errorMessage.append(" enough space for domain name for the registry key.");
			
			rightsData->SetMessage(errorMessage);
			rightsData->SetStatus(error);

			continue;
        }
		
		// Call LookupAccountSid again to retrieve the name of the account and the
		// name of the first domain on which this SID is found.

        if (LookupAccountSid(NULL,					// name of local or remote computer
							 psid,					// security identifier
							 owner_name,			// account name buffer
							 &owner_name_size,		// size of account name buffer
							 domain_name,			// domain name
							 &domain_name_size,		// size of domain name buffer
							 &sid_type) == 0)		// SID type
		{
			string errorMessage = "";
			errorMessage.append("ERROR: Unable to get the ");
			errorMessage.append("name of the account for this SID for the registry key.");
			
			rightsData->SetMessage(errorMessage);
			rightsData->SetStatus(error);

			continue;
        }

		// Convert access mask to binary.
		int j;
		char mask[33];

		for (j = 0; j < 32; j++) {

			if (ace->Mask & (1 << j))
				mask[j] = '1';
			else
				mask[j] = '0';
		}
		mask[32] = 0;

		
		rightsData->trustee_name->value = owner_name;
		rightsData->trustee_name->dataType = stringType;

		rightsData->trustee_domain->value = domain_name;
		rightsData->trustee_domain->dataType = stringType;

		// Produce textual SID.
		//
		// SMC-AUDIT: REVIEW: where are the restrictions on buffer size for writing to
		// sid_string?  Can an attacker control the SID in any fashion?
		//
		// ARB:  The buffer's size is controlled inside GetTextualSid().

		LPTSTR sid_string;
		Common::GetTextualSid(psid, &sid_string);
		rightsData->trustee_sid->value = sid_string;
		rightsData->trustee_sid->dataType = stringType;
		free(sid_string);
		
		rightsData->acl_type->value = "";
		rightsData->acl_type->dataType = stringType;
		rightsData->acl_type->status = notCollected;
		
		rightsData->standard_delete->value = mask[16];
		rightsData->standard_delete->dataType = booleanType;
		
		rightsData->standard_read_control->value = mask[17];
		rightsData->standard_read_control->dataType = booleanType;
		
		rightsData->standard_write_dac->value = mask[18];
		rightsData->standard_write_dac->dataType = booleanType;
		
		rightsData->standard_write_owner->value = mask[19];
		rightsData->standard_write_owner->dataType = booleanType;
		
		rightsData->standard_synchronize->value = mask[20];
		rightsData->standard_synchronize->dataType = booleanType;
		
		rightsData->access_system_security->value = mask[24];
		rightsData->access_system_security->dataType = booleanType;
		
		rightsData->generic_read->value = mask[31];
		rightsData->generic_read->dataType = booleanType;
		
		rightsData->generic_write->value = mask[30];
		rightsData->generic_write->dataType = booleanType;
		
		rightsData->generic_execute->value = mask[29];
		rightsData->generic_execute->dataType = booleanType;
		
		rightsData->generic_all->value = mask[28];
		rightsData->generic_all->dataType = booleanType;
		
		rightsData->key_query_value->value = mask[0];
		rightsData->key_query_value->dataType = booleanType;
		
		rightsData->key_set_value->value = mask[1];
		rightsData->key_set_value->dataType = booleanType;
		
		rightsData->key_create_sub_key->value = mask[2];
		rightsData->key_create_sub_key->dataType = booleanType;
		
		rightsData->key_enumerate_sub_keys->value = mask[3];
		rightsData->key_enumerate_sub_keys->dataType = booleanType;
		
		rightsData->key_notify->value = mask[4];
		rightsData->key_notify->dataType = booleanType;
		
		rightsData->key_create_link->value = mask[5];
		rightsData->key_create_link->dataType = booleanType;
		
		rightsData->key_wow64_64key->value = mask[8];
		rightsData->key_wow64_64key->dataType = booleanType;
		
		rightsData->key_wow64_32key->value = mask[9];
		rightsData->key_wow64_32key->dataType = booleanType;		
		
		rightsData->key_wow64_res->value = mask[10];
		rightsData->key_wow64_res->dataType = booleanType;
	}

	free(domain_name);
	free(owner_name);
	LocalFree(pSD);

	return rightsData;
}

void RegistryEffectiveRightsProbe::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 RegistryEffectiveRightsProbe::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("(RegistryEffectiveRightsProbe) The registry hive '");
		errorMessage.append(hiveIn);
		errorMessage.append("' does not exist.");
		throw RegistryEffectiveRightsProbeException(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 RegistryEffectiveRightsProbe::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("(RegistryEffectiveRightsProbe) The registry hive '");
		errorMessage.append(hiveIn);
		errorMessage.append("' does not exist.");
		throw RegistryEffectiveRightsProbeException(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);	
}

HKEY RegistryEffectiveRightsProbe::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 RegistryEffectiveRightsProbe::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);
	}
}

//****************************************************************************************//
//							RegistryEffectiveRightsProbeException Class							  //	
//****************************************************************************************//
RegistryEffectiveRightsProbeException::RegistryEffectiveRightsProbeException(string errMsgIn, int severity) : Exception(errMsgIn, severity)
{
	// -----------------------------------------------------------------------
	//	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.
	//
	// -----------------------------------------------------------------------

}

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

}