2342 lines
68 KiB
C
2342 lines
68 KiB
C
/*++
|
|
|
|
Copyright (c) 1989-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sdbapi.c
|
|
|
|
Abstract:
|
|
|
|
BUGBUG: This module implements ...
|
|
|
|
Author:
|
|
|
|
dmunsil created sometime in 1999
|
|
|
|
Revision History:
|
|
|
|
several people contributed (vadimb, clupu, ...)
|
|
|
|
--*/
|
|
|
|
#include "sdbp.h"
|
|
#include "initguid.h"
|
|
|
|
DEFINE_GUID(GUID_SYSMAIN_SDB, 0x11111111, 0x1111, 0x1111, 0x11, 0x11, 0x11, 0x11, \
|
|
0x11, 0x11, 0x11, 0x11);
|
|
DEFINE_GUID(GUID_APPHELP_SDB, 0x22222222, 0x2222, 0x2222, 0x22, 0x22, 0x22, 0x22, \
|
|
0x22, 0x22, 0x22, 0x22);
|
|
DEFINE_GUID(GUID_SYSTEST_SDB, 0x33333333, 0x3333, 0x3333, 0x33, 0x33, 0x33, 0x33, \
|
|
0x33, 0x33, 0x33, 0x33);
|
|
DEFINE_GUID(GUID_DRVMAIN_SDB, 0xF9AB2228, 0x3312, 0x4A73, 0xB6, 0xF9, 0x93, 0x6D, \
|
|
0x70, 0xE1, 0x12, 0xEF);
|
|
DEFINE_GUID(GUID_MSIMAIN_SDB, 0xD8FF6D16, 0x6A3A, 0x468A, 0x8B, 0x44, 0x01, 0x71, \
|
|
0x4D, 0xDC, 0x49, 0xEA);
|
|
DEFINE_GUID(GUID_APPHELP_SP_SDB, 0x44444444, 0x4444, 0x4444, 0x44, 0x44, 0x44, 0x44, \
|
|
0x44, 0x44, 0x44, 0x44);
|
|
|
|
#ifdef _DEBUG_SPEW
|
|
|
|
//
|
|
// Shim Debug output support
|
|
//
|
|
int g_iShimDebugLevel = SHIM_DEBUG_UNINITIALIZED;
|
|
|
|
DBGLEVELINFO g_rgDbgLevelInfo[DEBUG_LEVELS] = {
|
|
{ "Err", sdlError },
|
|
{ "Warn", sdlWarning },
|
|
{ "Fail", sdlFail },
|
|
{ "Info", sdlInfo }
|
|
};
|
|
|
|
PCH g_szDbgLevelUser = "User";
|
|
|
|
#endif // _DEBUG_SPEW
|
|
|
|
|
|
|
|
BOOL
|
|
SdbpInitializeSearchDBContext(
|
|
PSEARCHDBCONTEXT pContext
|
|
);
|
|
|
|
|
|
#if defined(KERNEL_MODE) && defined(ALLOC_PRAGMA)
|
|
#pragma alloc_text(PAGE, ShimExceptionHandler)
|
|
#pragma alloc_text(PAGE, SdbpCreateSearchDBContext)
|
|
#pragma alloc_text(PAGE, SdbpInitializeSearchDBContext)
|
|
#pragma alloc_text(PAGE, SdbpReleaseSearchDBContext)
|
|
#pragma alloc_text(PAGE, SdbpCheckForMatch)
|
|
#pragma alloc_text(PAGE, SdbpSearchDB)
|
|
#pragma alloc_text(PAGE, SdbpCreateSearchDBContext)
|
|
#pragma alloc_text(PAGE, SdbGetDatabaseMatch)
|
|
#pragma alloc_text(PAGE, SdbQueryData)
|
|
#pragma alloc_text(PAGE, SdbQueryDataEx)
|
|
#pragma alloc_text(PAGE, SdbReadEntryInformation)
|
|
#pragma alloc_text(PAGE, PrepareFormatForUnicode)
|
|
#pragma alloc_text(PAGE, ShimDbgPrint)
|
|
#endif
|
|
|
|
#if DBG
|
|
const BOOL g_bDBG = TRUE;
|
|
#else
|
|
const BOOL g_bDBG = FALSE;
|
|
#endif
|
|
|
|
//
|
|
// Exception handler
|
|
//
|
|
|
|
ULONG
|
|
ShimExceptionHandler(
|
|
PEXCEPTION_POINTERS pexi,
|
|
char* szFile,
|
|
DWORD dwLine
|
|
)
|
|
{
|
|
#ifndef KERNEL_MODE // in kmode exceptions won't work anyway
|
|
|
|
DBGPRINT((sdlError,
|
|
"ShimExceptionHandler",
|
|
"Shim Exception %#x in module \"%hs\", line %d, at address %#p. flags:%#x. !exr %#p !cxr %#p",
|
|
pexi->ExceptionRecord->ExceptionCode,
|
|
szFile,
|
|
dwLine,
|
|
CONTEXT_TO_PROGRAM_COUNTER(pexi->ContextRecord),
|
|
pexi->ExceptionRecord->ExceptionFlags,
|
|
pexi->ExceptionRecord,
|
|
pexi->ContextRecord));
|
|
|
|
//
|
|
// Special-case stack overflow exception which is likely to occur due to
|
|
// low memory conditions during stress. The process is dead anyway so we
|
|
// will not handle this exception.
|
|
//
|
|
if (pexi->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
#if DBG
|
|
SDB_BREAK_POINT();
|
|
#endif // DBG
|
|
|
|
#endif // KERNEL_MODE
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
BOOL
|
|
SdbpResolveAndSplitPath(
|
|
IN DWORD dwFlags, // context flags (SEARCHDBF_NO_LFN in particular)
|
|
IN LPCTSTR szFullPath, // a full UNC or DOS path & filename, "c:\foo\myfile.ext"
|
|
OUT LPTSTR szDir, // the drive and dir portion of the filename "c:\foo\"
|
|
OUT LPTSTR szName, // the filename portion "myfile"
|
|
OUT LPTSTR szExt // the extension portion ".ext"
|
|
)
|
|
/*++
|
|
Return: TRUE on success, FALSE otherwise.
|
|
|
|
Desc: This function takes a full path and splits it into pieces ala splitpath,
|
|
but also converts short file names to long names.
|
|
NOTE: The caller is responsible for allocating enough space
|
|
for the passed-in strings to take any portion of the path.
|
|
For safety, allocate at least MAX_PATH WCHARS for each piece.
|
|
--*/
|
|
{
|
|
TCHAR* szCursor;
|
|
TCHAR szLongFileName[MAX_PATH + 1];
|
|
BOOL bFound;
|
|
DWORD i;
|
|
|
|
assert(szFullPath && szDir && szName && szExt);
|
|
|
|
//
|
|
// Parse the directory.
|
|
//
|
|
szDir[0] = _T('\0');
|
|
|
|
szCursor = _tcsrchr(szFullPath, _T('\\')); // last backslash please
|
|
if (szCursor == NULL) {
|
|
szCursor = (LPTSTR)szFullPath;
|
|
} else {
|
|
_tcsncpy(szDir, szFullPath, szCursor - szFullPath + 1);
|
|
szDir[szCursor - szFullPath + 1] = _T('\0');
|
|
}
|
|
|
|
#ifndef KERNEL_MODE
|
|
|
|
//
|
|
// Make sure we're using the long filename
|
|
//
|
|
if (dwFlags & SEARCHDBF_NO_LFN) {
|
|
assert(_tcslen(szCursor) < CHARCOUNT(szLongFileName));
|
|
_tcscpy(szLongFileName, szCursor);
|
|
} else {
|
|
if (!SdbpGetLongFileName(szFullPath, szLongFileName)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
#else // KERNEL_MODE
|
|
|
|
//
|
|
// When we are in kernel mode, our file name is always considered to be "long".
|
|
// At this point szCursor points to the last '\\' or to the beginning of the name.
|
|
//
|
|
if (*szCursor == _T('\\')) {
|
|
++szCursor;
|
|
}
|
|
|
|
//
|
|
// Make sure that we have enough room for the name.
|
|
//
|
|
assert(wcslen(szCursor) < CHARCOUNT(szLongFileName));
|
|
wcscpy(szLongFileName, szCursor);
|
|
|
|
#endif // KERNEL_MODE
|
|
|
|
//
|
|
// Parse name & extension
|
|
//
|
|
szExt[0] = _T('\0');
|
|
szName[0] = _T('\0');
|
|
|
|
//
|
|
// Within the long file name find the last dot
|
|
//
|
|
szCursor = _tcsrchr(szLongFileName, _T('.'));
|
|
|
|
if (szCursor != NULL) {
|
|
_tcsncpy(szName, szLongFileName, szCursor - szLongFileName);
|
|
szName [szCursor-szLongFileName] = _T('\0');
|
|
_tcscpy(szExt, szCursor);
|
|
} else {
|
|
_tcscpy(szName, szLongFileName);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SdbpCreateSearchDBContext(
|
|
PSEARCHDBCONTEXT pContext,
|
|
LPCTSTR szPath,
|
|
LPCTSTR szModuleName,
|
|
LPCTSTR pEnvironment
|
|
)
|
|
/*++
|
|
Return: TRUE - search db context was successfully created
|
|
|
|
Desc: This function creates context for searching the database, in particular, the
|
|
context is initalized with the path of probable local database location,
|
|
executable path is broken down into containing directory and the filename part.
|
|
--*/
|
|
{
|
|
DWORD dwPathLen;
|
|
BOOL bReturn = FALSE;
|
|
TCHAR* szDirectory = NULL;
|
|
TCHAR* szExt = NULL;
|
|
TCHAR* szFullName = NULL;
|
|
TCHAR* szFileName = NULL;
|
|
TCHAR* szModule = NULL;
|
|
|
|
assert(NULL != szPath);
|
|
assert(NULL != pContext);
|
|
|
|
dwPathLen = _tcslen(szPath);
|
|
|
|
//
|
|
// Allocate enough to guarantee our strings will not overflow
|
|
//
|
|
szDirectory = SdbAlloc((dwPathLen + 1) * sizeof(TCHAR));
|
|
szFullName = SdbAlloc((_MAX_PATH + 1) * sizeof(TCHAR));
|
|
|
|
if (szModuleName) {
|
|
szModule = SdbAlloc((_tcslen(szModuleName) + 1) * sizeof(TCHAR));
|
|
if (!szModule) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpCreateSearchDBContext",
|
|
"Unable to allocate memory for szModule.\n"));
|
|
goto out;
|
|
}
|
|
_tcscpy(szModule, szModuleName);
|
|
}
|
|
|
|
STACK_ALLOC(szExt, (_MAX_PATH + 1) * sizeof(TCHAR));
|
|
STACK_ALLOC(szFileName, (_MAX_PATH + 1) * sizeof(TCHAR));
|
|
|
|
if (!szDirectory || !szExt || !szFullName || !szFileName || !pContext) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpCreateSearchDBContext",
|
|
"Unable to allocate memory for strings.\n"));
|
|
goto out;
|
|
}
|
|
|
|
if (!SdbpResolveAndSplitPath(pContext->dwFlags, szPath, szDirectory, szFileName, szExt)) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpCreateSearchDBContext",
|
|
"Unable to parse executable path for \"%s\".\n",
|
|
szPath));
|
|
goto out;
|
|
}
|
|
|
|
_tcscpy(szFullName, szFileName);
|
|
_tcscat(szFullName, szExt);
|
|
|
|
pContext->pEnvironment = pEnvironment;
|
|
pContext->szDir = szDirectory;
|
|
pContext->szName = szFullName; // fullname (filename + ext)
|
|
pContext->szModuleName = szModule;
|
|
|
|
//
|
|
// We do not retain szExt (don't need it)
|
|
//
|
|
// Calculate this later -- implied by RtlZeroMemory statement above
|
|
//
|
|
pContext->pSearchParts = NULL;
|
|
pContext->szProcessHistory = NULL;
|
|
|
|
bReturn = TRUE;
|
|
|
|
out:
|
|
if (szExt != NULL) {
|
|
STACK_FREE(szExt);
|
|
}
|
|
|
|
if (szFileName != NULL) {
|
|
STACK_FREE(szFileName);
|
|
}
|
|
|
|
if (!bReturn) {
|
|
|
|
if (szDirectory != NULL) {
|
|
SdbFree(szDirectory);
|
|
}
|
|
if (szFullName != NULL) {
|
|
SdbFree(szFullName);
|
|
}
|
|
|
|
if (szModule != NULL) {
|
|
SdbFree(szModule);
|
|
}
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SdbpInitializeSearchDBContext(
|
|
PSEARCHDBCONTEXT pContext
|
|
)
|
|
/*++
|
|
Return: TRUE - the context was successfully initialized with the process history
|
|
which was broken down into the separate search paths
|
|
|
|
Desc: This function prepares search context for use, obtaining and parsing process
|
|
history into separate paths. The array of these search paths is used then
|
|
by the caller to inquire about matching files that might be present in one
|
|
of the these places.
|
|
In Kernel mode use SEARCHDBF_NO_PROCESS_HISTORY flag within context
|
|
it will include only the current exe path into the process history
|
|
--*/
|
|
{
|
|
BOOL bSuccess = TRUE;
|
|
LPTSTR pszProcessHistory = NULL;
|
|
|
|
if (pContext->pSearchParts != NULL) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (pContext->dwFlags & SEARCHDBF_NO_PROCESS_HISTORY) {
|
|
|
|
pszProcessHistory = pContext->szProcessHistory;
|
|
|
|
if (pszProcessHistory == NULL) {
|
|
|
|
DWORD DirLen = _tcslen(pContext->szDir);
|
|
DWORD NameLen = _tcslen(pContext->szName);
|
|
|
|
//
|
|
// We create a temporary process history
|
|
//
|
|
pContext->szProcessHistory = SdbAlloc((DirLen + NameLen + 1) * sizeof(TCHAR));
|
|
|
|
if (pContext->szProcessHistory == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpInitializeSearchDBContext",
|
|
"Failed to allocate buffer %d bytes\n",
|
|
(DirLen + NameLen + 1) * sizeof(TCHAR)));
|
|
return FALSE;
|
|
}
|
|
|
|
pszProcessHistory = pContext->szProcessHistory;
|
|
|
|
RtlMoveMemory(pszProcessHistory, pContext->szDir, DirLen * sizeof(TCHAR));
|
|
RtlMoveMemory(pszProcessHistory + DirLen, pContext->szName, NameLen * sizeof(TCHAR));
|
|
|
|
*(pszProcessHistory + DirLen + NameLen) = TEXT('\0');
|
|
}
|
|
|
|
//
|
|
// When we are here -- we either have a process history or we just
|
|
// created it consisting of a single search item
|
|
//
|
|
|
|
} else {
|
|
|
|
#ifndef KERNEL_MODE
|
|
if (pContext->szProcessHistory == NULL) {
|
|
|
|
pContext->szProcessHistory = GetProcessHistory(pContext->pEnvironment,
|
|
pContext->szDir,
|
|
pContext->szName);
|
|
if (pContext->szProcessHistory == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpInitializeSearchDBContext",
|
|
"Failed to retrieve process history\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
pszProcessHistory = pContext->szProcessHistory;
|
|
#else
|
|
//
|
|
// This is the case with KERNEL_MODE. YOU HAVE TO SET SEARCHDBF_NO_PROCESS_HISTORY
|
|
//
|
|
assert(FALSE);
|
|
pszProcessHistory = NULL;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// At this point pszProcessHistory is NOT NULL
|
|
//
|
|
assert(pszProcessHistory != NULL);
|
|
|
|
DBGPRINT((sdlInfo,
|
|
"SdbpInitializeSearchDBContext",
|
|
"Using Process History: \"%s\"\n",
|
|
pszProcessHistory));
|
|
|
|
bSuccess = SdbpCreateSearchPathPartsFromPath(pszProcessHistory, &pContext->pSearchParts);
|
|
|
|
if (bSuccess) {
|
|
pContext->dwFlags |= SEARCHDBF_INITIALIZED;
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
void
|
|
SdbpReleaseSearchDBContext(
|
|
PSEARCHDBCONTEXT pContext
|
|
)
|
|
/*++
|
|
Return: void
|
|
|
|
Desc: Resets search DB context, frees memory allocated for each of the
|
|
temporary buffers.
|
|
--*/
|
|
{
|
|
if (pContext == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (pContext->szProcessHistory != NULL) {
|
|
SdbFree(pContext->szProcessHistory);
|
|
pContext->szProcessHistory = NULL;
|
|
}
|
|
|
|
if (pContext->pSearchParts != NULL) {
|
|
SdbFree(pContext->pSearchParts);
|
|
pContext->pSearchParts = NULL;
|
|
}
|
|
|
|
if (pContext->szDir != NULL) {
|
|
SdbFree(pContext->szDir);
|
|
pContext->szDir = NULL;
|
|
}
|
|
|
|
if (pContext->szName != NULL) {
|
|
SdbFree(pContext->szName);
|
|
pContext->szName = NULL;
|
|
}
|
|
|
|
if (pContext->szModuleName != NULL) {
|
|
SdbFree(pContext->szModuleName);
|
|
pContext->szModuleName = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
SdbpIsExeEntryEnabled(
|
|
IN PDB pdb,
|
|
IN TAGID tiExe,
|
|
OUT GUID* pGUID,
|
|
OUT DWORD* pdwFlags
|
|
)
|
|
{
|
|
TAGID tiExeID;
|
|
DWORD i;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//
|
|
// Get the EXE's GUID
|
|
//
|
|
tiExeID = SdbFindFirstTag(pdb, tiExe, TAG_EXE_ID);
|
|
|
|
if (tiExeID == TAGID_NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpIsExeEntryEnabled",
|
|
"Failed to read TAG_EXE_ID for tiExe 0x%x !\n",
|
|
tiExe));
|
|
goto error;
|
|
}
|
|
|
|
if (!SdbReadBinaryTag(pdb, tiExeID, (PBYTE)pGUID, sizeof(GUID))) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpIsExeEntryEnabled",
|
|
"Failed to read the GUID for tiExe 0x%x !\n",
|
|
tiExe));
|
|
goto error;
|
|
}
|
|
|
|
if (!SdbGetEntryFlags(pGUID, pdwFlags)) {
|
|
DBGPRINT((sdlWarning,
|
|
"SdbpIsExeEntryEnabled",
|
|
"No flags for tiExe 0x%lx\n",
|
|
tiExe));
|
|
|
|
*pdwFlags = 0;
|
|
} else {
|
|
DBGPRINT((sdlInfo,
|
|
"SdbpIsExeEntryEnabled",
|
|
"Retrieved flags for this app 0x%x.\n",
|
|
*pdwFlags));
|
|
}
|
|
|
|
if (!(*pdwFlags & SHIMREG_DISABLE_SHIM)) {
|
|
fSuccess = TRUE;
|
|
}
|
|
|
|
error:
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
#define EXTRA_BUF_SPACE (16 * sizeof(TCHAR))
|
|
|
|
//
|
|
// Matching an entry:
|
|
//
|
|
// 1. We check whether each file exists by calling SdbGetFileInfo
|
|
// 2. Each file's info is stored in FILEINFOCHAINITEM (allocated on the stack) - such as pointer
|
|
// to the actual FILEINFO structure (stored in file attribute cache) and tiMatch denoting
|
|
// the entry in the database for a given MATCHING_FILE
|
|
// 3. After we have verified that all the matching files do exist -- we proceed to walk the
|
|
// chain of FILEINFOCHAINITEM structures and call SdbCheckAllAttributes to check on all the
|
|
// other attributes of the file
|
|
// 4. Cleanup: File attribute cache is destroyed when the database is closed via call to
|
|
// SdbCleanupAttributeMgr
|
|
// 5. No cleanup is needed for FILEINFOCHAINITEM structures (they are allocated on the stack and
|
|
// just "go away")
|
|
//
|
|
//
|
|
|
|
typedef struct tagFILEINFOCHAINITEM {
|
|
PVOID pFileInfo; // pointer to the actual FILEINFO
|
|
// structure (from attribute cache)
|
|
TAGID tiMatch; // matching entry in the database
|
|
|
|
struct tagFILEINFOCHAINITEM* pNextItem; // pointer to the next matching file
|
|
|
|
} FILEINFOCHAINITEM, *PFILEINFOCHAINITEM;
|
|
|
|
|
|
BOOL
|
|
SdbpCheckForMatch(
|
|
IN HSDB hSDB, // context ptr
|
|
IN PDB pdb, // pdb to get match criteria from
|
|
IN TAGID tiExe, // TAGID of exe record to get match criteria from
|
|
IN PSEARCHDBCONTEXT pContext, // search db context (includes name/path)
|
|
OUT PMATCHMODE pMatchMode, // the match mode of this EXE
|
|
OUT GUID* pGUID,
|
|
OUT DWORD* pdwFlags
|
|
)
|
|
/*++
|
|
Return: TRUE if match is good, FALSE if this EXE doesn't match.
|
|
|
|
Desc: Given an EXE tag and a name and dir, checks the DB for MATCHING_FILE
|
|
tags, and checks all the matching info available for each the
|
|
files listed. If all the files check out, returns TRUE. If any of
|
|
the files don't exist, or don't match on one of the given
|
|
criteria, returns FALSE.
|
|
--*/
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
BOOL bMatchLogicNot = FALSE;
|
|
BOOL bAllAttributesMatch = FALSE;
|
|
TAGID tiMatch;
|
|
TCHAR* szTemp = NULL;
|
|
LONG nFullPathBufSize = 0;
|
|
LONG nFullPathReqBufSize = 0;
|
|
LPTSTR szFullPath = NULL;
|
|
LONG i;
|
|
LONG NameLen = _tcslen(pContext->szName);
|
|
LONG MatchFileLen;
|
|
PSEARCHPATHPARTS pSearchPath;
|
|
PSEARCHPATHPART pSearchPathPart;
|
|
NTSTATUS Status;
|
|
PFILEINFOCHAINITEM pFileInfoItem = NULL;
|
|
PFILEINFOCHAINITEM pFileInfoItemList = NULL; // holds the list of matching files
|
|
// which were found
|
|
PFILEINFOCHAINITEM pFileInfoItemNext; // holds the next item in the list
|
|
PVOID pFileInfo = NULL; // points to the current file's
|
|
// information structure
|
|
BOOL bDisableAttributeCache = FALSE; // will be set according to search
|
|
|
|
TAGID tiName, tiTemp, tiMatchLogicNot;
|
|
TCHAR* szMatchFile = NULL;
|
|
HANDLE hFileHandle; // handle for the file we're checking, optimization
|
|
LPVOID pImageBase; // pointer to the image
|
|
DWORD dwImageSize = 0;
|
|
WORD wDefaultMatchMode;
|
|
|
|
//
|
|
// Check context's flags
|
|
//
|
|
if (pContext->dwFlags & SEARCHDBF_NO_ATTRIBUTE_CACHE) {
|
|
bDisableAttributeCache = TRUE;
|
|
}
|
|
|
|
//
|
|
// Loop through matching criteria.
|
|
//
|
|
tiMatch = SdbFindFirstTag(pdb, tiExe, TAG_MATCHING_FILE);
|
|
|
|
while (tiMatch != TAGID_NULL) {
|
|
|
|
tiMatchLogicNot = SdbFindFirstTag(pdb, tiMatch, TAG_MATCH_LOGIC_NOT);
|
|
bMatchLogicNot = (tiMatchLogicNot != TAGID_NULL);
|
|
|
|
tiName = SdbFindFirstTag(pdb, tiMatch, TAG_NAME);
|
|
|
|
if (!tiName) {
|
|
goto out;
|
|
}
|
|
|
|
szTemp = SdbGetStringTagPtr(pdb, tiName);
|
|
|
|
if (szTemp == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpCheckForMatch",
|
|
"Failed to get the string from the database.\n"));
|
|
goto out;
|
|
}
|
|
|
|
if (szTemp[0] == TEXT('*')) {
|
|
//
|
|
// This is a signal that we should use the exe name.
|
|
//
|
|
szMatchFile = pContext->szName;
|
|
MatchFileLen = NameLen;
|
|
hFileHandle = pContext->hMainFile;
|
|
pImageBase = pContext->pImageBase;
|
|
dwImageSize = pContext->dwImageSize;
|
|
|
|
} else {
|
|
|
|
szMatchFile = szTemp;
|
|
MatchFileLen = _tcslen(szMatchFile);
|
|
hFileHandle = INVALID_HANDLE_VALUE;
|
|
pImageBase = NULL;
|
|
}
|
|
|
|
//
|
|
// When searching for files, we look in all process' exe directories,
|
|
// starting with the current process and working backwards through the process
|
|
// tree.
|
|
//
|
|
|
|
//
|
|
// See that the context is good...
|
|
//
|
|
if (!(pContext->dwFlags & SEARCHDBF_INITIALIZED)) {
|
|
|
|
if (!SdbpInitializeSearchDBContext(pContext)) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpCheckForMatch",
|
|
"Failed to initialize SEARCHDBCONTEXT.\n"));
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
pSearchPath = pContext->pSearchParts;
|
|
|
|
assert(pSearchPath != NULL);
|
|
|
|
for (i = 0; i < (LONG)pSearchPath->PartCount && NULL == pFileInfo; ++i) {
|
|
|
|
pSearchPathPart = &pSearchPath->Parts[i];
|
|
|
|
//
|
|
// There are two ways to specify a matching file: A relative path
|
|
// from the EXE, or an absolute path. To specify an absolute path,
|
|
// an environment variable (like "%systemroot%") must be used
|
|
// as the base of the path. Therefore, we check for the first character
|
|
// of the matching file to be % and if so, we assume that it is an
|
|
// absolute path.
|
|
//
|
|
#ifndef KERNEL_MODE
|
|
if (szMatchFile[0] == TEXT('%')) {
|
|
//
|
|
// Absolute path. Contains environment variables, get expanded size.
|
|
//
|
|
nFullPathReqBufSize = SdbExpandEnvironmentStrings(szMatchFile, NULL, 0);
|
|
|
|
} else
|
|
#endif // KERNEL_MODE
|
|
{
|
|
//
|
|
// Relative path. Determine size of full path.
|
|
//
|
|
nFullPathReqBufSize = (pSearchPathPart->PartLength + MatchFileLen + 1) * sizeof(TCHAR);
|
|
}
|
|
|
|
if (nFullPathBufSize < nFullPathReqBufSize) {
|
|
//
|
|
// Need to realloc the buffer.
|
|
//
|
|
if (szFullPath == NULL) {
|
|
nFullPathBufSize = _MAX_PATH * sizeof(TCHAR);
|
|
|
|
if (nFullPathReqBufSize >= nFullPathBufSize) {
|
|
nFullPathBufSize = nFullPathReqBufSize + EXTRA_BUF_SPACE;
|
|
}
|
|
} else {
|
|
STACK_FREE(szFullPath);
|
|
nFullPathBufSize = nFullPathReqBufSize + EXTRA_BUF_SPACE;
|
|
}
|
|
|
|
STACK_ALLOC(szFullPath, nFullPathBufSize);
|
|
}
|
|
|
|
if (szFullPath == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpCheckForMatch",
|
|
"Failed to allocate %d bytes for FullPath.\n",
|
|
nFullPathBufSize));
|
|
goto out;
|
|
}
|
|
|
|
#ifndef KERNEL_MODE
|
|
if (szMatchFile[0] == TEXT('%')) {
|
|
//
|
|
// Absolute Path. Path contains environment variables, expand it.
|
|
//
|
|
if (!SdbExpandEnvironmentStrings(szMatchFile, szFullPath, nFullPathBufSize)) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpCheckForMatch",
|
|
"SdbExpandEnvironmentStrings failed to expand strings for %s.\n",
|
|
szMatchFile));
|
|
goto out;
|
|
}
|
|
|
|
} else
|
|
#endif // KERNEL_MODE
|
|
{
|
|
//
|
|
// Relative path. Concatenate EXE directory with specified relative path.
|
|
//
|
|
RtlMoveMemory(szFullPath,
|
|
pSearchPathPart->pszPart,
|
|
pSearchPathPart->PartLength * sizeof(TCHAR));
|
|
|
|
RtlMoveMemory(szFullPath + pSearchPathPart->PartLength,
|
|
szMatchFile,
|
|
(MatchFileLen + 1) * sizeof(TCHAR));
|
|
}
|
|
|
|
pFileInfo = SdbGetFileInfo(hSDB,
|
|
szFullPath,
|
|
hFileHandle,
|
|
pImageBase,
|
|
dwImageSize, // this will be set ONLY if pImageBase != NULL
|
|
bDisableAttributeCache);
|
|
|
|
//
|
|
// This is not a bug, attributes are cleaned up when the database
|
|
// context is released.
|
|
//
|
|
}
|
|
|
|
if (pFileInfo == NULL && !bMatchLogicNot) {
|
|
DBGPRINT((sdlInfo,
|
|
"SdbpCheckForMatch",
|
|
"Matching file \"%s\" not found.\n",
|
|
szMatchFile));
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// Create and store a new FILEINFOITEM on the stack
|
|
//
|
|
STACK_ALLOC(pFileInfoItem, sizeof(*pFileInfoItem));
|
|
|
|
if (pFileInfoItem == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpCheckForMatch",
|
|
"Failed to allocate %d bytes for FILEINFOITEM\n",
|
|
sizeof(*pFileInfoItem)));
|
|
goto out;
|
|
}
|
|
|
|
pFileInfoItem->pFileInfo = pFileInfo;
|
|
pFileInfoItem->tiMatch = tiMatch;
|
|
pFileInfoItem->pNextItem = pFileInfoItemList;
|
|
pFileInfoItemList = pFileInfoItem;
|
|
|
|
//
|
|
// We have the matching file.
|
|
// Remember where it is for the second pass when we check all the file attributes.
|
|
//
|
|
tiMatch = SdbFindNextTag(pdb, tiExe, tiMatch);
|
|
|
|
//
|
|
// Reset the file matching. we don't touch this file again for now, it's info
|
|
// is safely linked in pFileInfoItemList
|
|
//
|
|
pFileInfo = NULL;
|
|
}
|
|
|
|
//
|
|
// We are still here. That means all the matching files have been found.
|
|
// Check all the other attributes using fileinfoitemlist information.
|
|
//
|
|
|
|
pFileInfoItem = pFileInfoItemList;
|
|
|
|
while (pFileInfoItem != NULL) {
|
|
|
|
tiMatchLogicNot = SdbFindFirstTag(pdb, pFileInfoItem->tiMatch, TAG_MATCH_LOGIC_NOT);
|
|
bMatchLogicNot = (tiMatchLogicNot != TAGID_NULL);
|
|
|
|
if (pFileInfoItem->pFileInfo != NULL) {
|
|
bAllAttributesMatch = SdbpCheckAllAttributes(hSDB,
|
|
pdb,
|
|
pFileInfoItem->tiMatch,
|
|
pFileInfoItem->pFileInfo);
|
|
} else {
|
|
bAllAttributesMatch = FALSE;
|
|
}
|
|
|
|
if (bAllAttributesMatch && bMatchLogicNot) {
|
|
DBGPRINT((sdlInfo,
|
|
"SdbpCheckForMatch",
|
|
"All attributes match, but LOGIC=\"NOT\" was used which negates the match.\n"));
|
|
goto out;
|
|
}
|
|
|
|
if (!bAllAttributesMatch && !bMatchLogicNot) {
|
|
//
|
|
// Debug output happened inside SdbpCheckAllAttributes, no
|
|
// need for further spew here.
|
|
//
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// Advance to the next item.
|
|
//
|
|
pFileInfoItem = pFileInfoItem->pNextItem;
|
|
}
|
|
|
|
//
|
|
// It's a match! get the match mode
|
|
//
|
|
if (pMatchMode) {
|
|
|
|
//
|
|
// Important: depending on a particular database, we may use a different mode if
|
|
// there is match mode tag
|
|
//
|
|
// For Custom DB: default is the all-additive mode
|
|
// For Main DB: default is normal mode
|
|
//
|
|
|
|
#ifndef KERNEL_MODE
|
|
wDefaultMatchMode = SdbpIsMainPDB(hSDB, pdb) ? MATCHMODE_DEFAULT_MAIN :
|
|
MATCHMODE_DEFAULT_CUSTOM;
|
|
#else // KERNEL_MODE
|
|
wDefaultMatchMode = MATCHMODE_DEFAULT_MAIN;
|
|
#endif // KERNEL_MODE
|
|
|
|
tiTemp = SdbFindFirstTag(pdb, tiExe, TAG_MATCH_MODE);
|
|
|
|
if (tiTemp) {
|
|
pMatchMode->dwMatchMode = SdbReadWORDTag(pdb, tiTemp, wDefaultMatchMode);
|
|
} else {
|
|
pMatchMode->dwMatchMode = wDefaultMatchMode;
|
|
}
|
|
}
|
|
|
|
bReturn = TRUE;
|
|
|
|
out:
|
|
|
|
pFileInfoItem = pFileInfoItemList;
|
|
|
|
while (pFileInfoItem != NULL) {
|
|
|
|
pFileInfoItemNext = pFileInfoItem->pNextItem;
|
|
|
|
if (pFileInfoItem->pFileInfo != NULL && bDisableAttributeCache) {
|
|
SdbFreeFileInfo(pFileInfoItem->pFileInfo);
|
|
}
|
|
|
|
STACK_FREE(pFileInfoItem);
|
|
pFileInfoItem = pFileInfoItemNext;
|
|
}
|
|
|
|
if (szFullPath != NULL) {
|
|
STACK_FREE(szFullPath);
|
|
}
|
|
|
|
if (bReturn) {
|
|
//
|
|
// One last matching criteria: verify the entry is not disabled.
|
|
//
|
|
bReturn = SdbpIsExeEntryEnabled(pdb, tiExe, pGUID, pdwFlags);
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
typedef enum _ADDITIVE_MODE {
|
|
AM_NORMAL,
|
|
AM_ADDITIVE_ONLY,
|
|
AM_NO_ADDITIVE
|
|
} ADDITIVE_MODE, *PADDITIVE_MODE;
|
|
|
|
LPCTSTR
|
|
SdbpFormatMatchModeType(
|
|
DWORD dwMatchMode
|
|
)
|
|
{
|
|
LPCTSTR pszMatchMode;
|
|
|
|
switch (dwMatchMode) {
|
|
|
|
case MATCH_ADDITIVE:
|
|
pszMatchMode = _T("Additive");
|
|
break;
|
|
|
|
case MATCH_EXCLUSIVE:
|
|
pszMatchMode = _T("Exclusive");
|
|
break;
|
|
|
|
case MATCH_NORMAL:
|
|
pszMatchMode = _T("Normal");
|
|
break;
|
|
|
|
default:
|
|
pszMatchMode = _T("Unknown");
|
|
break;
|
|
}
|
|
|
|
return pszMatchMode;
|
|
}
|
|
|
|
LPCTSTR
|
|
SdbpFormatMatchMode(
|
|
PMATCHMODE pMatchMode
|
|
)
|
|
{
|
|
static TCHAR szMatchMode[MAX_PATH];
|
|
|
|
LPTSTR pszMatchMode = szMatchMode;
|
|
int nChars = CHARCOUNT(szMatchMode);
|
|
int nLen;
|
|
|
|
nLen = _sntprintf(pszMatchMode,
|
|
nChars,
|
|
_T("0x%.2x%.2x [Mode: %s"),
|
|
pMatchMode->Flags,
|
|
pMatchMode->Type,
|
|
SdbpFormatMatchModeType(pMatchMode->Type));
|
|
if (nLen < 0) {
|
|
goto eh;
|
|
}
|
|
|
|
nChars -= nLen;
|
|
pszMatchMode += nLen;
|
|
|
|
eh:
|
|
|
|
//
|
|
// Just in case, truncate
|
|
//
|
|
if (nLen < 0) {
|
|
szMatchMode[CHARCOUNT(szMatchMode) - 1] = _T('\0');
|
|
}
|
|
|
|
return szMatchMode;
|
|
}
|
|
|
|
/*++
|
|
SdbpCheckExe
|
|
|
|
Checks a particular instance of an application in an SDB against for a match
|
|
Information on the file is passed through pContext parameter
|
|
|
|
result is returned in ptiExes
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
SdbpCheckExe(
|
|
IN HSDB hSDB, //
|
|
IN PDB pdb, //
|
|
IN TAGID tiExe, // tag for an exe in the database
|
|
IN OUT PDWORD pdwNumExes, // returns (and passes in) the number of accumulated exe matches
|
|
IN OUT PSEARCHDBCONTEXT pContext, // information about the file which we match against
|
|
IN ADDITIVE_MODE eMode, // target Match mode, we filter entries based on this parameter
|
|
IN BOOL bDebug, // debug flag
|
|
OUT PMATCHMODE pMatchMode, // returns match mode used if success
|
|
OUT TAGID* ptiExes, // returns another entry in array of matched exes
|
|
OUT GUID* pGUID, // matched exe id
|
|
OUT DWORD* pdwFlags // matched exe flags
|
|
)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
TAGID tiAppName = TAGID_NULL;
|
|
LPTSTR szAppName = NULL;
|
|
LPCTSTR pszMatchMode = NULL;
|
|
TAGID tiRuntimePlatform;
|
|
DWORD dwRuntimePlatform;
|
|
TAGID tiOSSKU;
|
|
DWORD dwOSSKU;
|
|
TAGID tiSP;
|
|
DWORD dwSPMask;
|
|
MATCHMODE MatchMode;
|
|
|
|
//
|
|
// For debug purposes we'd like to know the name of the app, which
|
|
// is more useful when the exe name is, say, AUTORUN.EXE or SETUP.EXE
|
|
//
|
|
tiAppName = SdbFindFirstTag(pdb, tiExe, TAG_APP_NAME);
|
|
|
|
if (tiAppName != TAGID_NULL) {
|
|
szAppName = SdbGetStringTagPtr(pdb, tiAppName);
|
|
}
|
|
|
|
DBGPRINT((sdlInfo, "SdbpCheckExe", "---------\n"));
|
|
DBGPRINT((sdlInfo,
|
|
"SdbpCheckExe",
|
|
"Index entry found for App: \"%s\" Exe: \"%s\"\n",
|
|
szAppName,
|
|
pContext->szName));
|
|
|
|
#ifndef KERNEL_MODE
|
|
|
|
//
|
|
// Check whether this exe is good for this platform first.
|
|
//
|
|
tiRuntimePlatform = SdbFindFirstTag(pdb, tiExe, TAG_RUNTIME_PLATFORM);
|
|
|
|
if (tiRuntimePlatform) {
|
|
dwRuntimePlatform = SdbReadDWORDTag(pdb, tiRuntimePlatform, RUNTIME_PLATFORM_ANY);
|
|
|
|
//
|
|
// Check for the platform match
|
|
//
|
|
if (!SdbpCheckRuntimePlatform(hSDB, szAppName, dwRuntimePlatform)) {
|
|
//
|
|
// Not the right platform. Debug spew would have occured in SdbpCheckRuntimePlatform
|
|
//
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
tiOSSKU = SdbFindFirstTag(pdb, tiExe, TAG_OS_SKU);
|
|
|
|
if (tiOSSKU) {
|
|
|
|
dwOSSKU = SdbReadDWORDTag(pdb, tiOSSKU, OS_SKU_ALL);
|
|
|
|
if (dwOSSKU != OS_SKU_ALL) {
|
|
|
|
PSDBCONTEXT pDBContext = (PSDBCONTEXT)hSDB;
|
|
|
|
//
|
|
// Check for the OS SKU match
|
|
//
|
|
if (!(dwOSSKU & pDBContext->dwOSSKU)) {
|
|
DBGPRINT((sdlInfo,
|
|
"SdbpCheckExe",
|
|
"OS SKU Mismatch for \"%s\" Database(0x%lx) vs 0x%lx\n",
|
|
(szAppName ? szAppName : TEXT("Unknown")),
|
|
dwOSSKU,
|
|
pDBContext->dwOSSKU));
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
|
|
tiSP = SdbFindFirstTag(pdb, tiExe, TAG_OS_SERVICE_PACK);
|
|
|
|
if (tiSP) {
|
|
dwSPMask = SdbReadDWORDTag(pdb, tiSP, 0xFFFFFFFF);
|
|
|
|
if (dwSPMask != 0xFFFFFFFF) {
|
|
|
|
PSDBCONTEXT pDBContext = (PSDBCONTEXT)hSDB;
|
|
|
|
//
|
|
// Check for the OS SKU match
|
|
//
|
|
if (!(dwSPMask & pDBContext->dwSPMask)) {
|
|
DBGPRINT((sdlInfo,
|
|
"SdbpCheckExe",
|
|
"OS SP Mismatch for \"%s\" Database(0x%lx) vs 0x%lx\n",
|
|
(szAppName ? szAppName : TEXT("Unknown")),
|
|
dwSPMask,
|
|
pDBContext->dwSPMask));
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
#endif // KERNEL_MODE
|
|
|
|
if (!SdbpCheckForMatch(hSDB, pdb, tiExe, pContext, &MatchMode, pGUID, pdwFlags)) {
|
|
goto out;
|
|
}
|
|
|
|
if (eMode == AM_ADDITIVE_ONLY && MatchMode.Type != MATCH_ADDITIVE) {
|
|
goto out;
|
|
}
|
|
|
|
if (eMode == AM_NO_ADDITIVE && MatchMode.Type == MATCH_ADDITIVE) {
|
|
goto out;
|
|
}
|
|
|
|
pszMatchMode = SdbpFormatMatchMode(&MatchMode);
|
|
|
|
//
|
|
// If we're in debug mode, don't actually put the ones we find on the
|
|
// list, just put up an error.
|
|
//
|
|
if (bDebug) {
|
|
|
|
//
|
|
// We are in debug mode, do not add the match
|
|
//
|
|
DBGPRINT((sdlError,
|
|
"SdbpCheckExe",
|
|
"-----------------------------------------------------\n"));
|
|
|
|
DBGPRINT((sdlError|sdlLogPipe,
|
|
"SdbpCheckExe",
|
|
"!!!! Multiple matches! App: '%s', Exe: '%s', Mode: %s\n",
|
|
hSDB, // so that the pipe would use hPipe if needed
|
|
szAppName,
|
|
pContext->szName,
|
|
pszMatchMode));
|
|
|
|
DBGPRINT((sdlError,
|
|
"SdbpCheckExe",
|
|
"-----------------------------------------------------\n"));
|
|
|
|
} else {
|
|
|
|
DBGPRINT((sdlWarning|sdlLogPipe,
|
|
"SdbpCheckExe",
|
|
"++++ Successful match for App: '%s', Exe: '%s', Mode: %s\n",
|
|
hSDB,
|
|
szAppName,
|
|
pContext->szName,
|
|
pszMatchMode));
|
|
|
|
//
|
|
// If this is an exclusive match, kill anything we've found up to now
|
|
//
|
|
if (MatchMode.Type == MATCH_EXCLUSIVE) {
|
|
RtlZeroMemory(ptiExes, sizeof(TAGID) * SDB_MAX_EXES);
|
|
*pdwNumExes = 0;
|
|
}
|
|
|
|
//
|
|
// Save this match on the list
|
|
//
|
|
ptiExes[*pdwNumExes] = tiExe;
|
|
(*pdwNumExes)++;
|
|
|
|
bSuccess = TRUE;
|
|
}
|
|
|
|
out:
|
|
//
|
|
// In case of success, return match mode information
|
|
//
|
|
|
|
if (bSuccess && pMatchMode != NULL) {
|
|
pMatchMode->dwMatchMode = MatchMode.dwMatchMode;
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SdbpSearchDB(
|
|
IN HSDB hSDB,
|
|
IN PDB pdb, // pdb to search in
|
|
IN TAG tiSearchTag, // OPTIONAL - target tag (TAG_EXE or TAG_APPHELP_EXE)
|
|
IN PSEARCHDBCONTEXT pContext,
|
|
OUT TAGID* ptiExes, // caller needs to provide array of size SDB_MAX_EXES
|
|
OUT GUID* pLastExeGUID,
|
|
OUT DWORD* pLastExeFlags,
|
|
OUT PMATCHMODE pMatchMode // reason why we stopped scanning
|
|
)
|
|
/*++
|
|
Return: TAGID of found EXE record, TAGID_NULL if not found.
|
|
|
|
Desc: This function searches a given shimDB for any EXEs with the given filename.
|
|
If it finds one, it checks all the MATCHING_FILE records by
|
|
calling SdbpCheckForMatch.
|
|
If any EXEs are found, the number of EXEs found is returned in ptiExes.
|
|
If not, it returns 0.
|
|
|
|
when we get the matching mode out of the particular exe -- it is checked
|
|
to see whether we need to continue and then this matching mode is returned
|
|
|
|
It will never return more than SDB_MAX_EXES EXE entries.
|
|
|
|
Debug Output is controlled by three factors
|
|
-- a global one (controlled via the ifdef DBG), TRUE on checked builds
|
|
-- a pipe handle in hSDB which is activated when we init the context
|
|
-- a local variable that is set when we are in one of the conditions above
|
|
when the variable bDebug is set -- we do not actually store the matches
|
|
|
|
--*/
|
|
{
|
|
TAGID tiDatabase, tiExe;
|
|
FIND_INFO FindInfo;
|
|
TAGID tiAppName = TAGID_NULL;
|
|
TCHAR* szAppName = _T("(unknown)");
|
|
BOOL bUsingIndex = FALSE;
|
|
DWORD dwNumExes = 0;
|
|
DWORD dwMatchMode = MATCH_NORMAL;
|
|
DWORD i;
|
|
DWORD dwAdditiveMode = MATCH_NORMAL;
|
|
BOOL bDebug = FALSE;
|
|
BOOL bMultiple = FALSE;
|
|
BOOL bSuccess = FALSE;
|
|
MATCHMODE MatchMode; // internal match mode
|
|
MATCHMODE MatchModeExe;
|
|
|
|
#ifndef KERNEL_MODE
|
|
|
|
if (pMatchMode) {
|
|
MatchMode.dwMatchMode = pMatchMode->dwMatchMode;
|
|
} else {
|
|
MatchMode.dwMatchMode = SdbpIsMainPDB(hSDB, pdb) ? MATCHMODE_DEFAULT_MAIN :
|
|
MATCHMODE_DEFAULT_CUSTOM;
|
|
}
|
|
#else // KERNEL_MODE
|
|
|
|
MatchMode.dwMatchMode = MATCHMODE_DEFAULT_MAIN;
|
|
|
|
#endif
|
|
|
|
if (!tiSearchTag) {
|
|
tiSearchTag = TAG_EXE;
|
|
}
|
|
|
|
//
|
|
// ADDITIVE MATCHES -- wildcards
|
|
//
|
|
if (tiSearchTag == TAG_EXE && SdbIsIndexAvailable(pdb, TAG_EXE, TAG_WILDCARD_NAME)) {
|
|
|
|
tiExe = SdbpFindFirstIndexedWildCardTag(pdb,
|
|
TAG_EXE,
|
|
TAG_WILDCARD_NAME,
|
|
pContext->szName,
|
|
&FindInfo);
|
|
|
|
while (tiExe != TAGID_NULL) {
|
|
|
|
bSuccess = SdbpCheckExe(hSDB,
|
|
pdb,
|
|
tiExe,
|
|
&dwNumExes,
|
|
pContext,
|
|
AM_ADDITIVE_ONLY, // match mode we request for this db
|
|
bDebug,
|
|
&MatchModeExe, // this is the matched tag from the db
|
|
ptiExes,
|
|
pLastExeGUID,
|
|
pLastExeFlags);
|
|
|
|
if (bSuccess) {
|
|
|
|
if (bDebug) {
|
|
bMultiple = TRUE; // if bDebug is set -- we already seen a match
|
|
} else {
|
|
|
|
//
|
|
// We got a match, update the state and make decision on whether to continue
|
|
//
|
|
MatchMode = MatchModeExe;
|
|
|
|
if (MatchModeExe.Type != MATCH_ADDITIVE) {
|
|
bDebug = (g_bDBG || SDBCONTEXT_IS_INSTRUMENTED(hSDB));
|
|
if (!bDebug) {
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
tiExe = SdbpFindNextIndexedWildCardTag(pdb, &FindInfo);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Normal EXEs
|
|
//
|
|
bUsingIndex = SdbIsIndexAvailable(pdb, tiSearchTag, TAG_NAME);
|
|
|
|
if (bUsingIndex) {
|
|
|
|
//
|
|
// Look in the index.
|
|
//
|
|
tiExe = SdbFindFirstStringIndexedTag(pdb,
|
|
tiSearchTag,
|
|
TAG_NAME,
|
|
pContext->szName,
|
|
&FindInfo);
|
|
|
|
if (tiExe == TAGID_NULL) {
|
|
DBGPRINT((sdlInfo,
|
|
"SdbpSearchDB",
|
|
"SdbFindFirstStringIndexedTag failed to locate exe: \"%s\".\n",
|
|
pContext->szName));
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Searching without an index...
|
|
//
|
|
DBGPRINT((sdlInfo, "SdbpSearchDB", "Searching database with no index.\n"));
|
|
|
|
//
|
|
// First get the DATABASE
|
|
//
|
|
tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
|
|
|
|
if (tiDatabase != TAGID_NULL) {
|
|
DBGPRINT((sdlError, "SdbpSearchDB", "No DATABASE tag found.\n"));
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// Then get the first EXE.
|
|
//
|
|
tiExe = SdbFindFirstNamedTag(pdb, tiDatabase, tiSearchTag, TAG_NAME, pContext->szName);
|
|
}
|
|
|
|
while (tiExe != TAGID_NULL) {
|
|
|
|
bSuccess = SdbpCheckExe(hSDB,
|
|
pdb,
|
|
tiExe,
|
|
&dwNumExes,
|
|
pContext,
|
|
AM_NORMAL,
|
|
bDebug,
|
|
&MatchModeExe,
|
|
ptiExes,
|
|
pLastExeGUID,
|
|
pLastExeFlags);
|
|
|
|
if (bSuccess) {
|
|
|
|
if (bDebug) {
|
|
|
|
bMultiple = TRUE; // if bDebug is set -- we already seen a match
|
|
|
|
} else {
|
|
|
|
//
|
|
// We got a match, update the state and make decision on whether to continue
|
|
// if we're not additive, we may go into debug mode
|
|
//
|
|
MatchMode = MatchModeExe;
|
|
|
|
if (MatchModeExe.Type != MATCH_ADDITIVE) {
|
|
bDebug = (g_bDBG || SDBCONTEXT_IS_INSTRUMENTED(hSDB));
|
|
if (!bDebug) {
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bUsingIndex) {
|
|
tiExe = SdbFindNextStringIndexedTag(pdb, &FindInfo);
|
|
} else {
|
|
tiExe = SdbpFindNextNamedTag(pdb, tiDatabase, tiExe, TAG_NAME, pContext->szName);
|
|
}
|
|
}
|
|
|
|
#ifndef KERNEL_MODE
|
|
//
|
|
// Now we search by module name, if one is available
|
|
// this case falls into 16-bit flags category
|
|
//
|
|
if (tiSearchTag == TAG_EXE && pContext->szModuleName) {
|
|
|
|
bUsingIndex = SdbIsIndexAvailable(pdb, tiSearchTag, TAG_16BIT_MODULE_NAME);
|
|
|
|
if (bUsingIndex) {
|
|
|
|
//
|
|
// Look in the index.
|
|
//
|
|
tiExe = SdbFindFirstStringIndexedTag(pdb,
|
|
tiSearchTag,
|
|
TAG_16BIT_MODULE_NAME,
|
|
pContext->szModuleName,
|
|
&FindInfo);
|
|
|
|
if (tiExe == TAGID_NULL) {
|
|
DBGPRINT((sdlInfo,
|
|
"SdbpSearchDB",
|
|
"SdbFindFirstStringIndexedTag failed to locate exe (MODNAME): \"%s\".\n",
|
|
pContext->szModuleName));
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Searching without an index...
|
|
//
|
|
DBGPRINT((sdlInfo, "SdbpSearchDB", "Searching database with no index.\n"));
|
|
|
|
//
|
|
// First get the DATABASE
|
|
//
|
|
tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
|
|
|
|
if (tiDatabase != TAGID_NULL) {
|
|
DBGPRINT((sdlError, "SdbpSearchDB", "No DATABASE tag found.\n"));
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// Then get the first EXE.
|
|
//
|
|
tiExe = SdbFindFirstNamedTag(pdb,
|
|
tiDatabase,
|
|
tiSearchTag,
|
|
TAG_16BIT_MODULE_NAME,
|
|
pContext->szModuleName);
|
|
}
|
|
|
|
while (tiExe != TAGID_NULL) {
|
|
|
|
bSuccess = SdbpCheckExe(hSDB,
|
|
pdb,
|
|
tiExe,
|
|
&dwNumExes,
|
|
pContext,
|
|
AM_NORMAL,
|
|
bDebug,
|
|
&MatchModeExe,
|
|
ptiExes,
|
|
pLastExeGUID,
|
|
pLastExeFlags);
|
|
|
|
if (bSuccess) {
|
|
if (bDebug) {
|
|
bMultiple = TRUE; // if bDebug is set -- we already seen a match
|
|
} else {
|
|
|
|
//
|
|
// We got a match, update the state and make decision on whether to continue
|
|
//
|
|
MatchMode = MatchModeExe;
|
|
|
|
if (MatchModeExe.Type != MATCH_ADDITIVE) {
|
|
bDebug = (g_bDBG || SDBCONTEXT_IS_INSTRUMENTED(hSDB));
|
|
if (!bDebug) {
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bUsingIndex) {
|
|
tiExe = SdbFindNextStringIndexedTag(pdb, &FindInfo);
|
|
} else {
|
|
tiExe = SdbpFindNextNamedTag(pdb,
|
|
tiDatabase,
|
|
tiExe,
|
|
TAG_16BIT_MODULE_NAME,
|
|
pContext->szModuleName);
|
|
}
|
|
}
|
|
}
|
|
#endif // KERNEL_MODE
|
|
|
|
//
|
|
// Now check for wild-card non-additive exes.
|
|
//
|
|
if (tiSearchTag == TAG_EXE && SdbIsIndexAvailable(pdb, TAG_EXE, TAG_WILDCARD_NAME)) {
|
|
|
|
tiExe = SdbpFindFirstIndexedWildCardTag(pdb,
|
|
TAG_EXE,
|
|
TAG_WILDCARD_NAME,
|
|
pContext->szName,
|
|
&FindInfo);
|
|
|
|
while (tiExe != TAGID_NULL) {
|
|
|
|
bSuccess = SdbpCheckExe(hSDB,
|
|
pdb,
|
|
tiExe,
|
|
&dwNumExes,
|
|
pContext,
|
|
AM_NO_ADDITIVE,
|
|
bDebug,
|
|
&MatchModeExe,
|
|
ptiExes,
|
|
pLastExeGUID,
|
|
pLastExeFlags);
|
|
|
|
if (bSuccess) {
|
|
|
|
if (bDebug) {
|
|
bMultiple = TRUE; // if bDebug is set -- we already seen a match
|
|
} else {
|
|
|
|
//
|
|
// we got a match, update the state and make decision on whether to continue
|
|
//
|
|
MatchMode = MatchModeExe;
|
|
|
|
if (MatchModeExe.Type != MATCH_ADDITIVE) {
|
|
bDebug = (g_bDBG || SDBCONTEXT_IS_INSTRUMENTED(hSDB));
|
|
if (!bDebug) {
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
tiExe = SdbpFindNextIndexedWildCardTag(pdb, &FindInfo);
|
|
}
|
|
}
|
|
|
|
out:
|
|
//
|
|
// Now report the final resolution of the match.
|
|
//
|
|
for (i = 0; i < dwNumExes; ++i) {
|
|
|
|
tiAppName = SdbFindFirstTag(pdb, ptiExes[i], TAG_APP_NAME);
|
|
|
|
if (tiAppName != TAGID_NULL) {
|
|
szAppName = SdbGetStringTagPtr(pdb, tiAppName);
|
|
} else {
|
|
szAppName = _T("(Unknown)");
|
|
}
|
|
|
|
DBGPRINT((sdlWarning,
|
|
"SdbpSearchDB",
|
|
"--------------------------------------------------------\n"));
|
|
|
|
DBGPRINT((sdlWarning|sdlLogPipe,
|
|
"SdbpSearchDB",
|
|
"+ Final match is App: \"%s\", exe: \"%s\".\n",
|
|
hSDB,
|
|
szAppName,
|
|
pContext->szName));
|
|
|
|
DBGPRINT((sdlWarning,
|
|
"SdbpSearchDB",
|
|
"--------------------------------------------------------\n"));
|
|
}
|
|
|
|
if (bMultiple) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpSearchDB",
|
|
"--------------------------------------------------------\n"));
|
|
|
|
DBGPRINT((sdlError|sdlLogPipe,
|
|
"SdbpSearchDB",
|
|
"!!!!!!! Multiple non-additive matches. !!!!!\n",
|
|
hSDB));
|
|
|
|
DBGPRINT((sdlError,
|
|
"SdbpSearchDB",
|
|
"--------------------------------------------------------\n"));
|
|
}
|
|
|
|
if (pMatchMode != NULL) {
|
|
pMatchMode->dwMatchMode = MatchMode.dwMatchMode;
|
|
}
|
|
|
|
return dwNumExes;
|
|
}
|
|
|
|
TAGREF
|
|
SdbGetDatabaseMatch(
|
|
IN HSDB hSDB,
|
|
IN LPCTSTR szPath,
|
|
IN HANDLE FileHandle OPTIONAL,
|
|
IN LPVOID pImageBase OPTIONAL,
|
|
IN DWORD dwImageSize OPTIONAL
|
|
)
|
|
/*++
|
|
Return: BUGBUG: ?
|
|
|
|
Desc: BUGBUG: ?
|
|
--*/
|
|
{
|
|
SEARCHDBCONTEXT Context;
|
|
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
|
|
TAGID tiExe = TAGID_NULL;
|
|
TAGID atiExes[SDB_MAX_EXES];
|
|
TAGREF trExe = TAGREF_NULL;
|
|
DWORD dwNumExes = 0;
|
|
GUID guid;
|
|
DWORD dwFlags = 0;
|
|
|
|
assert(pSdbContext->pdbMain && szPath);
|
|
|
|
RtlZeroMemory(&Context, sizeof(Context)); // do this so that we don't trip later
|
|
RtlZeroMemory(atiExes, sizeof(atiExes));
|
|
|
|
Context.dwFlags |= (SEARCHDBF_NO_PROCESS_HISTORY | SEARCHDBF_NO_ATTRIBUTE_CACHE);
|
|
|
|
if (FileHandle != INVALID_HANDLE_VALUE || pImageBase != NULL) {
|
|
Context.dwFlags |= SEARCHDBF_NO_LFN;
|
|
}
|
|
|
|
Context.hMainFile = FileHandle; // used to optimize attribute retrieval
|
|
Context.pImageBase = pImageBase; // this will be used and not a file handle
|
|
Context.dwImageSize = dwImageSize; // size of the image
|
|
|
|
DBGPRINT((sdlInfo, "SdbGetDatabaseMatch", "Looking for \"%s\"\n", szPath));
|
|
|
|
//
|
|
// Create search db context, no process history needed.
|
|
//
|
|
if (!SdbpCreateSearchDBContext(&Context, szPath, NULL, NULL)) {
|
|
DBGPRINT((sdlError,
|
|
"SdbGetDatabaseMatch",
|
|
"Failed to create search DB context.\n"));
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// We will be searching the main db
|
|
//
|
|
dwNumExes = SdbpSearchDB(pSdbContext,
|
|
pSdbContext->pdbMain,
|
|
TAG_EXE,
|
|
&Context,
|
|
atiExes,
|
|
&guid,
|
|
&dwFlags,
|
|
NULL);
|
|
//
|
|
// Convert to TAGREF
|
|
//
|
|
if (dwNumExes) {
|
|
|
|
//
|
|
// Always use the last exe in the list, as it will be the most specific
|
|
//
|
|
tiExe = atiExes[dwNumExes - 1];
|
|
|
|
if (!SdbTagIDToTagRef(hSDB, pSdbContext->pdbMain, tiExe, &trExe)) {
|
|
DBGPRINT((sdlError,
|
|
"SdbGetDatabaseMatch",
|
|
"Failed to convert tagid to tagref\n"));
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
out:
|
|
|
|
SdbpReleaseSearchDBContext(&Context);
|
|
|
|
return trExe;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SdbQueryData(
|
|
IN HSDB hSDB, // database handle
|
|
IN TAGREF trExe, // tagref of the matching exe
|
|
IN LPCTSTR lpszDataName, // if this is null, will try to return all the policy names
|
|
OUT LPDWORD lpdwDataType, // pointer to data type (REG_SZ, REG_BINARY, etc)
|
|
OUT LPVOID lpBuffer, // buffer to fill with information
|
|
IN OUT LPDWORD lpdwBufferSize // pointer to buffer size
|
|
)
|
|
{
|
|
return SdbQueryDataEx(hSDB, trExe, lpszDataName, lpdwDataType, lpBuffer, lpdwBufferSize, NULL);
|
|
}
|
|
|
|
|
|
DWORD
|
|
SdbQueryDataExTagID(
|
|
IN PDB pdb, // database handle
|
|
IN TAGID tiExe, // tagref of the matching exe
|
|
IN LPCTSTR lpszDataName, // if this is null, will try to return all the policy names
|
|
OUT LPDWORD lpdwDataType, // pointer to data type (REG_SZ, REG_BINARY, etc)
|
|
OUT LPVOID lpBuffer, // buffer to fill with information
|
|
IN OUT LPDWORD lpdwBufferSize, // pointer to buffer size
|
|
OUT TAGID* ptiData // optional pointer to the retrieved data tag
|
|
)
|
|
/*++
|
|
Return: Error code or ERROR_SUCCESS if successful
|
|
|
|
Desc: See complete description with sample code
|
|
in doc subdirectory
|
|
--*/
|
|
{
|
|
TAGID tiData;
|
|
BOOL bSuccess;
|
|
TAGID tiParent;
|
|
TAGID tiName;
|
|
TAGID tiValue;
|
|
TAGID tiValueType;
|
|
DWORD cbSize;
|
|
DWORD dwValueType;
|
|
LPCTSTR pszName;
|
|
LPTSTR pszNameBuffer = NULL;
|
|
LPTSTR pSlash;
|
|
LPTSTR pchBuffer;
|
|
DWORD dwData;
|
|
TAG tData;
|
|
ULONGLONG ullData;
|
|
LPVOID lpValue;
|
|
DWORD Status = ERROR_NOT_SUPPORTED; // have it initialized
|
|
|
|
if (lpszDataName == NULL) {
|
|
|
|
if (lpdwBufferSize == NULL) {
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
goto ErrHandle;
|
|
}
|
|
|
|
cbSize = 0;
|
|
|
|
tiData = SdbFindFirstTag(pdb, tiExe, TAG_DATA);
|
|
if (!tiData) {
|
|
//
|
|
// Bad entry.
|
|
//
|
|
DBGPRINT((sdlError,
|
|
"SdbQueryDataExTagID",
|
|
"The entry 0x%x does not appear to have data\n",
|
|
tiExe));
|
|
|
|
Status = ERROR_INTERNAL_DB_CORRUPTION;
|
|
goto ErrHandle;
|
|
}
|
|
|
|
while (tiData) {
|
|
|
|
//
|
|
// Pass one: Calculate the size needed.
|
|
//
|
|
tiName = SdbFindFirstTag(pdb, tiData, TAG_NAME);
|
|
|
|
if (!tiName) {
|
|
DBGPRINT((sdlError,
|
|
"SdbQueryDataExTagID",
|
|
"The entry 0x%x does not contain a name tag\n",
|
|
tiData));
|
|
Status = ERROR_INTERNAL_DB_CORRUPTION;
|
|
goto ErrHandle;
|
|
}
|
|
|
|
pszName = SdbGetStringTagPtr(pdb, tiName);
|
|
|
|
if (!pszName) {
|
|
DBGPRINT((sdlError,
|
|
"SdbQueryDataExTagID",
|
|
"The entry 0x%x contains NULL name\n",
|
|
tiName));
|
|
Status = ERROR_INTERNAL_DB_CORRUPTION;
|
|
goto ErrHandle;
|
|
}
|
|
|
|
cbSize += (_tcslen(pszName) + 1) * sizeof(*pszName);
|
|
|
|
tiData = SdbFindNextTag(pdb, tiExe, tiData);
|
|
}
|
|
|
|
cbSize += sizeof(*pszName); // for the final 0
|
|
|
|
//
|
|
// We are done, compare the size.
|
|
//
|
|
if (lpBuffer == NULL || *lpdwBufferSize < cbSize) {
|
|
*lpdwBufferSize = cbSize;
|
|
Status = ERROR_INSUFFICIENT_BUFFER;
|
|
goto ErrHandle;
|
|
}
|
|
|
|
//
|
|
// lpBuffer != NULL here and there is enough room
|
|
//
|
|
pchBuffer = (LPTSTR)lpBuffer;
|
|
|
|
tiData = SdbFindFirstTag(pdb, tiExe, TAG_DATA);
|
|
|
|
while (tiData) {
|
|
|
|
tiName = SdbFindFirstTag(pdb, tiData, TAG_NAME);
|
|
|
|
if (tiName) {
|
|
pszName = SdbGetStringTagPtr(pdb, tiName);
|
|
|
|
if (pszName) {
|
|
_tcscpy(pchBuffer, pszName);
|
|
pchBuffer += _tcslen(pchBuffer) + 1;
|
|
}
|
|
}
|
|
|
|
tiData = SdbFindNextTag(pdb, tiExe, tiData);
|
|
}
|
|
|
|
//
|
|
// The buffer has been filled, terminate.
|
|
//
|
|
*pchBuffer++ = TEXT('\0');
|
|
|
|
//
|
|
// Save the size written to the buffer
|
|
//
|
|
*lpdwBufferSize = (DWORD)((ULONG_PTR)pchBuffer - (ULONG_PTR)lpBuffer);
|
|
|
|
//
|
|
// Save data type
|
|
//
|
|
if (lpdwDataType != NULL) {
|
|
*lpdwDataType = REG_MULTI_SZ;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// In this case we allow the query to proceed if
|
|
// the buffer is null and lpdwBufferSize is not null or lpBufferSize is not null
|
|
//
|
|
if (lpBuffer == NULL && lpdwBufferSize == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbQueryDataExTagID",
|
|
"One of lpBuffer or lpdwBufferSize should not be null\n"));
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
goto ErrHandle;
|
|
}
|
|
|
|
//
|
|
// Expect the name to be in format "name1\name2..."
|
|
//
|
|
STACK_ALLOC(pszNameBuffer, (_tcslen(lpszDataName) + 1) * sizeof(*pszNameBuffer));
|
|
|
|
if (pszNameBuffer == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbQueryDataExTagID",
|
|
"Cannot allocate temporary buffer for parsing the name \"%s\"\n",
|
|
lpszDataName));
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ErrHandle;
|
|
}
|
|
|
|
tiParent = tiExe;
|
|
tiData = TAGID_NULL;
|
|
|
|
do {
|
|
pSlash = _tcschr(lpszDataName, TEXT('\\'));
|
|
|
|
if (pSlash == NULL) {
|
|
_tcscpy(pszNameBuffer, lpszDataName);
|
|
lpszDataName = NULL;
|
|
} else {
|
|
_tcsncpy(pszNameBuffer, lpszDataName, pSlash - lpszDataName);
|
|
pszNameBuffer[pSlash - lpszDataName] = TEXT('\0');
|
|
lpszDataName = pSlash + 1; // go to the next char
|
|
}
|
|
|
|
tiData = SdbFindFirstNamedTag(pdb, tiParent, TAG_DATA, TAG_NAME, pszNameBuffer);
|
|
tiParent = tiData;
|
|
|
|
} while (lpszDataName != NULL && *lpszDataName != TEXT('\0') && tiData != TAGID_NULL);
|
|
|
|
if (!tiData) {
|
|
DBGPRINT((sdlError,
|
|
"SdbQueryDataExTagID",
|
|
"The entry \"%s\" not found\n",
|
|
pszNameBuffer));
|
|
Status = ERROR_NOT_FOUND;
|
|
goto ErrHandle;
|
|
}
|
|
|
|
//
|
|
// Looks like we found the entry, query value type
|
|
//
|
|
dwValueType = REG_NONE;
|
|
|
|
tiValueType = SdbFindFirstTag(pdb, tiData, TAG_DATA_VALUETYPE);
|
|
|
|
if (!tiValueType) {
|
|
DBGPRINT((sdlWarning,
|
|
"SdbQueryDataExTagID",
|
|
"The entry 0x%x does not have valuetype information\n",
|
|
tiData));
|
|
} else {
|
|
dwValueType = SdbReadDWORDTag(pdb, tiValueType, REG_NONE);
|
|
}
|
|
|
|
cbSize = 0;
|
|
lpValue = NULL;
|
|
|
|
if (dwValueType != REG_NONE) {
|
|
|
|
//
|
|
// Find data tag
|
|
//
|
|
cbSize = 0;
|
|
|
|
switch (dwValueType) {
|
|
|
|
case REG_SZ:
|
|
//
|
|
// string data
|
|
//
|
|
tData = TAG_DATA_STRING;
|
|
break;
|
|
|
|
case REG_DWORD:
|
|
tData = TAG_DATA_DWORD;
|
|
break;
|
|
|
|
case REG_QWORD:
|
|
tData = TAG_DATA_QWORD;
|
|
break;
|
|
|
|
case REG_BINARY:
|
|
tData = TAG_DATA_BITS;
|
|
break;
|
|
|
|
default:
|
|
DBGPRINT((sdlError,
|
|
"SdbQueryDataExTagID",
|
|
"The entry 0x%x contains bad valuetype information 0x%x\n",
|
|
tiData,
|
|
dwValueType));
|
|
Status = ERROR_INTERNAL_DB_CORRUPTION;
|
|
goto ErrHandle;
|
|
break;
|
|
}
|
|
|
|
tiValue = SdbFindFirstTag(pdb, tiData, tData);
|
|
|
|
//
|
|
// Find what the data size is if needed
|
|
//
|
|
if (!tiValue) {
|
|
|
|
DBGPRINT((sdlWarning,
|
|
"SdbQueryDataExTagID",
|
|
"The entry 0x%x contains no value\n",
|
|
tiData));
|
|
Status = ERROR_NOT_FOUND;
|
|
goto ErrHandle;
|
|
|
|
}
|
|
|
|
//
|
|
// For those who have no size quite yet...
|
|
// (binary and a string)
|
|
//
|
|
switch (dwValueType) {
|
|
|
|
case REG_SZ:
|
|
pchBuffer = SdbGetStringTagPtr(pdb, tiValue);
|
|
|
|
if (pchBuffer == NULL) {
|
|
DBGPRINT((sdlWarning,
|
|
"SdbQueryDataExTagID",
|
|
"The entry 0x%x contains bad string value 0x%x\n",
|
|
tiData,
|
|
tiValue));
|
|
Status = ERROR_NOT_FOUND;
|
|
goto ErrHandle;
|
|
}
|
|
|
|
cbSize = (_tcslen(pchBuffer) + 1) * sizeof(*pchBuffer);
|
|
lpValue = (LPVOID)pchBuffer;
|
|
break;
|
|
|
|
case REG_BINARY:
|
|
cbSize = SdbGetTagDataSize(pdb, tiValue); // binary tag
|
|
lpValue = SdbpGetMappedTagData(pdb, tiValue);
|
|
|
|
if (lpValue == NULL) {
|
|
DBGPRINT((sdlWarning,
|
|
"SdbQueryDataExTagID",
|
|
"The entry 0x%x contains bad binary value 0x%x\n",
|
|
tiData,
|
|
tiValue));
|
|
Status = ERROR_NOT_FOUND;
|
|
goto ErrHandle;
|
|
}
|
|
break;
|
|
|
|
case REG_DWORD:
|
|
dwData = SdbReadDWORDTag(pdb, tiValue, 0);
|
|
cbSize = sizeof(dwData);
|
|
lpValue = (LPVOID)&dwData;
|
|
break;
|
|
|
|
case REG_QWORD:
|
|
ullData = SdbReadQWORDTag(pdb, tiValue, 0);
|
|
cbSize = sizeof(ullData);
|
|
lpValue = (LPVOID)&ullData;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// At this point we have everything we need to get the pointer to data.
|
|
//
|
|
}
|
|
|
|
//
|
|
// Fix the output params and exit.
|
|
//
|
|
Status = ERROR_SUCCESS;
|
|
|
|
if (cbSize == 0) {
|
|
goto SkipCopy;
|
|
}
|
|
|
|
if (lpBuffer == NULL || (lpdwBufferSize != NULL && *lpdwBufferSize < cbSize)) {
|
|
Status = ERROR_INSUFFICIENT_BUFFER;
|
|
goto SkipCopy;
|
|
}
|
|
|
|
//
|
|
// Buffer size checked out, now if buffer exists -- copy
|
|
//
|
|
if (lpBuffer != NULL) {
|
|
RtlMoveMemory(lpBuffer, lpValue, cbSize);
|
|
}
|
|
|
|
SkipCopy:
|
|
|
|
if (lpdwBufferSize) {
|
|
*lpdwBufferSize = cbSize;
|
|
}
|
|
|
|
if (lpdwDataType) {
|
|
*lpdwDataType = dwValueType;
|
|
}
|
|
|
|
if (ptiData) {
|
|
*ptiData = tiData;
|
|
}
|
|
|
|
ErrHandle:
|
|
|
|
if (pszNameBuffer != NULL) {
|
|
STACK_FREE(pszNameBuffer);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DWORD
|
|
SdbQueryDataEx(
|
|
IN HSDB hSDB, // database handle
|
|
IN TAGREF trExe, // tagref of the matching exe
|
|
IN LPCTSTR lpszDataName, // if this is null, will try to return all the policy names
|
|
OUT LPDWORD lpdwDataType, // pointer to data type (REG_SZ, REG_BINARY, etc)
|
|
OUT LPVOID lpBuffer, // buffer to fill with information
|
|
IN OUT LPDWORD lpdwBufferSize, // pointer to buffer size
|
|
OUT TAGREF* ptrData // optional pointer to the retrieved data tag
|
|
)
|
|
{
|
|
BOOL bSuccess;
|
|
PDB pdb = NULL;
|
|
TAGID tiExe = TAGID_NULL;
|
|
TAGID tiData;
|
|
NTSTATUS Status;
|
|
|
|
bSuccess = SdbTagRefToTagID(hSDB, trExe, &pdb, &tiExe);
|
|
|
|
if (!bSuccess) {
|
|
DBGPRINT((sdlError,
|
|
"SdbQueryDataEx",
|
|
"Failed to convert tagref 0x%x to tagid\n",
|
|
trExe));
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
goto ErrHandle;
|
|
}
|
|
|
|
Status = SdbQueryDataExTagID(pdb,
|
|
tiExe,
|
|
lpszDataName,
|
|
lpdwDataType,
|
|
lpBuffer,
|
|
lpdwBufferSize,
|
|
&tiData);
|
|
//
|
|
// See that we convert the output param
|
|
//
|
|
if (ptrData != NULL && NT_SUCCESS(Status)) {
|
|
if (!SdbTagIDToTagRef(hSDB, pdb, tiData, ptrData)) {
|
|
Status = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
ErrHandle:
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOL
|
|
SdbReadEntryInformation(
|
|
IN HSDB hSDB,
|
|
IN TAGREF trExe,
|
|
OUT PSDBENTRYINFO pEntryInfo
|
|
)
|
|
/*++
|
|
Return: BUGBUG: ?
|
|
|
|
Desc: BUGBUG: ?
|
|
--*/
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
TAGID tiExe;
|
|
TAGID tiData;
|
|
TAGID tiExeID;
|
|
TAGID tiPolicy;
|
|
TAGID tiRegPath;
|
|
PDB pdb;
|
|
SDBENTRYINFO EntryInfo;
|
|
|
|
RtlZeroMemory(&EntryInfo, sizeof(EntryInfo));
|
|
|
|
bSuccess = SdbTagRefToTagID(hSDB, trExe, &pdb, &tiExe);
|
|
|
|
if (!bSuccess) {
|
|
DBGPRINT((sdlError,
|
|
"SdbReadEntryInformation",
|
|
"Failed to convert tagref 0x%x to tagid\n",
|
|
trExe));
|
|
goto ErrHandle;
|
|
}
|
|
|
|
//
|
|
// Get the EXE's ID
|
|
//
|
|
tiExeID = SdbFindFirstTag(pdb, tiExe, TAG_EXE_ID);
|
|
|
|
if (tiExeID == TAGID_NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbReadEntryInformation",
|
|
"Failed to read TAG_EXE_ID for tiExe 0x%x !\n",
|
|
tiExe));
|
|
goto ErrHandle;
|
|
}
|
|
|
|
bSuccess = SdbReadBinaryTag(pdb,
|
|
tiExeID,
|
|
(PBYTE)&EntryInfo.guidID,
|
|
sizeof(EntryInfo.guidID));
|
|
if (!bSuccess) {
|
|
DBGPRINT((sdlError,
|
|
"SdbReadEntryInformation",
|
|
"Failed to read GUID referenced by 0x%x\n",
|
|
tiExeID));
|
|
goto ErrHandle;
|
|
}
|
|
|
|
//
|
|
// Get the database id
|
|
//
|
|
if (!SdbGetDatabaseID(pdb, &EntryInfo.guidDB)) {
|
|
DBGPRINT((sdlError,
|
|
"SdbReadEntryInformation",
|
|
"Failed to read GUID of the database\n"));
|
|
goto ErrHandle;
|
|
}
|
|
|
|
//
|
|
// Retrieve entry flags as referenced by the registry
|
|
//
|
|
if (!SdbGetEntryFlags(&EntryInfo.guidID, &EntryInfo.dwFlags)) {
|
|
DBGPRINT((sdlWarning,
|
|
"SdbReadEntryInformation",
|
|
"No flags for tiExe 0x%x\n",
|
|
tiExe));
|
|
|
|
EntryInfo.dwFlags = 0;
|
|
} else {
|
|
DBGPRINT((sdlInfo,
|
|
"SdbReadEntryInformation",
|
|
"Retrieved flags for this app 0x%x.\n",
|
|
EntryInfo.dwFlags));
|
|
}
|
|
|
|
//
|
|
// Read the data tags
|
|
//
|
|
tiData = SdbFindFirstTag(pdb, tiExe, TAG_DATA);
|
|
|
|
EntryInfo.tiData = tiData;
|
|
|
|
if (tiData == TAGID_NULL) {
|
|
//
|
|
// This is not a data entry
|
|
//
|
|
DBGPRINT((sdlWarning,
|
|
"SdbReadEntryInformation",
|
|
"Entry tiExe 0x%x does not contain TAG_DATA.\n",
|
|
tiExe));
|
|
}
|
|
|
|
if (pEntryInfo != NULL) {
|
|
RtlMoveMemory(pEntryInfo, &EntryInfo, sizeof(*pEntryInfo));
|
|
}
|
|
|
|
bSuccess = TRUE;
|
|
|
|
ErrHandle:
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
//
|
|
// We may be compiled UNICODE or ANSI
|
|
// If we are compiled UNICODE we need to use UNICODE sprintf and convert
|
|
// the result back to ANSI for output with DbgPrint. This is accomplished
|
|
// by %ls format in DbgPrint. Format and Function name are always passed
|
|
// in as ANSI though. TCHAR strings are formatted just with %s
|
|
//
|
|
|
|
void
|
|
PrepareFormatForUnicode(
|
|
PCH fmtUnicode,
|
|
PCH format
|
|
)
|
|
{
|
|
PCH pfmt;
|
|
CHAR ch;
|
|
size_t nch;
|
|
long width;
|
|
PCH pend;
|
|
|
|
strcpy(fmtUnicode, format);
|
|
pfmt = fmtUnicode;
|
|
|
|
while('\0' != (ch = *pfmt++)) {
|
|
if (ch == '%') {
|
|
|
|
if (*pfmt == '%') {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Skip the characters that relate to - + 0 ' ' #
|
|
//
|
|
nch = strspn(pfmt, "-+0 #");
|
|
pfmt += nch;
|
|
|
|
//
|
|
// Parse the width.
|
|
//
|
|
if (*pfmt == '*') {
|
|
//
|
|
// Parameter defines the width
|
|
//
|
|
++pfmt;
|
|
} else {
|
|
//
|
|
// See whether we have width
|
|
//
|
|
if (isdigit(*pfmt)) {
|
|
pend = NULL;
|
|
width = atol(pfmt);
|
|
|
|
while (isdigit(*pfmt)) {
|
|
++pfmt;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now we can have: .precision
|
|
//
|
|
if (*pfmt == '.') {
|
|
++pfmt;
|
|
width = atol(pfmt);
|
|
|
|
while (isdigit(*pfmt)) {
|
|
++pfmt;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now is the format (one of: h, l, L, I64)
|
|
//
|
|
ch = *pfmt;
|
|
pend = strchr("hlLNFw", ch);
|
|
if (pend != NULL) {
|
|
++pfmt; // move past the modifier char
|
|
} else {
|
|
if (ch == 'I' && !strncpy(pfmt, "I64", 3)) {
|
|
pfmt += 3;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We should have a type character here.
|
|
//
|
|
if (*pfmt == 's') {
|
|
//
|
|
// Convert to UPPER, making it UNICODE string with ansi vsnprintf
|
|
//
|
|
*pfmt = 'S';
|
|
}
|
|
|
|
//
|
|
// Move past the format char if we are not at the end
|
|
//
|
|
if (*pfmt != '\0') {
|
|
++pfmt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|