You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2436 lines
69 KiB
2436 lines
69 KiB
/*++
|
|
|
|
Copyright (c) 1989-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sdbapiplus.c
|
|
|
|
Abstract:
|
|
|
|
BUGBUG: This module implements ...
|
|
|
|
Author:
|
|
|
|
dmunsil created sometime in 1999
|
|
|
|
Revision History:
|
|
|
|
several people contributed (vadimb, clupu, ...)
|
|
|
|
--*/
|
|
|
|
#include "sdbp.h"
|
|
|
|
extern const TCHAR g_szProcessHistory[] = TEXT("__PROCESS_HISTORY");
|
|
extern const TCHAR g_szCompatLayer[] = TEXT("__COMPAT_LAYER");
|
|
extern const TCHAR g_szWhiteSpaceDelimiters[] = TEXT(" \t");
|
|
|
|
#ifdef _DEBUG_SPEW
|
|
extern DBGLEVELINFO g_rgDbgLevelInfo[];
|
|
extern PCH g_szDbgLevelUser;
|
|
#endif // _DEBUG_SPEW
|
|
|
|
LPTSTR
|
|
SdbpGetLayerFlags(
|
|
IN LPTSTR pszLayerString,
|
|
OUT DWORD* pdwLayerFlags
|
|
)
|
|
/*++
|
|
Return: Beginning of the layer string after the special characters used to
|
|
indicate the layer flags.
|
|
|
|
Desc: We current support these layer flags:
|
|
|
|
'!' means don't use any EXE entries
|
|
'#' means go ahead and apply layers to system EXEs.
|
|
|
|
The flags can be combined.
|
|
--*/
|
|
{
|
|
DWORD dwLayerFlags = 0;
|
|
|
|
//
|
|
// Skip over the white spaces...
|
|
//
|
|
pszLayerString += _tcsspn(pszLayerString, g_szWhiteSpaceDelimiters);
|
|
|
|
//
|
|
// Next up is the ! or # or both
|
|
//
|
|
while (*pszLayerString != _T('\0') &&
|
|
_tcschr(TEXT("!# \t"), *pszLayerString) != NULL) {
|
|
|
|
if (*pszLayerString == _T('!')) {
|
|
dwLayerFlags |= LAYER_USE_NO_EXE_ENTRIES;
|
|
} else if (*pszLayerString == _T('#')) {
|
|
dwLayerFlags |= LAYER_APPLY_TO_SYSTEM_EXES;
|
|
}
|
|
|
|
pszLayerString++;
|
|
}
|
|
|
|
if (pdwLayerFlags) {
|
|
*pdwLayerFlags = dwLayerFlags;
|
|
}
|
|
|
|
return pszLayerString;
|
|
}
|
|
|
|
BOOL
|
|
SdbpCheckRuntimePlatform(
|
|
IN PSDBCONTEXT pContext, // pointer to the database channel
|
|
IN LPCTSTR pszMatchingFile,
|
|
IN DWORD dwPlatformDB
|
|
)
|
|
{
|
|
DWORD dwPlatform = pContext->dwRuntimePlatform;
|
|
BOOL bMatch = FALSE;
|
|
BOOL bMatchElement;
|
|
DWORD dwElement;
|
|
INT i;
|
|
|
|
if (dwPlatformDB == RUNTIME_PLATFORM_ANY) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Check for all 3 supported platforms.
|
|
//
|
|
for (i = 0; i < 3; ++i) {
|
|
dwElement = (dwPlatformDB >> (i * 8)) & RUNTIME_PLATFORM_MASK_ELEMENT;
|
|
if (!(dwElement & RUNTIME_PLATFORM_FLAG_VALID)) { // this is not a valid element - move on
|
|
continue;
|
|
}
|
|
|
|
bMatchElement = (dwPlatform == (dwElement & RUNTIME_PLATFORM_MASK_VALUE));
|
|
if (dwElement & RUNTIME_PLATFORM_FLAG_NOT_ELEMENT) {
|
|
bMatchElement = !bMatchElement;
|
|
}
|
|
|
|
bMatch |= bMatchElement;
|
|
}
|
|
|
|
if (dwPlatformDB & RUNTIME_PLATFORM_FLAG_NOT) {
|
|
bMatch = !bMatch;
|
|
}
|
|
|
|
if (!bMatch) {
|
|
DBGPRINT((sdlInfo,
|
|
"SdbpCheckRuntimePlatform",
|
|
"Platform Mismatch for \"%s\" Database(0x%lx) vs 0x%lx\n",
|
|
(pszMatchingFile ? pszMatchingFile : TEXT("Unknown")),
|
|
dwPlatformDB,
|
|
dwPlatform));
|
|
}
|
|
|
|
return bMatch;
|
|
}
|
|
|
|
BOOL
|
|
SafeNCat(
|
|
LPTSTR lpszDest,
|
|
int nSize,
|
|
LPCTSTR lpszSrc,
|
|
int nSizeAppend
|
|
)
|
|
{
|
|
int nLen = (int)_tcslen(lpszDest);
|
|
int nLenAppend = (int)_tcslen(lpszSrc);
|
|
|
|
if (nSizeAppend >= 0 && nLenAppend > nSizeAppend) {
|
|
nLenAppend = nSizeAppend;
|
|
}
|
|
|
|
if (nSize < nLen + nLenAppend + 1) {
|
|
return FALSE;
|
|
}
|
|
|
|
RtlCopyMemory(lpszDest + nLen, lpszSrc, nLenAppend * sizeof(*lpszSrc));
|
|
*(lpszDest + nLen + nLenAppend) = TEXT('\0');
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
SdbpSanitizeXML(
|
|
LPTSTR pchOut,
|
|
int nSize,
|
|
LPCTSTR lpszXML
|
|
)
|
|
{
|
|
LPCTSTR pch;
|
|
LPCTSTR pchCur = lpszXML;
|
|
const static LPCTSTR rgSC[] = { TEXT("&"), TEXT("""), TEXT("<"), TEXT(">") };
|
|
LPCTSTR rgSpecialChars = TEXT("&\"<>"); // should be the same as above
|
|
LPCTSTR pchSpecial;
|
|
int iReplace; // & should be first in both lists above
|
|
int nLen = 0;
|
|
int i;
|
|
|
|
if (nSize < 1) {
|
|
return FALSE;
|
|
}
|
|
|
|
*pchOut = TEXT('\0');
|
|
|
|
while (*pchCur) {
|
|
|
|
pch = _tcspbrk(pchCur, rgSpecialChars);
|
|
if (NULL == pch) {
|
|
// no more chars -- copy the rest
|
|
if (!SafeNCat(pchOut, nSize, pchCur, -1)) {
|
|
return FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// copy up to pch
|
|
if (!SafeNCat(pchOut, nSize, pchCur, (int)(pch - pchCur))) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (*pch == TEXT('&')) {
|
|
for (i = 0; i < ARRAYSIZE(rgSC); ++i) {
|
|
nLen = (int)_tcslen(rgSC[i]);
|
|
if (_tcsnicmp(rgSC[i], pch, nLen) == 0) {
|
|
// ok, move along, we are not touching this
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i < ARRAYSIZE(rgSC)) {
|
|
// do not touch the string
|
|
// nLen is the length we need to skip
|
|
if (!SafeNCat(pchOut, nSize, pch, nLen)) {
|
|
return FALSE;
|
|
}
|
|
pchCur = pch + nLen;
|
|
continue;
|
|
}
|
|
|
|
iReplace = 0;
|
|
} else {
|
|
|
|
pchSpecial = _tcschr(rgSpecialChars, *pch);
|
|
if (pchSpecial == NULL) {
|
|
// internal error -- what is this ?
|
|
return FALSE;
|
|
}
|
|
|
|
iReplace = (int)(pchSpecial - rgSpecialChars);
|
|
}
|
|
|
|
// so instead of pch we will have rgSC[i]
|
|
if (!SafeNCat(pchOut, nSize, rgSC[iReplace], -1)) {
|
|
return FALSE;
|
|
}
|
|
pchCur = pch + 1; // move on to the next char
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
SdbTagIDToTagRef(
|
|
IN HSDB hSDB,
|
|
IN PDB pdb, // PDB the TAGID is from
|
|
IN TAGID tiWhich, // TAGID to convert
|
|
OUT TAGREF* ptrWhich // converted TAGREF
|
|
)
|
|
/*++
|
|
Return: TRUE if a TAGREF was found, FALSE otherwise.
|
|
|
|
Desc: Converts a PDB and TAGID into a TAGREF, by packing the high bits of the
|
|
TAGREF with a constant that tells us which PDB, and the low bits with
|
|
the TAGID.
|
|
--*/
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
DWORD dwIndex = SDBENTRY_INVALID_INDEX;
|
|
|
|
if (SdbpFindLocalDatabaseByPDB(hSDB, pdb, FALSE, &dwIndex)) {
|
|
*ptrWhich = tiWhich | SDB_INDEX_TO_MASK(dwIndex);
|
|
bReturn = TRUE;
|
|
}
|
|
|
|
if (!bReturn) {
|
|
DBGPRINT((sdlError, "SdbTagIDToTagRef", "Bad PDB.\n"));
|
|
*ptrWhich = TAGREF_NULL;
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL
|
|
SdbTagRefToTagID(
|
|
IN HSDB hSDB,
|
|
IN TAGREF trWhich, // TAGREF to convert
|
|
OUT PDB* ppdb, // PDB the TAGREF is from
|
|
OUT TAGID* ptiWhich // TAGID within that PDB
|
|
)
|
|
/*++
|
|
Return: TRUE if the TAGREF is valid and was converted, FALSE otherwise.
|
|
|
|
Desc: Converts a TAGREF type to a TAGID and a PDB. This manages the interface
|
|
between NTDLL, which knows nothing of PDBs, and the shimdb, which manages
|
|
three separate PDBs. The TAGREF incorporates the TAGID and a constant
|
|
that tells us which PDB the TAGID is from. In this way, the NTDLL client
|
|
doesn't need to know which DB the info is coming from.
|
|
--*/
|
|
{
|
|
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
|
|
BOOL bReturn = TRUE;
|
|
TAGID tiWhich = TAGID_NULL;
|
|
PDB pdb = NULL;
|
|
DWORD dwIndex;
|
|
PSDBENTRY pEntry;
|
|
|
|
assert(ppdb && ptiWhich);
|
|
|
|
tiWhich = trWhich & TAGREF_STRIP_TAGID;
|
|
dwIndex = SDB_MASK_TO_INDEX(trWhich & TAGREF_STRIP_PDB);
|
|
|
|
//
|
|
// Dynamically open a custom sdb.
|
|
//
|
|
pEntry = SDBGETENTRY(pSdbContext, dwIndex);
|
|
|
|
if (pEntry->dwFlags & SDBENTRY_VALID_ENTRY) {
|
|
pdb = pEntry->pdb;
|
|
} else {
|
|
if (pEntry->dwFlags & SDBENTRY_VALID_GUID) {
|
|
|
|
//
|
|
// We have a "half-baked" entry, make sure we
|
|
// fill this entry in.
|
|
//
|
|
GUID guidDB = pEntry->guidDB;
|
|
|
|
pEntry->dwFlags = 0; // invalidate an entry so that we know it's empty
|
|
|
|
bReturn = SdbOpenLocalDatabaseEx(hSDB,
|
|
&guidDB,
|
|
SDBCUSTOM_GUID | SDBCUSTOM_USE_INDEX,
|
|
&pdb,
|
|
&dwIndex);
|
|
if (!bReturn) {
|
|
goto cleanup;
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if (pdb == NULL) {
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
if (!bReturn) {
|
|
//
|
|
// NULL out the output on failure.
|
|
//
|
|
pdb = NULL;
|
|
tiWhich = TAGID_NULL;
|
|
}
|
|
|
|
if (ppdb != NULL) {
|
|
*ppdb = pdb;
|
|
}
|
|
|
|
if (ptiWhich != NULL) {
|
|
*ptiWhich = tiWhich;
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
PDB
|
|
SdbGetLocalPDB(
|
|
IN HSDB hSDB
|
|
)
|
|
{
|
|
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
|
|
|
|
if (pSdbContext) {
|
|
return pSdbContext->pdbLocal;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
BOOL
|
|
SdbIsTagrefFromMainDB(
|
|
IN TAGREF trWhich // TAGREF to test if it's from the main DB
|
|
)
|
|
/*++
|
|
Return: TRUE if the TAGREF is from sysmain.sdb, FALSE otherwise.
|
|
|
|
Desc: Checks if the provided TAGREF belongs to sysmain.sdb.
|
|
--*/
|
|
{
|
|
return ((trWhich & TAGREF_STRIP_PDB) == PDB_MAIN);
|
|
}
|
|
|
|
BOOL
|
|
SdbIsTagrefFromLocalDB(
|
|
IN TAGREF trWhich // TAGREF to test if it's from the local DB
|
|
)
|
|
/*++
|
|
Return: TRUE if the TAGREF is from a local SDB, FALSE otherwise.
|
|
|
|
Desc: Checks if the provided TAGREF belongs to a local SDB.
|
|
--*/
|
|
{
|
|
return ((trWhich & TAGREF_STRIP_PDB) == PDB_LOCAL);
|
|
}
|
|
|
|
BOOL
|
|
SdbGetDatabaseGUID(
|
|
IN HSDB hSDB, // HSDB of the sdbContext (optional)
|
|
IN PDB pdb, // PDB of the database in question
|
|
OUT GUID* pguidDB // the guid of the DB
|
|
)
|
|
/*++
|
|
Return: TRUE if the GUID could be retrieved from the pdb, FALSE otherwise.
|
|
|
|
Desc: Gets the GUID from an SDB file. If the hSDB is passed in, it will
|
|
also check if the GUID is from systest or sysmain and return
|
|
one of the hard-coded GUIDs for those files.
|
|
--*/
|
|
{
|
|
if (!pdb) {
|
|
DBGPRINT((sdlError, "SdbGetDatabaseGUID", "NULL pdb passed in.\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pguidDB) {
|
|
DBGPRINT((sdlError, "SdbGetDatabaseGUID", "NULL pguidDB passed in.\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (hSDB) {
|
|
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
|
|
DWORD dwIndex;
|
|
|
|
if (SdbpFindLocalDatabaseByPDB(hSDB, pdb, FALSE, &dwIndex)) {
|
|
|
|
//
|
|
// Found the db, copy guid, we're done
|
|
//
|
|
if (pSdbContext->rgSDB[dwIndex].dwFlags & SDBENTRY_VALID_GUID) {
|
|
RtlCopyMemory(pguidDB, &pSdbContext->rgSDB[dwIndex].guidDB, sizeof(*pguidDB));
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return SdbGetDatabaseID(pdb, pguidDB);
|
|
}
|
|
|
|
PDB
|
|
SdbGetPDBFromGUID(
|
|
IN HSDB hSDB, // HSDB
|
|
IN GUID* pguidDB // the guid of the DB
|
|
)
|
|
{
|
|
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
|
|
PSDBENTRY pEntry;
|
|
DWORD dwIndex;
|
|
PDB pdb = NULL;
|
|
|
|
if (!pSdbContext) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!SdbpFindLocalDatabaseByGUID(hSDB, pguidDB, FALSE, &dwIndex)) {
|
|
return NULL;
|
|
}
|
|
|
|
pEntry = &pSdbContext->rgSDB[dwIndex];
|
|
|
|
if (pEntry->dwFlags & SDBENTRY_VALID_ENTRY) {
|
|
pdb = pEntry->pdb;
|
|
} else {
|
|
//
|
|
// Open local db
|
|
//
|
|
if (!SdbOpenLocalDatabaseEx(hSDB,
|
|
pguidDB,
|
|
SDBCUSTOM_GUID|SDBCUSTOM_USE_INDEX,
|
|
&pdb,
|
|
&dwIndex)) {
|
|
DBGPRINT((sdlWarning, "SdbGetPDBFromGUID", "Failed to open dormant pdb\n"));
|
|
}
|
|
}
|
|
|
|
return pdb;
|
|
}
|
|
|
|
typedef struct tagFlagInfoEntry {
|
|
|
|
ULONGLONG ullFlagMask; // mask of the flag
|
|
DWORD dwSize; // size of the structure
|
|
TAG tFlagType;
|
|
TCHAR szCommandLine[1];
|
|
|
|
} FLAGINFOENTRY, *PFLAGINFOENTRY;
|
|
|
|
typedef struct tagFlagInfo {
|
|
DWORD dwSize; // total size
|
|
DWORD dwCount; // number of entries
|
|
//
|
|
// This member below is not allowed due to 0-size szCommandLine array, so it's implied
|
|
//
|
|
// FLAGINFOENTRY FlagInfoEntry[0]; // not a real array
|
|
//
|
|
} FLAGINFO, *PFLAGINFO;
|
|
|
|
typedef struct tagFlagInfoListEntry* PFLAGINFOLISTENTRY;
|
|
|
|
typedef struct tagFlagInfoListEntry {
|
|
|
|
ULONGLONG ullFlagMask;
|
|
TAG tFlagType;
|
|
LPCTSTR pszCommandLine; // points to the currently open db
|
|
DWORD dwEntrySize;
|
|
PFLAGINFOLISTENTRY pNext;
|
|
|
|
} FLAGINFOLISTENTRY;
|
|
|
|
typedef FLAGINFOLISTENTRY* PFLAGINFOCONTEXT;
|
|
|
|
#define ALIGN_ULONGLONG(p) \
|
|
((((ULONG_PTR)(p)) + (sizeof(ULONGLONG) - 1)) & ~(sizeof(ULONGLONG) - 1))
|
|
|
|
BOOL
|
|
SDBAPI
|
|
SdbpPackCmdLineInfo(
|
|
IN PVOID pvFlagInfoList,
|
|
OUT PVOID* ppFlagInfo
|
|
)
|
|
{
|
|
PFLAGINFOLISTENTRY pFlagInfoList = (PFLAGINFOLISTENTRY)pvFlagInfoList;
|
|
PFLAGINFOLISTENTRY pEntry;
|
|
DWORD dwSize = 0;
|
|
DWORD dwFlagCount = 0;
|
|
PFLAGINFO pFlagInfo;
|
|
PFLAGINFOENTRY pFlagInfoEntry;
|
|
|
|
pEntry = pFlagInfoList;
|
|
|
|
while (pEntry != NULL) {
|
|
pEntry->dwEntrySize = (DWORD)ALIGN_ULONGLONG(sizeof(FLAGINFOENTRY) +
|
|
(_tcslen(pEntry->pszCommandLine) +
|
|
1) * sizeof(TCHAR));
|
|
dwSize += pEntry->dwEntrySize;
|
|
pEntry = pEntry->pNext;
|
|
++dwFlagCount;
|
|
}
|
|
|
|
dwSize += sizeof(FLAGINFO);
|
|
|
|
//
|
|
// Allocate memory
|
|
//
|
|
pFlagInfo = (PFLAGINFO)SdbAlloc(dwSize);
|
|
|
|
if (pFlagInfo == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpPackCmdLineInfo",
|
|
"Failed to allocate 0x%lx bytes for FlagInfo\n",
|
|
dwSize));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
pFlagInfo->dwSize = dwSize;
|
|
pFlagInfo->dwCount = dwFlagCount;
|
|
pFlagInfoEntry = (PFLAGINFOENTRY)(pFlagInfo + 1);
|
|
|
|
pEntry = pFlagInfoList;
|
|
|
|
while (pEntry != NULL) {
|
|
//
|
|
// Create an entry
|
|
//
|
|
pFlagInfoEntry->ullFlagMask = pEntry->ullFlagMask;
|
|
pFlagInfoEntry->dwSize = pEntry->dwEntrySize;
|
|
pFlagInfoEntry->tFlagType = pEntry->tFlagType;
|
|
|
|
//
|
|
// Copy the string
|
|
//
|
|
StringCchCopy(&pFlagInfoEntry->szCommandLine[0],
|
|
(pFlagInfoEntry->dwSize - sizeof(FLAGINFOENTRY))/sizeof(pFlagInfoEntry->szCommandLine[0]),
|
|
pEntry->pszCommandLine);
|
|
|
|
//
|
|
// Advance to the next entry
|
|
//
|
|
pFlagInfoEntry = (PFLAGINFOENTRY)((PBYTE)pFlagInfoEntry + pFlagInfoEntry->dwSize);
|
|
|
|
pEntry = pEntry->pNext;
|
|
}
|
|
|
|
*ppFlagInfo = (PVOID)pFlagInfo;
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
BOOL
|
|
SDBAPI
|
|
SdbpFreeFlagInfoList(
|
|
IN PVOID pvFlagInfoList
|
|
)
|
|
{
|
|
PFLAGINFOLISTENTRY pFlagInfoList = (PFLAGINFOLISTENTRY)pvFlagInfoList;
|
|
PFLAGINFOLISTENTRY pNext;
|
|
|
|
while (pFlagInfoList != NULL) {
|
|
pNext = pFlagInfoList->pNext;
|
|
SdbFree(pFlagInfoList);
|
|
pFlagInfoList = pNext;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SDBAPI
|
|
SdbQueryFlagInfo(
|
|
IN PVOID pvFlagInfo,
|
|
IN TAG tFlagType,
|
|
IN ULONGLONG ullFlagMask,
|
|
OUT LPCTSTR* ppCmdLine
|
|
)
|
|
{
|
|
PFLAGINFO pFlagInfo = (PFLAGINFO)pvFlagInfo;
|
|
PFLAGINFOENTRY pFlagInfoEntry = (PFLAGINFOENTRY)(pFlagInfo+1);
|
|
int i;
|
|
|
|
for (i = 0; i < (int)pFlagInfo->dwCount; ++i) {
|
|
|
|
if (pFlagInfoEntry->tFlagType == tFlagType &&
|
|
pFlagInfoEntry->ullFlagMask == ullFlagMask) {
|
|
|
|
if (ppCmdLine != NULL) {
|
|
*ppCmdLine = &pFlagInfoEntry->szCommandLine[0];
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
pFlagInfoEntry = (PFLAGINFOENTRY)((PBYTE)pFlagInfoEntry + pFlagInfoEntry->dwSize);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
SDBAPI
|
|
SdbFreeFlagInfo(
|
|
IN PVOID pvFlagInfo
|
|
)
|
|
{
|
|
PFLAGINFO pFlagInfo = (PFLAGINFO)pvFlagInfo;
|
|
|
|
if (pFlagInfo != NULL) {
|
|
SdbFree(pFlagInfo);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
SDBAPI
|
|
SdbpGetFlagCmdLine(
|
|
IN PFLAGINFOCONTEXT* ppFlagInfo,
|
|
IN HSDB hSDB,
|
|
IN TAGREF trFlagRef,
|
|
IN TAG tFlagType,
|
|
IN ULONGLONG ullFlagMask,
|
|
IN BOOL bOverwrite
|
|
)
|
|
{
|
|
TAGREF trFlagCmdLine;
|
|
BOOL bReturn = FALSE;
|
|
LPCTSTR lpszCmdLine;
|
|
PFLAGINFOLISTENTRY pFlagInfoListEntry;
|
|
PFLAGINFOLISTENTRY pFlagPrev;
|
|
|
|
//
|
|
// We start by getting the cmd line
|
|
//
|
|
trFlagCmdLine = SdbFindFirstTagRef(hSDB, trFlagRef, TAG_COMMAND_LINE);
|
|
|
|
if (trFlagCmdLine == TAGREF_NULL) { // no cmd line for this flag
|
|
bReturn = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Now we get the rest of the info
|
|
//
|
|
lpszCmdLine = SdbpGetStringRefPtr(hSDB, trFlagCmdLine);
|
|
|
|
if (lpszCmdLine == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpGetFlagCmdLine",
|
|
"Failed to read TAG_COMMAND_LINE string\n"));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Check whether we have already command line for this flag
|
|
//
|
|
pFlagInfoListEntry = *ppFlagInfo;
|
|
pFlagPrev = NULL;
|
|
|
|
while (pFlagInfoListEntry != NULL) {
|
|
|
|
if (pFlagInfoListEntry->tFlagType == tFlagType &&
|
|
pFlagInfoListEntry->ullFlagMask == ullFlagMask) {
|
|
break;
|
|
}
|
|
|
|
pFlagPrev = pFlagInfoListEntry;
|
|
pFlagInfoListEntry = pFlagInfoListEntry->pNext;
|
|
}
|
|
|
|
if (pFlagInfoListEntry != NULL) {
|
|
|
|
if (bOverwrite) { // found the same flag, overwrite
|
|
|
|
if (pFlagPrev == NULL) {
|
|
*ppFlagInfo = pFlagInfoListEntry->pNext;
|
|
} else {
|
|
pFlagPrev->pNext = pFlagInfoListEntry->pNext;
|
|
}
|
|
|
|
SdbFree(pFlagInfoListEntry);
|
|
|
|
} else { // same entry, no overwriting
|
|
bReturn = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have everything we need - make a context entry
|
|
//
|
|
pFlagInfoListEntry = (PFLAGINFOLISTENTRY)SdbAlloc(sizeof(FLAGINFOLISTENTRY));
|
|
|
|
if (pFlagInfoListEntry == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpGetFlagCmdLine",
|
|
"Failed to allocate FLAGINFOLISTENTRY\n"));
|
|
goto Cleanup;
|
|
}
|
|
|
|
pFlagInfoListEntry->ullFlagMask = ullFlagMask;
|
|
pFlagInfoListEntry->tFlagType = tFlagType;
|
|
pFlagInfoListEntry->pszCommandLine = lpszCmdLine;
|
|
pFlagInfoListEntry->pNext = *ppFlagInfo;
|
|
*ppFlagInfo = pFlagInfoListEntry;
|
|
|
|
bReturn = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SDBAPI
|
|
SdbQueryFlagMask(
|
|
IN HSDB hSDB,
|
|
IN SDBQUERYRESULT* psdbQuery,
|
|
IN TAG tFlagType,
|
|
OUT ULONGLONG* pullFlags,
|
|
IN OUT PVOID* ppFlagInfo OPTIONAL
|
|
)
|
|
{
|
|
DWORD dwInd;
|
|
TAGREF trFlagRef;
|
|
TAGREF trFlag;
|
|
TAGREF trFlagMask;
|
|
ULONGLONG ullFlagMask;
|
|
PFLAGINFOCONTEXT pFlagInfoContext = NULL;
|
|
|
|
if (pullFlags == NULL) {
|
|
DBGPRINT((sdlError, "SdbQueryFlagMask", "Invalid parameter.\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
*pullFlags = 0;
|
|
|
|
if (ppFlagInfo != NULL) {
|
|
pFlagInfoContext = *(PFLAGINFOCONTEXT*)ppFlagInfo;
|
|
}
|
|
|
|
for (dwInd = 0; psdbQuery->atrExes[dwInd] != TAGREF_NULL && dwInd < SDB_MAX_EXES; dwInd++) {
|
|
|
|
trFlagRef = SdbFindFirstTagRef(hSDB, psdbQuery->atrExes[dwInd], TAG_FLAG_REF);
|
|
|
|
while (trFlagRef != TAGREF_NULL) {
|
|
|
|
trFlag = SdbGetFlagFromFlagRef(hSDB, trFlagRef);
|
|
|
|
if (trFlag == TAGREF_NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbQueryFlagMask",
|
|
"Failed to get TAG from TAGREF 0x%x.\n",
|
|
trFlagRef));
|
|
break;
|
|
}
|
|
|
|
ullFlagMask = 0;
|
|
|
|
trFlagMask = SdbFindFirstTagRef(hSDB, trFlag, tFlagType);
|
|
|
|
if (trFlagMask != TAGREF_NULL) {
|
|
ullFlagMask = SdbReadQWORDTagRef(hSDB, trFlagMask, 0);
|
|
}
|
|
|
|
*pullFlags |= ullFlagMask;
|
|
|
|
//
|
|
// Now we get command line - if we have retrieved the flag mask
|
|
//
|
|
if (ppFlagInfo != NULL && ullFlagMask) {
|
|
if (!SdbpGetFlagCmdLine(&pFlagInfoContext,
|
|
hSDB,
|
|
trFlagRef,
|
|
tFlagType,
|
|
ullFlagMask,
|
|
TRUE)) {
|
|
//
|
|
// BUGBUG: this has to be handled as an error
|
|
// Currently we do not do this b/c it is not
|
|
// as important -- pFlagInfoContext will not be
|
|
// touched if this function had failed
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
trFlagRef = SdbFindNextTagRef(hSDB, psdbQuery->atrExes[dwInd], trFlagRef);
|
|
}
|
|
}
|
|
|
|
for (dwInd = 0;
|
|
psdbQuery->atrLayers[dwInd] != TAGREF_NULL && dwInd < SDB_MAX_LAYERS;
|
|
dwInd++) {
|
|
|
|
trFlagRef = SdbFindFirstTagRef(hSDB, psdbQuery->atrLayers[dwInd], TAG_FLAG_REF);
|
|
|
|
while (trFlagRef != TAGREF_NULL) {
|
|
trFlag = SdbGetFlagFromFlagRef(hSDB, trFlagRef);
|
|
|
|
if (trFlag == TAGREF_NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbQueryFlagMask",
|
|
"Failed to get TAG from TAGREF 0x%x.\n",
|
|
trFlagRef));
|
|
break;
|
|
}
|
|
|
|
ullFlagMask = 0;
|
|
|
|
trFlagMask = SdbFindFirstTagRef(hSDB, trFlag, tFlagType);
|
|
|
|
if (trFlagMask != TAGREF_NULL) {
|
|
ullFlagMask = SdbReadQWORDTagRef(hSDB, trFlagMask, 0);
|
|
}
|
|
|
|
*pullFlags |= ullFlagMask;
|
|
|
|
if (ppFlagInfo != NULL && ullFlagMask) {
|
|
SdbpGetFlagCmdLine(&pFlagInfoContext,
|
|
hSDB,
|
|
trFlagRef,
|
|
tFlagType,
|
|
ullFlagMask,
|
|
FALSE);
|
|
}
|
|
|
|
trFlagRef = SdbFindNextTagRef(hSDB, psdbQuery->atrLayers[dwInd], trFlagRef);
|
|
}
|
|
}
|
|
|
|
if (ppFlagInfo != NULL) {
|
|
*ppFlagInfo = (PVOID)pFlagInfoContext;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SdbpIsPathOnCdRom(
|
|
LPCTSTR pszPath
|
|
)
|
|
{
|
|
TCHAR szDrive[5];
|
|
UINT unType;
|
|
|
|
if (pszPath == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpIsPathOnCdRom",
|
|
"NULL parameter passed for szPath.\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (pszPath[1] != _T(':') && pszPath[1] != _T('\\')) {
|
|
//
|
|
// Not a path we recognize.
|
|
//
|
|
DBGPRINT((sdlInfo,
|
|
"SdbpIsPathOnCdRom",
|
|
"\"%s\" not a full path we can operate on.\n",
|
|
pszPath));
|
|
return FALSE;
|
|
}
|
|
|
|
if (pszPath[1] == _T('\\')) {
|
|
//
|
|
// Network path.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy(szDrive, _T("c:\\"), 4 * sizeof(TCHAR));
|
|
szDrive[0] = pszPath[0];
|
|
|
|
unType = GetDriveType(szDrive);
|
|
|
|
if (unType == DRIVE_CDROM) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
SdbpBuildSignature(
|
|
IN LPCTSTR pszPath,
|
|
OUT LPTSTR pszPathSigned,
|
|
IN DWORD cchSize // size of pszPathSigned (in characters)
|
|
)
|
|
{
|
|
TCHAR szDir[MAX_PATH];
|
|
TCHAR* pszEnd;
|
|
DWORD dwSignature = 0;
|
|
HANDLE hFind;
|
|
WIN32_FIND_DATA ffd;
|
|
int nCount = 9;
|
|
|
|
_tcsncpy(szDir, pszPath, MAX_PATH);
|
|
szDir[MAX_PATH - 1] = 0;
|
|
|
|
pszEnd = _tcsrchr(szDir, _T('\\'));
|
|
if (pszEnd != NULL) {
|
|
++pszEnd;
|
|
} else {
|
|
pszEnd = szDir;
|
|
}
|
|
|
|
*pszEnd++ = _T('*');
|
|
*pszEnd = _T('\0');
|
|
|
|
hFind = FindFirstFile(szDir, &ffd);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE) {
|
|
DBGPRINT((sdlInfo,
|
|
"SdbPathRequiresSignature",
|
|
"\"%s\" not a full path we can operate on.\n",
|
|
pszPath));
|
|
return FALSE;
|
|
}
|
|
|
|
do {
|
|
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
|
ffd.nFileSizeLow != 0) {
|
|
|
|
dwSignature = ((dwSignature << 1) | (dwSignature >> 31)) ^ ffd.nFileSizeLow;
|
|
|
|
nCount--;
|
|
}
|
|
|
|
if (!FindNextFile(hFind, &ffd)) {
|
|
break;
|
|
}
|
|
|
|
} while (nCount > 0);
|
|
|
|
FindClose(hFind);
|
|
|
|
//
|
|
// pszPath always starts with x:\\
|
|
//
|
|
StringCchPrintf(pszPathSigned, cchSize, _T("SIGN=%X %s"), dwSignature, pszPath + 3);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LPTSTR
|
|
GetProcessHistory(
|
|
IN LPCTSTR pEnvironment,
|
|
IN LPTSTR szDir,
|
|
IN LPTSTR szName
|
|
)
|
|
/*++
|
|
Return: The __PROCESS_HISTORY content from the environment.
|
|
|
|
Desc: The function retrieves Process History given the environment, an exe name and
|
|
it's directory. Process History is constructed from the __PROCESS_HISTORY environment
|
|
variable with an addition of the current exe path. The memory buffer returned from this
|
|
function should be freed using SdbFree
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG ProcessHistorySize = 0;
|
|
ULONG DirLen = 0, NameLen = 0;
|
|
DWORD dwBufferLength = 0;
|
|
LPTSTR szProcessHistory = NULL;
|
|
LPTSTR pszHistory = NULL;
|
|
|
|
assert(szDir != NULL && szName != NULL);
|
|
|
|
DirLen = (ULONG)_tcslen(szDir);
|
|
NameLen = (ULONG)_tcslen(szName);
|
|
|
|
Status = SdbpGetEnvVar(pEnvironment,
|
|
g_szProcessHistory,
|
|
NULL,
|
|
&dwBufferLength);
|
|
|
|
if (STATUS_BUFFER_TOO_SMALL == Status) {
|
|
ProcessHistorySize = (DirLen + NameLen + 2 + dwBufferLength) * sizeof(TCHAR);
|
|
} else {
|
|
//
|
|
// We assume that the environment variable is not available.
|
|
//
|
|
assert(Status == STATUS_VARIABLE_NOT_FOUND);
|
|
|
|
ProcessHistorySize = (DirLen + NameLen + 1) * sizeof(TCHAR);
|
|
}
|
|
|
|
//
|
|
// Allocate the buffer, regardless of whether there is
|
|
// an environment variable or not. Later, we will check Status again
|
|
// to see whether we need to try to query for an environment variable
|
|
// with a valid buffer.
|
|
//
|
|
pszHistory = szProcessHistory = SdbAlloc(ProcessHistorySize);
|
|
|
|
if (szProcessHistory == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"GetProcessHistory",
|
|
"Unable to allocate %d bytes for process history.\n",
|
|
ProcessHistorySize));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
*pszHistory = 0;
|
|
|
|
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
|
|
|
//
|
|
// In this case we have tried to obtain the __PROCESS_HISTORY and
|
|
// the variable was present as indicated by the status
|
|
//
|
|
Status = SdbpGetEnvVar(pEnvironment,
|
|
g_szProcessHistory,
|
|
szProcessHistory,
|
|
&dwBufferLength);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
//
|
|
// See if we have ';' at the end of this.
|
|
//
|
|
pszHistory = szProcessHistory + dwBufferLength - 1;
|
|
|
|
if (*pszHistory != TEXT(';')) {
|
|
*++pszHistory = TEXT(';');
|
|
}
|
|
|
|
++pszHistory;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The __PROCESS_HISTORY environment variable has the following format:
|
|
//
|
|
// __PROCESS_HISTORY=C:\ProcessN-2.exe;D:\ProcessN-1.exe
|
|
//
|
|
// and then the following lines tack on the current process like so:
|
|
//
|
|
// __PROCESS_HISTORY=C:\ProcessN-2.exe;D:\ProcessN-1.exe;D:\Child\ProcessN.exe
|
|
//
|
|
|
|
RtlMoveMemory(pszHistory, szDir, DirLen * sizeof(TCHAR));
|
|
pszHistory += DirLen;
|
|
|
|
RtlMoveMemory(pszHistory, szName, NameLen * sizeof(TCHAR));
|
|
pszHistory += NameLen;
|
|
*pszHistory = TEXT('\0');
|
|
|
|
return szProcessHistory;
|
|
}
|
|
|
|
TAGREF
|
|
SdbpGetNamedLayerFromExe(
|
|
IN HSDB hSDB,
|
|
IN PDB pdb,
|
|
IN TAGID tiLayer,
|
|
OUT DWORD* pdwLayerFlags
|
|
)
|
|
/*++
|
|
Return: A TAGREF for the layer under the EXE tag or TAGREF_NULL if there is no layer.
|
|
|
|
Desc: BUGBUG: ?
|
|
--*/
|
|
{
|
|
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
|
|
TAGREF trLayer;
|
|
TAGID tiDatabase, tiName;
|
|
TCHAR* pszName;
|
|
BOOL bSuccess;
|
|
|
|
//
|
|
// Read the layer's name.
|
|
//
|
|
tiName = SdbFindFirstTag(pdb, tiLayer, TAG_NAME);
|
|
|
|
if (tiName == TAGID_NULL) {
|
|
DBGPRINT((sdlError, "SdbpGetNamedLayerFromExe", "Layer tag w/o a name.\n"));
|
|
return TAGREF_NULL;
|
|
}
|
|
|
|
pszName = SdbGetStringTagPtr(pdb, tiName);
|
|
|
|
if (pszName == NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpGetNamedLayerFromExe",
|
|
"Cannot read the name of the layer tag.\n"));
|
|
return TAGREF_NULL;
|
|
}
|
|
|
|
//
|
|
// Need to get the layer flags here.
|
|
//
|
|
pszName = SdbpGetLayerFlags(pszName, pdwLayerFlags);
|
|
|
|
//
|
|
// First, try to find the layer in the same db as the EXE
|
|
//
|
|
tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
|
|
|
|
assert(tiDatabase != TAGID_NULL);
|
|
|
|
trLayer = TAGREF_NULL;
|
|
|
|
tiLayer = SdbFindFirstNamedTag(pdb,
|
|
tiDatabase,
|
|
TAG_LAYER,
|
|
TAG_NAME,
|
|
pszName);
|
|
|
|
if (tiLayer != TAGID_NULL) {
|
|
bSuccess = SdbTagIDToTagRef(pSdbContext, pdb, tiLayer, &trLayer);
|
|
|
|
if (!bSuccess) {
|
|
DBGPRINT((sdlError, "SdbpGetNamedLayerFromExe", "Cannot get tag ref from tag id.\n"));
|
|
}
|
|
|
|
return trLayer;
|
|
}
|
|
|
|
if (pdb != pSdbContext->pdbMain) {
|
|
//
|
|
// Try it now in the main db
|
|
//
|
|
tiDatabase = SdbFindFirstTag(pSdbContext->pdbMain, TAGID_ROOT, TAG_DATABASE);
|
|
|
|
tiLayer = SdbFindFirstNamedTag(pSdbContext->pdbMain,
|
|
tiDatabase,
|
|
TAG_LAYER,
|
|
TAG_NAME,
|
|
pszName);
|
|
|
|
if (tiLayer != TAGID_NULL) {
|
|
bSuccess = SdbTagIDToTagRef(pSdbContext, pSdbContext->pdbMain, tiLayer, &trLayer);
|
|
|
|
if (!bSuccess) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpGetNamedLayerFromExe",
|
|
"Cannot get tag ref from tag id.\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
return trLayer;
|
|
}
|
|
|
|
|
|
TAGREF
|
|
SDBAPI
|
|
SdbGetNamedLayer(
|
|
IN HSDB hSDB, // database context
|
|
IN TAGREF trLayerRef // tagref of a record referencing a layer
|
|
)
|
|
{
|
|
PDB pdb = NULL;
|
|
TAGID tiLayerRef = TAGID_NULL;
|
|
|
|
if (!SdbTagRefToTagID(hSDB, trLayerRef, &pdb, &tiLayerRef)) {
|
|
DBGPRINT((sdlError, "SdbGetNamedLayer",
|
|
"Error converting tagref 0x%lx to tagid\n", trLayerRef));
|
|
return TAGREF_NULL;
|
|
}
|
|
|
|
return SdbpGetNamedLayerFromExe(hSDB, pdb, tiLayerRef, NULL);
|
|
}
|
|
|
|
//
|
|
// This code is only needed when not running in Kernel Mode
|
|
//
|
|
|
|
TAGREF
|
|
SdbGetLayerTagReg(
|
|
IN HSDB hSDB,
|
|
IN LPCTSTR szLayer
|
|
)
|
|
/*++
|
|
Return: BUGBUG: ?
|
|
|
|
Desc: BUGBUG: ?
|
|
--*/
|
|
{
|
|
TAGID tiDatabase;
|
|
TAGID tiLayer;
|
|
TAGREF trLayer;
|
|
PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
|
|
|
|
if (pSdbContext == NULL || pSdbContext->pdbMain == NULL) {
|
|
DBGPRINT((sdlError, "SdbGetLayerTagReg", "Invalid parameters.\n"));
|
|
return TAGREF_NULL;
|
|
}
|
|
|
|
tiDatabase = SdbFindFirstTag(pSdbContext->pdbMain, TAGID_ROOT, TAG_DATABASE);
|
|
|
|
tiLayer = SdbFindFirstNamedTag(pSdbContext->pdbMain,
|
|
tiDatabase,
|
|
TAG_LAYER,
|
|
TAG_NAME,
|
|
szLayer);
|
|
|
|
if (tiLayer == TAGID_NULL) {
|
|
DBGPRINT((sdlError, "SdbGetLayerTagReg", "No layer \"%s\" exists.\n", szLayer));
|
|
return TAGREF_NULL;
|
|
}
|
|
|
|
if (!SdbTagIDToTagRef(hSDB, pSdbContext->pdbMain, tiLayer, &trLayer)) {
|
|
DBGPRINT((sdlError,
|
|
"SdbGetLayerTagReg",
|
|
"Cannot get tagref for tagid 0x%x.\n",
|
|
tiLayer));
|
|
return TAGREF_NULL;
|
|
}
|
|
|
|
return trLayer;
|
|
}
|
|
|
|
BOOL
|
|
SdbParseLayerString(
|
|
IN PSDBCONTEXT pSdbContext,
|
|
IN LPTSTR pszLayerString,
|
|
IN PSDBQUERYRESULT pQueryResult,
|
|
IN PDWORD pdwLayers,
|
|
OUT DWORD* pdwLayerFlags
|
|
)
|
|
{
|
|
TCHAR* pszLayerStringStart = NULL;
|
|
TCHAR szLayer[MAX_PATH];
|
|
TAGID tiDatabase = TAGID_NULL;
|
|
TAGID tiLayer = TAGID_NULL;
|
|
PDB pdbLayer = NULL; // pdb that contains the match for the layer
|
|
|
|
UNREFERENCED_PARAMETER(pdwLayers);
|
|
|
|
pszLayerString = SdbpGetLayerFlags(pszLayerString, pdwLayerFlags);
|
|
|
|
//
|
|
// Now we should be at the beginning of the layer string.
|
|
//
|
|
while (pszLayerString != NULL && *pszLayerString != _T('\0')) {
|
|
//
|
|
// Beginning of the string, remember the ptr
|
|
//
|
|
pszLayerStringStart = pszLayerString;
|
|
|
|
//
|
|
// Move the end to the first space.
|
|
//
|
|
pszLayerString = _tcspbrk(pszLayerStringStart, g_szWhiteSpaceDelimiters);
|
|
|
|
//
|
|
// Check whether it's all the way to the end
|
|
//
|
|
if (pszLayerString != NULL) {
|
|
//
|
|
// Terminate the string...
|
|
//
|
|
*pszLayerString++ = _T('\0');
|
|
|
|
//
|
|
// Skip white space.
|
|
//
|
|
pszLayerString += _tcsspn(pszLayerString, g_szWhiteSpaceDelimiters);
|
|
}
|
|
|
|
//
|
|
// Now pszLayerStringStart points to the layer string that needs
|
|
// to be examined.
|
|
//
|
|
StringCchCopy(szLayer, CHARCOUNT(szLayer), pszLayerStringStart);
|
|
|
|
//
|
|
// Search the layer in the test database first.
|
|
//
|
|
if (pSdbContext->pdbTest != NULL) {
|
|
tiDatabase = SdbFindFirstTag(pSdbContext->pdbTest, TAGID_ROOT, TAG_DATABASE);
|
|
pdbLayer = pSdbContext->pdbTest;
|
|
|
|
tiLayer = SdbFindFirstNamedTag(pSdbContext->pdbTest,
|
|
tiDatabase,
|
|
TAG_LAYER,
|
|
TAG_NAME,
|
|
szLayer);
|
|
}
|
|
|
|
if (tiLayer == TAGID_NULL) {
|
|
//
|
|
// Now search the layer in the main database.
|
|
//
|
|
tiDatabase = SdbFindFirstTag(pSdbContext->pdbMain, TAGID_ROOT, TAG_DATABASE);
|
|
pdbLayer = pSdbContext->pdbMain;
|
|
|
|
tiLayer = SdbFindFirstNamedTag(pSdbContext->pdbMain,
|
|
tiDatabase,
|
|
TAG_LAYER,
|
|
TAG_NAME,
|
|
szLayer);
|
|
}
|
|
|
|
if (tiLayer != TAGID_NULL) {
|
|
goto foundDB;
|
|
}
|
|
|
|
//
|
|
// Check if the layer is defined in a custom database
|
|
//
|
|
{
|
|
DWORD dwLocalIndex = 0;
|
|
|
|
while (SdbOpenNthLocalDatabase((HSDB)pSdbContext, szLayer, &dwLocalIndex, TRUE)) {
|
|
|
|
tiDatabase = SdbFindFirstTag(pSdbContext->pdbLocal, TAGID_ROOT, TAG_DATABASE);
|
|
|
|
if (tiDatabase != TAGID_NULL) {
|
|
tiLayer = SdbFindFirstNamedTag(pSdbContext->pdbLocal,
|
|
tiDatabase,
|
|
TAG_LAYER,
|
|
TAG_NAME,
|
|
szLayer);
|
|
|
|
if (tiLayer != TAGID_NULL) {
|
|
pdbLayer = pSdbContext->pdbLocal;
|
|
goto foundDB;
|
|
}
|
|
} else {
|
|
DBGPRINT((sdlError, "SdbParseLayerString", "Local database is corrupted!\n"));
|
|
}
|
|
|
|
SdbCloseLocalDatabase((HSDB)pSdbContext);
|
|
}
|
|
}
|
|
|
|
foundDB:
|
|
if (tiLayer != TAGID_NULL) {
|
|
|
|
if (!SdbpAddMatch(pQueryResult,
|
|
pSdbContext,
|
|
pdbLayer,
|
|
NULL,
|
|
0,
|
|
&tiLayer,
|
|
1,
|
|
NULL,
|
|
0,
|
|
NULL)) {
|
|
//
|
|
// Error would have already been logged
|
|
//
|
|
break;
|
|
}
|
|
|
|
DBGPRINT((sdlWarning|sdlLogShimViewer,
|
|
"SdbParseLayerString",
|
|
"Invoking compatibility layer \"%s\".\n",
|
|
pSdbContext,
|
|
szLayer));
|
|
|
|
}
|
|
|
|
tiLayer = TAGID_NULL;
|
|
pdbLayer = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
SdbOpenNthLocalDatabase(
|
|
IN HSDB hSDB, // handle to the database channel
|
|
IN LPCTSTR pszItemName, // the name of the exectutable, without the path or the layer name
|
|
IN LPDWORD pdwIndex, // zero based index of the local DB to open
|
|
IN BOOL bLayer
|
|
)
|
|
/*++
|
|
Return: TRUE on success, FALSE otherwise.
|
|
|
|
Desc: Opens the Nth local database.
|
|
--*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
GUID guidDB;
|
|
DWORD dwIndex;
|
|
|
|
//
|
|
// Keep trying until there aren't any more user SDB files, or
|
|
// we find one we can open. This is to guard against a missing file
|
|
// causing us to ignore all further SDB files.
|
|
//
|
|
while (!bRet) {
|
|
if (!SdbGetNthUserSdb(hSDB, pszItemName, bLayer, pdwIndex, &guidDB)) {
|
|
break; // we have no more dbs
|
|
}
|
|
|
|
//
|
|
// Resolve the database we got through the local database interface
|
|
//
|
|
DBGPRINT((sdlInfo,
|
|
"SdbOpenNthLocalDatabase",
|
|
"Attempting to open local database %d\n",
|
|
*pdwIndex));
|
|
|
|
//
|
|
// See if we already have the database open
|
|
//
|
|
if (SdbpFindLocalDatabaseByGUID(hSDB, &guidDB, FALSE, &dwIndex)) {
|
|
|
|
PSDBENTRY pEntry = SDBGETENTRY(hSDB, dwIndex);
|
|
|
|
//
|
|
// This database is already open, remember, we treat pdbLocal as a junk
|
|
// pointer, which ALWAYS stores the result of this operation
|
|
//
|
|
assert(pEntry->dwFlags & SDBENTRY_VALID_ENTRY);
|
|
assert(pEntry->pdb != NULL);
|
|
|
|
((PSDBCONTEXT)hSDB)->pdbLocal = pEntry->pdb;
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
|
|
dwIndex = PDB_LOCAL;
|
|
bRet = SdbOpenLocalDatabaseEx(hSDB,
|
|
&guidDB,
|
|
SDBCUSTOM_GUID_BINARY|SDBCUSTOM_USE_INDEX,
|
|
NULL,
|
|
&dwIndex);
|
|
//
|
|
// In reality the function above will not do extra work to map the db
|
|
// if it already is mapped and opened (retained)
|
|
//
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*++
|
|
|
|
SdbGetMatchingExe
|
|
|
|
This is where the bulk of the work gets done. A full path of an EXE gets passed in,
|
|
and the function searches the database for potential matches. If a match is found,
|
|
the TAGREF of the EXE record in the database is passed back to be used for future
|
|
queries. If no match is found, the return is TAGREF_NULL.
|
|
|
|
The TAGREF returned by this function must be released by calling SdbReleaseMatchingExe
|
|
when finished with it. This only pertains to this TAGREF, not to TAGREFs in general.
|
|
|
|
ppContext is an optional parameter
|
|
if NULL, it has no effect
|
|
if not-null then it contains a pointer to the retained search context which
|
|
is useful when performing multiple search passes
|
|
|
|
using ppContext:
|
|
|
|
PVOID pContext = NULL;
|
|
|
|
SdbGetMatchingExe(TAG_EXE, L"foo\foo.exe", pEnv, &pContext, &trExe, &trLayer);
|
|
|
|
then you can use the context like this:
|
|
|
|
SdbGetMatchingExe(TAG_APPHELP_EXE, L"foo\foo.exe", pEnv, &pContext, &trExe, &trLayer);
|
|
|
|
to free the search context use
|
|
vFreeSearchDBContext(&pContext); <<< pContext is released and set to NULL
|
|
|
|
this is done to cache path-related information for a given exe file
|
|
|
|
--*/
|
|
BOOL
|
|
SdbpCleanupForExclusiveMatch(
|
|
IN PSDBCONTEXT pSdbContext,
|
|
IN PDB pdb
|
|
)
|
|
{
|
|
DWORD dwIndex;
|
|
PSDBENTRY pEntry;
|
|
|
|
//
|
|
// In doing a cleanup we do not touch the temp db since it's the one
|
|
// that is currently open (hence pdb parameter)
|
|
//
|
|
for (dwIndex = 2; dwIndex < ARRAYSIZE(pSdbContext->rgSDB); ++dwIndex) {
|
|
|
|
if (!SDBCUSTOM_CHECK_INDEX(pSdbContext, dwIndex)) {
|
|
continue;
|
|
}
|
|
|
|
pEntry = SDBGETENTRY(pSdbContext, dwIndex);
|
|
|
|
if (pEntry->pdb == pdb) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Nuke this entry
|
|
//
|
|
if (!SdbCloseLocalDatabaseEx((HSDB)pSdbContext, NULL, dwIndex)) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpCleanupForExclusiveMatch",
|
|
"Failed to close local database\n"));
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOL
|
|
SdbpAddMatch(
|
|
IN OUT PSDBQUERYRESULT pQueryResult,
|
|
IN PSDBCONTEXT pSdbContext,
|
|
IN PDB pdb,
|
|
IN TAGID* ptiExes,
|
|
IN DWORD dwNumExes,
|
|
IN TAGID* ptiLayers,
|
|
IN DWORD dwNumLayers,
|
|
IN GUID* pguidExeID,
|
|
IN DWORD dwExeFlags,
|
|
IN OUT PMATCHMODE pMatchMode
|
|
)
|
|
{
|
|
DWORD dwIndex, dwLayerFlags = 0;
|
|
TAGID tiLayer;
|
|
TAGREF trLayer;
|
|
BOOL bSuccess = FALSE;
|
|
|
|
UNREFERENCED_PARAMETER(dwExeFlags);
|
|
UNREFERENCED_PARAMETER(pguidExeID);
|
|
|
|
if (pMatchMode != NULL) {
|
|
|
|
switch (pMatchMode-> Type) {
|
|
|
|
case MATCH_ADDITIVE:
|
|
//
|
|
// We're ok, add the match
|
|
//
|
|
break;
|
|
|
|
case MATCH_NORMAL:
|
|
//
|
|
// Go ahead, store the result
|
|
//
|
|
break;
|
|
|
|
case MATCH_EXCLUSIVE:
|
|
//
|
|
// Purge what we have so far
|
|
//
|
|
RtlZeroMemory(pQueryResult, sizeof(*pQueryResult));
|
|
|
|
//
|
|
// Cleanup all the custom sdbs, we will not need to apply any.
|
|
// We need to cleanse all the custom sdbs EXCEPT pdb.
|
|
// This is a tricky operation since pdb may be hosted in any of the custom sdb
|
|
// cells
|
|
//
|
|
SdbpCleanupForExclusiveMatch(pSdbContext, pdb);
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// We don't know what this mode is -- error
|
|
//
|
|
DBGPRINT((sdlError,
|
|
"SdbpAddMatch",
|
|
"Unknown match mode 0x%lx\n",
|
|
(DWORD)pMatchMode->Type));
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check whether this sdb is a custom sdb or local sdb
|
|
//
|
|
if (SdbpIsLocalTempPDB(pSdbContext, pdb)) {
|
|
|
|
//
|
|
// Permanentize this sdb -- note that pdb may change while we are here!
|
|
//
|
|
if (SdbpRetainLocalDBEntry(pSdbContext, &pdb) == SDBENTRY_INVALID_INDEX) {
|
|
|
|
//
|
|
// Can't permanentize, forget it then
|
|
//
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// the value retrieved may have been a bad one, thus we check for pdb
|
|
//
|
|
if (pdb == NULL) {
|
|
//
|
|
// this means we have a bad entry in local sdb table
|
|
//
|
|
assert(FALSE);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now pdb is either test, main or a permanentized local entry
|
|
//
|
|
if (ptiExes != NULL) {
|
|
for (dwIndex = 0; dwIndex < dwNumExes; ++dwIndex) {
|
|
|
|
if (pQueryResult->dwExeCount >= ARRAYSIZE(pQueryResult->atrExes)) {
|
|
|
|
DBGPRINT((sdlError,
|
|
"SdbpAddMatch",
|
|
"Failed to add the exe: exe count exceeded, tiExe was 0x%lx\n",
|
|
ptiExes[dwIndex]));
|
|
break;
|
|
}
|
|
|
|
bSuccess = SdbTagIDToTagRef(pSdbContext,
|
|
pdb,
|
|
ptiExes[dwIndex],
|
|
&pQueryResult->atrExes[pQueryResult->dwExeCount]);
|
|
|
|
if (!bSuccess) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpAddMatch",
|
|
"Failed to convert tiExe 0x%x to trExe.\n",
|
|
ptiExes[dwIndex]));
|
|
continue;
|
|
}
|
|
|
|
++pQueryResult->dwExeCount;
|
|
|
|
tiLayer = SdbFindFirstTag(pdb, ptiExes[dwIndex], TAG_LAYER);
|
|
|
|
while (tiLayer != TAGID_NULL) {
|
|
|
|
trLayer = SdbpGetNamedLayerFromExe(pSdbContext, pdb, tiLayer, &dwLayerFlags);
|
|
|
|
if (trLayer == TAGREF_NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpAddMatch",
|
|
"Failed to convert 0x%lx to layer ref\n",
|
|
tiLayer));
|
|
goto NextLayer;
|
|
}
|
|
|
|
if (pQueryResult->dwLayerCount >= ARRAYSIZE(pQueryResult->atrLayers)) {
|
|
|
|
DBGPRINT((sdlError,
|
|
"SdbpAddMatch",
|
|
"Failed to add the layer: layer count exceeded, tiExe was 0x%lx\n",
|
|
ptiExes[dwIndex]));
|
|
break;
|
|
}
|
|
|
|
pQueryResult->atrLayers[pQueryResult->dwLayerCount] = trLayer;
|
|
pQueryResult->dwLayerFlags |= dwLayerFlags;
|
|
|
|
++pQueryResult->dwLayerCount;
|
|
|
|
NextLayer:
|
|
tiLayer = SdbFindNextTag(pdb, ptiExes[dwIndex], tiLayer);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ptiLayers != NULL) {
|
|
|
|
for (dwIndex = 0; dwIndex < dwNumLayers; ++dwIndex) {
|
|
|
|
trLayer = SdbpGetNamedLayerFromExe(pSdbContext, pdb, ptiLayers[dwIndex], &dwLayerFlags);
|
|
|
|
if (trLayer == TAGREF_NULL) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpAddMatch",
|
|
"Failed to get layer from 0x%lx\n",
|
|
ptiLayers[dwIndex]));
|
|
continue;
|
|
}
|
|
|
|
if (pQueryResult->dwLayerCount >= ARRAYSIZE(pQueryResult->atrLayers)) {
|
|
DBGPRINT((sdlError,
|
|
"SdbpAddMatch",
|
|
"Failed to add the match: layer count exceeded, trLayer was 0x%lx\n",
|
|
trLayer));
|
|
break; // note that we simply truncate our match
|
|
}
|
|
|
|
pQueryResult->atrLayers[pQueryResult->dwLayerCount] = trLayer;
|
|
pQueryResult->dwLayerFlags |= dwLayerFlags;
|
|
++pQueryResult->dwLayerCount;
|
|
}
|
|
}
|
|
|
|
bSuccess = TRUE;
|
|
|
|
cleanup:
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SdbpCaptureCustomSDBInformation(
|
|
IN OUT PSDBQUERYRESULT pQueryResult,
|
|
IN PSDBCONTEXT pSdbContext
|
|
)
|
|
{
|
|
DWORD dwIndex;
|
|
TAGREF trExe;
|
|
TAGREF trLayer;
|
|
DWORD dwDatabaseIndex;
|
|
PSDBENTRY pEntry;
|
|
DWORD dwMap = 0;
|
|
DWORD dwMask;
|
|
|
|
//
|
|
// Go through results, pick those sdbs that we need...
|
|
//
|
|
for (dwIndex = 0; dwIndex < pQueryResult->dwExeCount; ++dwIndex) {
|
|
|
|
//
|
|
// Get custom sdb for each tagref
|
|
//
|
|
trExe = pQueryResult->atrExes[dwIndex];
|
|
|
|
dwDatabaseIndex = SDB_MASK_TO_INDEX(trExe);
|
|
|
|
dwMask = (1UL << dwDatabaseIndex);
|
|
|
|
if (!(dwMap & dwMask)) {
|
|
//
|
|
// Copy the guid
|
|
//
|
|
pEntry = SDBGETENTRY(pSdbContext, dwDatabaseIndex);
|
|
RtlCopyMemory(&pQueryResult->rgGuidDB[dwDatabaseIndex], &pEntry->guidDB, sizeof(GUID));
|
|
dwMap |= dwMask;
|
|
}
|
|
}
|
|
|
|
for (dwIndex = 0; dwIndex < pQueryResult->dwLayerCount; ++dwIndex) {
|
|
|
|
trLayer = pQueryResult->atrLayers[dwIndex];
|
|
|
|
dwDatabaseIndex = SDB_MASK_TO_INDEX(trLayer);
|
|
|
|
dwMask = (1UL << dwDatabaseIndex);
|
|
|
|
if (!(dwMap & dwMask)) {
|
|
pEntry = SDBGETENTRY(pSdbContext, dwDatabaseIndex);
|
|
RtlCopyMemory(&pQueryResult->rgGuidDB[dwDatabaseIndex], &pEntry->guidDB, sizeof(GUID));
|
|
dwMap |= dwMask;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Map to all the entries we have.
|
|
// Technically we do not need it, but just in case...
|
|
//
|
|
pQueryResult->dwCustomSDBMap = dwMap;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SdbGetMatchingExe(
|
|
IN HSDB hSDB OPTIONAL,
|
|
IN LPCTSTR szPath,
|
|
IN LPCTSTR szModuleName, // Optional -- only useful for 16-bit apps
|
|
IN LPCTSTR pszEnvironment,
|
|
IN DWORD dwFlags,
|
|
OUT PSDBQUERYRESULT pQueryResult
|
|
)
|
|
/*++
|
|
Return: TRUE if the specified EXE has a match in the database, FALSE otherwise.
|
|
|
|
Desc: This is where the bulk of the work gets done. A full path of an EXE gets
|
|
passed in, and the function searches the database for potential matches.
|
|
If a match is found, the TAGREF of the EXE record in the database is
|
|
passed back to be used for future queries. If no match is found, the
|
|
return is TAGREF_NULL.
|
|
The TAGREF returned by this function must be released by calling
|
|
SdbReleaseMatchingExe when finished with it. This only pertains to
|
|
this TAGREF, not to TAGREFs in general.
|
|
--*/
|
|
{
|
|
PDB pdb = NULL; // pdb that contains the match for the EXE
|
|
TAG tSection = TAG_EXE;
|
|
TAGID atiExes[SDB_MAX_EXES];
|
|
DWORD dwLayers = 0;
|
|
BOOL bReleaseDatabase = FALSE;
|
|
DWORD dwBufferSize;
|
|
DWORD dwLocalIndex = 0;
|
|
DWORD dwNumExes = 0;
|
|
MATCHMODE MatchMode = { 0 };
|
|
GUID guidExeID = { 0 };
|
|
DWORD dwExeFlags = 0;
|
|
DWORD dwLayerFlags = 0;
|
|
|
|
PSDBCONTEXT pSdbContext;
|
|
SEARCHDBCONTEXT Context;
|
|
BOOL bInstrumented = FALSE;
|
|
BOOL bMatchComplete = FALSE;
|
|
|
|
RtlZeroMemory(pQueryResult, sizeof(SDBQUERYRESULT));
|
|
RtlZeroMemory(atiExes, sizeof(atiExes));
|
|
|
|
if (hSDB == NULL) {
|
|
hSDB = SdbInitDatabase(HID_DOS_PATHS, NULL);
|
|
|
|
if (hSDB == NULL) {
|
|
DBGPRINT((sdlError, "SdbGetMatchingExe", "Failed to open the database.\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
bReleaseDatabase = TRUE;
|
|
}
|
|
|
|
pSdbContext = (PSDBCONTEXT)hSDB;
|
|
|
|
//
|
|
// Initialize matching mode - we set the InterType to none (meaning the first match will
|
|
// be used to start the process) and IntraType is set to normal (does not really matter)
|
|
//
|
|
|
|
MatchMode.Type = MATCH_NORMAL;
|
|
|
|
//
|
|
// Check whether we have an instrumented run
|
|
//
|
|
bInstrumented = SDBCONTEXT_IS_INSTRUMENTED(hSDB);
|
|
|
|
assert(pSdbContext->pdbMain && szPath);
|
|
|
|
RtlZeroMemory(&Context, sizeof(Context)); // do this so that we don't trip later
|
|
|
|
//
|
|
// We shall use it later to optimize file attribute retrieval
|
|
//
|
|
Context.hMainFile = INVALID_HANDLE_VALUE;
|
|
|
|
__try {
|
|
|
|
NTSTATUS Status;
|
|
TCHAR szCompatLayer[MAX_PATH + 1];
|
|
|
|
//
|
|
// Check for system exes that WE KNOW we don't want to patch
|
|
//
|
|
DBGPRINT((sdlInfo, "SdbGetMatchingExe", "Looking for \"%s\".\n", szPath));
|
|
|
|
if (_tcsnicmp(szPath, TEXT("\\??\\"), 4) == 0 ||
|
|
_tcsnicmp(szPath, TEXT("\\SystemRoot\\"), 12) == 0) {
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// If the search context had been supplied use it, otherwise create one
|
|
//
|
|
if (!SdbpCreateSearchDBContext(&Context, szPath, szModuleName, pszEnvironment)) {
|
|
DBGPRINT((sdlError, "SdbGetMatchingExe", "Failed to create search DB context.\n"));
|
|
goto out;
|
|
}
|
|
|
|
//
|
|
// Make sure no local database is opened.
|
|
//
|
|
SdbCloseLocalDatabase(hSDB);
|
|
|
|
if (!(dwFlags & SDBGMEF_IGNORE_ENVIRONMENT)) {
|
|
//
|
|
// See if there's an environment variable set called "__COMPAT_LAYER".
|
|
// If so, grab the layers from that variable.
|
|
//
|
|
dwBufferSize = sizeof(szCompatLayer) / sizeof(szCompatLayer[0]);
|
|
|
|
Status = SdbpGetEnvVar(pszEnvironment,
|
|
g_szCompatLayer,
|
|
szCompatLayer,
|
|
&dwBufferSize);
|
|
|
|
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
|
DBGPRINT((sdlWarning,
|
|
"SdbGetMatchingExe",
|
|
"__COMPAT_LAYER name cannot exceed 256 characters.\n"));
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
SdbParseLayerString(pSdbContext,
|
|
szCompatLayer,
|
|
pQueryResult,
|
|
&dwLayers,
|
|
&dwLayerFlags);
|
|
|
|
if (dwLayerFlags & LAYER_USE_NO_EXE_ENTRIES) {
|
|
//
|
|
// This is an exclusive matching case, once we determined
|
|
// that the layers cannot be appended to we get out.
|
|
//
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// At this point we might have all the info from the env variable.
|
|
// See if we do, and if so -- check bAppendLayer
|
|
//
|
|
dwBufferSize = sizeof(szCompatLayer);
|
|
|
|
if (SdbGetPermLayerKeys(szPath, szCompatLayer, &dwBufferSize, GPLK_ALL)) {
|
|
|
|
SdbParseLayerString(pSdbContext,
|
|
szCompatLayer,
|
|
pQueryResult,
|
|
&dwLayers,
|
|
&dwLayerFlags);
|
|
|
|
if (dwLayerFlags & LAYER_USE_NO_EXE_ENTRIES) {
|
|
goto out;
|
|
}
|
|
} else {
|
|
if (dwBufferSize > sizeof(szCompatLayer)) {
|
|
DBGPRINT((sdlWarning,
|
|
"SdbGetMatchingExe",
|
|
"Layers in registry cannot exceed %d characters\n",
|
|
sizeof(szCompatLayer)/sizeof(szCompatLayer[0])));
|
|
}
|
|
}
|
|
|
|
//
|
|
// This block deals with searching local sdbs
|
|
//
|
|
dwLocalIndex = 0;
|
|
|
|
while (SdbOpenNthLocalDatabase(hSDB, Context.szName, &dwLocalIndex, FALSE)) {
|
|
|
|
dwNumExes = SdbpSearchDB(pSdbContext,
|
|
pSdbContext->pdbLocal,
|
|
tSection,
|
|
&Context,
|
|
atiExes,
|
|
&guidExeID,
|
|
&dwExeFlags,
|
|
&MatchMode);
|
|
|
|
if (dwNumExes) {
|
|
pdb = pSdbContext->pdbLocal;
|
|
|
|
//
|
|
// Report matches in local sdb with mode
|
|
//
|
|
DBGPRINT((sdlInfo,
|
|
"SdbGetMatchingExe",
|
|
"Found in local database.\n"));
|
|
|
|
if (!bMatchComplete) {
|
|
|
|
//
|
|
// Add the match in
|
|
//
|
|
if (!SdbpAddMatch(pQueryResult,
|
|
pSdbContext,
|
|
pdb,
|
|
atiExes,
|
|
dwNumExes,
|
|
NULL, 0, // no layers
|
|
&guidExeID,
|
|
dwExeFlags,
|
|
&MatchMode)) {
|
|
//
|
|
// Failed to secure a match, stop matching
|
|
//
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have "current running state" flags in dwMatchingMode
|
|
//
|
|
if (MatchMode.Type != MATCH_ADDITIVE) {
|
|
|
|
if (bInstrumented) {
|
|
//
|
|
// We are running instrumented, prevent further storing of results
|
|
//
|
|
bMatchComplete = TRUE;
|
|
|
|
//
|
|
// Modify match mode so that we keep matching to see if
|
|
// we get any more matches.
|
|
//
|
|
MatchMode.Type = MATCH_ADDITIVE;
|
|
|
|
} else {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Note that we do not leak local sdb here since the match was made
|
|
// in a local sdb. Since we added the match, local sdb is "permanentized"
|
|
//
|
|
}
|
|
|
|
//
|
|
// If the match was added, there is no local db to close.
|
|
// However the call below will just (quietly) exit, no harm done.
|
|
//
|
|
SdbCloseLocalDatabase(hSDB);
|
|
}
|
|
|
|
//
|
|
// Search systest.sdb database
|
|
//
|
|
if (pSdbContext->pdbTest != NULL) {
|
|
dwNumExes = SdbpSearchDB(pSdbContext,
|
|
pSdbContext->pdbTest,
|
|
tSection,
|
|
&Context,
|
|
atiExes,
|
|
&guidExeID,
|
|
&dwExeFlags,
|
|
&MatchMode);
|
|
|
|
if (dwNumExes) {
|
|
pdb = pSdbContext->pdbTest;
|
|
|
|
if (!bMatchComplete) {
|
|
|
|
if (!SdbpAddMatch(pQueryResult,
|
|
pSdbContext,
|
|
pdb,
|
|
atiExes,
|
|
dwNumExes,
|
|
NULL,
|
|
0, // no layers
|
|
&guidExeID,
|
|
dwExeFlags,
|
|
&MatchMode)) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (MatchMode.Type != MATCH_ADDITIVE) {
|
|
if (bInstrumented) {
|
|
//
|
|
// We are running instrumented, prevent further storing of results
|
|
//
|
|
bMatchComplete = TRUE;
|
|
|
|
//
|
|
// Modify match mode so that we keep matching to see if we
|
|
// get any more matches.
|
|
//
|
|
MatchMode.Type = MATCH_ADDITIVE;
|
|
|
|
} else {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
DBGPRINT((sdlInfo, "SdbGetMatchingExe", "Using SysTest.sdb\n"));
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Search the main db
|
|
//
|
|
dwNumExes = SdbpSearchDB(pSdbContext,
|
|
pSdbContext->pdbMain,
|
|
tSection,
|
|
&Context,
|
|
atiExes,
|
|
&guidExeID,
|
|
&dwExeFlags,
|
|
&MatchMode);
|
|
if (dwNumExes) {
|
|
pdb = pSdbContext->pdbMain;
|
|
|
|
if (!bMatchComplete) {
|
|
|
|
if (!SdbpAddMatch(pQueryResult,
|
|
pSdbContext,
|
|
pdb,
|
|
atiExes,
|
|
dwNumExes,
|
|
NULL,
|
|
0, // no layers
|
|
&guidExeID,
|
|
dwExeFlags,
|
|
&MatchMode)) { // also match mode!!!
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
DBGPRINT((sdlInfo, "SdbGetMatchingExe", "Using Sysmain.sdb\n"));
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
//
|
|
// We are done matching. Before we return, we need to capture all the
|
|
// custom sdb entries that we used while producing the result of this query.
|
|
//
|
|
SdbpCaptureCustomSDBInformation(pQueryResult, pSdbContext);
|
|
|
|
} __except (SHIM_EXCEPT_HANDLER) {
|
|
RtlZeroMemory(pQueryResult, sizeof(SDBQUERYRESULT));
|
|
}
|
|
|
|
if (dwLayers >= SDB_MAX_LAYERS) {
|
|
DBGPRINT((sdlWarning,
|
|
"SdbGetMatchingExe",
|
|
"Hit max layer limit at %d. Perhaps we need to bump it.\n",
|
|
dwLayers));
|
|
}
|
|
|
|
//
|
|
// Free search context stuff
|
|
//
|
|
SdbpReleaseSearchDBContext(&Context);
|
|
|
|
if (bReleaseDatabase) {
|
|
SdbReleaseDatabase(hSDB);
|
|
}
|
|
|
|
return (pQueryResult->atrExes[0] != TAGREF_NULL ||
|
|
pQueryResult->atrLayers[0] != TAGREF_NULL);
|
|
}
|
|
|
|
|
|
void
|
|
SdbReleaseMatchingExe(
|
|
IN HSDB hSDB,
|
|
IN TAGREF trExe
|
|
)
|
|
/*++
|
|
Return: void.
|
|
|
|
Desc: Releases globally allocated data and closes a local database, if it exists.
|
|
The TAGREF of the exe is passed in purely for possible future use.
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(trExe);
|
|
|
|
SdbpCleanupLocalDatabaseSupport(hSDB);
|
|
}
|
|
|
|
SHIMVIEWER_OPTION g_eShimViewerOption = SHIMVIEWER_OPTION_UNINITIAZED;
|
|
|
|
#ifndef WIN32A_MODE
|
|
|
|
SHIMVIEWER_OPTION
|
|
SdbGetShowDebugInfoOption(
|
|
void
|
|
)
|
|
{
|
|
UNICODE_STRING ustrKeyPath = {0};
|
|
UNICODE_STRING ustrValue;
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE KeyHandle;
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
|
|
ULONG KeyValueBuffer[64];
|
|
ULONG KeyValueLength;
|
|
|
|
g_eShimViewerOption = SHIMVIEWER_OPTION_NO;
|
|
|
|
//
|
|
// Check if the user wants the debug spew. If for some reason we can't
|
|
// get the info, we'll return success anyway and not show any debug info.
|
|
//
|
|
if (!SdbpBuildUserKeyPath(APPCOMPAT_KEY_PATH_W_WITH_SLASH, &ustrKeyPath)) {
|
|
DBGPRINT((sdlWarning,
|
|
"GetShowDebugInfoOption",
|
|
"Failed to format current user key path for \"%s\"",
|
|
APPCOMPAT_LOCATION_W));
|
|
goto out;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&ustrKeyPath,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
status = NtOpenKey(
|
|
&KeyHandle,
|
|
KEY_QUERY_VALUE | SdbpGetWow64Flag(),
|
|
&ObjectAttributes);
|
|
|
|
SdbFree(ustrKeyPath.Buffer);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DBGPRINT((sdlWarning,
|
|
"GetShowDebugInfoOption",
|
|
"Failed to open Key HKCU\\%s Status 0x%lx",
|
|
APPCOMPAT_LOCATION_W,
|
|
status));
|
|
goto out;
|
|
}
|
|
|
|
KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyValueBuffer;
|
|
RtlInitUnicodeString(&ustrValue, SHIMENG_SHOW_DEBUG_INFO);
|
|
|
|
status = NtQueryValueKey(
|
|
KeyHandle,
|
|
&ustrValue,
|
|
KeyValuePartialInformation,
|
|
KeyValueInformation,
|
|
sizeof(KeyValueBuffer),
|
|
&KeyValueLength);
|
|
|
|
NtClose(KeyHandle);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DBGPRINT((sdlWarning,
|
|
"GetShowDebugInfoOption",
|
|
"Failed to read value info for value %s for key HKCU\\%s Status 0x%lx",
|
|
SHIMENG_SHOW_DEBUG_INFO,
|
|
APPCOMPAT_LOCATION_W,
|
|
status));
|
|
goto out;
|
|
}
|
|
|
|
if (KeyValueInformation->Type != REG_DWORD) {
|
|
DBGPRINT((sdlWarning,
|
|
"GetShowDebugInfoOption",
|
|
"Unexpected value type 0x%x for value %s under key HKCU\\%s",
|
|
KeyValueInformation->Type,
|
|
SHIMENG_SHOW_DEBUG_INFO,
|
|
APPCOMPAT_LOCATION_W));
|
|
goto out;
|
|
}
|
|
|
|
if (*(DWORD*)(&KeyValueInformation->Data[0]) != 0) {
|
|
g_eShimViewerOption = SHIMVIEWER_OPTION_YES;
|
|
}
|
|
|
|
out:
|
|
|
|
return g_eShimViewerOption;
|
|
}
|
|
|
|
#endif // WIN32A_MODE
|
|
|
|
int __cdecl
|
|
ShimDbgPrint(
|
|
int iLevelAndFlags,
|
|
PCH pszFunctionName,
|
|
PCH Format,
|
|
...
|
|
)
|
|
{
|
|
int nch = 0;
|
|
|
|
#ifdef _DEBUG_SPEW
|
|
|
|
CHAR Buffer[2048];
|
|
INT i;
|
|
PCH pchLevel = NULL;
|
|
PCH pchBuffer = Buffer;
|
|
PCH pchEnd = pchBuffer;
|
|
PCH pszFormat = NULL;
|
|
PCH pszMessage= Buffer;
|
|
va_list arglist;
|
|
size_t cchRemaining = CHARCOUNT(Buffer);
|
|
int iLevel = FILTER_DBG_LEVEL(iLevelAndFlags);
|
|
HSDB hSDB = NULL;
|
|
HRESULT hr;
|
|
BOOL bSendInfoToSV; // Do we want to send spew to shimviewer?
|
|
|
|
//
|
|
// Check to see whether the debug output is initialized
|
|
//
|
|
if (g_iShimDebugLevel == SHIM_DEBUG_UNINITIALIZED) {
|
|
g_iShimDebugLevel = GetShimDbgLevel();
|
|
}
|
|
|
|
//
|
|
// Check to see whether we need to print anything.
|
|
// The criteria is such that we won't print a thing if iLevel does not fit,
|
|
// but we will use the pipe when it is provided.
|
|
//
|
|
bSendInfoToSV = !!(iLevelAndFlags & sdlLogShimViewer);
|
|
|
|
if (!bSendInfoToSV && iLevel > g_iShimDebugLevel) {
|
|
return 0;
|
|
}
|
|
|
|
#ifndef WIN32A_MODE
|
|
|
|
if (bSendInfoToSV) {
|
|
if (g_eShimViewerOption == SHIMVIEWER_OPTION_UNINITIAZED) {
|
|
SdbGetShowDebugInfoOption();
|
|
}
|
|
}
|
|
|
|
#endif // WIN32A_MODE
|
|
|
|
PREPARE_FORMAT(pszFormat, Format);
|
|
|
|
if (pszFormat == NULL) {
|
|
|
|
//
|
|
// Can't convert format for debug output
|
|
//
|
|
return 0;
|
|
}
|
|
|
|
va_start(arglist, Format);
|
|
|
|
//
|
|
// Now on to the contents
|
|
//
|
|
if (bSendInfoToSV) {
|
|
//
|
|
// The first arg then is hSDB
|
|
//
|
|
hSDB = va_arg(arglist, HSDB);
|
|
|
|
//
|
|
// For pipe out we prepend output with [pid:0x%.8lx]
|
|
//
|
|
StringCchPrintfExA(pchBuffer,
|
|
CHARCOUNT(Buffer),
|
|
&pchEnd,
|
|
&cchRemaining,
|
|
0,
|
|
"[pid: 0x%.8lx]",
|
|
GetCurrentProcessId());
|
|
|
|
pszMessage = pchEnd;
|
|
}
|
|
|
|
//
|
|
// Do we have a comment for this debug level? if so, print it
|
|
//
|
|
for (i = 0; i < DEBUG_LEVELS; ++i) {
|
|
if (g_rgDbgLevelInfo[i].iLevel == iLevel) {
|
|
pchLevel = (PCH)g_rgDbgLevelInfo[i].szStrTag;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pchLevel == NULL) {
|
|
pchLevel = g_szDbgLevelUser;
|
|
}
|
|
|
|
StringCchPrintfExA(pchEnd,
|
|
cchRemaining,
|
|
&pchEnd,
|
|
&cchRemaining,
|
|
0,
|
|
"[%-4hs]",
|
|
pchLevel);
|
|
|
|
if (pszFunctionName) {
|
|
|
|
//
|
|
// Single-byte char going into UNICODE buffer
|
|
//
|
|
StringCchPrintfExA(pchEnd, cchRemaining, &pchEnd, &cchRemaining, 0, "[%-20hs] ", pszFunctionName);
|
|
}
|
|
|
|
//
|
|
// _vsntprintf this will not work for UNICODE Win2000
|
|
//
|
|
hr = StringCchVPrintfExA(pchEnd, cchRemaining, &pchEnd, &cchRemaining, 0, pszFormat, arglist);
|
|
|
|
if (FAILED(hr)) {
|
|
return 0;
|
|
}
|
|
|
|
va_end(arglist);
|
|
|
|
#ifndef WIN32A_MODE
|
|
|
|
if (bSendInfoToSV) {
|
|
SdbpWriteToShimViewer(hSDB, Buffer);
|
|
}
|
|
|
|
nch = DbgPrint("%s", pszMessage);
|
|
|
|
STACK_FREE(pszFormat);
|
|
|
|
#else // WIN32A_MODE
|
|
|
|
OutputDebugString(pszMessage);
|
|
|
|
nch = (int)(pchEnd - pszMessage);
|
|
|
|
#endif // WIN32A_MODE
|
|
|
|
#endif // _DEBUG_SPEW
|
|
|
|
return nch;
|
|
}
|