|
|
//-----------------------------------------------------------------------//
//
// File: query.cpp
// Created: Jan 1997
// By: Martin Holladay (a-martih)
// Purpose: Registry Query Support for REG.CPP
// Modification History:
// Created - Jan 1997 (a-martih)
// Aug 1997 (John Whited) Implemented a Binary output function for
// REG_BINARY
// Oct 1997 (martinho) fixed output for REG_MULTI_SZ \0 delimited strings
// April 1998 - MartinHo - Incremented to 1.05 for REG_MULTI_SZ bug fixes.
// Correct support for displaying query REG_MULTI_SZ of. Fix AV.
// April 1999 Zeyong Xu: re-design, revision -> version 2.0
//
//------------------------------------------------------------------------//
#include "stdafx.h"
#include "reg.h"
//
// query specific structure
//
typedef struct __tagRegQueryInfo { // instance level variables
BOOL bShowKey; BOOL bKeyMatched; BOOL bValueNameMatched; BOOL bUpdateMatchCount;
// ...
DWORD dwMatchCount; } TREG_QUERY_INFO, *PTREG_QUERY_INFO;
//
// function prototypes
//
BOOL ParseQueryCmdLine( DWORD argc, LPCWSTR argv[], PTREG_PARAMS pParams, BOOL* pbUsage ); LONG QueryValue( HKEY hKey, LPCWSTR pwszFullKey, LPCWSTR pwszValueName, PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo ); LONG QueryEnumValues( HKEY hKey, LPCWSTR pwszFullKey, PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo ); LONG QueryEnumKeys( HKEY hKey, LPCWSTR pwszFullKey, PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo ); BOOL SearchData( LPBYTE pByteData, DWORD dwType, DWORD dwSize, PTREG_PARAMS pParams ); BOOL ParseTypeInfo( LPCWSTR pwszTypes, PTREG_PARAMS pParams );
//
// implementation
//
//-----------------------------------------------------------------------//
//
// QueryRegistry()
//
//-----------------------------------------------------------------------//
LONG QueryRegistry( DWORD argc, LPCWSTR argv[] ) /*++
Routine Description: Main function for QUERY option which calls appropriate functions
Arguments: None Return Value: ERROR_SUCCESS on success EXIT_FAILURE on failure --*/ { // local variables
LONG lResult = 0; HKEY hKey = NULL; BOOL bResult = FALSE; BOOL bUsage = FALSE; TREG_PARAMS params; DWORD dwExitCode = 0; TREG_QUERY_INFO info; BOOL bSearchMessage = FALSE;
if ( argc == 0 || argv == NULL ) { SetLastError( ERROR_INVALID_PARAMETER ); ShowLastError( stderr ); return 1; }
// initialize the global data structure
InitGlobalData( REG_QUERY, ¶ms );
//
// Parse the cmd-line
//
bResult = ParseQueryCmdLine( argc, argv, ¶ms, &bUsage ); if ( bResult == FALSE ) { ShowLastErrorEx( stderr, SLE_INTERNAL ); FreeGlobalData( ¶ms ); return 1; }
// check whether we need to display the usage
if ( bUsage == TRUE ) { Usage( REG_QUERY ); FreeGlobalData( ¶ms ); return 0; }
//
// Connect to the Remote Machine(s) - if applicable
//
bResult = RegConnectMachine( ¶ms ); if( bResult == FALSE ) { SaveErrorMessage( -1 ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); FreeGlobalData( ¶ms ); return 1; }
//
// Open the registry key
//
lResult = RegOpenKeyEx( params.hRootKey, params.pwszSubKey, 0, KEY_READ, &hKey ); if( lResult != ERROR_SUCCESS) { SaveErrorMessage( lResult ); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); FreeGlobalData( ¶ms ); return 1; }
// show a blank line below starting the output
ShowMessage( stdout, L"\n" );
//
// do the query
//
ZeroMemory( &info, sizeof( TREG_QUERY_INFO ) ); if( params.pwszSearchData == NULL && params.pwszValueName != NULL && params.arrTypes == NULL && params.bRecurseSubKeys == FALSE ) { info.bShowKey = TRUE; if ( params.pwszValueName != NULL && ( StringLength( params.pwszValueName, 0 ) == 0 || FindOneOf2( params.pwszValueName, L"*?", TRUE, 0 ) == -1 ) ) { lResult = QueryValue( hKey, params.pwszFullKey, params.pwszValueName, ¶ms, &info );
bSearchMessage = FALSE; ShowMessage( stdout, L"\n" ); } else { bSearchMessage = TRUE; lResult = QueryEnumValues( hKey, params.pwszFullKey, ¶ms, &info ); } } else { info.bShowKey = TRUE; lResult = QueryEnumKeys( hKey, params.pwszFullKey, ¶ms, &info );
// determine the kind of success message that needs to be displayed
bSearchMessage = ! ( params.pwszSearchData == NULL && params.pwszValueName == NULL && params.arrTypes == NULL ); }
dwExitCode = 0; if ( lResult == ERROR_SUCCESS ) { if ( bSearchMessage == FALSE ) { //
// BUG: 698877 Reg.exe: Need to turn off newly-added success messages to avoid breaking scripts
// that parse output
//
// SaveErrorMessage( ERROR_SUCCESS );
// ShowLastErrorEx( stdout, SLE_INTERNAL );
//
} else { if ( info.dwMatchCount == 0 ) { dwExitCode = 1; }
// ...
ShowMessageEx( stdout, 1, TRUE, STATISTICS_QUERY, info.dwMatchCount ); } } else { dwExitCode = 1; ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); }
// release the handle
SafeCloseKey( &hKey );
// return the error code
return dwExitCode; }
//------------------------------------------------------------------------//
//
// ParseQueryCmdLine()
//
//------------------------------------------------------------------------//
BOOL ParseQueryCmdLine( DWORD argc, LPCWSTR argv[], PTREG_PARAMS pParams, BOOL* pbUsage ) /*++
Routine Description: Parse the command line arguments
Arguments: None Return Value: REG_STATUS --*/ { //
// local variables
DWORD dw = 0; DWORD dwLength = 0; LPCWSTR pwszTemp = NULL; LPCWSTR pwszSearchData = NULL;
// query parser result trackers
LONG lResult = 0; BOOL bResult = FALSE;
// query operation validators
BOOL bHasSeparator = FALSE;
//
// implementation starts from here
//
// check the input
if ( argc == 0 || argv == NULL || pParams == NULL || pbUsage == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return FALSE; }
// check whether this function is being called for
// valid operation or not
if ( pParams->lOperation < 0 || pParams->lOperation >= REG_OPTIONS_COUNT ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return FALSE; }
//
// Do we have a *valid* number of cmd-line params
//
if( argc < 3 || argc > 12 ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_QUERY ] ); return FALSE; } else if ( StringCompareEx( argv[ 1 ], L"QUERY", TRUE, 0 ) != 0 ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return FALSE; } else if( InString( argv[ 2 ], L"/?|-?|/h|-h", TRUE ) == TRUE ) { if ( argc == 3 ) { *pbUsage = TRUE; return TRUE; } else { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_QUERY ] ); return FALSE; } }
// Machine Name and Registry key
//
bResult = BreakDownKeyString( argv[ 2 ], pParams ); if( bResult == FALSE ) { return FALSE; }
// parsing the command line arguments
bResult = TRUE; lResult = ERROR_SUCCESS; pParams->dwSearchFlags = 0; pParams->bExactMatch = FALSE; pParams->bCaseSensitive = FALSE; pParams->bRecurseSubKeys = FALSE; pParams->bShowTypeNumber = FALSE; for( dw = 3; dw < argc; dw++ ) { // /f -- search the registry
if( StringCompareEx( argv[ dw ], L"/f", TRUE, 0 ) == 0 ) { if ( pwszSearchData != NULL ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; }
// ...
dw++; if( dw < argc ) { pwszSearchData = argv[ dw ]; } else { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } }
// /k -- searches the REGISTRY KEYS
else if ( StringCompareEx( argv[ dw ], L"/k", TRUE, 0 ) == 0 ) { if ( pParams->dwSearchFlags & REG_FIND_KEYS ) { // /k is already specified
bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; }
// ...
pParams->dwSearchFlags |= REG_FIND_KEYS; }
// /v -- searches/displays contents of the specific value names
else if( StringCompareEx( argv[ dw ], L"/v", TRUE, 0 ) == 0 ) { if( pParams->pwszValueName != NULL || (pParams->dwSearchFlags & REG_FIND_VALUENAMES) ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; }
if( dw + 1 < argc ) { // determine the length of the current argument
dwLength = StringLength( argv[ dw + 1 ], 0 );
// since the value for the /v switch is optional,
// we need to see if the user specified the next switch
// or data to this switch
if ( dwLength < 2 || argv[ dw + 1 ][ 0 ] != L'/' || InString( argv[ dw + 1 ] + 1, L"z|ve|f|k|d|c|e|s|t|se", TRUE ) == FALSE ) { // get the value for /v
dw++; dwLength++; pParams->pwszValueName = (LPWSTR) AllocateMemory( dwLength * sizeof( WCHAR ) ); if ( pParams->pwszValueName == NULL ) { lResult = ERROR_OUTOFMEMORY; break; }
// ...
StringCopy( pParams->pwszValueName, argv[ dw ], dwLength ); } } else { // since the value for the /v is optional
// this is a valid condition
}
// if the /v is specified and no memory is allocated for the buffer
if ( pParams->pwszValueName == NULL ) { // set the flag
pParams->dwSearchFlags |= REG_FIND_VALUENAMES; } }
// /ve -- displays the data for empty value name "(Default)"
else if( StringCompareEx( argv[ dw ], L"/ve", TRUE, 0 ) == 0 ) { if( pParams->pwszValueName != NULL || (pParams->dwSearchFlags & REG_FIND_VALUENAMES) ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; }
pParams->pwszValueName = (LPWSTR) AllocateMemory( 2 * sizeof( WCHAR ) ); if ( pParams->pwszValueName == NULL) { lResult = ERROR_OUTOFMEMORY; break; } }
// /d -- searches the DATA field of the REGISTRY
else if ( StringCompareEx( argv[ dw ], L"/d", TRUE, 0 ) == 0 ) { if ( pParams->dwSearchFlags & REG_FIND_DATA ) { // /d is already specified
bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; }
// ...
pParams->dwSearchFlags |= REG_FIND_DATA; }
// /c -- case sensitive search
else if( StringCompareEx( argv[ dw ], L"/c", TRUE, 0 ) == 0 ) { if ( pParams->bCaseSensitive == TRUE ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; }
// ...
pParams->bCaseSensitive = TRUE; }
// /e -- exact text match
else if( StringCompareEx( argv[ dw ], L"/e", TRUE, 0 ) == 0 ) { if ( pParams->bExactMatch == TRUE ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; }
// ...
pParams->bExactMatch = TRUE; }
// /z -- show the type number along with the text
else if ( StringCompareEx( argv[ dw ], L"/z", TRUE, 0 ) == 0 ) { if ( pParams->bShowTypeNumber == TRUE ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; }
// ...
pParams->bShowTypeNumber = TRUE; }
// /s -- recursive search/display
else if( StringCompareEx( argv[ dw ], L"/s", TRUE, 0 ) == 0 ) { if( pParams->bRecurseSubKeys == TRUE ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; }
pParams->bRecurseSubKeys = TRUE; }
// /se -- seperator to display for REG_MULTI_SZ valuename type
else if( StringCompareEx( argv[ dw ], L"/se", TRUE, 0 ) == 0 ) { if( bHasSeparator == TRUE ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; }
dw++; if( dw < argc ) { if( StringLength( argv[ dw ], 0 ) == 1 ) { bHasSeparator = TRUE; StringCopy( pParams->wszSeparator, argv[ dw ], SIZE_OF_ARRAY( pParams->wszSeparator ) ); } else { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } } else { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } }
// /t -- REGISTRY value type that only needs to be shown
else if( StringCompareEx( argv[ dw ], L"/t", TRUE, 0 ) == 0 ) { if ( pParams->arrTypes != NULL ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; }
dw++; if( dw < argc ) { if ( ParseTypeInfo( argv[ dw ], pParams ) == FALSE ) { if ( GetLastError() == (DWORD) MK_E_SYNTAX ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } else { bResult = TRUE; lResult = GetLastError(); break; } } } else { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } }
// default -- invalid
else { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; break; } }
//
// validate the search information specified
if ( lResult == ERROR_SUCCESS ) { if ( pwszSearchData == NULL ) { if ( pParams->dwSearchFlags != 0 || pParams->bExactMatch == TRUE || pParams->bCaseSensitive == TRUE ) { bResult = FALSE; lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT; } } else if ( pParams->dwSearchFlags == 0 ) { if ( pParams->pwszValueName == NULL ) { pParams->dwSearchFlags = REG_FIND_ALL; } else { pParams->dwSearchFlags = REG_FIND_KEYS | REG_FIND_DATA; } } }
// prepare the final search pattern
if ( pwszSearchData != NULL && lResult == ERROR_SUCCESS ) { // determine the length of the search pattern
dwLength = StringLength( pwszSearchData, 0 ); if ( pParams->bExactMatch == FALSE ) { dwLength += 2; }
// accomodate space for null characters
dwLength++;
// allocate memory
pParams->pwszSearchData = AllocateMemory( (dwLength + 2) * sizeof( WCHAR ) ); if ( pParams->pwszSearchData == NULL ) { lResult = ERROR_OUTOFMEMORY; } else { // if the /e is not specified -- we will search for "*<text>*"
// otherwise if /e is specified we will search exactly for "<text>"
// where "<text>" is what is specified by user at the command prompt
StringCopy( pParams->pwszSearchData, L"", dwLength ); if ( pParams->bExactMatch == FALSE ) { StringCopy( pParams->pwszSearchData, L"*", dwLength ); }
// ...
StringConcat( pParams->pwszSearchData, pwszSearchData, dwLength );
// ...
if ( pParams->bExactMatch == FALSE ) { StringConcat( pParams->pwszSearchData, L"*", dwLength ); } } }
//
// if /t is specified, then /s needs to be specified
// if /s is not specified, then atleast /v or /ve should not be specified
//
// if ( lResult == ERROR_SUCCESS && pParams->arrTypes != NULL &&
// pParams->bRecurseSubKeys == FALSE && pParams->pwszValueName != NULL )
// {
// bResult = FALSE;
// lResult = IDS_ERROR_INVALID_SYNTAX_WITHOPT;
// }
//
// parse the pattern information if specified by user and store only
// the optimized version of it
//
if ( lResult == ERROR_SUCCESS ) { //
// value name
//
if ( pParams->pwszValueName != NULL && StringLength( pParams->pwszValueName, 0 ) != 0 ) { pwszTemp = ParsePattern( pParams->pwszValueName ); if ( pwszTemp == NULL ) { lResult = GetLastError(); }
// copy the optimized pattern into the original buffer
dw = GetBufferSize( pParams->pwszValueName ); StringCopy( pParams->pwszValueName, pwszTemp, dw ); }
//
// search data
//
if ( pParams->pwszSearchData != NULL ) { pwszTemp = ParsePattern( pParams->pwszSearchData ); if ( pwszTemp == NULL ) { lResult = GetLastError(); }
// copy the optimized pattern into the original buffer
dw = GetBufferSize( pParams->pwszSearchData ); StringCopy( pParams->pwszSearchData, pwszTemp, dw ); } }
//
// check the end result
//
if( lResult != ERROR_SUCCESS ) { if( bResult == FALSE ) { SetLastError( (DWORD) MK_E_SYNTAX ); SetReason2( 1, ERROR_INVALID_SYNTAX_WITHOPT, g_wszOptions[ REG_QUERY ] ); } else { SaveErrorMessage( lResult ); } } else { }
// return the result
return (lResult == ERROR_SUCCESS); }
//-----------------------------------------------------------------------//
//
// QueryValue()
//
//-----------------------------------------------------------------------//
LONG QueryValue( HKEY hKey, LPCWSTR pwszFullKey, LPCWSTR pwszValueName, PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo ) { // local variables
LONG lResult = 0; DWORD dwType = 0; DWORD dwLength = 0; PBYTE pByteData = NULL; TREG_SHOW_INFO showinfo; BOOL bDataMatched = FALSE;
// check the input
if ( hKey == NULL || pwszFullKey == NULL || pwszValueName == NULL || pParams == NULL || pInfo == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); lResult = ERROR_INVALID_PARAMETER; goto cleanup; }
// get the size of the buffer to hold the value associated with the value name
lResult = RegQueryValueEx( hKey, pwszValueName, NULL, NULL, NULL, &dwLength ); if ( lResult != ERROR_SUCCESS ) { // special case -- "(Default)" value
if ( lResult == ERROR_FILE_NOT_FOUND && StringLength( pwszValueName, 0 ) == 0 ) { dwLength = StringLength( GetResString2( IDS_VALUENOTSET, 0 ), 0 ) + 1; dwLength *= sizeof( WCHAR ); } else { SaveErrorMessage( lResult ); goto cleanup; } }
//
// to handle the corrupted registry data properly, adjust the memory
// allocation size which is divisible by 2
//
dwLength += (dwLength % 2);
// allocate the buffer
pByteData = (LPBYTE) AllocateMemory( (dwLength + 2) * sizeof( BYTE ) ); if ( pByteData == NULL ) { SaveErrorMessage( ERROR_OUTOFMEMORY ); lResult = ERROR_OUTOFMEMORY; goto cleanup; }
// now get the data
lResult = RegQueryValueEx( hKey, pwszValueName, NULL, &dwType, pByteData, &dwLength ); if ( lResult != ERROR_SUCCESS ) { // special case -- "(Default)" value
if ( lResult == ERROR_FILE_NOT_FOUND && StringLength( pwszValueName, 0 ) == 0 ) { dwType = REG_SZ; StringCopy( (LPWSTR) pByteData, GetResString2( IDS_VALUENOTSET, 0 ), dwLength / sizeof( WCHAR )); } else { SaveErrorMessage( lResult ); goto cleanup; } }
// check whether the data matches with the search pattern specified
bDataMatched = TRUE; // default
if ( pInfo->bValueNameMatched == FALSE ) { if ( pParams->dwSearchFlags & REG_FIND_DATA ) { bDataMatched = SearchData( pByteData, dwType, dwLength, pParams ); if ( bDataMatched == TRUE ) { pInfo->dwMatchCount++; } } }
// check the result of the search
if ( bDataMatched == FALSE ) { SetLastError( ERROR_NOT_FOUND ); lResult = ERROR_SUCCESS; goto cleanup; }
// if the bUpdateMatchCount flag is set -- increment the matched
// count by 1 and reset the flag
if ( pInfo->bUpdateMatchCount == TRUE ) { if ( pParams->pwszValueName == NULL && pParams->arrTypes == NULL ) { pInfo->dwMatchCount++; }
// ...
pInfo->bUpdateMatchCount = FALSE; }
// show the full key -- if needed
if ( pInfo->bShowKey == TRUE ) { // display the key path for which query proceeds
ShowMessageEx( stdout, 1, TRUE, L"%s\n", pwszFullKey );
// flag off -- this will block from display the full key for each value
pInfo->bShowKey = FALSE; }
// update the match count -- if needed
if ( pParams->pwszValueName != NULL || pParams->arrTypes != NULL ) { pInfo->dwMatchCount++; }
// init to ZERO
ZeroMemory( &showinfo, sizeof( TREG_SHOW_INFO ) );
// set the data
showinfo.pwszValueName = pwszValueName; showinfo.dwType = dwType; showinfo.pByteData = pByteData; showinfo.pwszSeparator = L" "; showinfo.dwMaxValueNameLength = 0; showinfo.dwPadLength = 4; showinfo.dwSize = dwLength; showinfo.pwszMultiSzSeparator = pParams->wszSeparator; if ( pParams->bShowTypeNumber == TRUE ) { showinfo.dwFlags |= RSI_SHOWTYPENUMBER; }
// show
ShowRegistryValue( &showinfo );
// end result
lResult = ERROR_SUCCESS;
cleanup:
// release the memory
FreeMemory( &pByteData );
// return
return lResult; }
LONG QueryEnumValues( HKEY hKey, LPCWSTR pwszFullKey, PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo ) /*++
Routine Description: Queries Values and Data
Arguments: None Return Value: ERROR_SUCCESS on success EXIT_FAILURE on failure --*/ { // local variables
DWORD dw = 0; LONG lResult = 0; DWORD dwType = 0; DWORD dwLength = 0; DWORD dwMaxLength = 0; DWORD dwValueNames = 0; LPWSTR pwszValueName = NULL;
// check the input
if ( hKey == NULL || pwszFullKey == NULL || pParams == NULL || pInfo == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); return ERROR_INVALID_PARAMETER; }
//
// First find out how much memory to allocate.
//
lResult = RegQueryInfoKey( hKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwValueNames, &dwMaxLength, NULL, NULL, NULL ); if ( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); return lResult; }
//
// do the memory allocations
//
// value name
dwMaxLength++; pwszValueName = (LPWSTR) AllocateMemory( dwMaxLength * sizeof( WCHAR ) ); if ( pwszValueName == NULL ) { SaveErrorMessage( ERROR_OUTOFMEMORY ); return lResult; }
//
// enumerate the value names and display
//
lResult = ERROR_SUCCESS; for( dw = 0; dw < dwValueNames; dw++ ) { dwLength = dwMaxLength; ZeroMemory( pwszValueName, dwLength * sizeof( WCHAR ) ); lResult = RegEnumValue( hKey, dw, pwszValueName, &dwLength, NULL, &dwType, NULL, NULL ); if ( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); break; }
// check if user is looking for any explicit value name
// this will improve the performance of the tool
if ( pParams->pwszValueName != NULL && MatchPatternEx( pwszValueName, pParams->pwszValueName, PATTERN_COMPARE_IGNORECASE | PATTERN_NOPARSING ) == FALSE ) { // skip processing this value name
continue; }
// filter on type information
if ( pParams->arrTypes != NULL && DynArrayFindLongEx( pParams->arrTypes, 1, dwType ) == -1 ) { // skip processing this value names
continue; }
// search for the pattern -- if needed
pInfo->bValueNameMatched = TRUE; // default
if ( pParams->dwSearchFlags & REG_FIND_VALUENAMES ) { pInfo->bValueNameMatched = SearchData( (BYTE*) pwszValueName, REG_SZ, dwLength * sizeof( WCHAR ), pParams ); if ( pInfo->bValueNameMatched == FALSE ) { if ( pParams->dwSearchFlags == REG_FIND_VALUENAMES ) { // user just want to search in the value names
// since the current didn't match skip this valuename
continue; } } else { if ( pParams->pwszValueName == NULL && pParams->arrTypes == NULL ) { pInfo->dwMatchCount++; } } } else if ( pParams->dwSearchFlags != 0 && pParams->pwszValueName == NULL && pParams->arrTypes == NULL ) { pInfo->bValueNameMatched = FALSE; }
// process the value of this regisry valuename
if ( pInfo->bValueNameMatched == TRUE || pParams->dwSearchFlags == 0 || pParams->dwSearchFlags & REG_FIND_DATA ) { lResult = QueryValue( hKey, pwszFullKey, pwszValueName, pParams, pInfo ); } }
// show the new line at the end -- only if needed
if ( pInfo->bShowKey == FALSE ) { ShowMessage( stdout, L"\n" ); }
// release the memory
FreeMemory( &pwszValueName );
// return
return lResult; }
LONG QueryEnumKeys( HKEY hKey, LPCWSTR pwszFullKey, PTREG_PARAMS pParams, PTREG_QUERY_INFO pInfo ) /*++
Routine Description: Queries Values and Data
Arguments: None Return Value: ERROR_SUCCESS on success EXIT_FAILURE on failure --*/ { // local variables
DWORD dw = 0; LONG lResult = 0; DWORD dwLength = 0; DWORD dwSubKeys = 0; DWORD dwMaxLength = 0; HKEY hSubKey = NULL; DWORD dwNewFullKeyLength = 0; LPWSTR pwszSubKey = NULL; LPWSTR pwszNewFullKey = NULL;
// check the input
if ( hKey == NULL || pwszFullKey == NULL || pParams == NULL || pInfo == NULL ) { SaveErrorMessage( ERROR_INVALID_PARAMETER ); lResult = ERROR_INVALID_PARAMETER; goto cleanup; }
// show the values under the current hive first
// NOTE: enumerate the values only when /F is not specified
// or subkey is matched or search flags specify to search in
// value names and/or data also
if ( pInfo->bKeyMatched == TRUE && pParams->dwSearchFlags == REG_FIND_KEYS && pParams->pwszValueName == NULL && pParams->arrTypes == NULL ) { // do nothing
} else if ( pParams->dwSearchFlags == 0 || pParams->dwSearchFlags != REG_FIND_KEYS || (pInfo->bKeyMatched == TRUE && (pParams->pwszValueName != NULL || pParams->arrTypes != NULL)) ) { lResult = QueryEnumValues( hKey, pwszFullKey, pParams, pInfo ); if ( lResult != ERROR_SUCCESS ) { goto cleanup; } }
//
// First find out how much memory to allocate.
//
lResult = RegQueryInfoKey( hKey, NULL, NULL, NULL, &dwSubKeys, &dwMaxLength, NULL, NULL, NULL, NULL, NULL, NULL ); if ( lResult != ERROR_SUCCESS ) { SaveErrorMessage( lResult ); goto cleanup; }
//
// SPECIAL CASE:
// -------------
// For HKLM\SYSTEM\CONTROLSET002 it is found to be API returning value 0 for dwMaxLength
// though there are subkeys underneath this -- to handle this, we are doing a workaround
// by assuming the max registry key length
//
if ( dwSubKeys != 0 && dwMaxLength == 0 ) { dwMaxLength = 256; } else if ( dwMaxLength < 256 ) { // always assume 100% more length that what is returned by the API
dwMaxLength *= 2; }
//
// do the memory allocations
//
// sub key
dwMaxLength++; pwszSubKey = (LPWSTR) AllocateMemory( dwMaxLength * sizeof( WCHAR ) ); if ( pwszSubKey == NULL ) { SaveErrorMessage( ERROR_OUTOFMEMORY ); lResult = ERROR_OUTOFMEMORY; goto cleanup; }
// buffer for new full key name
dwNewFullKeyLength = StringLength( pwszFullKey, 0 ) + dwMaxLength + 1; pwszNewFullKey = (LPWSTR) AllocateMemory( dwNewFullKeyLength * sizeof( WCHAR ) ); if ( pwszNewFullKey == NULL ) { SaveErrorMessage( ERROR_OUTOFMEMORY ); lResult = ERROR_OUTOFMEMORY; goto cleanup; }
//
// enumerate the value names and display
//
lResult = ERROR_SUCCESS; for( dw = 0; dw < dwSubKeys; dw++ ) { dwLength = dwMaxLength; ZeroMemory( pwszSubKey, dwLength * sizeof( WCHAR ) ); lResult = RegEnumKeyEx( hKey, dw, pwszSubKey, &dwLength, NULL, NULL, NULL, NULL ); if ( lResult != ERROR_SUCCESS ) { // **********************************************************
// simply ignore the error here -- for a detailed description
// check the raid bug #572077
// **********************************************************
lResult = ERROR_SUCCESS; continue; }
// search for the pattern -- if needed
pInfo->bKeyMatched = TRUE; // default
pInfo->bUpdateMatchCount = FALSE; if ( pParams->dwSearchFlags & REG_FIND_KEYS ) { pInfo->bKeyMatched = SearchData( (BYTE*) pwszSubKey, REG_SZ, dwLength * sizeof( WCHAR ), pParams ); if ( pInfo->bKeyMatched == FALSE ) { if ( pParams->bRecurseSubKeys == FALSE && pParams->dwSearchFlags == REG_FIND_KEYS ) { // user just want to search in the key names
// and there is no recursion
// since the current didn't match skip this key
continue; } } else { pInfo->bUpdateMatchCount = TRUE; } } else if ( pParams->dwSearchFlags != 0 || pParams->pwszValueName != NULL ) { pInfo->bKeyMatched = FALSE; }
// format the new full key name
StringCopy( pwszNewFullKey, pwszFullKey, dwNewFullKeyLength ); StringConcat( pwszNewFullKey, L"\\", dwNewFullKeyLength ); StringConcat( pwszNewFullKey, pwszSubKey, dwNewFullKeyLength );
// show the key name
pInfo->bShowKey = TRUE; if ( pInfo->bKeyMatched == TRUE && pParams->pwszValueName == NULL && pParams->arrTypes == NULL ) { // update the match count
pInfo->dwMatchCount++; pInfo->bUpdateMatchCount = FALSE;
// ...
pInfo->bShowKey = FALSE; ShowMessageEx( stdout, 1, TRUE, L"%s\n", pwszNewFullKey ); }
// check whether we need to recurse or not
if ( pParams->bRecurseSubKeys == TRUE ) { lResult = RegOpenKeyEx( hKey, pwszSubKey, 0, KEY_READ, &hSubKey ); if ( lResult == ERROR_SUCCESS ) { // enumerate the sub-keys
lResult = QueryEnumKeys( hSubKey, pwszNewFullKey, pParams, pInfo );
// close the sub key
SafeCloseKey( &hSubKey ); } else { // **********************************************************
// simply ignore the error here -- for a detailed description
// check the raid bug #572077
// **********************************************************
lResult = ERROR_SUCCESS; } } }
cleanup:
// release the memory
FreeMemory( &pwszSubKey ); FreeMemory( &pwszNewFullKey );
// return
return lResult; }
BOOL SearchData( LPBYTE pByteData, DWORD dwType, DWORD dwSize, PTREG_PARAMS pParams ) { // local variables
DWORD dw = 0; DWORD dwLength = 0; BOOL bResult = FALSE; LPCWSTR pwszEnd = NULL; LPCWSTR pwszData = NULL; LPWSTR pwszString = NULL; LPCWSTR pwszSeparator = NULL; BOOL bShowSeparator = FALSE; DWORD dwFlags = 0;
// check input
if ( pByteData == NULL || pParams == NULL ) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; }
switch( dwType ) { case REG_SZ: case REG_EXPAND_SZ: { pwszData = (LPCWSTR) pByteData; break; }
default: { // allocate memory which is double the (dwSize + 1) & +10 -> buffer
// but do this only for types that need memory allocation
dwLength = (dwSize + 1) * 2 + 10; pwszString = (LPWSTR) AllocateMemory( dwLength * sizeof( WCHAR ) ); if ( pwszString == NULL ) { return FALSE; }
// ...
pwszData = pwszString; } }
switch( dwType ) { case REG_MULTI_SZ: { //
// Replace '\0' with "\0" for MULTI_SZ
//
pwszEnd = (LPCWSTR) pByteData; pwszSeparator = pParams->wszSeparator; StringCopy( pwszString, cwszNullString, dwLength ); while( ((BYTE*) pwszEnd) < (pByteData + dwSize) ) { if( *pwszEnd == 0 ) { // enable the display of value separator and skip this
pwszEnd++; bShowSeparator = TRUE; } else { // check whether we need to display the separator or not
if ( bShowSeparator == TRUE ) { StringConcat( pwszString, pwszSeparator, dwLength ); }
// ...
StringConcat( pwszString, pwszEnd, dwLength ); pwszEnd += StringLength( pwszEnd, 0 ); } }
// ...
break; }
case REG_SZ: case REG_EXPAND_SZ: // do nothing
break;
default: { StringCopy( pwszString, cwszNullString, dwLength ); for( dw = 0; dw < dwSize; dw++ ) { if ( SetReason2( 1, L"%02X", pByteData[ dw ] ) == FALSE ) { FreeMemory( &pwszString ); SetLastError( ERROR_OUTOFMEMORY ); return FALSE; }
// ...
StringConcat( pwszString, GetReason(), dwLength ); }
// ...
break; }
case REG_DWORD: case REG_DWORD_BIG_ENDIAN: { if ( StringCompare( pParams->pwszSearchData, L"0x", TRUE, 2 ) == 0 ) { if ( SetReason2( 1, L"0x%x", *((DWORD*) pByteData) ) == FALSE ) { FreeMemory( &pwszString ); SetLastError( ERROR_OUTOFMEMORY ); return FALSE; } } else { if ( SetReason2( 1, L"%d", *((DWORD*) pByteData) ) == FALSE ) { FreeMemory( &pwszString ); SetLastError( ERROR_OUTOFMEMORY ); return FALSE; } }
// ...
StringCopy( pwszString, GetReason(), dwLength ); break; } }
// do the search now
bResult = TRUE; if ( pParams->bExactMatch == FALSE ) { // prepare the comparision flags
dwFlags = PATTERN_NOPARSING; dwFlags |= ((pParams->bCaseSensitive == FALSE) ? PATTERN_COMPARE_IGNORECASE : 0);
// ...
if ( MatchPatternEx( pwszData, pParams->pwszSearchData, dwFlags ) == FALSE ) { bResult = FALSE; SetLastError( ERROR_NOT_FOUND ); } } else { if ( StringCompare( pwszData, pParams->pwszSearchData, (pParams->bCaseSensitive == FALSE), 0 ) != 0 ) { bResult = FALSE; SetLastError( ERROR_NOT_FOUND ); } }
// release the memory allocated
FreeMemory( &pwszString );
// return
return bResult; }
BOOL ParseTypeInfo( LPCWSTR pwszTypes, PTREG_PARAMS pParams ) { // local variables
LONG lArrayIndex = 0; LONG lLength = 0; LONG lIndex = 0; LONG lStart = 0; LONG lType = 0; LPCWSTR pwsz = NULL;
// check input
if ( pwszTypes == NULL || pParams == NULL ) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; }
// validate the types array
if ( pParams->arrTypes == NULL ) { pParams->arrTypes = CreateDynamicArray(); if ( pParams->arrTypes == NULL ) { SetLastError( ERROR_OUTOFMEMORY ); return FALSE; } }
// parse the types information
lStart = lIndex = 0; while ( lIndex != -1 ) { lIndex = FindString2( pwszTypes, L",", TRUE, lStart ); if ( lIndex == -1 ) { lLength = 0; } else { lLength = lIndex - lStart; }
// append a row
lArrayIndex = DynArrayAppendRow( pParams->arrTypes, 2 ); if ( lArrayIndex == -1 ) { SetLastError( ERROR_OUTOFMEMORY ); return FALSE; }
// add the type info
if ( DynArraySetString2( pParams->arrTypes, lArrayIndex, 0, pwszTypes + lStart, lLength ) == -1 ) { SetLastError( ERROR_OUTOFMEMORY ); return FALSE; }
// get the type back from array
pwsz = DynArrayItemAsString2( pParams->arrTypes, lArrayIndex, 0 ); if ( pwsz == NULL ) { SetLastError( (DWORD) STG_E_UNKNOWN ); return FALSE; }
// determine the numeric equivalent of it
lType = IsRegDataType( pwsz ); if( lType == -1 ) { if (IsNumeric( pwsz, 10, TRUE ) == TRUE ) { lType = AsLong( pwsz, 10 ); } else { SetLastError( (DWORD) MK_E_SYNTAX ); return FALSE; } }
if ( DynArraySetLong2( pParams->arrTypes, lArrayIndex, 1, lType ) == -1 ) { SetLastError( ERROR_OUTOFMEMORY ); return FALSE; }
// update the start position
lStart = lIndex + 1; }
// ...
SetLastError( ERROR_SUCCESS ); return TRUE; }
|