Leaked source code of windows server 2003
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

/*++
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("&amp;"), TEXT("&quot;"), TEXT("&lt;"), TEXT("&gt;") };
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;
}