|
|
//*************************************************************
//
// Hash table for registry Rsop data
//
// Microsoft Confidential
// Copyright (c) Microsoft Corporation 1999
// All rights reserved
//
// History: 7-Jun-99 SitaramR Created
//
//*************************************************************
#include "uenv.h"
#include "reghash.h"
#include "rsop.h"
#include <strsafe.h>
REGKEYENTRY * AllocRegKeyEntry( WCHAR *pwszKeyName ); void FreeRegKeyEntry( REGKEYENTRY *pKeyEntry ); REGVALUEENTRY *AllocValueEntry( WCHAR *pwszValueName ); void FreeValueEntry( REGVALUEENTRY *pValueEntry ); REGDATAENTRY * AllocDataEntry( REGOPERATION opnType, DWORD dwType, DWORD dwLen, BYTE *pData, WCHAR *pwszGPO, WCHAR *pwszSOM, WCHAR *pwszCommand); void FreeDataEntry( REGDATAENTRY *pDataEntry ); BOOL DeleteRegTree( REGHASHTABLE *pHashTable, WCHAR *pwszKeyName, WCHAR *pwszGPO, WCHAR *pwszSOM, WCHAR *szCommand); REGKEYENTRY * FindRegKeyEntry( REGHASHTABLE *pHashTable, WCHAR *pwszKeyName, BOOL bCreate ); REGVALUEENTRY * FindValueEntry( REGHASHTABLE *pHashTable, WCHAR *pwszKeyName, WCHAR *pwszValueName, BOOL bCreate ); BOOL AddDataEntry( REGVALUEENTRY *pValueEntry, REGOPERATION opnType, DWORD dwType, DWORD dwLen, BYTE *pData, WCHAR *pwszGPO, WCHAR *pwszSOM, WCHAR *pwszCommand);
////////////////////////////////////////////////////////////////////////
// Hash Table for registry policies
// ----------------------------------
//
// This hash table is used to log rsop data for registry policies.
// A hash table entry is created for each registry entry. The registry entry
// name itself is used to calculate the hash table.
//
// Each Registry entry has a link to each of the values modified by policy.
// These values are in a link list and sorted by the valueNames.
//
// Each Value has the list of Data that are being set on the Values. This
// sorted by the order of execution. The topmost value will contain the final value.
// The Data entries have fields that mark the value as deleted and the Command
// associated with the action. To look for the possible commands look in the
// ParseRegistryFile.
//
// Additionally, in the hash table 2 special case values exist.
// a. **Command Value. The Data under this value will contain all the commands
// that are executed under this key.
//
// b. An ""(Empty ValueName) This valuename represents the modifications happening
// to the key itself. For example a key can deleted or added..
//
// Note:
// The szCommand that is passed in has to be non NULL but can be an empty string.
// There is a dependency on it in AddDataEntry and in logger.cpp. There is an Assert
// for this in AddRegHashEntry
//
////////////////////////////////////////////////////////////////////////
//*************************************************************
//
// AllocHashTable
//
// Purpose: Allocates a new hash table
//
// Returns: Pointer to hash table
//
//*************************************************************
REGHASHTABLE * AllocHashTable() { DWORD i;
REGHASHTABLE *pHashTable = (REGHASHTABLE *) LocalAlloc (LPTR, sizeof(REGHASHTABLE));
if ( pHashTable == NULL ) { DebugMsg((DM_WARNING, TEXT("AllocHashTable: Failed to alloc hashtable."))); return NULL; }
for ( i=0; i<HASH_TABLE_SIZE; i++) { pHashTable->aHashTable[i] = 0; }
pHashTable->hrError = S_OK;
return pHashTable; }
//*************************************************************
//
// FreeHashTable
//
// Purpose: Deletes a hash table
//
// Parameters: pHashTable - Hash table to delete
//
//*************************************************************
void FreeHashTable( REGHASHTABLE *pHashTable ) { DWORD i;
if ( pHashTable == NULL ) return;
for ( i=0; i<HASH_TABLE_SIZE; i++ ) { REGKEYENTRY *pKeyEntry = pHashTable->aHashTable[i];
while ( pKeyEntry ) { REGKEYENTRY *pNext = pKeyEntry->pNext; FreeRegKeyEntry( pKeyEntry ); pKeyEntry = pNext; } } }
//*************************************************************
//
// AllocRegKey
//
// Purpose: Allocates a new registry key entry
//
// Returns: Pointer to registr key entry
//
//*************************************************************
REGKEYENTRY * AllocRegKeyEntry( WCHAR *pwszKeyName ) { REGKEYENTRY *pKeyEntry = (REGKEYENTRY *) LocalAlloc (LPTR, sizeof(REGKEYENTRY)); if ( pKeyEntry == NULL ) { DebugMsg((DM_WARNING, TEXT("AllocRegKeyEntry: Failed to alloc key entry."))); return NULL; }
DWORD dwKeyNameLength = lstrlen(pwszKeyName) + 1; pKeyEntry->pwszKeyName = (WCHAR *) LocalAlloc (LPTR, ( dwKeyNameLength ) * sizeof(WCHAR));
if ( pKeyEntry->pwszKeyName == NULL ) { DebugMsg((DM_WARNING, TEXT("AllocRegKeyEntry: Failed to alloc key name."))); LocalFree( pKeyEntry ); return NULL; }
HRESULT hr = StringCchCopy( pKeyEntry->pwszKeyName, dwKeyNameLength, pwszKeyName );
if(FAILED(hr)){ LocalFree( pKeyEntry->pwszKeyName ); LocalFree( pKeyEntry ); return NULL; }
return pKeyEntry; }
//*************************************************************
//
// FreeRegKeyEntry
//
// Purpose: Deletes a registry key entry
//
// Parameters: pKeyEntry - Entry to delete
//
//*************************************************************
void FreeRegKeyEntry( REGKEYENTRY *pKeyEntry ) { REGVALUEENTRY *pValueEntry = NULL;
if ( pKeyEntry == NULL ) return;
LocalFree( pKeyEntry->pwszKeyName );
pValueEntry = pKeyEntry->pValueList; while ( pValueEntry ) { REGVALUEENTRY *pNext = pValueEntry->pNext; FreeValueEntry( pValueEntry ); pValueEntry = pNext; }
LocalFree( pKeyEntry ); }
//*************************************************************
//
// AllocValueEntry
//
// Purpose: Allocates a new value entry
//
// Returns: Pointer to value entry
//
//*************************************************************
REGVALUEENTRY *AllocValueEntry( WCHAR *pwszValueName ) { REGVALUEENTRY *pValueEntry = (REGVALUEENTRY *) LocalAlloc (LPTR, sizeof(REGVALUEENTRY)); if ( pValueEntry == NULL ) { DebugMsg((DM_WARNING, TEXT("AllocValueEntry: Failed to alloc value entry."))); return NULL; }
DWORD dwValNameLength = lstrlen(pwszValueName) + 1; pValueEntry->pwszValueName = (WCHAR *) LocalAlloc (LPTR, ( dwValNameLength ) * sizeof(WCHAR));
if ( pValueEntry->pwszValueName == NULL ) { DebugMsg((DM_WARNING, TEXT("AllocValueEntry: Failed to alloc key name."))); LocalFree( pValueEntry ); return NULL; }
HRESULT hr = StringCchCopy( pValueEntry->pwszValueName, dwValNameLength, pwszValueName );
if(FAILED(hr)){ LocalFree( pValueEntry->pwszValueName ); LocalFree( pValueEntry ); return NULL; }
return pValueEntry; }
//*************************************************************
//
// FreeValueEntry
//
// Purpose: Deletes a value entry
//
// Parameters: pValueEntry - Entry to delete
//
//*************************************************************
void FreeValueEntry( REGVALUEENTRY *pValueEntry ) { REGDATAENTRY *pDataEntry = NULL;
if ( pValueEntry == NULL ) return;
LocalFree( pValueEntry->pwszValueName );
pDataEntry = pValueEntry->pDataList; while ( pDataEntry ) { REGDATAENTRY *pNext = pDataEntry->pNext; FreeDataEntry( pDataEntry ); pDataEntry = pNext; }
LocalFree( pValueEntry ); }
//*************************************************************
//
// AllocDataEntry
//
// Purpose: Allocates a new data entry
//
// Returns: Pointer to data entry
//
//*************************************************************
REGDATAENTRY * AllocDataEntry( REGOPERATION opnType, DWORD dwType, DWORD dwLen, BYTE *pData, WCHAR *pwszGPO, WCHAR *pwszSOM, WCHAR *pwszCommand) { BOOL bResult = FALSE; REGDATAENTRY *pDataEntry = (REGDATAENTRY *) LocalAlloc (LPTR, sizeof(REGDATAENTRY)); if ( pDataEntry == NULL ) { DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc data entry."))); return NULL; }
if ( opnType == REG_ADDVALUE ) pDataEntry->bDeleted = FALSE; else pDataEntry->bDeleted = TRUE;
pDataEntry->bAdmPolicy = FALSE; pDataEntry->dwValueType = dwType; pDataEntry->dwDataLen = dwLen;
if ( pData ) { pDataEntry->pData = (BYTE *) LocalAlloc (LPTR, dwLen); if ( pDataEntry->pData == NULL ) { DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc data."))); goto Exit; }
CopyMemory( pDataEntry->pData, pData, dwLen ); }
DmAssert( pwszGPO != NULL && pwszSOM != NULL ); DWORD dwGPOLength = lstrlen(pwszGPO) + 1; pDataEntry->pwszGPO = (WCHAR *) LocalAlloc (LPTR, ( dwGPOLength ) * sizeof(WCHAR));
if ( pDataEntry->pwszGPO == NULL ) { DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc Gpo name."))); goto Exit; }
HRESULT hr = StringCchCopy( pDataEntry->pwszGPO, dwGPOLength, pwszGPO );
if(FAILED(hr)) goto Exit;
DWORD dwSOMLength = lstrlen(pwszSOM) + 1; pDataEntry->pwszSOM = (WCHAR *) LocalAlloc (LPTR, ( dwSOMLength ) * sizeof(WCHAR));
if ( pDataEntry->pwszSOM == NULL ) { DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc Sdou name."))); goto Exit; }
hr = StringCchCopy( pDataEntry->pwszSOM, dwSOMLength, pwszSOM );
if(FAILED(hr)) goto Exit;
DWORD dwCmdLength = lstrlen(pwszCommand) + 1; pDataEntry->pwszCommand = (WCHAR *) LocalAlloc (LPTR, ( dwCmdLength ) * sizeof(WCHAR));
if ( pDataEntry->pwszCommand == NULL ) { DebugMsg((DM_WARNING, TEXT("AllocDataEntry: Failed to alloc Sdou name."))); goto Exit; }
hr = StringCchCopy( pDataEntry->pwszCommand, dwCmdLength, pwszCommand );
if(FAILED(hr)) goto Exit;
bResult = TRUE;
Exit:
if ( !bResult ) { LocalFree( pDataEntry->pData ); LocalFree( pDataEntry->pwszGPO ); LocalFree( pDataEntry->pwszSOM ); if (pDataEntry->pwszCommand) LocalFree(pDataEntry->pwszCommand); LocalFree( pDataEntry); return NULL; }
return pDataEntry;
}
//*************************************************************
//
// FreeDataEntry
//
// Purpose: Deletes a data entry
//
// Parameters: pDataEntry - Entry to delete
//
//*************************************************************
void FreeDataEntry( REGDATAENTRY *pDataEntry ) { if ( pDataEntry ) { LocalFree( pDataEntry->pData ); LocalFree( pDataEntry->pwszGPO ); LocalFree( pDataEntry->pwszSOM ); LocalFree( pDataEntry); } }
//*************************************************************
//
// Hash
//
// Purpose: Maps a key name to a hash bucket
//
// Parameters: pwszName - Key name
//
// Returns: Hash bucket
//
//*************************************************************
DWORD Hash( WCHAR *pwszName ) { DWORD dwLen = lstrlen( pwszName ); DWORD dwHashValue = 0;
for ( ; dwLen>0; pwszName++ ) { dwHashValue = toupper(*pwszName) + 31 * dwHashValue; dwLen--; }
return dwHashValue % HASH_TABLE_SIZE; }
//*************************************************************
//
// AddRegHashEntry
//
// Purpose: Adds a registry key to the hash table
//
// Parameters: pwszName - Key name
//
//*************************************************************
BOOL AddRegHashEntry( REGHASHTABLE *pHashTable, REGOPERATION opnType, WCHAR *pwszKeyName, WCHAR *pwszValueName, DWORD dwType, DWORD dwDataLen, BYTE *pData, WCHAR *pwszGPO, WCHAR *pwszSOM, WCHAR *szCommand, BOOL bCreateCommand) { REGVALUEENTRY *pValueEntry = NULL; BOOL bResult = FALSE; REGKEYENTRY *pKeyEntry=NULL; switch (opnType) {
case REG_DELETEKEY: bResult = DeleteRegTree( pHashTable, pwszKeyName, pwszGPO, pwszSOM, szCommand ); break; case REG_INTERNAL_DELETESINGLEKEY: case REG_DELETEALLVALUES: pKeyEntry = FindRegKeyEntry( pHashTable, pwszKeyName, FALSE ); if ( pKeyEntry == NULL ) {
//
// Delete all values is similar to policy being disabled and
// so do nothing.
//
if (opnType == REG_DELETEALLVALUES) { bResult = TRUE; break; } else // no command entry in this case.
return TRUE; }
pValueEntry = pKeyEntry->pValueList; while ( pValueEntry ) {
if (lstrcmp(pValueEntry->pwszValueName, TEXT("")) != 0) {
if (CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, pValueEntry->pwszValueName, -1, STARCOMMAND, -1) != CSTR_EQUAL) {
//
// Mark the value as deleted
//
bResult = AddDataEntry( pValueEntry, opnType, 0, 0, NULL, pwszGPO, pwszSOM, szCommand ); if ( !bResult ) return FALSE; } } else {
//
// Mark the key as deleted
//
if (opnType == REG_INTERNAL_DELETESINGLEKEY) { bResult = AddDataEntry( pValueEntry, opnType, 0, 0, NULL, pwszGPO, pwszSOM, szCommand ); if ( !bResult ) return FALSE; } } pValueEntry = pValueEntry->pNext; }
bResult = TRUE;
break; case REG_ADDVALUE: case REG_SOFTADDVALUE:
//
// We have to make a value with no name to represent the creation of key itself..
//
pValueEntry = FindValueEntry( pHashTable, pwszKeyName, TEXT(""), TRUE ); if ( pValueEntry == NULL ) return FALSE;
bResult = AddDataEntry( pValueEntry, opnType, 0, 0, NULL, pwszGPO, pwszSOM, szCommand );
if (!bResult) return FALSE; if ((!pwszValueName) || (!(*pwszValueName)) || (dwDataLen == 0) || (dwType == REG_NONE)) break;
// fall through
case REG_DELETEVALUE: pValueEntry = FindValueEntry( pHashTable, pwszKeyName, pwszValueName, TRUE ); if ( pValueEntry == NULL ) return FALSE;
//
// In case of SOFTADDVALUE the final decision to add the value is made in
// AddDataEntry
//
bResult = AddDataEntry( pValueEntry, opnType, dwType, dwDataLen, pData, pwszGPO, pwszSOM, szCommand );
break; default: DmAssert(FALSE && "Unknown Case Selector for AddRegHashEntry"); }
DmAssert(szCommand);
//
// If everything succeeded, then log the command if
// bCreateCommand is true. This is done creating or adding
// to a value called **Command. This means that this value is not
// Settable by adm file..
//
if ((bResult) && (bCreateCommand) && (opnType != REG_INTERNAL_DELETESINGLEKEY) && (*szCommand != TEXT('\0'))) { pValueEntry = FindValueEntry( pHashTable, pwszKeyName, STARCOMMAND, TRUE ); if ( pValueEntry == NULL ) return FALSE;
bResult = AddDataEntry( pValueEntry, REG_ADDVALUE, 0, sizeof(TCHAR)*(lstrlen(szCommand)+1), (BYTE *)szCommand, pwszGPO, pwszSOM, szCommand); }
return bResult; }
//*************************************************************
//
// DeleteRegTree
//
// Purpose: Deletes a key and all its subkeys
//
// Parameters: pHashTable - Hash table
// pwszKeyName - Key name to delete
// pwszGPO - Gpo
// pwszSOM - Sdou that the Gpo is linked to
//
//*************************************************************
BOOL DeleteRegTree( REGHASHTABLE *pHashTable, WCHAR *pwszKeyName, WCHAR *pwszGPO, WCHAR *pwszSOM, WCHAR *szCommand) { DWORD i=0; DWORD dwKeyLen = lstrlen( pwszKeyName );
for ( i=0; i<HASH_TABLE_SIZE; i++ ) {
REGKEYENTRY *pKeyEntry = pHashTable->aHashTable[i]; while ( pKeyEntry ) {
BOOL bAdd = FALSE; DWORD dwKeyLen2 = lstrlen(pKeyEntry->pwszKeyName);
if ( dwKeyLen2 >= dwKeyLen && CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, pKeyEntry->pwszKeyName, dwKeyLen, pwszKeyName, dwKeyLen ) == CSTR_EQUAL) {
//
// It's a prefix if length and strings match, or if one
// string is bigger and there is a '\' at the right place.
//
if ( dwKeyLen2 > dwKeyLen ) {
if ( pKeyEntry->pwszKeyName[dwKeyLen] == L'\\' ) bAdd = TRUE; } else bAdd = TRUE;
if ( bAdd ) { BOOL bResult = AddRegHashEntry( pHashTable, REG_INTERNAL_DELETESINGLEKEY, pKeyEntry->pwszKeyName, NULL, 0, 0, NULL, pwszGPO, pwszSOM, szCommand, FALSE ); if ( !bResult ) return FALSE; }
} // if dwKeyLen2 >= dwKeyLen
pKeyEntry = pKeyEntry->pNext;
} // while
} // for
return TRUE; }
//*************************************************************
//
// FindRegKeyEntry
//
// Purpose: Looks up a reg key entry in hash table
//
// Parameters: pHashTable - Hash table
// pwszKeyName - Key name to find
// bCreate - Should key be created if not found ?
//
//*************************************************************
REGKEYENTRY * FindRegKeyEntry( REGHASHTABLE *pHashTable, WCHAR *pwszKeyName, BOOL bCreate ) { DWORD dwHashValue = Hash( pwszKeyName ); REGKEYENTRY *pCurPtr = pHashTable->aHashTable[dwHashValue]; REGKEYENTRY *pTrailPtr = NULL;
while ( pCurPtr != NULL ) {
INT iResult = CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE, pwszKeyName, -1, pCurPtr->pwszKeyName, -1 );
if ( iResult == CSTR_EQUAL ) { return pCurPtr; } else if ( iResult == CSTR_LESS_THAN ) {
//
// Keys are in ascending order, so insert if bCreate
//
if ( bCreate ) {
REGKEYENTRY *pKeyEntry = AllocRegKeyEntry( pwszKeyName ); if ( pKeyEntry == NULL ) return 0;
pKeyEntry->pNext = pCurPtr; if ( pTrailPtr == NULL ) pHashTable->aHashTable[dwHashValue] = pKeyEntry; else pTrailPtr->pNext = pKeyEntry;
return pKeyEntry;
} else return NULL;
} else {
//
// Advance down the list
//
pTrailPtr = pCurPtr; pCurPtr = pCurPtr->pNext;
}
}
//
// End of list or null list case
//
if ( bCreate ) { REGKEYENTRY *pKeyEntry = AllocRegKeyEntry( pwszKeyName ); if ( pKeyEntry == NULL ) return 0;
pKeyEntry->pNext = 0; if ( pTrailPtr == NULL ) pHashTable->aHashTable[dwHashValue] = pKeyEntry; else pTrailPtr->pNext = pKeyEntry;
return pKeyEntry; }
return NULL; }
//*************************************************************
//
// FindValueEntry
//
// Purpose: Looks up a value entry in hash table
//
// Parameters: pHashTable - Hash table
// pwszKeyName - Key name to find
// pwszValueName - Value name to find
// bCreate - Should key be created if not found ?
//
//*************************************************************
REGVALUEENTRY * FindValueEntry( REGHASHTABLE *pHashTable, WCHAR *pwszKeyName, WCHAR *pwszValueName, BOOL bCreate ) { REGVALUEENTRY *pCurPtr = NULL; REGVALUEENTRY *pTrailPtr = NULL;
REGKEYENTRY *pKeyEntry = FindRegKeyEntry( pHashTable, pwszKeyName, bCreate ); if ( pKeyEntry == NULL ) return NULL;
pCurPtr = pKeyEntry->pValueList; pTrailPtr = NULL;
while ( pCurPtr != NULL ) {
INT iResult = CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE, pwszValueName, -1, pCurPtr->pwszValueName, -1 );
if ( iResult == CSTR_EQUAL ) { return pCurPtr; } else if ( iResult == CSTR_LESS_THAN ) {
//
// Keys are in ascending order, so insert if bCreate
//
if ( bCreate ) {
REGVALUEENTRY *pValueEntry = AllocValueEntry( pwszValueName ); if ( pValueEntry == NULL ) return 0;
pValueEntry->pNext = pCurPtr; if ( pTrailPtr == NULL ) pKeyEntry->pValueList = pValueEntry; else pTrailPtr->pNext = pValueEntry;
return pValueEntry;
} else return NULL;
} else {
//
// Advance down the list
//
pTrailPtr = pCurPtr; pCurPtr = pCurPtr->pNext;
}
}
//
// End of list or null list case
//
if ( bCreate ) {
REGVALUEENTRY *pValueEntry = AllocValueEntry( pwszValueName ); if ( pValueEntry == NULL ) return 0;
pValueEntry->pNext = 0; if ( pTrailPtr == NULL ) pKeyEntry->pValueList = pValueEntry; else pTrailPtr->pNext = pValueEntry;
return pValueEntry; }
return NULL; }
//*************************************************************
//
// AddDataEntry
//
// Purpose: Adds a data entry to a value entry struct
//
// Parameters: pValueEntry - Value entry
// opnType - Operation type
// dwType - Type of registry data
// dwLen - Length of registry data
// pData - Data
// pwszGPO - Gpo that set this value
// pwszSOM - Sdou that the Gpo is linked to
//
//*************************************************************
BOOL AddDataEntry( REGVALUEENTRY *pValueEntry, REGOPERATION opnType, DWORD dwType, DWORD dwLen, BYTE *pData, WCHAR *pwszGPO, WCHAR *pwszSOM, WCHAR *pwszCommand) { REGDATAENTRY *pDataEntry = NULL;
if (opnType == REG_SOFTADDVALUE) {
//
// if the data list is null or if the first value (highest precedence value is deleted)
// then add it to the list
//
if ((pValueEntry->pDataList == NULL) || (pValueEntry->pDataList->pNext->bDeleted)) opnType = REG_ADDVALUE; else return TRUE; // return without adding the value.
}
pDataEntry = AllocDataEntry( opnType, dwType, dwLen, pData, pwszGPO, pwszSOM, pwszCommand ); if ( pDataEntry == NULL ) return FALSE; //
// Prepend to data list because entries at beginning of list have higher precedence
//
pDataEntry->pNext = pValueEntry->pDataList; pValueEntry->pDataList = pDataEntry;
return TRUE; }
|